尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

树莓派4B Ubuntu 22.04串口配置与通信实战指南

树莓派4B Ubuntu 22.04串口配置与通信实战指南 1. 项目概述为什么要在树莓派4B上折腾Ubuntu 22.04的串口如果你手头有一块树莓派4B并且已经厌倦了官方的Raspberry Pi OS或者你的项目需要更标准的Linux发行版环境那么给树莓派4B刷上Ubuntu 22.04 Server绝对是一个值得尝试的选择。Ubuntu Server提供了更纯粹的Linux体验、更稳定的软件源和更广泛的社区支持特别适合用于物联网网关、边缘计算节点或者需要长期稳定运行的服务端应用。然而当你兴冲冲地装好系统准备用最经典的串口UART方式连接传感器、单片机或者调试其他嵌入式设备时很可能会发现事情没那么简单。树莓派4B的硬件串口默认被蓝牙模块占用而Ubuntu 22.04在树莓派上的默认配置又和Raspberry Pi OS有所不同直接使用/dev/ttyS0或/dev/ttyAMA0可能会遇到没数据、权限错误或者根本找不到设备的问题。这个项目要解决的就是打通树莓派4B在Ubuntu 22.04系统下的串口通信链路让你能像在传统嵌入式开发板上一样稳定、可靠地使用串口进行数据收发和调试。我之所以花时间折腾这个是因为在一个工业数据采集项目中需要树莓派作为网关通过串口连接多个RS485传感器。Raspberry Pi OS在某些驱动和库的版本上遇到了兼容性问题而Ubuntu 22.04 LTS的长期支持特性更符合项目要求。踩过一系列坑之后我把从系统安装、串口配置、权限设置到实际测试的完整流程和心得记录下来希望能帮你省下大量搜索和试错的时间。2. 核心需求解析树莓派4B串口的特殊性要搞定串口通信首先得理解树莓派4B的串口硬件布局和Ubuntu系统下的软件映射这和我们在x86电脑或者传统ARM开发板上的经验不太一样。2.1 树莓派4B的UART资源盘点树莓派4B板载了多个UART控制器但并非所有都能直接给用户使用PL011 UART这是一个功能完整的、高性能的UART通常对应硬件UART0。在早期的树莓派上它默认映射到GPIO的TXGPIO14和RXGPIO15引脚也就是那个40针排针的8号和10号针脚。然而在树莓派4B上这个PL011 UART默认分配给了蓝牙模块使用以实现蓝牙的HCI通信。这是第一个关键点。Mini UART这是一个由内核驱动实现的、功能相对简单的UART通常对应UART1。它的波特率依赖于核心时钟频率因此稳定性不如PL011。在默认配置下这个Mini UART被映射到了GPIO14和GPIO15供用户使用。所以我们的目标通常有两种一是直接使用默认分配给用户的Mini UART/dev/ttyS0二是通过配置“交换”把功能更强的PL011 UART/dev/ttyAMA0从蓝牙那里“抢”过来给GPIO引脚用。选择哪种方案取决于你的需求。2.2 Ubuntu 22.04 for Raspberry Pi的默认状态当你从Ubuntu官网下载并安装“Ubuntu 22.04 LTS for Raspberry Pi”镜像后系统对串口的处理方式与Raspberry Pi OS有细微差别。默认情况下串口控制台登录被禁用与一些基础镜像不同Ubuntu Server默认不会通过串口提供登录终端getty服务。这其实是好事意味着串口设备可以被我们独占用于应用通信而不会被登录会话占用。设备文件映射你需要通过ls -l /dev/tty*命令来查看具体的设备文件。通常/dev/ttyAMA0对应PL011 UART/dev/ttyS0对应Mini UART。但它们的最终功能取决于设备树Device Tree的配置。权限问题默认情况下串口设备文件属于dialout用户组。普通用户如ubuntu需要被添加到dialout组才能有读写权限否则会报“Permission denied”错误。理解这些是后续所有操作的基础。我的建议是除非你有必须使用蓝牙的需求否则将PL011 UART交换到GPIO引脚是更优选择能获得更稳定的通信性能特别是在高波特率如115200以上或需要硬件流控RTS/CTS的场景下。3. 系统准备与串口配置实战理论清楚了我们开始动手。整个过程可以分为系统安装、基础配置、串口功能切换和权限设置四个步骤。3.1 为树莓派4B安装Ubuntu 22.04 Server首先你需要准备一张至少8GB的Micro SD卡。从Ubuntu官方网站下载“Ubuntu 22.04 LTS for Raspberry Pi”的镜像文件通常是.xz压缩格式。我推荐使用Raspberry Pi Imager这个工具进行烧录它非常直观而且会自动处理镜像解压。在Raspberry Pi Imager中选择你的SD卡然后点击“Choose OS” - “Other general-purpose OS” - “Ubuntu” - “Ubuntu Server 22.04 LTS (RPi 4/400)” 。接着点击“Choose Storage”选择你的SD卡。这里有一个关键操作不要急着点“WRITE”先按下键盘上的CtrlShiftX这会打开“高级选项”菜单。在高级选项中我强烈建议你预先做两件事启用SSH并设置密码勾选“Enable SSH”并选择“Use password authentication”设置一个强密码。这样系统首次启动后你就可以通过网络SSH登录无需连接显示器和键盘。配置Wi-Fi可选如果你不方便接网线在这里填入你的Wi-Fi SSID和密码。这样树莓派开机后就能自动联网方便后续通过SSH访问和安装软件。设置完成后点击“Save”再点击“WRITE”开始烧录。烧录完成后将SD卡插入树莓派4B上电启动。3.2 首次登录与基础环境配置等待几分钟首次启动会进行扩容等操作你应该可以通过之前设置的密码使用SSH连接到树莓派。默认用户名是ubuntu。ssh ubuntu你的树莓派IP地址登录后第一件事是更新系统确保所有软件包都是最新的sudo apt update sudo apt upgrade -y更新完成后建议重启一次sudo reboot。接下来安装一些我们后续可能会用到的工具比如用于串口调试的minicom和用于查看硬件信息的device-tree-compilersudo apt install -y minicom device-tree-compiler3.3 核心步骤配置设备树以启用GPIO串口这是整个流程中最关键的一步我们需要修改引导配置告诉内核我们想怎么使用串口硬件。备份原始配置操作前先备份总是一个好习惯。sudo cp /boot/firmware/config.txt /boot/firmware/config.txt.bak sudo cp /boot/firmware/cmdline.txt /boot/firmware/cmdline.txt.bak编辑config.txt文件这个文件决定了硬件的基本初始化参数。sudo nano /boot/firmware/config.txt在文件末尾添加以下几行配置。它们的含义如下# 启用UART无论是Mini UART还是PL011 enable_uart1 # 将PL011 UART (ttyAMA0) 交换到GPIO14/15引脚 dtoverlayuart5 # 禁用蓝牙以彻底释放PL011 UART。如果你需要蓝牙则不要加这一行并考虑使用Mini UART方案。 dtoverlaydisable-btenable_uart1这是必须的它确保UART控制器被上电并初始化。dtoverlayuart5这个叠加层Overlay是树莓派4B专用的它的作用是将ttyAMA0PL011 UART重新映射到GPIO14和GPIO15引脚。注意在树莓派4B上这个叠加层的名字是uart5而不是早期型号的pi3-miniuart-bt或pi3-disable-bt用错会导致配置无效。dtoverlaydisable-bt这行会禁用蓝牙硬件。因为PL011之前被蓝牙占用如果我们想独占PL011用于GPIO串口最简单的办法就是禁用蓝牙。如果你的项目同时需要蓝牙和高质量串口那么配置会复杂很多可能需要手动配置蓝牙使用Mini UART这超出了本文基础范围。添加完成后按CtrlX然后按Y再按Enter保存退出。检查并清理cmdline.txt文件这个文件包含了传递给Linux内核的启动参数。我们需要确保里面没有关于串口控制台的参数否则它会占用我们想用的串口设备。sudo nano /boot/firmware/cmdline.txt检查这一行内容。在Ubuntu for Raspberry Pi的默认安装中通常不包含类似consoleserial0,115200或consolettyAMA0,115200这样的参数。如果发现有请将其删除。删除后这一行应该只剩下关于根文件系统等的基本参数。保存并退出。重启系统让所有配置生效。sudo reboot3.4 验证配置与设置权限重启并重新SSH登录后我们来验证配置是否成功。查看串口设备ls -l /dev/ttyAMA0 /dev/ttyS0你应该能看到类似以下的输出crw-rw---- 1 root dialout 204, 64 May 10 10:30 /dev/ttyAMA0 crw-rw---- 1 root dialout 4, 64 May 10 10:30 /dev/ttyS0这表示两个串口设备都存在。根据我们的配置uart5叠加层现在/dev/ttyAMA0PL011应该已经被映射到了GPIO14/15引脚。验证引脚映射我们可以通过读取设备树状态来确认。sudo dtoverlay -l这个命令会列出所有已加载的设备树叠加层。你应该能看到uart5在列表中。 更详细地可以查看sudo cat /sys/kernel/debug/pinctrl/fe201000.serial/pins或者一个更简单的方法是使用raspi-gpio工具如果已安装来查看GPIO14/15的功能复用状态但Ubuntu Server默认可能没有。一个实用的替代方法是我们直接进行物理连接测试。将用户加入dialout组为了避免每次都用sudo把你的用户添加到串口所属的用户组。sudo usermod -a -G dialout $USER重要这个改动需要重新登录退出SSH会话再重新连接才能生效。仅仅su - $USER可能不够。4. 硬件连接与通信测试配置好了软件现在需要连接硬件进行实测。你需要一个USB转TTL串口模块比如常见的CH340、CP2102、FT232等芯片的模块。4.1 物理连接注意事项安全第一务必在树莓派断电的情况下进行连接连接USB转TTL模块到树莓派4B的GPIO引脚USB转TTL模块的GND-树莓派GPIO的GND例如第6针脚。USB转TTL模块的RX-树莓派GPIO的TX (GPIO14)第8针脚。USB转TTL模块的TX-树莓派GPIO的RX (GPIO15)第10针脚。核心口诀RX接TXTX接RXGND接GND。千万不要把模块的VCC通常是5V或3.3V接到树莓派的GPIO上树莓派的GPIO是3.3V电平接5V可能会损坏板子我们的连接只涉及数据线和地线。将USB转TTL模块插入你的电脑用于测试的电脑不是树莓派。4.2 使用Minicom进行双向测试首先在你的电脑上比如另一台Linux机器或Windows上使用Putty、MobaXterm等打开串口终端连接USB转TTL模块对应的端口如COM3或/dev/ttyUSB0设置波特率为115200数据位8停止位1无校验位8N1无流控。然后在树莓派的SSH终端里我们使用minicom作为串口调试工具。启动Minicom配置并发送数据sudo minicom -D /dev/ttyAMA0 -b 115200如果提示minicom: cannot open /dev/ttyAMA0: Permission denied说明之前的用户组设置还没生效请确认已重新登录或者暂时用sudo运行。进入minicom界面是一个简单的终端直接打字。你输入的字符会通过树莓派的TX线发送出去。此时你应该能在电脑的串口终端上看到这些字符。接收数据测试 在minicom界面中按CtrlA然后按Z可以看到minicom的帮助菜单。再按E可以打开本地回显这样你在树莓派端也能看到自己发的字符但这不是必须的。 现在在电脑的串口终端里输入一些字符。这些字符会通过电脑发送到树莓派的RX线。如果一切正常你将在树莓派的minicom界面中看到这些字符。测试完成后在minicom中按CtrlA然后按X选择Yes退出。4.3 使用Python脚本进行自动化测试使用命令行工具测试直观但实际项目更多是用编程语言控制。这里提供一个简单的Python3测试脚本它既能发送也能接收。首先在树莓派上安装Python的串口库pyserialsudo apt install -y python3-serial # 或者使用pip安装 pip3 install pyserial然后创建一个测试脚本uart_test.py#!/usr/bin/env python3 import serial import time import threading def read_from_port(ser): while True: if ser.in_waiting 0: data ser.read(ser.in_waiting) print(fReceived: {data.decode(utf-8, errorsignore)}, end) def main(): # 配置串口参数根据你的实际设备文件修改 port /dev/ttyAMA0 # 使用我们配置好的PL011 UART baudrate 115200 try: # 打开串口 ser serial.Serial(port, baudrate, timeout1) print(fSerial port {port} opened at {baudrate} baud.) except serial.SerialException as e: print(fError opening serial port: {e}) return # 启动一个线程来持续监听接收数据 reader_thread threading.Thread(targetread_from_port, args(ser,)) reader_thread.daemon True reader_thread.start() try: while True: # 从标准输入读取一行并发送在终端中手动输入 # 注意在SSH中运行这样可以直接输入 send_data input(Enter text to send (or quit to exit): ) if send_data.lower() quit: break ser.write((send_data \n).encode(utf-8)) print(fSent: {send_data}) except KeyboardInterrupt: print(\nExiting...) finally: ser.close() print(Serial port closed.) if __name__ __main__: main()运行这个脚本python3 uart_test.py。在一个终端运行它然后在电脑的串口终端发送信息你应该能在树莓派的这个脚本输出中看到接收到的数据。同时在脚本提示“Enter text to send”时输入内容电脑的串口终端也能收到。这个脚本采用了多线程一个线程负责持续监听串口接收缓冲区并打印出来主线程负责处理用户输入和发送是一个很实用的基础框架。5. 高级配置与性能调优基础通信通了但为了应对更复杂的场景我们还需要了解一些高级配置。5.1 调整串口缓冲区与超时在高频、大数据量传输时默认的缓冲区大小可能不够可能导致数据丢失。pyserial和系统底层都提供了调整空间。在Python中可以在初始化Serial对象时设置ser serial.Serial( port/dev/ttyAMA0, baudrate115200, bytesizeserial.EIGHTBITS, parityserial.PARITY_NONE, stopbitsserial.STOPBITS_ONE, timeoutNone, # 读超时None为阻塞模式 xonxoffFalse, # 软件流控 rtsctsFalse, # 硬件RTS/CTS流控需连接对应引脚 dsrdtrFalse, # 硬件DSR/DTR流控 write_timeoutNone, # 写超时 inter_byte_timeoutNone, # 字节间超时 # 以下两个参数影响读性能 # read()操作会尝试读取最多这个字节数但受限于底层缓冲 # exclusiveTrue 可以阻止其他进程打开同一端口 )对于Linux系统本身可以通过stty命令或ioctl系统调用来调整底层终端设备参数但这通常需要更深入的编程。5.2 硬件流控RTS/CTS的使用如果你的设备支持硬件流控用于防止数据丢失树莓派4B的PL011 UART是支持的。你需要额外连接GPIO引脚树莓派GPIO16 (BCM 23)- 设备的CTS树莓派GPIO17 (BCM 24)- 设备的RTS然后在config.txt中确保你的uart5叠加层没有禁用流控默认是启用的。在Python代码中将rtsctsTrue。注意Mini UART不支持硬件流控。5.3 固定设备名与udev规则默认的/dev/ttyAMA0名字是固定的但如果你有多个串口设备比如通过USB转串口扩展设备名可能会变如/dev/ttyUSB0,/dev/ttyUSB1。为了在程序中可靠地使用特定设备可以通过udev规则为其创建固定的符号链接。例如为特定的USB转串口模块通过其供应商ID和产品ID识别创建一个别名插入设备用lsusb找到其ID比如1a86:7523CH340。创建规则文件sudo nano /etc/udev/rules.d/99-usb-serial.rules加入一行将1a86和7523替换为你的设备IDSUBSYSTEMtty, ATTRS{idVendor}1a86, ATTRS{idProduct}7523, SYMLINKttyMyDevice重新加载udev规则并重启服务sudo udevadm control --reload-rules sudo udevadm trigger重新插拔设备现在除了/dev/ttyUSBx还会出现一个固定的/dev/ttyMyDevice链接。6. 常见问题与深度排查指南即使按照步骤操作你也可能会遇到一些问题。这里汇总了我遇到过的典型情况及其解决方法。6.1 问题速查表问题现象可能原因排查步骤与解决方案ls /dev/ttyAMA0无此设备1.config.txt中enable_uart1未设置或错误。2. 设备树叠加层未正确加载。1. 检查/boot/firmware/config.txt内容确保enable_uart1存在且无误。2. 运行sudo dtoverlay -l和sudo vcdbg log msgPermission denied错误当前用户不在dialout组。1. 执行groups命令查看当前用户所属组。2. 使用sudo usermod -a -G dialout $USER添加并重新登录SSH会话。3. 临时使用sudo运行命令测试。Minicom或Python能打开设备但收发无数据1. 线接反了TX/RX。2. 波特率等参数不匹配。3. 流控设置错误。4. 串口被其他进程占用。1.重点检查确保是树莓派TX接模块RX树莓派RX接模块TX。2. 双方树莓派和电脑终端的波特率、数据位、停止位、校验位必须完全一致。3. 在minicom或代码中关闭流控xonxoff, rtscts设为False。4. 使用sudo lsof /dev/ttyAMA0查看是哪个进程占用了端口。发送数据正常但接收不到任何数据1. 电脑端串口终端设置或连接问题。2. 树莓派端RX引脚接触不良或损坏。3. 电平不匹配虽不常见但3.3V与5V设备混接可能有问题。1. 用短接测试在树莓派断电下用杜邦线将GPIO14 (TX) 和 GPIO15 (RX)短接。上电后用minicom发送字符如果能在minicom里看到自己发送的字符本地回显说明树莓派自身串口环路是通的问题在外围。2. 换一个USB转TTL模块或电脑USB口测试。3. 确保模块是3.3V电平的或者确认其RX脚能容忍3.3V输入。通信数据出现乱码波特率不匹配是最大可能。1. 精确核对双方波特率。115200和9600是常用值但必须一致。2. 检查电脑端串口工具和树莓派代码中的波特率设置。3. 尝试降低波特率如降到9600测试是否稳定。系统启动后蓝牙失效在config.txt中加入了dtoverlaydisable-bt。如果你需要蓝牙不要添加disable-bt叠加层。此时你需要使用Mini UART (/dev/ttyS0) 进行GPIO串口通信但需要额外配置蓝牙使用PL011 UART这涉及更复杂的设备树和hciattach配置通常不建议新手操作。6.2 深度排查命令工具箱当问题比较复杂时以下命令能帮你深入系统内部查看状态查看内核启动信息中的串口相关部分dmesg | grep -E \tty|uart|serial\这会显示内核识别串口设备的过程看看是否有错误信息。查看详细的硬件映射信息# 查看串口设备对应的物理地址和中断 sudo cat /proc/tty/driver/serial # 或查看更详细的信息 sudo cat /sys/kernel/debug/pinctrl/fe201000.serial/pingroups # 对于PL011检查串口当前参数设置stty -F /dev/ttyAMA0 -a这个命令会输出该串口设备的所有当前设置包括波特率、数据位等非常有用。测试串口发送不依赖Pythonecho \hello\ /dev/ttyAMA0这行命令会直接向串口发送字符串“hello”。可以在短接TX/RX后用cat /dev/ttyAMA0来接收测试最基本的发送功能。检查设备树叠加层是否生效# 查看所有已加载的叠加层 sudo dtoverlay -l # 查看某个叠加层的参数如uart5 sudo dtparam -l | grep uart6.3 关于Mini UART (ttyS0) 的稳定性问题如果你因为需要蓝牙而选择使用Mini UART (/dev/ttyS0)需要特别注意它的一个固有缺陷其波特率依赖于核心时钟频率core_freq。当CPU频率因负载或节能策略发生变化时如启用ondemand调速器Mini UART的波特率可能会发生漂移导致通信错误。解决方案 在/boot/firmware/config.txt中固定核心时钟频率core_freq250或者更激进地直接固定CPU频率调速器为性能模式但这可能增加功耗echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor为了持久化可以将后者写入启动脚本。但最根本的解决方案还是如前所述使用PL011 UART并禁用蓝牙以获得最好的稳定性。7. 项目集成与实战心得将串口通信集成到实际项目中远不止是收发几个字符那么简单。下面分享几个我在实际项目中积累的经验点。7.1 在后台服务中可靠地使用串口如果你写的是一个需要长期运行的后台服务比如一个数据采集守护进程直接使用上面的Python脚本可能不够健壮。你需要考虑异常处理与重连串口设备可能因为意外拔插、电磁干扰等原因断开。你的代码必须能捕获serial.SerialException异常并在等待一段时间后尝试重新初始化连接。资源释放确保在程序退出无论是正常退出还是被信号终止时能关闭串口。可以使用atexit模块注册清理函数或者使用try...finally语句块。使用pySerial的read_until或readline对于有明确分隔符如换行符\n的协议使用ser.readline()比手动循环读取ser.read()更方便。但要注意设置合理的timeout避免在数据不完整时无限阻塞。考虑使用异步对于高并发或需要同时处理网络和串口IO的项目可以考虑使用asyncio配合pyserial-asyncio库避免线程管理的复杂性。7.2 与常见硬件协议对接串口通信本身只是物理层实际应用中需要遵循特定的应用层协议。Modbus RTU这是工业领域最常用的协议之一。在Python中可以使用pymodbus库pip3 install pymodbus的RTU版本来轻松实现主站读取传感器或从站模拟设备功能。关键是要正确设置串口参数波特率、数据位、停止位、校验位——Modbus RTU通常使用8N1或8E1。自定义文本协议很多传感器输出简单的ASCII文本如\TEMP:25.6,HUM:60\。处理这类协议时解析的鲁棒性很重要。建议使用状态机或正则表达式来解析并处理好数据帧不完整、粘包的情况。二进制协议处理二进制数据时struct模块是你的好帮手可以方便地打包和解包数据。一定要明确字节序大端/小端。7.3 性能与稳定性监控对于7x24小时运行的项目加入简单的监控是很有必要的。日志记录使用Python的logging模块将发送和接收的重要数据、发生的错误记录到文件或系统日志syslog中。设置日志轮转避免日志文件无限增大。简单看门狗可以设计一个简单的线程定期比如每分钟通过串口发送一个“心跳”查询指令并期待设备的响应。如果连续多次无响应则触发报警或重启串口连接。系统服务化使用systemd将你的Python脚本管理为系统服务。这样可以实现开机自启、崩溃自动重启、集中日志管理。一个简单的.service文件就能搞定。我个人在多个基于树莓派和Ubuntu Server的物联网网关项目中都采用了“PL011 UART 禁用蓝牙 Python守护进程 systemd管理”的方案。这套组合拳提供了接近工业级的稳定性和可维护性。最大的教训就是硬件连接一定要反复确认特别是TX/RX在投入长期运行前务必进行至少24小时的压力测试模拟各种数据收发情况才能提前发现潜在的稳定性问题。
返回列表