DDZZ669 发表于 2022-11-26 17:03

玩转RP2040之Python开发环境搭建

<div class='showpostmsg'><p><br />
</p>

<p cid="n0" mdtype="paragraph">上篇文章:<a href="https://bbs.eeworld.com.cn/thread-1225624-1-1.html" target="_blank">玩转RP2040之开箱测评与上电运行</a>,介绍了RP2040的硬件和上电使用情况,本篇来进行软件开发环境的搭建。</p>

<p>&nbsp;</p>

<p cid="n2" mdtype="paragraph">RP2040支持Python或C语言开发,本篇使用Python来进行开发。</p>

<h1 cid="n3" mdtype="heading">1 软件环境搭建</h1>

<p cid="n4" mdtype="paragraph">这款RP2040板子与树莓派的另一款产品Pico的处理器都是RP2040,因此可以参考RaspberryPi Pico的教程:</p>

<p cid="n5" mdtype="paragraph"><a href="https://pico.wiki/index.php/2021/04/27/getting-started-with-raspberry-pi-pico-basic-intro.html">https://pico.wiki/index.php/2021/04/27/getting-started-with-raspberry-pi-pico-basic-intro.html</a></p>

<h2 cid="n6" mdtype="heading">1.1 下载Python固件</h2>

<p cid="n7" mdtype="paragraph">进入树莓派官网:<a href="https://www.raspberrypi.com/documentation/microcontrollers/micropython.html">https://www.raspberrypi.com/documentation/microcontrollers/micropython.html</a>,下载对应的Python固件,我下载的固件名称为:rp2-pico-20221116-unstable-v1.19.1-682-gd1ed0f161.uf2</p>

<p cid="n8" mdtype="paragraph"></p>

<p cid="n9" mdtype="paragraph">下载固件后,需要烧录到板子中,实际上,只需要将这个固件拖拽到板子中即可。</p>

<p cid="n10" mdtype="paragraph">操作步骤为:</p>

<ul cid="n11" data-mark="-" mdtype="list">
        <li cid="n12" mdtype="list_item">
        <p cid="n13" mdtype="paragraph">按下BOOT和RESET,然板子复位</p>
        </li>
        <li cid="n14" mdtype="list_item">
        <p cid="n15" mdtype="paragraph">松开RESET(BOOT仍按下),然板子进入BOOT</p>
        </li>
        <li cid="n16" mdtype="list_item">
        <p cid="n17" mdtype="paragraph">等电脑上弹出RPI-RP2的盘符(文件夹)后,可松开BOOT</p>
        </li>
        <li cid="n18" mdtype="list_item">
        <p cid="n19" mdtype="paragraph">然后把下载的python固件拖拽到这个盘中即可</p>
        </li>
        <li cid="n20" mdtype="list_item">
        <p cid="n21" mdtype="paragraph">拖拽成功后,盘符会自动消失,此时固件烧录工作即完成</p>
        </li>
</ul>

<p cid="n22" mdtype="paragraph"></p>

<p cid="n23" mdtype="paragraph">注意,固件烧录后,板子自动的程序也会消失,所以此时再重启板子,会是黑屏状态。</p>

<h2 cid="n24" mdtype="heading">1.2 下载Thonny</h2>

<p cid="n25" mdtype="paragraph">Thonny为 一个面向初学者的Python IDE</p>

<p cid="n26" mdtype="paragraph">去Thonny官网:<a href="https://thonny.org/">https://thonny.org/</a> 下载Windows版的安装包,安装即可。</p>

<p cid="n27" mdtype="paragraph"></p>

<h1 cid="n28" mdtype="heading">2 程序烧录测试</h1>

<p cid="n29" mdtype="paragraph">板子连接电脑,用Thonny打开Python例程,右下角切换到Pi Pico,然后点击左上角的下载键。</p>

<p cid="n30" mdtype="paragraph"></p>

<p cid="n31" mdtype="paragraph">下载完成后,即可看到程序的运行结果:</p>

<p cid="n32" mdtype="paragraph"></p>

<p cid="n33" mdtype="paragraph">注意,这种下载方式,程序还行没有固化到板子中,掉电重启后,程序也不在了,需要重新进行程序下载才能看到程序的运行。</p>

<h1 cid="n34" mdtype="heading">3 程序固化到板子中</h1>

<p cid="n35" mdtype="paragraph">研究了一下Thonny这个软件,发现可以将Python程序放到板子中,操作方法是点击菜单中的文件-&gt;另存为,会弹出一个窗口,提示保存到电脑还是Pico中,选择Pico后,即可保存python文件到板子中。</p>

<p cid="n36" mdtype="paragraph"></p>

<p cid="n37" mdtype="paragraph">在保存的时候,还可以重命名文件,如我的重命名为main.py。注意到,保存到板子中的文件,Thonny中的文件名会显示一个中括号,并且Thonny窗口的顶部信息也会显示此文件在Pico中。</p>

<p cid="n38" mdtype="paragraph"></p>

<p cid="n39" mdtype="paragraph">此时点击运行,运行的就是板子中的python程序,并且板子调电后,也能开机运行板子中的python程序,从而可以说明程序已经固化到板子中了。</p>

<h1 cid="n40" mdtype="heading">4 多文件项目结构</h1>

<p cid="n41" mdtype="paragraph">上面的测试程序,整个代码都是在一个.py文件中,不便于代码分类管理。实际上,我们可以将代码按功能进行拆分,也是也可在板子中运行的。我这里将LCD和IMU的代码单独分离出来,整理为3个文件:</p>

<ul cid="n42" data-mark="-" mdtype="list">
        <li cid="n43" mdtype="list_item">
        <p cid="n44" mdtype="paragraph">main.py</p>
        </li>
        <li cid="n45" mdtype="list_item">
        <p cid="n46" mdtype="paragraph">mylcd.py</p>
        </li>
        <li cid="n47" mdtype="list_item">
        <p cid="n48" mdtype="paragraph">myimu.py</p>
        </li>
</ul>

<p cid="n49" mdtype="paragraph">注意,在运行时,需要将这3个文件都放到板子中再点击运行,不放到板子中,运行main.py,会报错找不到另外两个文件的。</p>

<p cid="n50" mdtype="paragraph">main.py</p>

<pre style="background:#555; padding:10px; color:#ddd !important;">
from machine import Pin,I2C,SPI,PWM,ADC
import mylcd
import myimu
import time

Vbat_Pin = 29

#主函数
if __name__==&#39;__main__&#39;:
&nbsp; &nbsp;#LCD
&nbsp; &nbsp;LCD = mylcd.LCD_GC9A01A()
&nbsp; &nbsp;LCD.set_bl_pwm(65535)
&nbsp; &nbsp;
&nbsp; &nbsp;#IMU
&nbsp; &nbsp;qmi8658=myimu.IMU_QMI8658C()
&nbsp; &nbsp;
&nbsp; &nbsp;#ADC
&nbsp; &nbsp;Vbat= ADC(Pin(Vbat_Pin)) &nbsp;
&nbsp; &nbsp;
&nbsp; &nbsp;while(True):
&nbsp; &nbsp; &nbsp; &nbsp;#read QMI8658
&nbsp; &nbsp; &nbsp; &nbsp;xyz=qmi8658.Read_XYZ()
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;LCD.fill(LCD.white)
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;LCD.fill_rect(0,0,240,40,LCD.red)
&nbsp; &nbsp; &nbsp; &nbsp;LCD.text(&quot;RP2040-LCD-1.28&quot;,60,25,LCD.white)
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;LCD.fill_rect(0,40,240,40,LCD.blue)
&nbsp; &nbsp; &nbsp; &nbsp;LCD.text(&quot;Waveshare&quot;,80,57,LCD.white)
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;LCD.fill_rect(0,80,120,120,0x1805)
&nbsp; &nbsp; &nbsp; &nbsp;LCD.text(&quot;ACC_X={:+.2f}&quot;.format(xyz),20,100-3,LCD.white)
&nbsp; &nbsp; &nbsp; &nbsp;LCD.text(&quot;ACC_Y={:+.2f}&quot;.format(xyz),20,140-3,LCD.white)
&nbsp; &nbsp; &nbsp; &nbsp;LCD.text(&quot;ACC_Z={:+.2f}&quot;.format(xyz),20,180-3,LCD.white)

&nbsp; &nbsp; &nbsp; &nbsp;LCD.fill_rect(120,80,120,120,0xF073)
&nbsp; &nbsp; &nbsp; &nbsp;LCD.text(&quot;GYR_X={:+3.2f}&quot;.format(xyz),125,100-3,LCD.white)
&nbsp; &nbsp; &nbsp; &nbsp;LCD.text(&quot;GYR_Y={:+3.2f}&quot;.format(xyz),125,140-3,LCD.white)
&nbsp; &nbsp; &nbsp; &nbsp;LCD.text(&quot;GYR_Z={:+3.2f}&quot;.format(xyz),125,180-3,LCD.white)
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;LCD.fill_rect(0,200,240,40,0x180f)
&nbsp; &nbsp; &nbsp; &nbsp;reading = Vbat.read_u16()*3.3/65535*2
&nbsp; &nbsp; &nbsp; &nbsp;LCD.text(&quot;Vbat={:.2f}&quot;.format(reading),80,215,LCD.white)
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;LCD.show()
&nbsp; &nbsp; &nbsp; &nbsp;time.sleep(0.1)</pre>

<p cid="n52" mdtype="paragraph">myimu.py</p>

<pre style="background:#555; padding:10px; color:#ddd !important;">
from machine import Pin,I2C,SPI,PWM,ADC

I2C_SDA = 6
I2C_SDL = 7

#IMU传感器--IIC接口
class IMU_QMI8658C(object):
&nbsp; &nbsp;def __init__(self,address=0X6B):
&nbsp; &nbsp; &nbsp; &nbsp;self._address = address
&nbsp; &nbsp; &nbsp; &nbsp;self._bus = I2C(id=1,scl=Pin(I2C_SDL),sda=Pin(I2C_SDA),freq=100_000)
&nbsp; &nbsp; &nbsp; &nbsp;bRet=self.WhoAmI()
&nbsp; &nbsp; &nbsp; &nbsp;if bRet :
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;self.Read_Revision()
&nbsp; &nbsp; &nbsp; &nbsp;else &nbsp;:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return NULL
&nbsp; &nbsp; &nbsp; &nbsp;self.Config_apply()

&nbsp; &nbsp;def _read_byte(self,cmd):
&nbsp; &nbsp; &nbsp; &nbsp;rec=self._bus.readfrom_mem(int(self._address),int(cmd),1)
&nbsp; &nbsp; &nbsp; &nbsp;return rec
&nbsp; &nbsp;def _read_block(self, reg, length=1):
&nbsp; &nbsp; &nbsp; &nbsp;rec=self._bus.readfrom_mem(int(self._address),int(reg),length)
&nbsp; &nbsp; &nbsp; &nbsp;return rec
&nbsp; &nbsp;def _read_u16(self,cmd):
&nbsp; &nbsp; &nbsp; &nbsp;LSB = self._bus.readfrom_mem(int(self._address),int(cmd),1)
&nbsp; &nbsp; &nbsp; &nbsp;MSB = self._bus.readfrom_mem(int(self._address),int(cmd)+1,1)
&nbsp; &nbsp; &nbsp; &nbsp;return (MSB &lt;&lt; 8) + LSB
&nbsp; &nbsp;def _write_byte(self,cmd,val):
&nbsp; &nbsp; &nbsp; &nbsp;self._bus.writeto_mem(int(self._address),int(cmd),bytes())
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp;def WhoAmI(self):
&nbsp; &nbsp; &nbsp; &nbsp;bRet=False
&nbsp; &nbsp; &nbsp; &nbsp;if (0x05) == self._read_byte(0x00):
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;bRet = True
&nbsp; &nbsp; &nbsp; &nbsp;return bRet
&nbsp; &nbsp;def Read_Revision(self):
&nbsp; &nbsp; &nbsp; &nbsp;return self._read_byte(0x01)
&nbsp; &nbsp;def Config_apply(self):
&nbsp; &nbsp; &nbsp; &nbsp;# REG CTRL1
&nbsp; &nbsp; &nbsp; &nbsp;self._write_byte(0x02,0x60)
&nbsp; &nbsp; &nbsp; &nbsp;# REG CTRL2 : QMI8658AccRange_8gand QMI8658AccOdr_1000Hz
&nbsp; &nbsp; &nbsp; &nbsp;self._write_byte(0x03,0x23)
&nbsp; &nbsp; &nbsp; &nbsp;# REG CTRL3 : QMI8658GyrRange_512dps and QMI8658GyrOdr_1000Hz
&nbsp; &nbsp; &nbsp; &nbsp;self._write_byte(0x04,0x53)
&nbsp; &nbsp; &nbsp; &nbsp;# REG CTRL4 : No
&nbsp; &nbsp; &nbsp; &nbsp;self._write_byte(0x05,0x00)
&nbsp; &nbsp; &nbsp; &nbsp;# REG CTRL5 : Enable Gyroscope And Accelerometer Low-Pass Filter
&nbsp; &nbsp; &nbsp; &nbsp;self._write_byte(0x06,0x11)
&nbsp; &nbsp; &nbsp; &nbsp;# REG CTRL6 : Disables Motion on Demand.
&nbsp; &nbsp; &nbsp; &nbsp;self._write_byte(0x07,0x00)
&nbsp; &nbsp; &nbsp; &nbsp;# REG CTRL7 : Enable Gyroscope And Accelerometer
&nbsp; &nbsp; &nbsp; &nbsp;self._write_byte(0x08,0x03)

&nbsp; &nbsp;def Read_Raw_XYZ(self):
&nbsp; &nbsp; &nbsp; &nbsp;xyz=
&nbsp; &nbsp; &nbsp; &nbsp;raw_timestamp = self._read_block(0x30,3)
&nbsp; &nbsp; &nbsp; &nbsp;raw_acc_xyz=self._read_block(0x35,6)
&nbsp; &nbsp; &nbsp; &nbsp;raw_gyro_xyz=self._read_block(0x3b,6)
&nbsp; &nbsp; &nbsp; &nbsp;raw_xyz=self._read_block(0x35,12)
&nbsp; &nbsp; &nbsp; &nbsp;timestamp = (raw_timestamp&lt;&lt;16)|(raw_timestamp&lt;&lt;8)|(raw_timestamp)
&nbsp; &nbsp; &nbsp; &nbsp;for i in range(6):
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# xyz=(raw_acc_xyz[(i*2)+1]&lt;&lt;8)|(raw_acc_xyz)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# xyz=(raw_gyro_xyz[((i+3)*2)+1]&lt;&lt;8)|(raw_gyro_xyz[(i+3)*2])
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;xyz = (raw_xyz[(i*2)+1]&lt;&lt;8)|(raw_xyz)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if xyz &gt;= 32767:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;xyz = xyz-65535
&nbsp; &nbsp; &nbsp; &nbsp;return xyz
&nbsp; &nbsp;def Read_XYZ(self):
&nbsp; &nbsp; &nbsp; &nbsp;xyz=
&nbsp; &nbsp; &nbsp; &nbsp;raw_xyz=self.Read_Raw_XYZ() &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;#QMI8658AccRange_8g
&nbsp; &nbsp; &nbsp; &nbsp;acc_lsb_div=(1&lt;&lt;12)
&nbsp; &nbsp; &nbsp; &nbsp;#QMI8658GyrRange_512dps
&nbsp; &nbsp; &nbsp; &nbsp;gyro_lsb_div = 64
&nbsp; &nbsp; &nbsp; &nbsp;for i in range(3):
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;xyz=raw_xyz/acc_lsb_div#(acc_lsb_div/1000.0)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;xyz=raw_xyz*1.0/gyro_lsb_div
&nbsp; &nbsp; &nbsp; &nbsp;return xyz</pre>

<p cid="n54" mdtype="paragraph">mylcd.py</p>

<pre style="background:#555; padding:10px; color:#ddd !important;">
from machine import Pin,I2C,SPI,PWM,ADC
import framebuf
import time

DC = 8
CS = 9
SCK = 10
MOSI = 11
RST = 12

BL = 25


#屏幕--SPI接口
class LCD_GC9A01A(framebuf.FrameBuffer):
&nbsp; &nbsp;def __init__(self):
&nbsp; &nbsp; &nbsp; &nbsp;self.width = 240 #屏幕宽度
&nbsp; &nbsp; &nbsp; &nbsp;self.height = 240 #屏幕高度
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;self.cs = Pin(CS,Pin.OUT)
&nbsp; &nbsp; &nbsp; &nbsp;self.rst = Pin(RST,Pin.OUT)
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;self.cs(1)
&nbsp; &nbsp; &nbsp; &nbsp;self.spi = SPI(1,100_000_000,polarity=0, phase=0,sck=Pin(SCK),mosi=Pin(MOSI),miso=None)
&nbsp; &nbsp; &nbsp; &nbsp;self.dc = Pin(DC,Pin.OUT)
&nbsp; &nbsp; &nbsp; &nbsp;self.dc(1)
&nbsp; &nbsp; &nbsp; &nbsp;self.buffer = bytearray(self.height * self.width * 2)
&nbsp; &nbsp; &nbsp; &nbsp;super().__init__(self.buffer, self.width, self.height, framebuf.RGB565)
&nbsp; &nbsp; &nbsp; &nbsp;self.init_display()
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;self.red &nbsp; = &nbsp; 0x07E0
&nbsp; &nbsp; &nbsp; &nbsp;self.green = &nbsp; 0x001f
&nbsp; &nbsp; &nbsp; &nbsp;self.blue= &nbsp; 0xf800
&nbsp; &nbsp; &nbsp; &nbsp;self.white = &nbsp; 0xffff
&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;self.fill(self.white) #先填充为白色
&nbsp; &nbsp; &nbsp; &nbsp;self.show()

&nbsp; &nbsp; &nbsp; &nbsp;self.pwm = PWM(Pin(BL))
&nbsp; &nbsp; &nbsp; &nbsp;self.pwm.freq(5000)
#省略......</pre>

<p cid="n56" mdtype="paragraph">将这3个文件保存到板子中的演示图如下,可以看到3个文件名都有中括号:</p>

<p cid="n57" mdtype="paragraph"></p>

<p cid="n58" mdtype="paragraph">在main.py上运行,可以运行成功,说明程序在板子中运行正常。</p>

<h1 cid="n59" mdtype="heading">5 总结</h1>

<p cid="n60" mdtype="paragraph">本篇介绍了RP2040的Python软件开发环境搭建,并进行了程序烧录测试、代码固化到板子中测试,Python项目拆分为多个文件运行测试。Thonny这个软件第一次用,可能还有一些功能没探索到,大家有哪里使用心得欢迎讨论分享。</p>
</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                                                                                (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                        }                </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>

Honghuzaitian 发表于 2022-11-27 00:31

很简单易学,这个板子试玩过,还不错,用来学MP可以的

dcexpert 发表于 2022-11-27 10:42

<p>thonny可以通过串口输出数据,自动画出折线图,这个功能比较有用</p>

DDZZ669 发表于 2022-11-27 13:59

dcexpert 发表于 2022-11-27 10:42
thonny可以通过串口输出数据,自动画出折线图,这个功能比较有用

<p>又get到一个未探索的功能,有时间试试<img height="48" src="https://bbs.eeworld.com.cn/static/editor/plugins/hkemoji/sticker/facebook/handshake.gif" width="48" /></p>
页: [1]
查看完整版本: 玩转RP2040之Python开发环境搭建