尧图精选

树莓派Pico串口通信实战:硬件接线、MicroPython编程与故障排查

🕒 发布时间:2026/9/7 11:36:23 📁 来源:尧图网络
拿到树莓派Pico想通过串口跟电脑、传感器、电机驱动板或者另一块单片机通信这几乎是绕不开的一步。Pico这块板子的串口通信说简单也简单MicroPython里几行代码就能收发数据说麻烦也麻烦引脚复用、电平匹配、波特率误差、缓冲区溢出任何一个环节没搞明白都会让你在调试台前怀疑人生。我前后用Pico做了不少项目从最简单的开发板串口打印到通过串口控制舵机、对接RS485电表、跟Unity客户端做数据交互踩过的坑不算少。这篇文章就把Pico串口通信这件事从头到尾捋一遍硬件上哪些引脚能用、MicroPython代码怎么写、串口调试工具怎么选、以及各种奇奇怪怪的故障怎么排查。适合刚入手Pico想跑通串口的新手也适合做实际项目时遇到通信问题的老哥对照着查。1. 为什么Pico的串口通信值得单独讲一篇1.1 Pico串口通信的硬件底子树莓派Pico的核心是RP2040芯片双核ARM Cortex-M0处理器主频最高能跑到133MHz。别看M0核心小外设其实很齐全两个UART外设编号UART0和UART1每个都支持完整的串口功能发送、接收、硬件流控CTS/RTS还能映射到多组GPIO引脚上。先说结论Pico的串口通信大体分两类。一类是USB虚拟串口也就是你用MicroUSB线把Pico插到电脑上Thonny里看到的那个REPL交互界面本质是通过USB CDC模拟出来的串口适合打印调试信息。另一类是真正的硬件UART串口走GPIO引脚比如GP0、GP1或者GP4、GP5适合跟外部设备通信比如STM32、ESP32、GPS模块、指纹模块、舵机控制板、RS232/RS485转接设备等。这两个串口是独立的你完全可以在USB串口上打印日志同时用硬件UART跟下位机设备对话互不干扰。这就引出一个很多新手容易混淆的点你在Thonny里打开串口监视器看到的其实是USB虚拟串口而不是Pico的硬件UART。如果你想让Pico的GP0和GP1对外发数据光在Thonny里操作是不够的必须写MicroPython代码主动初始化硬件UART通过引脚发出去。1.2 串口在Pico项目里的角色串口在嵌入式项目里的地位有点像家庭里的水管系统平时感觉不到它的存在一旦出问题整个项目就瘫了。我用Pico做的几个项目里串口的用途大概有这几类第一类是调试输出。程序跑起来之后关键变量的值、运行状态、错误信息通过串口打到电脑上看。这种场景USB虚拟串口就够了Thonny的Shell窗口就是干这个的。第二类是与外设通信。Pico作为主控通过硬件UART去控制舵机、读取传感器数据、跟电池管理系统BMS板对话。这种场景需要用GPIO引脚上的硬件UART。第三类是跟其他上位机/设备联调。比如做一个Pico的数据采集器把环境数据通过串口发给电脑上的Python脚本或者Unity客户端或者反过来Unity发送控制指令Pico接收后去操作舵机。这种场景中电脑端要么用物理USB转TTL线接到Pico的UART引脚要么就把Pico当作USB设备做串口通信需要单独刷USB Host或USB设备固件。我甚至还碰到过用Pico的UART去解析串口屏幕指令的项目类似陶晶驰串口屏跟单片机通信的思路。所以串口通信不仅是基础技能更是实际项目中比GPIO点灯重要得多的硬功夫。2. 硬件接线与引脚选择别在这个环节翻车2.1 UART引脚复用规则速查Pico的引脚布局网上到处都有我这里直接给一份跟UART相关的速查表省得你们再去翻手册。UART外设TX引脚选项RX引脚选项UART0GP0、GP12、GP16GP1、GP13、GP17UART1GP4、GP8、GP20GP5、GP9、GP21MicroPython里默认情况下UART0用的就是GP0TX和GP1RXUART1用的就是GP4TX和GP5RX。但这两个UART并不是被锁死在这几个引脚上Pico的GPIO矩阵允许你把UART功能映射到很多引脚具体哪些能映射需要查数据手册的GPIO功能表。有个实操技巧设计PCB或者面包板接线的时候优先用GP0/GP1或者GP4/GP5因为MicroPython的默认配置免去了一步绑定引脚的麻烦。如果你要做复杂一点的项目需要用GP0做别的功能那再把UART映射到其他引脚初始化时手动指定tx和rx参数就行了。需要留意的是部分引脚在同一时刻只能选一种外设功能比如你GP12已经做了PWM舵机那么UART0的TX就不能用GP12了这个在资源紧张的板子上很容易打架。所以规划引脚时要先把UART通道留出来剩下的再去分配GPIO。2.2 接线时的四个关键细节接线这部分看着简单实际上是最容易出玄学问题的地方。我总结了四个关键点第一交叉连接。两个设备串口互联一定是设备A的TX接设备B的RX设备A的RX接设备B的TX中间必须共地。很多人第一次接线把两个TX接在一起结果什么都收不到然后开始怀疑代码写错了。如果你用USB转TTL模块连PicoUSB转TTL的TX要接Pico的RX引脚USB转TTL的RX要接Pico的TX引脚顺序千万不能反。第二电平匹配。Pico的GPIO是3.3V逻辑电平TTL电平标准的传感器模块大多兼容3.3V可以直接怼上去。但如果是RS232电平的设备比如老式工控机串口、RS485总线设备绝不能直接接必须通过MAX3232、MAX485这类电平转换芯片。RS232电平是正负12V直接接Pico会把GPIO烧掉RS485是差分信号原理上就是另一套协议。我接过一个正泰电表的485调试中间就放了一个RS485转TTL模块电源也要单独供别指望Pico的3.3V能带动整个485总线。第三避免带电插拔。USB转TTL模块跟Pico之间最好在断电状态下接线。带电插拔的时候很容易造成瞬时电压尖峰轻则导致通信异常重则损坏GPIO。我自己就干过一次接好的线没断电就重新拔插结果Pico那个GPIO烧了后面只能换引脚。第四上拉电阻。个别情况下如果外设的TX引脚在空闲时是浮空状态会导致接收端不断收到乱码。解决办法是在RX引脚上加一个10kΩ左右的上拉电阻把空闲电平拉到高电平这样串口线路上没有说话的时候呈现的是稳定的停止位状态。3. MicroPython环境下串口编程从收发到实用封装3.1 UART初始化关键参数怎么定MicroPython中初始化UART很简单核心是machine.UART类。最基本的写法是这样from machine import UART, Pin # 使用UART0默认引脚GP0(TX)和GP1(RX) uart UART(0, baudrate9600, txPin(0), rxPin(1))关键在于参数选择。baudrate波特率是每秒传输的bit数常见的有9600、19200、38400、115200。选多少主要看外设要求GPS模块一般用9600蓝牙模块很多默认是9600或115200跟电脑调试我习惯用115200速度更快。要注意的是部分老设备对波特率误差很敏感如果两端标称波特率不一致或者使用了劣质USB转TTL芯片通信直接就是乱码。除了波特率还有几个参数需要注意bits默认8位parity校验位默认Nonestop停止位默认1。绝大多数场景下8数据位、无校验、1停止位也就是常说的8N1是嵌入式世界的事实标准。timeout参数用于控制接收超时单位是毫秒。这个参数直接影响read()和readline()的行为如果不设置默认情况下可能会阻塞等待很长一段时间。建议在初始化时显式加上uart UART(0, baudrate115200, txPin(0), rxPin(1), timeout500)意思就是读取时最多等500毫秒没数据就返回None或空字节避免程序卡死。3.2 最简单的串口收发测试初始化好之后发送数据用write()方法接收数据用read()或者readline()。最简单的一个测试程序from machine import UART, Pin import time uart UART(0, baudrate115200, txPin(0), rxPin(1), timeout100) uart.write(Hello from Pico!\r\n) while True: if uart.any(): # 有数据可读 data uart.read() # 读取所有可用数据 uart.write(Received: data \r\n) time.sleep_ms(10)这里的uart.any()返回接收缓冲区中的字节数非0说明有数据。uart.read()默认读取所有缓冲区里的内容如果你想按长度读取可以传参比如uart.read(4)读取4个字节。测试的时候用USB转TTL模块把Pico的GP0和GP1连到电脑打开任意一个串口调试助手选对COM口号和波特率就能看到Pico发来的Hello from Pico!。你在电脑上发送任意字符串Pico收到后会原样返回再加上Received: 前缀。这里有一个容易被忽略的细节MicroPython的UART接收是有缓冲区上限的Pico的硬件UART引脚上有16字节硬件FIFO再加软件buffer。如果数据来得快而你读得慢缓冲区满了之后新数据会直接丢弃。这就是后面讲丢字节问题的一个根源。3.3 进阶中断接收、环形缓冲区与协议解析实际项目中轮询读取uart.any()这种方式太粗糙了。比如你要一边处理舵机控制一边接收串口指令如果主循环被舵机占用了太多时间串口数据就会丢失。这时候有两种进阶方案一种是用中断或后台线程接收另一种是做一个环形缓冲区。MicroPython中可以用uart.irq()来注册接收中断from machine import UART, Pin import time uart UART(1, baudrate115200, txPin(4), rxPin(5)) received [] def uart_handler(u): if u.any(): received.append(u.read(1)) uart.irq(handleruart_handler, triggerUART.IRQ_RX) while True: if received: line b.join(received) print(line) received.clear() time.sleep_ms(20)UART.IRQ_RX会在接收到数据时触发中断这样即使主循环在处理其他事情也不会漏掉串口数据。另一种做法是用环形缓冲区这个在数据量稍大的时候更可靠。环形缓冲区本质上是一个固定大小的数组一个写指针和一个读指针新数据往写指针处放读数据从读指针处取指针到末尾后回绕到开头。class RingBuffer: def __init__(self, size256): self.buf bytearray(size) self.head 0 self.tail 0 self.size size def put(self, data): for b in data: self.buf[self.head] b self.head (self.head 1) % self.size def get(self, lengthNone): if self.head self.tail: return b if length is None: data bytearray() while self.head ! self.tail: data.append(self.buf[self.tail]) self.tail (self.tail 1) % self.size return bytes(data) data bytearray() for _ in range(length): if self.head self.tail: break data.append(self.buf[self.tail]) self.tail (self.tail 1) % self.size return bytes(data)拿到完整数据后通常还要做协议解析。比如你和上位机约定好帧格式帧头0xAA、数据长度、命令字、数据、校验和。解析的逻辑通常是先查找帧头然后根据长度取完整一帧再做校验。这期间要用一个状态机或者简单的标记变量来记录找帧头的阶段避免每次都从0开始。我之前做Pico控制舵机的项目就是通过串口接收上位机发送的三字节指令帧头0xAA、舵机编号、角度值。Pico解析后映射到对应的PWM通道驱动舵机转到指定角度。串口链路在这里就是整个系统的神经线上位机一挥手舵机就跟着动。4. 串口调试工具选型别只用串口助手下拉框4.1 Windows/Linux下的图形化与命令行工具串口调试这件事工具选对了效率翻一倍。我平时电脑上同时装着好几款工具用途不一样。Windows下最常用的几款PuTTY老牌工具除了SSH它的串口模式也很好用。打开后选Serial填COM口和波特率就能直接连。优点是轻量、稳定缺点是发十六进制数据不太方便适合看文本日志。MobaXterm颜值高功能全左边文件树右边终端会话串口、SSH、SFTP都能管。如果你想在一个工具里同时管理多台设备的串口和SSH这个推荐。SSCOM老工程师都知道的经典串口调试助手界面朴素但功能扎实支持发送十六进制、周期发送、时间戳显示。用来跟设备调试二进制协议很顺手。Serial Studio这是一款开源的可视化串口调试工具能把串口数据解析成曲线图、仪表盘适合做传感器数据可视化。Pico发一串CSV格式数据过来Serial Studio直接画成波形省得自己写Python脚本画图。Linux下我一般用命令行工具# 查看串口设备 ls /dev/ttyUSB* /dev/ttyACM* # minicom -D /dev/ttyUSB0 -b 115200 minicom -D /dev/ttyUSB0 -b 115200 # 或者用更简单的screen screen /dev/ttyUSB0 115200Linux下用Python pyserial做自动化测试也特别方便后面细说。另外提一嘴有些场景你需要在宿主机Windows上跟VMware里的Linux虚拟机进行串口通信。这个不是Pico本身的问题但做嵌入式开发时经常遇到。VMware里给虚拟机添加串口设备可以把它映射到Windows宿主机的物理串口或者映射到命名管道如\\.\pipe\com_1这时候Windows宿主机上用带命名管道支持的串口工具就能跟虚拟机的串口对上话。思路就是物理USB转TTL插在Windows上Windows上开一个软件把这个串口数据转发给VMware的虚拟串口虚拟机里的Linux再访问/dev/ttyS0。这个方案适合在Linux里跑编译工具链同时又要用Linux下的串口调试工具来调试开发板的情况。4.2 Python第三方库pyserial自动化的利器如果你需要做自动化测试或者批量处理数据图形化串口工具有点笨拙。这时候Python加pyserial是最优解。安装pyserialpip install pyserial打开串口并读写import serial import time ser serial.Serial( portCOM3, # Windows下是COMxLinux下是/dev/ttyUSB0 baudrate115200, bytesizeserial.EIGHTBITS, parityserial.PARITY_NONE, stopbitsserial.STOPBITS_ONE, timeout0.5 ) if ser.is_open: print(f串口已打开: {ser.name}) # 发送命令 ser.write(bLED_ON\r\n) # 读取响应 data ser.readline() print(f收到: {data}) ser.close()用pyserial可以做很多事情定时给Pico发心跳包、把传感器数据记录到CSV文件、模拟上位机做压力测试等。我之前写过一个小脚本用pyserial每秒读取一次Pico发来的温度数据存储到InfluxDB里做曲线分析全程无人值守。有个细节要注意Windows下COM口的编号可能因为插的USB口不同而变代码里如果写死了COM3换个USB口就找不到了。建议用serial.tools.list_ports枚举所有串口根据描述筛选出目标设备import serial.tools.list_ports ports serial.tools.list_ports.comports() for port in ports: print(port.device, port.description)4.3 硬件辅助USB转TTL芯片与逻辑分析仪串口调试软件只是一半另一半是硬件。最常用的硬件是USB转TTL模块市面上常见的芯片有CH340、CP2102、FT232。CH340最便宜几块钱包邮驱动也成熟日常调试完全够用。CP2102也便宜稳定性稍好。FT232是很多专业工程师的最爱兼容性极好在Windows、Linux、macOS下基本免驱而且输出波形更干净适合波特率比较高的场合。我的经验是日常调MicroPythonCH340够用如果是调高速串口比如921600以上或者做长期运行的嵌入式系统建议上FT232抗干扰能力确实有差别。逻辑分析仪是另一个神器。串口通信看不见摸不着你以为发了个字节实际上波形什么情况你根本不知道。这时候一个几十块钱的8通道逻辑分析仪加上Saleae Logic或者PulseView软件直接把TX和RX线上的波形抓出来哪个字节发错了、时序对不对、起始位和停止位是否标准一目了然。操作上把逻辑分析仪的两个通道夹在Pico的TX和RX引脚上采样率设置在波特率的10倍以上比如115200波特率用1MHz采样率就够了。触发方式选UART RX下降沿就能抓到一帧完整的数据波形。我可以负责任地说串口问题里头至少有三成靠逻辑分析仪一眼就能定位。比如两边标称都是9600但一端实际输出的是9610另一端按9580来收短期内能对长时间通信就出现随机乱码。这种问题用万用表测不出来用逻辑分析仪看波形周期却能直接算出来。5. 真实场景中遇到的坑波特率、乱码、丢字节5.1 波特率9600能通4800反而没数据有朋友遇到过这种情况STM32跟传感器用9600波特率通信正常改成4800波特率就完全没数据。这种问题一般有几个思路排查第一确认两端波特率是否真的都是4800。很多传感器模块出厂默认9600你在代码里改成4800但模块还是以9600的频率往外发数据那肯定是乱码或者无数据。解决方案是看看模块手册有没有波特率修改指令或者拨码开关。第二波特率误差超标。串口通信在每一帧的起始位进行同步只要波特率误差在一定范围内就能接收正确这个容忍范围通常是±2%~±3%。如果发端以4800发送收端以4808接收误差0.17%没问题但如果USB转TTL模块用的是劣质晶振误差达到5%9600时可能勉强能通4800时反而容易出错。这个逻辑听起来反直觉其实是晶振温漂和分频系数的综合结果。第三软件配置不一致。9600能通4800无数据很有可能是改波特率时把数据位、校验位、停止位也改了。比如你原来9600是8N1改成4800时不小心设置成了7E1帧结构不一样自然对不上。排查这类问题最直接的办法是逻辑分析仪抓波形量一下实际波特率跟设置的是否一致。如果没有逻辑分析仪也可以让Pico发一串已知数据再用电脑另一串口工具收看看能不能解码出来。5.2 乱码、丢字节问题可能出在哪乱码和丢字节是串口调试里最磨人的两类问题。我按踩坑概率从高到低列一下现象可能原因检查方法全乱码波特率不匹配检查两端波特率设置全乱码TX/RX接反交叉互换TX和RX首字节丢失上电初始化未完成外部设备先发数据Pico初始化后延时100ms再通信偶发丢字节缓冲区溢出读太慢用uart.any()非阻塞读取或开启中断偶发乱码/错误帧供电不足或共地不良检查电源稳定性确保共地接收数据错位协议解析未重同步加帧头校验超时后重置状态机其中MicroPython场景里丢字节最常见的原因是主循环读取不及时。举个典型例子你在while True里先做了一大堆延时操作比如time.sleep(0.2)然后才去处理串口数据。Pico的UART硬件FIFO只有16字节如果一帧数据超过16字节后面进来的数据就会覆盖前面的旧数据你读出来就是丢字节或者错位。解决办法就是前面说的用中断环形缓冲区把数据先囤起来主循环里想什么时候处理就什么时候处理。另外一个比较隐蔽的问题出现在USB转TTL模块上。CH340在Windows下如果驱动版本不对或者电脑的USB口是扩展HUB接出来的偶发会丢字节。我遇到过一次代码怎么查都没问题最后换了一个USB口问题就消失了。后来怀疑是那个USB HUB供电不稳串口的电平波形有毛刺。提到供电Pico的GPIO输出能力是有限制的整个3.3V输出电流通常不建议超过300mA。如果你用Pico的3.3V同时给GPS模块、蓝牙模块、逻辑电平转换器供电电压很可能会被拉低串口电平幅值不够导致接收端无法识别。这类问题不好查因为电压表量出来可能还有3.2V但峰值电平已经不够了。稳妥的做法是外接稳压电源或者至少把功耗大的外围模块单独供电。5.3 串口自测三板斧回环测试、引脚互换、排除法遇到串口通信异常我通常按这三板斧排查高效又直接第一板斧回环测试。把Pico的TX引脚直接短接到同一个UART的RX引脚上然后代码里发一个字节再尝试读取。如果能读到刚才发出去的内容说明Pico的UART外设和GPIO功能是好的问题大概率在外围接线或对方设备。这相当于把问题从自身硬件和外部链路之间切了一刀。from machine import UART, Pin uart UART(0, baudrate115200, txPin(0), rxPin(1)) # 把GP0和GP1用杜邦线短接 uart.write(bloopback test) data uart.read() print(回环数据:, data)第二板斧引脚互换。如果回环测试正常插上USB转TTL模块还是收不到试试把TX接RX、RX接TX这个顺序换个方向。杜邦线色的干扰经常让人看错排针顺序尤其是面包板上引脚挨得密的时候。第三板斧排除法。把外设断开只留Pico和USB转TTL用串口助手发一个固定字符Pico收到后返回固定字符。如果这个闭环能通说明Pico端和电脑端都没问题再逐步接入外设看到底是哪个环节引入的问题。这个方法看起来笨但一次能缩小一半的问题范围比在代码里反复改参数高效得多。还有一种常见情况是Thonny占用串口。MicroPython的USB虚拟串口被Thonny的Shell占用着你在电脑上用串口工具去连那个COM口会提示端口被占用或者打开失败。解决办法是调硬件UART时用USB转TTL连GP0/GP1不要和USB虚拟串口抢COM口如果非要连USB虚拟串口确保Thonny已经断开连接或者干脆用其他终端工具直接连COM口。6. 把串口通信做得更稳我的几个实操心得文章写到这儿核心内容都讲完了最后分享几个我在实际项目里沉淀下来的经验。第一代码里统一封装串口协议层。别在业务代码里到处直接调uart.write()和uart.read()把协议解析、帧组帧、校验计算都封装成独立模块业务层只调用send_command(cmd_id, data)和register_callback(cmd_id, handler)这类接口。这样做的好处是同一套协议既能用在Pico上也能在电脑上用Python模拟测试联调效率翻倍。第二串口日志一定要带时间戳。调试Pico跟外设通信时我把每个收到的帧都打印上time.ticks_ms()这样一旦出现丢帧能直接看出是周期性丢的还是随机丢的。如果是周期性的多半跟主循环的某个耗时操作有关如果是随机的多半跟中断竞争或硬件时序有关。第三别把串口线当永久连接。开发阶段的杜邦线插接方便但接触不良的问题特别多尤其是面包板上的杜邦线稍微碰一下就会出现半个字符的杂波。如果项目需要长期跑建议直接用焊接的连接线或者带螺丝端子模块一劳永逸。串口通信这件事本质上就是约定好速度、交换数据、处理突发情况这三个环节。Pico的MicroPython已经把底层寄存器封装得足够友好硬件特性也相当稳定真正决定项目顺不顺的往往是你对协议设计的思考和排查问题时的方法。把这篇文章里提到的引脚规划、缓冲机制、排查三板斧都用上你会发现串口不仅是基础技能甚至能成为最可靠的调试伙伴。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →