ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

树莓派串口完全指南:PL011与mini UART及蓝牙抢占详解

树莓派串口完全指南:PL011与mini UART及蓝牙抢占详解 做树莓派开发串口是躲不开的硬骨头。不管你是想接一块GPS模块、给ESP32小车发控制指令还是打算用STM32做底层控制、树莓派做上层决策最终都要面对/dev目录底下那一排乱糟糟的设备名ttyAMA0、ttyS0、ttyUSB0、ttyACM0……刚上手的人十有八九要在这里卡住——明明在排针上接了 TTL 电平的 TX、RX、GND为什么数据就是不出来更麻烦的是树莓派3B/4B上还藏着一个“蓝牙抢串口”的历史问题很多人折腾到半夜才发现自己一直在跟一个被系统占用的端口较劲。这篇是“树莓派串口完全指南”系列的第一篇把“各串口”这件事彻底讲清楚树莓派内部到底有几个UART控制器各自有什么脾气GPIO14/15上默认是哪一个蓝牙是怎么插一脚的以及树莓派5上串口体系为什么变了。顺便把权限配置、回环测试、USB转串口这些高频场景也一并覆盖。适合刚拿到板子准备做UART通信的小白也适合被串口名折腾过但仍没理清头绪的开发者。1. 树莓派上的串口资源从SoC到40pin排针1.1 两个串口控制器PL011与mini UART树莓派主芯片里并不是只有一个串口而是至少有两套UART控制器在运作分别叫PL011和mini UART。这个设计从树莓派初代一路延续到4B直到树莓派5才被彻底改头换面。PL011 是ARM体系里经典的PrimeCell UART IP属于“正规军”。它拥有独立的时钟源波特率精度高FIFO更充裕支持硬件流控RTS/CTS中断和DMA机制也完整。你可以把它理解成一条高标准的高速公路无论是跑 9600 波特率还是 115200 波特率数据都能稳稳定时送达。mini UART 则完全是另一路画风它挂在AUX外设总线上是博通为了省面积和成本塞进去的精简UART。它的时钟来源于GPU核心频率核心频率一变波特率就跟着飘。迷你串口的FIFO小没有硬件流控DMA支持也残缺更像一条“乡间小路”平时低速跑跑还行一旦遇到CPU负载波动或者高波特率传输就容易丢字节、出乱码。很多人在树莓派3之后觉得串口不如以前稳定原因基本都出在这里——你很可能在用 mini UART而不是 PL011。我把这两个控制器的区别整理成了下面这张表方便你对照排查对比项PL011 (ttyAMA0)mini UART (ttyS0)时钟来源独立UART时钟跟随GPU核心频率波特率稳定性高低负载高时漂移硬件流控支持RTS/CTS不支持FIFO大小较大较小DMA支持完整有限/不可靠推荐使用高波特率、长时间传输临时调试、低波特率所以记住一个核心原则能用 PL011 就绝不用 mini UART。后面所有配置动作基本都是为了把这个原则落实到位。1.2 设备节点映射ttyAMA0、ttyS0到底谁是谁Linux 下每个串口控制器都会暴露成一个字符设备树莓派上最常见的就是ttyAMA0和ttyS0。但这两个名字和物理引脚之间不是固定对应关系它俩的映射会受蓝牙、设备树配置、内核cmdline参数影响。以树莓派3B/3B/4B为例最常见的情况是这样的板载蓝牙开启时蓝牙固件占用 PL011ttyAMA0被分配给蓝牙使用GPIO14/15上的串口变成 mini UART设备节点是ttyS0。板载蓝牙关闭时ttyAMA0PL011回到 GPIO14/15成为真正的用户串口。Linux为了不让应用层直接面对这种混乱又提供了两个软链接/dev/serial0和/dev/serial1。它们由udev根据设备树别名自动创建其中serial0通常指向40pin排针上的主串口serial1通常指向蓝牙对应的串口。所以我更推荐你在代码和工具里一律使用/dev/serial0而不是写死ttyAMA0或ttyS0。这样即使你换一台机器、改了一种配置应用层代码都不用动。有经验的开发者还会留意/proc/device-tree/aliases/目录里面直接存着 serial0 和 serial1 的指向。这个目录里的内容比/dev下的软链接更底层排查问题时价值很大。1.3 40pin排针上真正能用的串口引脚40pin排针上默认的串口引脚非常固定GPIO14 对应 TXDGPIO15 对应 RXD。物理引脚编号分别是8号和10号。GND 随便取一个即可常用6号或9号引脚。这里必须强调一个新手极其容易踩的坑树莓派的串口是3.3V TTL 电平不是 RS232 电平也不是5V电平。你用USB转串口模块连接时必须把模块跳到3.3V档位用STM32、ESP32这类3.3V单板连接时直接TX-RX、RX-TX、GND-GND交叉相接即可。如果对方是5V逻辑的Arduino老款板子强烈建议加电平转换模块或者使用3.3V版本的开发板否则轻则通信异常重则直接烧掉树莓派GPIO。另外GPIO14/15在树莓派上还有其他复用功能比如I2S、PCM等使用时需要确认没有其他外设抢占。不过绝大多数情况下系统默认就会把它们作为串口功能我们真正要处理的其实是“系统自身占用”的问题这一点在第三章详细展开。2. 实用第一课确认 GPIO14/15 上到底是哪个串口2.1 通过设备树别名快速定位拿到一台树莓派第一步不是急着写代码而是确认当前系统到底把哪个设备节点映射到了 GPIO14/15 上。最简单的方法就是看serial0指向哪里ls -l /dev/serial*正常情况下你会看到类似这样的输出lrwxrwxrwx 1 root root 5 xxx /dev/serial0 - ttyS0 lrwxrwxrwx 1 root root 5 xxx /dev/serial1 - ttyAMA0这表示 GPIO14/15 当前走的是ttyS0也就是 mini UART而ttyAMA0被蓝牙占了。如果你已经关了蓝牙并清掉了控制台参数就可能看到相反的结果/dev/serial0 - ttyAMA0。再深入一点可以查看/proc/device-tree/aliases/uart*cat /proc/device-tree/aliases/uart*以及内核日志里对每个tty设备的初始化信息dmesg | grep tty这些命令组合起来能在半分钟内把一台陌生树莓派的串口拓扑摸清。我自己拿到新板子或者刷了新镜像后一定会先跑一遍这几个命令再决定后续配置方案。2.2 检查串口是否被控制台占用很多人在串口上收发数据时发现“写入成功但没有任何输出”或者更迷惑的是——树莓派重启时串口里冒出一堆内核日志然后就安静了。这通常意味着你的串口被当作Linux 内核控制台或登录终端占用了。占用串口的主要有两类进程一是内核 cmdline 里的consoleserial0,115200参数它会把内核日志输出重定向到串口二是 systemd 的serial-gettyttyAMA0.service或serial-gettyttyS0.service它会在这个串口上跑一个登录终端。两者只要有一个在工作你的用户程序就无法独占串口。检查方法sudo systemctl status serial-getty* cat /boot/firmware/cmdline.txt # 旧版本镜像路径是 /boot/cmdline.txt如果服务是 running或者 cmdline 里出现了consoleserial0/consolettyAMA0/consolettyS0那就说明串口被系统占用了。解决方案在第三章这里只需要先养成“写串口前先查占用”的习惯。2.3 回环测试验证通道在你修改任何配置之前先做一次回环测试确认硬件物理链路是通的。把树莓派 GPIO14物理8号和 GPIO15物理10号用一个杜邦线直接短接然后用串口工具往serial0发一条数据。因为 TX 和 RX 短接自己发的内容会原样传回自己。在命令行里可以用minicom或picocom也能用一段很短的 Python 把收发一次测完import serial ser serial.Serial(/dev/serial0, 115200, timeout1) ser.write(bhello rpi\r\n) data ser.read(64) print(received:, data) ser.close()如果能正常打印出received: bhello rpi\r\n说明从系统到引脚的整条链路通畅。如果这里就不通别急着改系统配置先去检查引脚短接是否牢固、杜邦线是否损坏、设备路径是否选对。回环测试能帮你把问题范围快速缩小到“硬件链路”还是“软件配置”。3. 串口能用之前的三个配置动作3.1 给当前用户加 dialout 权限树莓派系统里的串口设备默认属于root:dialout普通用户直接访问会出现Permission denied。解决办法不是用sudo chmod 666而是把当前用户加入 dialout 组sudo usermod -aG dialout $USER执行完这条命令后必须重新登录或者重启会话用户组权限才会生效。如果你是在终端里操作直接重启树莓派是最省心的。我见过不少人在/dev/ttyS0上遇到Permission denied后习惯性加个 sudo 去跑程序这样虽然能用但在 ROS2、Docker 这类环境里权限管理会非常混乱。正确姿势是把自己加入 dialout 组让普通用户也能直接访问串口设备后续调试轻松得多。另外提醒一句Ubuntu 22.04 等系统上用户可能叫ubuntu命令一样sudo usermod -aG dialout ubuntu改完记得验证id看输出里有没有dialout。3.2 关掉内核控制台和登录 shell把主串口让出来这是整个配置里最关键的一步。推荐用树莓派官方的raspi-config来做因为它会同步修改 cmdline、systemd 服务等一堆关联配置不容易出错sudo raspi-config进入Interface Options - Serial Port它会连续问两个问题Would you like a login shell to be accessible over serial?要不要把串口作为登录终端——选No。Would you like the serial port hardware to be enabled?要不要启用串口硬件——选Yes。选完重启GPIO14/15 上就没有 console 和 getty 抢占了。如果你更喜欢手动改步骤也直观以新版 Raspberry Pi OS / Ubuntu 22.04 为例先编辑/boot/firmware/cmdline.txt把里面consoleserial0,115200或consolettyAMA0,115200删除保留其他内核参数。比如原来是consoleserial0,115200 consoletty1 rootPARTUUIDxxx rootfstypeext4 fsck.repairyes rootwait改成consoletty1 rootPARTUUIDxxx rootfstypeext4 fsck.repairyes rootwait然后再编辑/boot/firmware/config.txt确认加入enable_uart1旧版系统路径是/boot/config.txt和/boot/cmdline.txt操作逻辑一样。手动改配置时特别提醒cmdline.txt 必须是单行文本千万别手滑按了换行否则内核启动会直接失败。改完先用cat检查再重启。3.3 enable_uart1 什么时候必须写enable_uart1这个参数在不同时代的树莓派系统里作用不太一样。早期固件默认会把 GPIO14/15 当作内核串口控制台且 UART 功能可能是关闭状态需要显式加上enable_uart1才能把硬件串口释放给用户。到了较新的 Raspberry Pi OS 里很多镜像已经默认开启了串口 但仍建议保留这一行尤其是在 Ubuntu 这类非官方系统上缺少它可能导致 GPIO14/15 完全没有信号。判断是否生效很简单重启后执行ls -l /dev/serial0如果软链接存在且指向一个真实设备说明硬件串口已被注册。如果/dev/serial0都找不到大概率是enable_uart1没写或者被其他 overlay 覆盖了。4. 蓝牙与PL011的历史纠葛树莓派3/4B的串口名为什么总变4.1 蓝牙到底占用了哪个串口从树莓派3开始板载蓝牙与处理器的通信就通过 UART 连接。为了获得稳定的蓝牙吞吐博通在硬件层面把 PL011也就是ttyAMA0分配给了蓝牙控制器40pin排针上的串口则被迫使用 mini UARTttyS0。这就解释了为什么很多老玩家会说“树莓派3以后的串口变垃圾了”不是串口本身消失而是你拿到手的就是那个没独立时钟、波特率随CPU负载飘的 mini UART。尤其是跑桌面系统时CPU频率上下跳动115200下丢包和乱码是家常便饭。在树莓派4B上这个结构依然没有本质变化。所以如果你在4B上做项目同时还想用 GPIO14/15 的串口基本只有两条路关掉蓝牙抢回 PL011或者接受 mini UART 的性能损失。4.2 关闭蓝牙抢回 PL011如果你的项目不需要板载蓝牙最推荐的做法是直接禁用蓝牙把 PL011 请回 GPIO14/15。在/boot/firmware/config.txt中加入dtoverlaydisable-bt同时按3.2节的方法删掉 cmdline 里的consoleserial0,115200重启后执行ls -l /dev/serial*你会看到serial0 - ttyAMA0GPIO14/15 终于回归 PL011。这才是做机器人、传感器采集、高速串口桥接时该有的串口状态。旧的 overlay 名字也叫pi3-disable-bt在新内核里统一成了disable-bt如果你查老资料看到前者不要惊讶。但要注意这个操作会直接屏蔽板载蓝牙控制器你的无线键盘、蓝牙音箱、蓝牙手柄都会断联。如果只是偶尔用蓝牙不建议走这条方案。4.3 mini UART 的波特率漂移与锁频如果你确实要保留蓝牙又不得不暂时用 mini UART那就要正视它的波特率漂移问题。mini UART 的时钟来自GPU核心频率默认情况下核心频率会随CPU负载动态调整。负载一高波特率就不再是标称值接收端自然解码失败。老办法是在 config.txt 里锁定核心频率core_freq250早期内核里这个参数有效但到树莓派4B之后核心频率管理的策略变了锁频效果很有限甚至可能影响其他外设性能。所以我的建议很直接不要和 mini UART 纠缠项目里买一个USB转串口模块都比死磕它划算。这也是很多树莓派爱好者到了最后殊途同归的选择。5. 树莓派5的串口扩展RP1带来更多可能5.1 树莓派5的串口体系变化树莓派5 在IO架构上做了大调整核心是启用了自研的 RP1 芯片作为IO控制器串口资源也随之丰富起来。它不像树莓派4B那样只有一个 PL011 加一个 mini UART 的简陋局面而是提供了多路UART可以更灵活地映射到40pin排针的不同引脚上。同时树莓派5 的蓝牙资源不再直接抢占主串口默认情况下 GPIO14/15 就能拿到品质良好的 UART 通道这让很多在4B上被蓝牙折磨过的开发者长舒一口气。需要注意的是树莓派5 的串口设备名也变多了。除了经典的ttyAMA0启用额外串口后还会出现ttyS0、ttyS1、ttyS2等一堆节点。具体哪个节点对应哪个引脚最好用dmesg | grep tty确认或者直接查/proc/device-tree/aliases/不要靠猜。5.2 通过设备树 overlay 启用额外UART树莓派5 上如果想引出第二路、第三路串口不需要外接USB转串口直接在 config.txt 里启用对应的设备树 overlay 即可。以典型的uart2-pinout为例dtoverlayuart2-pinout重启后执行ls -l /dev/tty*大概率会看到新增了一个 tty 节点同时可以在 dmesg 里确认它绑定到了哪个引脚组。这里的“pinout”后缀决定了引脚位置不同版本固件支持的引脚组合略有差异务必以官方手册为准。这类overlay 的好处是你可以把多路传感器分别挂在不同串口上互不干扰非常适合搞机器人或者多设备通信的场景。不过也要提醒一句树莓派5 的额外UART虽然多但部分引脚可能需要和其他功能复用启用前最好先看一眼当前项目的GPIO分配表避免两个外设打架。5.3 树莓派Pico的UART别搞混经常有人把树莓派Pico和树莓派Linux系统放在一起聊然后被串口命名弄晕。Pico是单片机运行的是MicroPython或C固件没有/dev/ttyAMA0这套东西。它的 RP2040 芯片内部有两路硬件UART分别叫uart0和uart1需要在自己代码里指定TX/RX引脚和波特率from machine import UART, Pin uart UART(0, baudrate115200, txPin(0), rxPin(1)) uart.write(bping) print(uart.read())如果你同时玩树莓派SBC和Pico会自动发现两者的串口完全是两套体系。Pico这边由你自己全权控制没有蓝牙抢占、没有console占用反而省心得多。团队里有人做Pico控制舵机、有人做树莓派上层逻辑最关键的就是把两边的串口参数统一好然后通过TX、RX、GND三根线对接。6. USB转串口把树莓派的串口数量翻倍6.1 CH340、CP2102、FTDI怎么选树莓派本身的串口引脚有限尤其4B时代更是捉襟见肘。这时候最通用的扩展方案就是 USB 转串口一根线插上系统就会多出一个/dev/ttyUSB0或ttyACM0。市面上最常见的三种芯片是 CH340、CP2102 和 FTDI价格和稳定性差异明显芯片常见品牌/模块驱动稳定性适用场景CH340蓝色/绿色小板Linux内核ch341驱动尚可刷机、低波特率调试CP2102黑壳小棒、紫板cp210x驱动较稳定常规串口调试FTDIFT232ftdi_sio驱动高高波特率、工业级项目在树莓派上这三种芯片通常都是免驱的插上就会自动识别。如果插上后没出设备先dmesg | tail看内核日志多数情况是线材问题或接触不良。CH340 从价格角度适合随便用用但如果项目里要做高速、长时限的串口通信建议直接买 FTDI 或 CP2102避免后期因为驱动稳定性问题浪费几天时间。还有些USB转串口模块默认输出5V电平插到树莓派前一定要确认模块的跳线帽是不是3.3V档。这个细节一疏忽轻则串口乱码重则烧引脚。6.2 电平、共地和接线禁忌连接USB转串口模块和树莓派时接线必须遵循交叉原则树莓派 TX 接模块 RX树莓派 RX 接模块 TXGND 接 GND。串口通信的收发节点天然是反的如果你把它俩的TX接TX、RX接RX两个发送端互怼互相驱动不仅收不到数据还可能造成损坏。共地也是一定要强调的点。两个设备之间只有把GND连起来参考电平才能一致否则信号电压完全没法判定高低电平。很多“串口发不出数据”的诡异问题最后查出来就是GND没接。另外前文提到的3.3V TTL电平问题在连接STM32、ESP32、Arduino等设备时同样适用。如果你有一个1.8V的串口传感器还需要用三极管或专用电平转换芯片把电平抬到3.3V千万不要尝试直接把1.8V信号接在树莓派3.3V引脚上。7. 常见的串口调试工具与最小收发示例7.1 minicom、picocom 的基本用法命令行下最常用的串口工具是minicom和picocom安装都很简单sudo apt install minicom picocomminicom 功能全但交互方式比较老派进入串口后按CtrlA再按Z可以打开帮助菜单退出是CtrlA再按X。连接命令minicom -D /dev/serial0 -b 115200picocom 就轻量得多适合快速看一眼收发是否正常picocom -b 115200 /dev/serial0退出序列是CtrlA CtrlX。它启动时默认是原始模式不会像 minicom 那样自行翻译控制字符观察十六进制数据时更准确。我用得最多的其实是 picocom因为不折腾、开箱即用适合在调试现场快速确认串口状态。minicom 则适合需要保存配置、定期连接同一个设备的场景。7.2 Python pyserial 快速收发做项目时用 Python 直接读写串口往往比命令行更顺手。安装依赖pip install pyserial然后一个最简收发程序import serial ser serial.Serial( port/dev/serial0, baudrate115200, bytesize8, parityN, stopbits1, timeout0.1 ) ser.write(bAT\r\n) resp ser.read(128) print(resp) ser.close()这里bytesize8, parityN, stopbits1就是常说的“8N1”格式。绝大多数串口外设的默认参数都是 8N1如果你的设备手册写着其他格式比如“7E1”或“8N2”对应修改这几个参数即可。timeout 参数也非常关键。它告诉串口在无数据时最多等待多少秒避免read()无限阻塞。实际开发里我会根据设备的响应速度自由调整比如GPS模块通常 100ms 内就会有数据返回而某些老式传感器可能要等 500ms 以上。7.3 调参要点8N1、波特率与超时串口通信的参数并不复杂但必须和另一端设备完全对齐。首先确认波特率两端不一致时你会看到满屏乱码或者偶尔几个字节正确。其次是数据位、停止位和校验位一般设备手册都会明确写“115200, 8, N, 1”这样的格式照抄即可。第三是流控如果你的外设没有 RTS/CTS 硬件流控串口的rtscts参数一定不要开否则双方都无法正常收发。在树莓派上还有一类特殊问题当设备是 mini UART 时CPU 负载会影响实际波特率即使用 115200 配置也可能收到错码。处理方案我们不重复了唯一要记住的判断思路是如果回环测试正常但接了对方设备就乱码优先怀疑波特率漂移或电平不匹配。8. 常见问题与排查技巧实录8.1 串口故障速查表结合这些年的实际经验我把树莓派串口场景里最高频的问题整理成一个速查表按“现象 - 原因 - 处理”的顺序来故障现象大概率原因处理办法访问报 Permission denied用户不在 dialout 组sudo usermod -aG dialout $USER后重新登录串口写入成功但无输出串口被 console/getty 占用清除 cmdline 串口参数关闭 serial-getty接外设全乱码回环正常波特率不匹配、电平不匹配、mini UART漂移核对参数优先用 PL011重启后串口没设备节点enable_uart1缺失config.txt 加enable_uart1蓝牙设备突然消失启用了disable-bt删除对应 overlayUSB转串口插上无 ttyUSB0驱动没加载、线材问题、供电不足dmesg查日志换线测试接STM32/ESP32时偶尔丢包线太长、供电不稳、波特率过高缩短杜邦线、降波特率、共地GPIO14/15接5V模块后无信号电平不匹配或引脚受损用3.3V模块或电平转换板这张表基本覆盖了从硬件到软件的所有坑。真到排查现场按表格顺序逐项排除比瞎猜高效得多。8.2 三个现场排查案例第一个案例是典型的“新系统串口默认关闭”问题。用户拿树莓派4B刷了 Ubuntu 22.04GPIO14/15 上始终没有任何信号输出ls /dev/serial*直接没有软链接。查了一圈发现/boot/firmware/config.txt里根本没写enable_uart1。加上这一行重启后/dev/serial0立刻出现串口恢复正常。很多人以为官方树莓派OS能用Ubuntu也能用其实这类系统默认裁剪比较狠必须自己补配置。第二个案例来自一个ROS2小车项目。树莓派4B上跑 ROS2 humble需要通过 GPIO 串口桥接 ESP32 底盘控制器同时还有一个USB转串口接了雷达模块。最初系统里 GPIO 串口被蓝牙占成了ttyS0控制指令总丢小车一抖一抖。最后就是加了dtoverlaydisable-bt清掉 cmdline 里的串口 consoleGPIO 串口变成ttyAMA0波特率一下子就稳了底盘控制延迟明显下降。这个案例很典型机器人场景里PL011 是底线mini UART 根本不够看。第三个案例是USB转串口模块驱动问题。插上 CP2102 模块后树莓派完全没有反应ls /dev/ttyUSB0报不存在。执行dmesg | tail发现内核输出提示usb设备断开把模块插到另一个USB口问题立刻消失——原来是树莓派USB口供电不稳带不动部分模块。后来换了一根供电粗一点的短线才彻底解决。USB转串口看似小事供电和线材质量直接决定稳定性。这三个案例覆盖了配置缺失、硬件资源抢占、供电不稳定三类树莓派串口最常见事故。如果你按前面的步骤把地基打牢再遇到问题基本都能从这张速查表里找到答案。最后分享一点个人习惯。我拿到任何一台树莓派第一步从来不是急着装软件而是先跑一遍dmesg | grep tty和ls -l /dev/serial*把当前串口映射记在纸上。做项目的原则也很简单能用 PL011 就不要碰 mini UART能用/dev/serial0就不要硬记ttyAMA0和ttyS0需要蓝牙又需要串口的时候优先考虑USB转串口而不是跟设备树死磕。这套原则帮我从树莓派3一路用到了树莓派5踩过的坑基本都写在前面了。如果你也遇到过串口名总是“漂移”的问题不妨先从关闭蓝牙、清空串口控制台这两步开始排查多半能省下好几个晚上。
返回列表