树莓派4 UART多串口配置与通信实战指南

发布时间:2026/10/15 21:40:12

树莓派4 UART多串口配置与通信实战指南 1. 为什么树莓派 4 的 UART 值得单独拿出来聊树莓派 4 这块板子但凡你玩过一阵子大概率都会碰到一个绕不开的需求接一个串口设备。可能是 GPS 模块、可能是某款工业传感器、可能是和另一块单片机做点对点通信也可能是调试一个老设备的控制台。这时候你会发现树莓派 4 的 UART 配置和树莓派 3 相比变化不小尤其是那个默认分配给蓝牙的 PL011 硬件串口坑了不少人。我自己第一次在树莓派 4 上接串口模块的时候就是照着树莓派 3 的老教程改的/boot/config.txt结果折腾了大半天数据死活收不到。后来才发现树莓派 4 的 UART 映射逻辑和树莓派 3 不一样mini UART 和 PL011 的分配关系变了而且默认情况下 GPIO 14/15 上引出来的那个串口性能并不理想。这篇内容就是把我自己在树莓派 4 上做 UART 多串口配置通信的完整过程整理出来。核心要解决的问题有三个第一搞清楚树莓派 4 上 UART 的硬件资源到底是怎么分配的第二把主串口从蓝牙手里抢回来让 GPIO 上的串口变成稳定可用的 PL011第三在需要多个串口的场景下通过软件或硬件方式扩展出额外的串口通道并且保证它们能同时稳定工作。适合谁看如果你手上有一块树莓派 4想接串口设备但被各种教程绕晕了或者你已经跑通了单个串口但想同时接两三个串口设备做数据采集和转发那这篇内容应该能帮你省下不少试错时间。我会尽量把每一步为什么这么做讲清楚而不是只丢一堆命令让你抄。2. 树莓派 4 UART 硬件资源与映射关系拆解2.1 树莓派 4 上到底有几个 UART先把这个事情说清楚不然后面配置全是糊涂账。树莓派 4 的 SoCBCM2711内部其实有多个 UART 控制器但在实际使用中我们最常打交道的是两个PL011这是 ARM 体系里标准的硬件串口性能稳定波特率精度高带独立的 FIFO是真正意义上的“好串口”。mini UART这是树莓派早期为了省成本搞出来的一个简化版串口它的波特率依赖于 GPU 核心频率一旦 CPU 频率发生变化波特率就会飘导致通信不稳定。在树莓派 3 上PL011 默认是分配给蓝牙的GPIO 14/15 上引出来的是 mini UART。到了树莓派 4情况变了PL011 的分配逻辑做了调整默认情况下GPIO 14/15 上引出来的串口变成了 PL011而蓝牙则改用 mini UART。听起来好像是好事但问题在于树莓派 4 默认并没有把 PL011 完全释放给 GPIO而是通过一个设备树覆盖层overlay来管理这个映射关系。除此之外树莓派 4 还可以通过额外的 UART 控制器扩展出更多串口。BCM2711 支持最多 6 个 UART包括 PL011 和几个 mini UART 变体但这些额外的 UART 需要通过在/boot/config.txt里加载对应的 overlay 才能启用并且它们会占用特定的 GPIO 引脚。2.2 为什么默认配置下串口不好用很多人拿到树莓派 4直接在 GPIO 14/15 上接串口模块然后发现要么收不到数据要么数据乱码要么波特率稍微高一点就不稳定。原因主要有两个第一默认情况下树莓派 4 的串口控制台serial console是开启的。也就是说系统会把内核启动日志和登录终端绑定在这个串口上。你接一个外部设备上去系统会往上面吐一堆启动信息你的设备如果解析不了这些数据就会表现得很奇怪。更麻烦的是如果你往串口发数据可能会被系统当成登录命令来处理。第二虽然树莓派 4 默认把 PL011 分配给了 GPIO 14/15但蓝牙那边仍然占着一部分资源而且如果你没有显式地禁用 serial console 并启用 UART overlayPL011 可能并没有完全按照你期望的方式工作。我实测下来的经验是只要你要用 GPIO 上的串口做正经通信第一步永远是先把 serial console 关掉然后把 UART 的状态确认清楚再谈其他。2.3 多串口扩展的硬件基础树莓派 4 的 40 针 GPIO 里默认只有 GPIO 14TXD和 GPIO 15RXD这一组串口引脚。如果你想接多个串口设备有几种思路第一种是用 USB 转串口模块。这是最省事的办法插上去就多一个/dev/ttyUSBx不需要动 GPIO 配置。缺点是每个模块都要占一个 USB 口而且质量参差不齐的模块容易掉线。第二种是启用树莓派 4 额外的 UART 控制器。通过加载dtoverlayuart2、dtoverlayuart3之类的 overlay可以把其他 UART 映射到指定的 GPIO 引脚上。这样你就能在不占用 USB 口的情况下多出几个硬件串口。缺点是可用引脚有限而且不同 UART 的引脚分配是固定的需要提前规划好。第三种是用 I2C 或 SPI 转串口芯片比如 SC16IS752 这类双通道 UART 扩展芯片。这种方式可以扩展出多个串口但需要额外的驱动配置复杂度较高。我自己的项目里通常是第一种和第二种混着用关键设备走硬件 UART次要设备走 USB 转串口。这样兼顾了稳定性和灵活性。3. 单串口基础配置从零到能收发数据3.1 关闭 serial console 并释放 PL011不管你后面要不要搞多串口这一步都是基础。树莓派 4 默认会把串口用作系统控制台你必须先把这个功能关掉才能让串口完全归你的应用程序使用。具体操作分两步。第一步修改/boot/cmdline.txt把里面的consoleserial0,115200这个参数删掉。这个文件里所有内容都在一行你只需要找到那个参数连同前面的空格一起删掉就行。改完之后大概是这个样子consoletty1 rootPARTUUIDxxxxxxxx-02 rootfstypeext4 elevatordeadline fsck.repairyes rootwait第二步关掉串口登录服务。在树莓派 4 上通常是这两个服务在管这件事sudo systemctl stop serial-gettyttyS0.service sudo systemctl disable serial-gettyttyS0.service sudo systemctl stop serial-gettyttyAMA0.service sudo systemctl disable serial-gettyttyAMA0.service注意ttyS0和ttyAMA0这两个设备名在不同配置下会指向不同的 UART。树莓派 4 默认情况下ttyAMA0对应的是 PL011ttyS0对应的是 mini UART。你把 serial console 关掉之后这两个设备就都可以被应用程序打开了。提示改完/boot/cmdline.txt之后必须重启才能生效。重启后可以用cat /proc/cmdline确认一下参数是否已经去掉。3.2 启用 UART 并确认设备节点接下来要确保 UART 硬件本身是启用的。在/boot/config.txt里你需要确认或添加这一行enable_uart1这一行的作用是让固件在启动时初始化 UART 硬件。对于树莓派 4 来说加上这一行之后PL011 会被分配到 GPIO 14/15 上并且系统会创建对应的设备节点。重启之后你可以用下面这个命令来确认串口设备是否存在ls -l /dev/serial*正常情况下你会看到类似这样的输出lrwxrwxrwx 1 root root 5 Jan 1 00:00 /dev/serial0 - ttyAMA0 lrwxrwxrwx 1 root root 5 Jan 1 00:00 /dev/serial1 - ttyS0这里serial0指向ttyAMA0说明 PL011 已经分配给了 GPIO 上的串口。serial1指向ttyS0那是给蓝牙用的 mini UART。你要用的就是serial0或者直接操作ttyAMA0。3.3 用 Python 做一次回环测试配置确认没问题之后先别急着接外部设备做一次回环测试最稳妥。所谓回环测试就是把树莓派的 TXD 和 RXD 用一根杜邦线短接起来然后发什么就应该收到什么。硬件上用一根母对母杜邦线把 GPIO 14物理引脚 8和 GPIO 15物理引脚 10连起来。然后跑下面这段 Python 代码import serial import time ser serial.Serial( port/dev/serial0, baudrate115200, parityserial.PARITY_NONE, stopbitsserial.STOPBITS_ONE, bytesizeserial.EIGHTBITS, timeout1 ) test_data bHello UART ser.write(test_data) time.sleep(0.1) received ser.read(len(test_data)) print(fSent: {test_data}) print(fReceived: {received}) ser.close()如果一切正常你会看到发送和接收的数据完全一致。如果收到的数据是乱码或者为空那就要回头检查波特率、接线和 serial console 是否真的关掉了。注意回环测试用的杜邦线一定要插紧。我遇到过好几次因为接触不良导致数据时有时无的情况排查了半天以为是软件问题结果就是线松了。4. 多串口扩展配置与通信实现4.1 通过 overlay 启用额外硬件串口树莓派 4 的 SoC 支持多个 UART你可以通过在/boot/config.txt里加载 overlay 来启用它们。常用的几个 overlay 和对应的引脚如下OverlayTXD 引脚RXD 引脚设备节点uart2GPIO 4 (pin 7)GPIO 5 (pin 29)/dev/ttyAMA1uart3GPIO 8 (pin 24)GPIO 9 (pin 21)/dev/ttyAMA2uart4GPIO 12 (pin 32)GPIO 13 (pin 33)/dev/ttyAMA3uart5GPIO 16 (pin 36)GPIO 17 (pin 11)/dev/ttyAMA4要启用 uart2 和 uart3你只需要在/boot/config.txt末尾加上dtoverlayuart2 dtoverlayuart3重启之后用ls /dev/ttyAMA*就能看到多出来的设备节点。这里有个细节需要注意启用这些额外 UART 之后对应的 GPIO 引脚就不能再作为普通 GPIO 使用了所以在规划引脚的时候要提前留好余量。另外这些额外 UART 默认也是 PL011 类型的硬件串口性能比 mini UART 好得多波特率可以跑到 921600 甚至更高。我在一个数据采集项目里同时用了 uart2 和 uart3分别接两个传感器跑 460800 波特率连续工作几天都没有丢包。4.2 用 USB 转串口模块做灵活扩展如果你不想占用 GPIO 引脚或者需要更多串口USB 转串口模块是最直接的选择。市面上常见的芯片有 CH340、CP2102、FT232 等在树莓派 4 上基本都能免驱识别插上去就会多出/dev/ttyUSB0、/dev/ttyUSB1这样的设备节点。不过这里有几个实操经验值得分享。第一不同批次的 CH340 模块质量差异很大有些便宜的模块在高温或者长时间工作后会出现掉线建议关键场景用 CP2102 或 FT232 芯片的模块。第二多个 USB 转串口模块同时插上去时设备节点的编号可能会在重启后发生变化导致你的程序打开错误的串口。解决办法是通过 udev 规则给每个模块绑定固定的别名。写一条 udev 规则比如在/etc/udev/rules.d/99-usb-serial.rules里加上SUBSYSTEMtty, ATTRS{idVendor}1a86, ATTRS{idProduct}7523, ATTRS{serial}USB001, SYMLINKttySensorA SUBSYSTEMtty, ATTRS{idVendor}10c4, ATTRS{idProduct}ea60, ATTRS{serial}USB002, SYMLINKttySensorB这样不管系统怎么分配ttyUSBx你的程序始终可以通过/dev/ttySensorA和/dev/ttySensorB来访问对应的设备。idVendor和idProduct可以用lsusb命令查到serial属性可以用udevadm info查看。4.3 多串口并发通信的代码结构当你同时操作多个串口时代码结构就很重要了。最简单的做法是开多个线程每个线程负责一个串口的读写。但这里有个坑Python 的serial库在多个线程同时读写同一个串口时可能会出现数据竞争。所以原则是一个串口只由一个线程负责不同串口之间通过队列来交换数据。下面是一个简化的多串口采集框架import serial import threading import queue import time class SerialReader(threading.Thread): def __init__(self, port, baudrate, data_queue): super().__init__() self.port port self.baudrate baudrate self.data_queue data_queue self.running True self.ser None def run(self): self.ser serial.Serial( portself.port, baudrateself.baudrate, timeout0.1 ) while self.running: if self.ser.in_waiting 0: data self.ser.read(self.ser.in_waiting) self.data_queue.put((self.port, data)) time.sleep(0.01) self.ser.close() def stop(self): self.running False if __name__ __main__: data_queue queue.Queue() readers [ SerialReader(/dev/ttyAMA0, 115200, data_queue), SerialReader(/dev/ttyAMA1, 460800, data_queue), SerialReader(/dev/ttyUSB0, 9600, data_queue), ] for r in readers: r.start() try: while True: port, data data_queue.get() print(f[{port}] {data.hex()}) except KeyboardInterrupt: for r in readers: r.stop() for r in readers: r.join()这个框架的好处是每个串口独立运行互不干扰主线程只需要从队列里取数据做统一处理。如果你要做数据转发比如把 uart2 收到的数据转发到 uart3也只需要在队列消费端做判断和转发即可。提示in_waiting属性在部分 USB 转串口芯片上可能不准如果发现数据读取有延迟可以改用固定长度读取或者基于超时的读取方式。5. 常见问题排查与避坑经验实录5.1 串口数据乱码或收不到数据这是最常见的问题排查顺序建议如下排查项检查方法可能原因波特率确认双方一致最常见尤其是非标准波特率接线TXD 接 RXDRXD 接 TXD交叉接线不是直连地线确认 GND 已连接不共地会导致电平参考错误serial consolecat /proc/cmdline未关闭会干扰通信设备节点ls -l /dev/serial*指向了错误的 UART权限ls -l /dev/ttyAMA0当前用户不在 dialout 组权限这个问题特别容易被忽略。树莓派上默认用户是pi但如果你新建了用户或者用sudo跑程序可能会遇到权限问题。把用户加到dialout组就能解决sudo usermod -a -G dialout $USER改完之后需要重新登录才生效。5.2 高波特率下数据丢失如果你把波特率设到 460800 或更高发现数据偶尔丢失大概率是以下几个原因第一mini UART 的波特率精度不够。如果你不小心用的是ttyS0mini UART高波特率下必然不稳定。确认你用的是ttyAMA0或ttyAMA1这类 PL011 设备。第二CPU 负载过高导致串口缓冲区溢出。PL011 虽然有 FIFO但容量有限。如果你的程序读取不够及时数据就会丢。解决办法是提高读取线程的优先级或者用select/poll来监听串口事件而不是轮询。第三USB 转串口模块的芯片性能不足。有些便宜的 CH340 模块在 460800 下就会丢数据换 CP2102 或 FT232 就好了。5.3 多个串口同时工作时的资源冲突当你启用多个硬件 UART 时最容易碰到的问题是引脚冲突。比如你启用了uart2它占用了 GPIO 4 和 GPIO 5但你的项目里正好又需要用 GPIO 4 做其他事情那就冲突了。所以在项目规划阶段就要把引脚分配表列清楚。另一个问题是中断冲突。虽然树莓派 4 的多个 UART 有独立的中断线但在高负载下如果多个串口同时高速收发CPU 的中断处理压力会比较大。我实测下来同时跑三个 460800 波特率的串口树莓派 4 的 CPU 占用大概在 15% 到 20% 之间还算可以接受。但如果你还要跑其他重负载任务就要考虑降低波特率或者减少同时工作的串口数量。5.4 设备节点在重启后变化这个问题主要出现在 USB 转串口模块上。每次重启系统可能会以不同的顺序枚举 USB 设备导致/dev/ttyUSB0和/dev/ttyUSB1对调。如果你在代码里硬编码了设备节点就会打开错误的串口。解决办法前面提过了就是用 udev 规则绑定固定别名。这里再补充一个细节有些便宜的 USB 转串口模块没有唯一的序列号导致 udev 无法区分。这种情况下你可以通过 USB 物理端口号来绑定比如KERNELS1-1.2这样的属性。用udevadm info -a -n /dev/ttyUSB0可以查到完整的属性链。6. 多串口通信的进阶玩法与性能调优6.1 用 select 实现非阻塞多路复用如果你的串口数量不多而且不想开一堆线程可以用select或者poll来做单线程多路复用。Python 的select模块可以同时监听多个文件描述符哪个有数据就处理哪个。这种方式比多线程更轻量但代码结构会稍微复杂一点。import serial import select ports [/dev/ttyAMA0, /dev/ttyAMA1, /dev/ttyUSB0] sers [serial.Serial(p, 115200, timeout0) for p in ports] while True: readable, _, _ select.select(sers, [], [], 0.1) for ser in readable: data ser.read(ser.in_waiting) print(f[{ser.port}] {data.hex()})这种方式的优点是资源占用低缺点是如果某个串口的数据处理逻辑很耗时会阻塞其他串口的读取。所以适合数据量不大、处理逻辑简单的场景。6.2 调整串口缓冲区大小Linux 内核为每个串口维护了发送和接收缓冲区。默认情况下接收缓冲区可能只有 4KB 左右。如果你短时间内收到大量数据而应用程序读取不及时缓冲区就会溢出。你可以通过setserial或者直接写/proc来调整但更推荐的方式是在打开串口时设置rtscts硬件流控让硬件来控制数据流。如果设备支持硬件流控把rtsctsTrue加上能极大减少数据丢失的概率。不过要注意硬件流控需要额外的两根线RTS 和 CTS接线时要一并接好。6.3 长时间运行稳定性建议如果你的树莓派要连续跑几天甚至几周做串口通信有几个经验值得参考第一给串口读取线程加上异常捕获和自动重连机制。USB 转串口模块偶尔会因为电磁干扰或者供电波动而掉线程序要能检测到SerialException并尝试重新打开串口。第二定期检查串口设备是否还在。可以通过os.path.exists(/dev/ttyAMA0)来判断如果设备消失了说明硬件出了问题。第三日志要写清楚。每个串口的收发数据量、错误次数、重连次数都记录下来方便出问题的时候回溯。我一般会用 Python 的logging模块按天切分日志文件避免单个文件过大。第四供电要稳定。树莓派 4 对电源比较敏感如果同时接了多个 USB 转串口模块建议用质量好一点的电源适配器输出电流至少 3A。供电不足会导致 USB 设备频繁掉线表现就是串口时好时坏。6.4 一个实际的多串口数据转发场景最后分享一个我自己做过的场景树莓派 4 同时接了一个 GPS 模块走 uart29600 波特率、一个环境传感器走 uart3115200 波特率和一个老式控制器走 USB 转串口4800 波特率。树莓派需要把这三个设备的数据汇总然后通过 uart0 转发给另一块主控板。实现思路很简单三个读取线程分别采集数据统一放到一个队列里主线程从队列取数据加上时间戳和设备标识打包成固定格式通过 uart0 发出去。整个系统跑了一周多没有出现丢包或者死机。关键点在于每个串口的读取线程独立、队列做缓冲、发送端做流量控制。这个方案的可扩展性也不错如果以后要加第四个设备只需要再加一个读取线程和对应的串口配置就行主线程的逻辑基本不用动。
延伸阅读

更多相关文章

2026/10/15 21:40:12

ArcGIS ModelBuilder批量裁剪遥感影像实战指南

简介:本资源是一份面向GIS初学者与ArcGIS实操用户的高效工作流指南,聚焦解决多边形面层驱动的影像批量裁剪这一典型生产需求。文档详细拆解了利用ArcGIS Desktop内置模型构建器(ModelBuilder)搭建自动化裁剪流程的完整路径&#x…

2026/10/15 21:40:12

C++ Builder课程设计:基于ODBC和Access的选课系统开发全流程

简介:这是一份面向计算机科学与技术专业学生的软件工程实践指导书,围绕选课系统的小型项目开发,帮助初学者按照软件工程思想与面向对象方法,将编程语言、数据库等专业知识综合运用到实际系统中。指导书明确了实验目的、专业方向与…

2026/10/15 21:40:12

XDMA实战笔记:通道模型、描述符队列与避坑指南

简介:Xilinx XDMA(DMA/Bridge Subsystem for PCI Express v4.1)中文读书笔记,以官方PG195文档为主线,并结合GitHub上的dma_ip_drivers驱动与Xilinx官方FAQ整理,弥补官方英文手册阅读门槛高、中文系统资料少…

2026/10/15 22:50:59

AI驱动PLC开发:WorkBuddy+TiaLink双引擎实现语义级代码生成

1. 这不是“写代码”,而是给PLC装上会思考的脑子你有没有试过在TIA Portal里反复修改一个计时器的预设值,就为了适配现场电机启停节奏的微小变化?有没有因为产线换型,不得不把三年前写的FC块翻出来,对着注释猜自己当年…

2026/10/15 22:50:59

线性回归从零实现:PyTorch梯度下降与自动求导实战

线性回归从零实现:PyTorch实战详解线性回归可能是很多人接触机器学习的第一个模型,但“会用sklearn.linear_model跑通一条.fit()”和“亲手把梯度下降写出来”完全是两码事。这个标题看着基础,实际操作中牵扯到的自动求导机制、参数初始化、损…

2026/10/15 22:50:59

openclaw使用体验:把本地代理失败改到 TaoToken 的排查记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 22:45:59

用Pandas自动生成人力月报:Excel手工报表流程的完整替代方案

在人力数据分析这个方向看得多了,我发现真正把同行拖垮的往往不是分析思路,而是Excel里那套复制粘贴、VLOOKUP、透视表、调格式的流水线。每月初收各部门花名册、入职台账、离职台账,串数据就得大半天,交上去的报表老板只看几个数…

2026/10/14 11:31:03

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/14 17:41:07

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/15 13:42:16

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/15 0:02:22

防关联浏览器哪个好?三款产品实测差异解析

新手做多店铺,最纠结的就是防关联浏览器选哪个。飞跨、网易、站斧这三款被问得最多,先给结论:要一体化省心、长期便宜,选站斧;要网易招牌和稳,选网易;预算紧做东南亚 Lazada,选飞跨。…

2026/10/15 0:02:22

影刀RPA深度实战:大模型Fine-tuning定制RPA专用Prompt与指令生成

影刀RPA深度实战:大模型Fine-tuning定制RPA专用Prompt与指令生成 一、技术背景 大模型(LLM)在通用场景下表现强大,但当我们将 GPT-4 或 Qwen 直接用于生成影刀RPA操作指令和 XPath 定位时,准确率通常只有 40%-60%。原因…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑