
1. 树莓派串口通信基础解析树莓派的串口通信功能是其与外部设备交互的重要方式之一。作为一名嵌入式开发者我经常使用UART接口连接各种传感器、模块和其他微控制器。树莓派提供了两种UART硬件PL011和mini UART它们各有特点。PL011 UART是ARM架构的原生UART控制器性能稳定且功能完整。它支持高达3Mbps的波特率具有独立的64字节收发FIFO支持硬件流控RTS/CTS。在实际项目中当需要可靠的高速通信时PL011是首选。mini UART则是Broadcom设计的简化版UART它的波特率与GPU核心频率相关。这意味着当GPU频率变化时如进行图形密集型任务时mini UART的波特率会随之漂移可能导致通信错误。mini UART也没有硬件流控和奇偶校验功能适合对稳定性要求不高的场景。注意树莓派3及更新型号默认将PL011分配给蓝牙模块而将mini UART分配给GPIO的UART引脚。这是很多初学者容易混淆的地方。2. 硬件准备与引脚配置2.1 硬件连接方式树莓派的UART使用GPIO14TXD和GPIO15RXD引脚。与PC或其他设备连接时需要注意电平转换直接连接其他3.3V设备时可以直连树莓派TXD → 对方RXD树莓派RXD → 对方TXD共地连接必不可少连接5V设备或PC时需要电平转换推荐使用MAX3232或CH340G等转换芯片也可以使用分压电阻1kΩ2kΩ进行简易转换2.2 启用UART接口在最新版Raspbian系统中UART默认是禁用的分配给蓝牙。启用步骤sudo raspi-config选择Interfacing Options → Serial第一个提示选择No禁用控制台登录第二个提示选择Yes启用硬件串口然后修改/boot/config.txt文件sudo nano /boot/config.txt添加或修改以下行enable_uart1 dtoverlaypi3-miniuart-bt保存后重启系统。3. Python实现UART通信3.1 安装pyserial库pip install pyserial3.2 基础通信示例import serial import time # 配置串口参数 ser serial.Serial( port/dev/serial0, # 使用别名确保兼容性 baudrate115200, parityserial.PARITY_NONE, stopbitsserial.STOPBITS_ONE, bytesizeserial.EIGHTBITS, timeout1 ) try: while True: # 发送数据 ser.write(bHello from Raspberry Pi\n) # 接收数据 if ser.in_waiting 0: received_data ser.readline() print(fReceived: {received_data.decode(utf-8).strip()}) time.sleep(1) except KeyboardInterrupt: print(Program terminated) finally: ser.close()3.3 高级功能实现二进制数据传输# 发送二进制数据 data bytes([0xAA, 0xBB, 0xCC]) ser.write(data) # 接收二进制数据 raw_data ser.read(3) # 读取3个字节使用线程实现全双工通信from threading import Thread def receive_thread(): while True: if ser.in_waiting: print(ser.readline().decode()) Thread(targetreceive_thread, daemonTrue).start()4. C语言实现UART通信4.1 使用wiringPi库首先安装wiringPisudo apt-get install wiringpi基础通信代码#include stdio.h #include string.h #include wiringPi.h #include wiringSerial.h int main() { int serial_port; char buffer[256]; if ((serial_port serialOpen(/dev/serial0, 115200)) 0) { fprintf(stderr, Unable to open serial device: %s\n, strerror(errno)); return 1; } if (wiringPiSetup() -1) { fprintf(stdout, Unable to start wiringPi: %s\n, strerror(errno)); return 1; } while (1) { // 发送数据 sprintf(buffer, Counter: %d\n, millis()/1000); serialPuts(serial_port, buffer); // 接收数据 while (serialDataAvail(serial_port)) { printf(%c, serialGetchar(serial_port)); fflush(stdout); } delay(1000); } return 0; }4.2 使用Linux原生API对于更底层的控制可以直接使用termios#include fcntl.h #include termios.h #include unistd.h int setup_uart(const char *device) { int fd open(device, O_RDWR | O_NOCTTY | O_NDELAY); if (fd -1) return -1; struct termios options; tcgetattr(fd, options); cfsetispeed(options, B115200); cfsetospeed(options, B115200); options.c_cflag | (CLOCAL | CREAD); options.c_cflag ~PARENB; options.c_cflag ~CSTOPB; options.c_cflag ~CSIZE; options.c_cflag | CS8; options.c_lflag ~(ICANON | ECHO | ECHOE | ISIG); options.c_oflag ~OPOST; tcsetattr(fd, TCSANOW, options); return fd; }5. 常见问题与解决方案5.1 波特率不匹配问题症状接收到的数据乱码 解决方法确认双方波特率设置一致检查时钟稳定性特别是使用mini UART时在config.txt中添加core_freq250固定核心频率5.2 数据丢失问题症状部分数据包丢失 解决方法实现软件流控XON/XOFF减小数据包大小增加接收缓冲区ser serial.Serial(..., rtsctsTrue) # 启用硬件流控5.3 权限问题症状无法打开/dev/serial0 解决方法sudo usermod -a -G dialout pi然后注销重新登录。6. 性能优化技巧提高通信可靠性添加数据校验CRC或校验和实现重传机制使用消息帧格式如[STX][DATA][ETX][CRC]提高吞吐量增大缓冲区大小ser serial.Serial(..., write_timeout0, xonxoffTrue, rtsctsTrue, dsrdtrTrue)使用DMA传输C语言实现多串口扩展使用USB转串口适配器如CP2102通过GPIO模拟软串口需要精确计时在实际项目中我通常会结合Python的快速开发优势和C语言的高性能特点。例如用Python实现上层协议解析而用C处理底层的高速数据采集。这种混合编程方式既能保证开发效率又能满足性能需求。