3、串口通信原理:UART协议、波特率、数据帧格式、奇偶校验、流控制等基本概念
在K210与单片机(如STM32、ESP32、Arduino)之间建立可靠的通信链路,串口(UART)是最常用、最直接的物理层与协议层方案。UART(Universal Asynchronous Receiver/Transmitter,通用异步收发器)是一种全双工、异步、串行通信协议,它只需要两根数据线(TX与RX)即可实现双向数据传输。理解UART的底层机制——包括波特率如何决定通信速率、数据帧如何封装有效信息、奇偶校验如何提供基础检错能力、流控制如何防止数据溢出——是编写稳定通信代码的前提。本章将从协议原理出发,结合K210与单片机实际连接场景,深入剖析这些核心概念,并给出可落地的配置建议与排障方法。
上图展示了K210与单片机之间UART通信的物理连接与数据帧结构。在硬件层面,K210的TX引脚必须连接到单片机的RX引脚,反之亦然,同时必须共地。在协议层面,每个数据帧由起始位、数据位、可选的校验位和停止位组成。下面我们将逐一拆解这些概念。
3.1 核心原理:UART如何工作
UART是一种异步串行协议,意味着通信双方不需要共享时钟信号。取而代之的是,双方必须预先约定完全相同的波特率(Baud Rate),即每秒传输的符号数。在UART中,一个符号通常对应一个比特(bit),因此波特率等同于比特率(bps)。例如,115200波特率意味着每秒传输115200个比特。
由于没有时钟线,接收端必须依靠起始位来同步。当线路空闲时,TX引脚保持高电平(逻辑1)。发送端要发送数据时,先将线路拉低一个波特率周期,这个低电平就是起始位。接收端检测到下降沿后,便以波特率为基准,在每个比特的中间时刻采样,从而恢复出数据位序列。
3.2 数据帧格式:从起始位到停止位
一个完整的UART数据帧由以下部分组成,默认顺序固定:
- 起始位(Start Bit):1位,低电平有效。用于同步接收端时钟。
- 数据位(Data Bits):通常为5、6、7或8位。K210与单片机通信最常用8位数据位,因为一个字节正好是8位。数据位采用低位先行(LSB First)发送,即先发送最低有效位。
- 校验位(Parity Bit):可选,用于简单的错误检测。分为无校验(None)、奇校验(Odd)和偶校验(Even)。
- 停止位(Stop Bit):1位或2位,高电平有效。表示一帧数据结束,并给接收端处理时间。
最常见的配置是8N1,即8个数据位、无校验位、1个停止位。此时一帧共10个比特(1起始 + 8数据 + 1停止)。如果使用偶校验,则配置为8E1,一帧共11个比特。
| 配置名称 | 数据位 | 校验位 | 停止位 | 帧总长度 | 典型应用场景 |
|---|---|---|---|---|---|
| 8N1 | 8 | 无 | 1 | 10 bit | 最通用,K210与单片机默认推荐 |
| 8E1 | 8 | 偶校验 | 1 | 11 bit | 对数据完整性要求稍高的工业总线 |
| 8O1 | 8 | 奇校验 | 1 | 11 bit | 与偶校验对称,较少用 |
| 7E1 | 7 | 偶校验 | 1 | 10 bit | 早期ASCII码传输(0-127) |
| 9N1 | 9 | 无 | 1 | 11 bit | 特殊场景,如LIN总线 |
3.3 奇偶校验:基础检错机制
奇偶校验是一种最简单的错误检测方法。其原理是:发送端统计数据位中“1”的个数,然后根据校验规则设置校验位,使得整个数据帧(数据位 + 校验位)中“1”的总数为奇数(奇校验)或偶数(偶校验)。
- 偶校验(Even Parity):如果数据位中“1”的个数为奇数,则校验位设为1,使总数为偶数;如果“1”的个数为偶数,则校验位设为0。
- 奇校验(Odd Parity):规则相反,保证“1”的总数为奇数。
接收端收到数据后,会重新计算“1”的个数,并与校验位比对。如果不一致,则说明传输过程中发生了奇数个比特翻转(例如1变0或0变1)。需要注意的是,奇偶校验只能检测出奇数个错误,如果恰好有2个比特翻转,则校验仍然通过,错误无法被发现。因此,它适用于对可靠性要求不高的场景,或者作为更高级协议(如CRC)的补充。
3.4 流控制:防止数据溢出
流控制(Flow Control)用于协调发送端与接收端的数据处理速度,防止接收端缓冲区溢出。UART流控制分为两种:
- 硬件流控制(RTS/CTS):使用额外的两根线。接收端在缓冲区满时拉低RTS(Request to Send)信号,发送端检测到CTS(Clear to Send)为低电平时暂停发送。K210的部分UART外设支持硬件流控制,但需要额外占用GPIO。
- 软件流控制(XON/XOFF):在数据流中插入特殊字符。接收端发送XOFF(0x13)请求暂停,发送XON(0x11)请求恢复。这种方式不占用额外引脚,但只适用于全双工且数据内容不包含0x11和0x13的场景。
在K210与单片机通信的典型场景中,由于AI识别结果的数据量通常不大(每次几十字节),且单片机处理速度足够快,一般不需要流控制。但如果单片机需要执行复杂的控制算法(如PID调节),导致无法及时读取串口缓冲区,则建议启用硬件流控制,或者采用“查询-应答”模式:K210发送一帧数据后,等待单片机返回ACK,再发送下一帧。
3.5 案例拆解:K210发送识别结果到STM32
下面通过一个具体案例,演示如何配置K210的UART,并发送AI识别结果到STM32单片机。
场景背景:K210运行YOLOv2模型,识别到目标物体后,将物体类别ID(1字节)和中心坐标X(2字节)、Y(2字节)打包成5字节数据,通过UART发送给STM32。STM32根据接收到的数据控制舵机云台跟踪目标。
关键参数:波特率115200,8N1格式,无流控制。K210使用UART0,TX为GPIO4,RX为GPIO5。STM32使用USART1,TX为PA9,RX为PA10。
K210端代码(MicroPython):
from machine import UART
import time
# 初始化UART0,波特率115200,8N1
uart = UART(UART.UART0, baudrate=115200, bits=8, parity=UART.PARITY_NONE, stop=1, timeout=1000)
uart.init(baudrate=115200, bits=8, parity=UART.PARITY_NONE, stop=1)
# 模拟AI识别结果
object_id = 1 # 类别ID,例如1代表"person"
center_x = 160 # 图像中心X坐标 (0-320)
center_y = 120 # 图像中心Y坐标 (0-240)
# 打包数据:帧头(0xAA) + 类别ID + X高字节 + X低字节 + Y高字节 + Y低字节 + 校验和
data = bytearray([0xAA, object_id, (center_x >> 8) & 0xFF, center_x & 0xFF,
(center_y >> 8) & 0xFF, center_y & 0xFF])
checksum = sum(data) & 0xFF
data.append(checksum)
# 发送数据
uart.write(data)
print("Sent:", data.hex())
STM32端接收逻辑(HAL库):
// 假设在中断回调中接收
uint8_t rx_buffer[7];
uint8_t rx_index = 0;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == USART1) {
rx_buffer[rx_index++] = received_byte;
if (rx_index == 1 && rx_buffer[0] != 0xAA) {
rx_index = 0; // 帧头不对,重新同步
}
if (rx_index == 7) {
// 校验和验证
uint8_t sum = 0;
for (int i = 0; i < 6; i++) sum += rx_buffer[i];
if ((sum & 0xFF) == rx_buffer[6]) {
// 数据有效,解析
uint8_t obj_id = rx_buffer[1];
uint16_t x = (rx_buffer[2] << 8) | rx_buffer[3];
uint16_t y = (rx_buffer[4] << 8) | rx_buffer[5];
// 控制舵机云台...
}
rx_index = 0;
}
HAL_UART_Receive_IT(&huart1, &received_byte, 1);
}
}
分析过程:K210发送的帧结构为:0xAA(帧头)、object_id、X高字节、X低字节、Y高字节、Y低字节、校验和。STM32在中断中逐字节接收,先检查帧头,再累积到7字节后计算校验和。如果校验通过,则解析坐标并驱动舵机。
结果与复盘:该方案在实际测试中,以115200波特率传输,每帧耗时约87微秒(10bit/115200),完全满足实时控制需求。但需要注意:
- 如果STM32主循环中有耗时操作(如延时),可能导致串口中断响应不及时,从而丢失字节。解决方案是提高中断优先级,或使用DMA接收。
- K210的UART发送缓冲区有限,如果连续发送大量数据,需要检查
uart.write()的返回值或使用流控。 - 校验和只能检测错误,不能纠正错误。如果校验失败,建议丢弃该帧并等待下一帧,而不是尝试恢复。
3.6 常见误区与总结复盘
在串口通信开发中,以下误区经常导致调试困难:
误区2:忘记共地。两个设备必须使用同一参考地,否则电平无法正确判断。在独立供电的系统中,务必连接GND线。
误区3:波特率不一致。即使微小偏差(如9600 vs 9600.1),长时间传输后也会累积误差导致乱码。建议使用晶振精度高的设备,并避免使用内部RC振荡器进行高波特率通信。
误区4:忽略数据位顺序。UART发送数据时是LSB先行。如果接收端按MSB先行解析,会导致字节值完全错误。
总结复盘:UART通信的核心在于“约定”。双方必须约定一致的波特率、数据帧格式、校验方式和流控策略。在K210与单片机系统中,推荐使用115200-8N1的配置,并在应用层增加简单的帧协议(帧头+长度+数据+校验)来增强可靠性。对于AI识别结果这类小数据量传输,无需硬件流控,但应确保接收端有足够的中断处理能力或使用DMA。掌握这些原理后,你就能快速定位通信问题,并设计出健壮的通信链路。