1. 从零认识Raspberry Pi Pico:它到底是什么?
如果你对微控制器(Microcontroller)的世界感兴趣,或者想找一个比Arduino更强大、比树莓派(Raspberry Pi)更简单直接的开源硬件平台来入门,那么Raspberry Pi Pico绝对是你绕不开的一个选择。我第一次拿到这块小小的红色电路板时,就被它的设计哲学打动了:它不像传统的树莓派那样是一个完整的微型计算机,需要运行操作系统;它更像是一个功能强大的“智能开关”或“微型大脑”,专门用来感知和控制物理世界。简单来说,Raspberry Pi Pico是一款由树莓派基金会设计的低成本、高性能的微控制器开发板,它的核心是一颗名为RP2040的芯片,这也是树莓派基金会自主研发的第一款微控制器芯片。
那么,Pico能做什么呢?它的应用场景非常广泛。你可以用它来制作一个自动浇花系统,通过土壤湿度传感器控制水泵;可以做一个桌面天气站,显示温湿度和空气质量;可以驱动复杂的LED灯带,制作炫酷的光效;甚至可以作为一个USB输入设备,比如自定义键盘或游戏手柄。与Arduino相比,Pico的RP2040芯片主频更高(133MHz),内存更大(264KB SRAM),并且原生支持MicroPython和C/C++编程,对于有一定编程基础,尤其是熟悉Python的开发者来说,上手门槛极低。对于新手而言,MicroPython的交互式编程环境让你可以像在电脑上写Python脚本一样,一行行代码地控制硬件,即时看到效果,这种反馈感是学习嵌入式开发最大的乐趣之一。
2. 开箱与硬件初探:认识你的Pico
当你拿到一块Raspberry Pi Pico时,首先需要认识它的“身体”。板子虽然小巧,但接口和功能却一点也不含糊。正面最显眼的就是那颗RP2040芯片,它是整个板子的“心脏”。围绕芯片,我们需要重点关注以下几个部分:
2.1 核心引脚与功能区域
Pico板子的两侧有两排共40个引脚,这被称为“双列直插”封装,你可以直接将它插在面包板上进行原型开发,非常方便。这些引脚并非随意排列,每个都有其特定功能。我们需要快速识别几类关键引脚:
- 电源引脚:包括
3V3(OUT)(3.3伏输出)、VSYS(系统输入电压,1.8-5.5V)和GND(接地)。为外部传感器供电时,通常使用3V3(OUT)。 - GPIO引脚:这是最重要的部分,共26个可编程的通用输入输出引脚。它们可以用来读取按钮状态(输入)、点亮LED(输出)、与传感器通信等。引脚编号从
GP0到GP28(中间有缺失)。 - 特殊功能引脚:例如
ADC_VREF(模拟参考电压)、RUN(复位引脚)、以及支持I2C、SPI、UART等通信协议的引脚。这些协议是微控制器与各种传感器、显示屏“对话”的语言。
2.2 板载关键元件除了RP2040,板上还有几个重要的元件:
- BOOTSEL按钮:位于Micro USB接口旁边。这是进入“下载模式”的钥匙。当你需要给Pico刷写新的固件或程序时,需要先按住这个按钮,再将Pico连接到电脑。
- 用户可编程LED:一颗小小的LED灯,连接在
GP25引脚上。这是你成功运行第一个程序的“Hello World”指示灯。 - Micro USB接口:用于供电和通信。通过它,你的电脑既可以给Pico供电,也能与之进行串口通信,传输程序和数据。
注意:Pico的工作电压是3.3V,它的GPIO引脚耐受电压也是3.3V。绝对不要将5V的电压直接连接到任何GPIO引脚上,这很可能会永久性地损坏你的Pico。在为外部模块供电前,务必确认其电压要求。
3. 搭建开发环境:选择你的编程武器
给Pico编程主要有两大阵营:MicroPython和C/C++。对于绝大多数初学者和快速原型开发者,我强烈推荐从MicroPython开始。
3.1 为什么首选MicroPython?MicroPython是Python 3的精简版本,专为微控制器设计。它的语法和标准Python几乎一样,这意味着你有海量的学习资源和库可以借鉴。更重要的是,它支持交互式解释器(REPL)。你可以通过串口直接连接到Pico,像在电脑的Python Shell里一样,输入一行命令(比如print(“Hello”)或点亮一个LED),立刻就能看到结果。这种即时反馈对于学习和调试来说是无价的。相比之下,C/C++需要编译、链接、下载整个流程,虽然执行效率更高,但对新手不够友好。
3.2 安装MicroPython固件要让Pico运行MicroPython,首先需要将MicroPython的“操作系统”(固件)刷写到Pico上。这个过程非常简单:
- 访问树莓派基金会官网,找到Pico的MicroPython固件页面,下载最新的
.uf2文件。 - 断开Pico与电脑的连接。按住Pico板上的BOOTSEL按钮不放,然后将Micro USB线连接到电脑。此时,电脑会识别到一个名为
RPI-RP2的可移动磁盘。 - 将下载好的
.uf2文件拖拽或复制到这个磁盘里。Pico会自动重启,磁盘会消失。至此,你的Pico就变成了一个MicroPython解释器。
3.3 选择代码编辑器与连接工具固件刷好后,你需要一个工具来写代码并发送给Pico。这里有几个优秀的选择:
- Thonny:这是对初学者最友好的集成开发环境(IDE),没有之一。它内置了MicroPython支持,能自动检测并连接Pico,集成了REPL和文件管理功能。你可以在Thonny中直接编写代码,点击运行,代码就会上传到Pico并执行。
- Mu Editor:另一款轻量级的Python编辑器,同样对MicroPython有很好的支持,界面更简洁。
- VS Code with Pico-Go:如果你已经是VS Code的用户,可以安装
Pico-Go扩展。它提供了类似的功能,但配置稍复杂一些。
我个人在带新手入门时,百分之百推荐Thonny。它的“开箱即用”体验能让你在五分钟内完成从硬件连接到点亮第一个LED的全过程,极大增强了初学者的信心。
4. 第一个程序:点亮LED与基础GPIO控制
现在,让我们用Thonny完成与Pico的第一次“对话”。打开Thonny,在右下角选择解释器为“MicroPython (Raspberry Pi Pico)”,并选择正确的串口。连接成功后,Shell窗口(REPL)会出现>>>提示符。
4.1 控制板载LED板载LED连接在GP25上。在Shell里输入以下代码:
from machine import Pin led = Pin(25, Pin.OUT) led.value(1)回车后,你应该立刻看到Pico上的绿色LED被点亮。led.value(0)则会关闭它。这几行代码做了三件事:导入控制引脚的machine模块;将GP25引脚对象初始化为输出模式;给这个引脚输出高电平(1)来点亮LED。
4.2 编写并运行一个完整的脚本在Shell里单行执行很方便,但我们通常需要编写能保存和重复运行的程序。在Thonny的上方编辑区,新建一个文件,输入以下代码:
from machine import Pin import time led = Pin(25, Pin.OUT) while True: led.toggle() # 切换LED状态(亮/灭) time.sleep(0.5) # 等待0.5秒点击工具栏的“运行”按钮(绿色箭头)。Thonny会提示你保存文件,请将其保存到Pico上(文件名如main.py)。保存后,程序会自动开始运行,你会看到LED开始以1秒的间隔(亮0.5秒,灭0.5秒)闪烁。这就是一个完整的、无限循环的MicroPython程序。
4.3 理解main.py的特殊性这里有一个非常重要的细节:当你将程序保存为main.py并放在Pico的根目录下时,Pico在每次上电或复位后,都会自动运行这个文件。这让你可以制作“脱机”运行的项目。比如,将这个闪烁程序保存为main.py后,即使拔掉USB线,用电池给Pico供电,它一开机就会自动开始闪烁。如果你想停止自动运行,只需将文件改名或删除即可。
5. 深入GPIO:读取输入与外部中断
学会了输出,接下来学习输入。最经典的例子就是读取一个按钮的状态。
5.1 硬件连接与上拉电阻你需要一个按钮开关、一个电阻(约10kΩ)和几根杜邦线。将按钮的一端连接到Pico的某个GPIO引脚(例如GP15),另一端连接到GND。同时,在GP15和3V3之间连接一个10kΩ的电阻,这被称为“上拉电阻”。它的作用是,当按钮未按下时,通过电阻将GP15引脚的电平稳定地拉到高电平(3.3V);当按钮按下时,GP15直接与GND接通,电平变为低电平(0V)。这样,我们就能通过检测GP15的电平是1还是0,来判断按钮是否被按下。
注意:RP2040芯片内部也集成了可软件控制的上拉和下拉电阻。在代码中,我们可以通过
Pin.PULL_UP参数来启用内部上拉电阻,从而省去外部物理电阻。这对于简化电路非常有用,但需要知道这个功能的存在。
5.2 轮询方式读取按钮编写以下代码:
from machine import Pin import time button = Pin(15, Pin.IN, Pin.PULL_UP) # 设置为输入模式,并启用内部上拉电阻 while True: if button.value() == 0: # 按钮按下时,引脚被拉低到0 print("Button Pressed!") time.sleep(0.1) # 短暂延迟,防止打印过快这段代码采用“轮询”的方式,在循环中不断检查按钮的状态。它的缺点是CPU一直在忙碌地检查,效率不高,并且可能错过非常短暂的按键动作。
5.3 使用外部中断实现高效响应更好的方式是使用“中断”。中断允许CPU在正常执行程序时,由某个外部事件(如引脚电平变化)来打断,并立即执行一段特定的处理函数。
from machine import Pin import time led = Pin(25, Pin.OUT) button = Pin(15, Pin.IN, Pin.PULL_UP) def button_handler(pin): led.toggle() print("Interrupt! LED toggled.") # 配置中断:当引脚从高电平变为低电平(下降沿)时触发中断,调用button_handler函数 button.irq(trigger=Pin.IRQ_FALLING, handler=button_handler) # 主循环可以空着,或者做其他事情 while True: time.sleep(1) print("Main loop is running...")上传并运行这段代码。现在,每次按下按钮,LED的状态会立即切换,并且Shell中会打印信息。你会发现,即使主循环里有长时间的sleep或打印,按钮响应依然非常及时。这就是中断的强大之处——它实现了异步、事件驱动的编程模型,在嵌入式开发中至关重要。
6. 模拟信号与PWM:让控制更精细
数字世界只有0和1,但现实世界是连续的。Pico如何读取温度传感器的连续电压值?如何让LED的亮度平滑变化?这就需要模拟信号处理能力。
6.1 ADC:读取模拟信号RP2040有一个12位精度的模数转换器,连接在GP26、GP27、GP28三个引脚上(以及内部温度传感器)。我们可以用它来读取电位器(可调电阻)的电压。将电位器的两端分别接3V3和GND,中间引脚接GP26。
from machine import ADC, Pin import time adc = ADC(Pin(26)) # 在GP26上创建ADC对象 while True: reading = adc.read_u16() # 读取一个0-65535之间的原始值 voltage = reading * 3.3 / 65535 # 转换为电压值(0-3.3V) print("ADC Reading: {}, Voltage: {:.2f}V".format(reading, voltage)) time.sleep(0.5)旋转电位器,你会看到输出的电压值在0到3.3V之间变化。这个电压值可以对应到任何物理量,比如通过分压电路读取光敏电阻的值来感知光线强度。
6.2 PWM:输出模拟效果脉冲宽度调制(PWM)是一种用数字信号模拟模拟输出的技术。它通过快速开关引脚,并调整“开”的时间(占空比)比例,来控制平均电压。对于LED来说,高占空比更亮,低占空比更暗。对于电机来说,则控制转速。
from machine import Pin, PWM import time # 在GP15上创建PWM对象,频率设为1000Hz pwm = PWM(Pin(15)) pwm.freq(1000) # 呼吸灯效果 while True: # 亮度从0增加到最大(占空比从0到65535) for duty in range(0, 65535, 100): pwm.duty_u16(duty) time.sleep(0.001) # 亮度从最大减小到0 for duty in range(65535, 0, -100): pwm.duty_u16(duty) time.sleep(0.001)将LED(需串联一个约220Ω的限流电阻)正极接GP15,负极接GND,运行这段代码,你会看到LED实现了平滑的呼吸效果。PWM是控制舵机、直流电机、LED调光等应用的基石。
7. 通信协议入门:I2C与传感器实战
微控制器很少单打独斗,它需要与各种传感器、执行器、显示屏通信。最常用的两种协议是I2C和SPI。这里我们以I2C为例,连接一个常见的BMP280温度气压传感器。
7.1 I2C协议简介I2C是一种简单的两线制串行通信总线,只需要一根数据线(SDA)和一根时钟线(SCL)。它支持多个设备挂载在同一总线上,每个设备都有一个唯一的地址。Pico上有多个I2C通道,硬件I2C0通常对应GP0(SDA)和GP1(SCL),或者GP4(SDA)和GP5(SCL)。
7.2 连接BMP280传感器将BMP280模块的VCC接Pico的3V3,GND接GND,SDA接GP0,SCL接GP1。
7.3 编写读取程序MicroPython的machine模块提供了I2C支持。我们还需要BMP280的驱动库。你可以先在电脑上下载bmp280.py库文件,然后通过Thonny的文件管理器上传到Pico。
from machine import I2C, Pin import time import bmp280 # 初始化I2C0,使用GP0和GP1,频率设为100kHz i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=100000) # 扫描I2C总线上的设备地址 devices = i2c.scan() print("I2C devices found:", [hex(addr) for addr in devices]) # 初始化BMP280传感器 sensor = bmp280.BMP280(i2c) while True: # 读取温度和气压 temperature = sensor.temperature pressure = sensor.pressure print("Temperature: {:.2f} C, Pressure: {:.2f} hPa".format(temperature, pressure/100)) # 帕斯卡转百帕 time.sleep(2)运行代码,如果一切正常,你将在Shell中看到打印出的温度和气压值。这个过程清晰地展示了嵌入式开发的典型工作流:硬件连接 -> 初始化通信协议 -> 调用驱动库 -> 读取数据。掌握了I2C,你就可以轻松连接OLED屏幕、加速度计、温湿度传感器等数十种常用模块。
8. 项目管理与进阶思路
当你开始构建更复杂的项目时,代码管理、电源管理和性能优化就变得重要起来。
8.1 代码组织与模块化不要把所有的代码都堆在main.py里。合理的做法是:
- 将硬件初始化代码(如引脚定义、I2C设置)放在文件开头或单独的配置模块中。
- 将为特定传感器或功能编写的代码封装成函数或类,放在独立的
.py文件里(如sensor_reader.py,led_controller.py)。 - 在
main.py中导入这些模块,并编写主循环逻辑。这使得代码清晰、易维护、可复用。
8.2 低功耗考量Pico设计用于低功耗场景。如果你的项目由电池供电,需要考虑省电:
- 在循环中使用
time.sleep()让CPU休眠。 - 使用
machine.deepsleep()深度睡眠模式,这需要连接GPIO到RUN引脚来实现唤醒。 - 关闭未使用的外设模块。
8.3 性能与限制虽然MicroPython易用,但在处理高速数据流(如高频传感器采样、复杂图像处理)或需要极精确时序控制时,可能会遇到性能瓶颈。这时,你可以考虑:
- 使用MicroPython的
viper或native装饰器来编译性能关键的函数。 - 切换到C/C++开发环境(如官方的Pico SDK),这将带来巨大的性能提升,但代价是开发复杂度增加。
- 利用RP2040的可编程I/O(PIO)这一独门绝技。PIO是芯片上的小型独立处理器,可以编程来实现自定义的硬件接口协议(如WS2812B LED灯带的时序),几乎不占用CPU资源。这是Pico相比其他微控制器的一大优势,虽然学习曲线较陡,但能解决许多棘手问题。
从点亮第一个LED到读取传感器数据,再到理解中断和通信协议,你已经走完了Raspberry Pi Pico入门的核心路径。这块小板子的魅力在于,它用一个极其平易近人的入口(MicroPython),将你引向了一个深不见底的嵌入式世界。接下来,试着将学到的知识组合起来:做一个按下按钮就记录温度并显示在OLED屏上的小装置,或者用PWM控制电机的速度。真正的学习,始于动手。