树莓派GPIO引脚功能与UART映射:BCM与wPi编号、UART0/UART1、硬件流控
说实话,刚接触树莓派GPIO的人,十有八九会被那两套编号搞晕。我当年第一次点亮LED,照着教程写GPIO 17,结果怎么都不亮——后来才发现教程用的是wPi编号,而我写的是BCM编号。嗯,这种坑踩过一次就记住了。
这一章,咱们就把GPIO的引脚功能、UART映射、编号体系彻底理清楚。你搞懂了这些,后面用pyserial跟工业设备通信才不会跑偏。
BCM编号 vs wPi编号:两套江湖规矩
树莓派40针排针上,每一针都有物理位置编号(Physical Pin Number),从1到40。但软件层面,大家用的却是另外两套编号:
| 编号体系 | 来源 | 特点 | 常用库 |
|---|---|---|---|
| BCM编号 | Broadcom SoC内部GPIO号 | 与芯片引脚直接对应,跨板卡一致 | RPi.GPIO、pigpio、wiringPi(BCM模式) |
| wPi编号 | Wiring Pi库自定义 | 按排针物理顺序重新编号,方便记忆 | wiringPi(已停更,但存量代码多) |
| Physical编号 | 排针物理位置 | 1~40,最直观,但软件不直接使用 | 仅用于参考 |
我个人习惯用BCM编号。为什么?因为它是芯片原厂的编号,换板子(比如从Pi 3B+换到Pi 4B)时,BCM编号基本不变。wPi编号虽然好记,但wiringPi库已经停更了,新项目再用它,有点给自己挖坑的意思。
核心原则:新项目一律用BCM编号。如果你接手旧代码看到wPi编号,先确认它用的是哪个库,再决定是否迁移。
UART0与UART1:两个串口的恩怨
树莓派上有两个硬件UART:UART0(也叫PL011)和UART1(也叫mini UART)。它们不是平级关系,性能差距挺大。
| 特性 | UART0 (PL011) | UART1 (mini UART) |
|---|---|---|
| 硬件基础 | 独立UART外设(ARM PL011) | 基于BCM2835 AUX模块 |
| 波特率精度 | 高,支持非标准波特率 | 低,依赖VPU时钟频率 |
| 硬件流控 | 支持(RTS/CTS) | 不支持 |
| FIFO深度 | 16字节 | 8字节 |
| 中断支持 | 完整 | 有限 |
| 默认用途 | 蓝牙(Pi 3B+/4B) | GPIO 14/15 串口终端 |
你想想看,如果跟工业设备通信,波特率要求115200甚至更高,数据量又大——用UART1就很容易丢数据。我在一个自动化产线项目里就吃过这个亏:设备偶尔丢包,排查了两天才发现是mini UART的FIFO太小,加上VPU频率波动导致波特率漂移。
避坑指南:工业通信场景,优先使用UART0。如果UART0被蓝牙占用,可以通过dtoverlay=disable-bt释放出来。别图省事直接用UART1,除非你只接调试终端。
GPIO引脚与UART映射关系
树莓派40针排针上,UART信号映射到固定的GPIO引脚。以BCM编号为例:
| UART实例 | TX (BCM) | RX (BCM) | RTS (BCM) | CTS (BCM) | 物理引脚 |
|---|---|---|---|---|---|
| UART0 | GPIO 14 | GPIO 15 | GPIO 17 | GPIO 16 | 8/10/11/12 |
| UART1 | GPIO 14 | GPIO 15 | 不支持 | 不支持 | 8/10 |
| UART0 (备用) | GPIO 0 | GPIO 1 | GPIO 2 | GPIO 3 | 27/28/3/5 |
注意,UART0和UART1的TX/RX默认都映射到GPIO 14/15。这意味着它们不能同时使用同一组引脚。你需要在/boot/config.txt里通过设备树覆盖来切换。
小技巧:如果你需要两个串口同时工作,可以把UART0映射到GPIO 0/1(物理引脚27/28),UART1保留在GPIO 14/15。这样就能同时使用两个硬件UART了。
硬件流控:什么时候必须用?
硬件流控(RTS/CTS)说白了就是让设备之间互相说“慢点,我还没处理完”。它用两根额外的信号线来实现:
- RTS(Request To Send):发送方告诉接收方“我要发数据了,你准备好没?”
- CTS(Clear To Send):接收方回答“准备好了,发吧”
我在项目中遇到过这样的情况:用115200波特率跟PLC通信,数据包长度256字节,没有流控。结果PLC那边处理不过来,缓冲区溢出,数据就丢了。后来加上RTS/CTS硬件流控,问题立刻解决。
什么时候必须用硬件流控?
- 波特率高于57600
- 数据包长度超过64字节
- 通信双方处理速度不匹配(比如树莓派快,设备慢)
- 半双工转全双工场景
如果只是接个调试终端,或者波特率9600、数据量很小,软件流控(XON/XOFF)也够用。但工业场景,我建议直接上硬件流控,省心。
知识结构总览
下面这张图把本章的核心逻辑串起来了。你一看就明白:编号体系、UART选择、引脚映射、流控决策,它们之间的关系。
实战:查看当前UART映射状态
在动手接线之前,先确认你的树莓派当前UART映射状态。打开终端,运行:
# 查看UART设备
ls -l /dev/serial*
# 查看GPIO功能复用状态
raspi-gpio get 14-15
# 查看设备树覆盖
dtoverlay -a | grep uart
输出示例:
/dev/serial0 -> ttyAMA0
/dev/serial1 -> ttyS0
GPIO 14: level=1 func=ALT0
GPIO 15: level=1 func=ALT0
这里serial0通常指向UART0(ttyAMA0),serial1指向UART1(ttyS0)。如果serial0指向ttyS0,说明UART0被蓝牙占用了,你需要释放它。
快速检查:运行ls -l /dev/serial*,看serial0指向谁。指向ttyAMA0就是UART0,指向ttyS0就是UART1。这个命令我几乎每次调试都会先用一遍。
释放UART0给串口使用
如果你用的是Pi 3B+或4B,UART0默认分配给蓝牙。想把它还给串口,编辑/boot/config.txt:
# 禁用蓝牙,释放UART0
dtoverlay=disable-bt
# 或者只禁用蓝牙的UART,保留蓝牙其他功能
dtoverlay=miniuart-bt
然后重启:
sudo reboot
重启后再看/dev/serial*,serial0应该指向ttyAMA0了。
注意:禁用蓝牙后,树莓派的蓝牙功能就没了。如果你需要蓝牙,用miniuart-bt方案——把UART1给蓝牙用,UART0留给串口。但UART1性能差,蓝牙通信可能受影响。我一般直接禁用蓝牙,反正工业场景很少用蓝牙。
小结
这一章的内容,说白了就是三件事:
- 编号用BCM,别用wPi,省得以后踩坑
- UART用0,别用1,除非你只接调试终端
- 流控用硬件,别省那两根线,工业通信稳定第一