通信协议基础:串口通信(UART)原理
各位同学,咱们今天聊点实在的。串口通信,也就是UART,是嵌入式开发里最基础、也最常用的通信方式。我做了十几年嵌入式,可以说90%的调试工作都离不开它。你想想看,一个单片机刚焊好,能不能跑起来?第一件事就是看串口有没有打印信息。
说白了,UART就是两个设备之间,用一根线发数据,一根线收数据。没有时钟线,全靠双方约定好节奏。这个节奏,就是我们常说的波特率。
波特率:通信的节拍器
波特率,单位是bps(bits per second),意思是每秒传输多少个比特。常见的波特率有9600、19200、115200。我个人习惯,调试时用115200,速度快;产品量产时用9600,抗干扰能力强。
核心要点:发送方和接收方的波特率必须一致,误差不能超过2%。否则就会出现乱码,甚至完全收不到数据。
我在项目中遇到过一件事。有个同事调试蓝牙模块,怎么都连不上。折腾了两天,最后发现是波特率设成了9600,但代码里写的是19200。嗯,这种低级错误,谁都会犯,但排查起来真的很费时间。
数据位、停止位、校验位
UART的一帧数据,就像一列火车。有车头、车厢、车尾。咱们来看看这列火车长什么样。
| 字段 | 长度 | 说明 |
|---|---|---|
| 起始位 | 1位 | 固定为0,表示开始传输 |
| 数据位 | 5~9位 | 常用8位,正好一个字节 |
| 校验位 | 0或1位 | 奇校验或偶校验 |
| 停止位 | 1或2位 | 固定为1,表示传输结束 |
数据位:最常见的是8位。为什么?因为一个字节就是8位,方便处理。有些老设备用7位,比如传ASCII码,但现在已经很少见了。
停止位:我建议用1位。2位停止位虽然更可靠,但会降低传输效率。只有在长距离通信或者干扰严重的环境下,才考虑用2位。
校验位:这个要重点说说。校验位分奇校验和偶校验。奇校验,就是让数据位+校验位里1的个数为奇数。偶校验则相反。
我的经验:校验位只能检测奇数个比特的错误。如果两个比特同时翻转,校验位是检测不出来的。所以,对数据可靠性要求高的场景,建议用更高级的校验方式,比如CRC。
我曾经在一个医疗理疗仪项目里,用了奇校验。结果发现偶尔会有数据错误,但校验位没报错。排查了很久,才发现是电源干扰导致连续两个比特翻转。从那以后,我对校验位的信任度就打了折扣。
物理层与协议层的区别
这个问题,很多初学者会搞混。我换个角度给你讲。
物理层:管的是「怎么传」。比如电压是多少伏,用几根线,接口是什么形状。RS232是±12V,TTL是0~3.3V或0~5V。这就是物理层的区别。
协议层:管的是「传什么」。比如数据怎么打包,先发什么后发什么,收到数据后怎么应答。Modbus、自定义协议,这些都是协议层的事。
你想想看,物理层就像公路,协议层就像交通规则。公路是水泥路还是柏油路,这是物理层;靠左行驶还是靠右行驶,这是协议层。两者缺一不可。
避坑指南:我曾经见过一个工程师,把TTL电平的串口直接连到RS232的设备上。结果呢?烧了。因为TTL是3.3V,RS232是±12V,电平不匹配。所以,做硬件连接前,一定要先确认物理层参数。
实际项目中的串口配置
咱们来看一个实际的代码片段。这是STM32上配置UART的典型写法:
// 串口初始化结构体
UART_HandleTypeDef huart1;
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200; // 波特率
huart1.Init.WordLength = UART_WORDLENGTH_8B; // 8位数据位
huart1.Init.StopBits = UART_STOPBITS_1; // 1位停止位
huart1.Init.Parity = UART_PARITY_NONE; // 无校验
huart1.Init.Mode = UART_MODE_TX_RX; // 收发模式
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; // 无硬件流控
HAL_UART_Init(&huart1);
这段代码里,我用了无校验、1位停止位、8位数据位。这是最常用的配置,也叫8N1。为什么不用校验?因为我的数据包里有CRC校验,协议层已经保证了可靠性,物理层就不需要再画蛇添足了。
注意:硬件流控(RTS/CTS)一般不用。除非你的设备之间距离很远,或者数据量很大。我做过一个项目,用了硬件流控,结果因为线没接对,导致数据一直发不出去。排查了整整一天。
串口通信的常见问题
- 乱码:先检查波特率,再检查数据位和停止位。如果都没问题,看看是不是电平不匹配。
- 丢数据:可能是缓冲区太小,或者中断优先级太低。我建议接收缓冲区至少256字节。
- 通信不稳定:检查地线。串口通信一定要共地,否则信号飘忽不定。
我记得有一次,一个理疗仪在客户现场频繁掉线。远程调试了半天,最后发现是地线接触不良。嗯,这种问题,示波器一看就知道,但远程确实难搞。
总结一下
串口通信,说难不难,说简单也不简单。物理层和协议层要分清楚,配置参数要匹配,硬件连接要可靠。做到这三点,基本就不会出大问题。
下一节课,咱们聊聊Modbus协议。那是工业领域最常用的串口协议,也是理疗仪远程控制的核心。到时候我会分享一些实际项目中的踩坑经验,敬请期待。