1. CMS32串口通信概述:串口通信基本原理、CMS32单片机UART模块特性、串口通信协议栈概览
1.1 串口通信,到底在聊什么?
串口通信,说白了就是两个设备之间,通过一根或两根数据线,一位一位地传数据。你想想看,单片机要跟传感器说话,要跟电脑上的串口助手聊天,靠的就是这个。
我刚开始做嵌入式那会儿,总觉得串口太简单了,不就是TX发、RX收嘛。直到有一次,一个设备在强干扰环境下死活收不到完整数据,我才意识到——看似简单的串口,坑其实不少。
串口通信的核心参数,就这几个:
- 波特率:每秒传多少位。9600、115200最常见。两边必须一致,否则就是乱码。
- 数据位:一般是8位,也有5、6、7位的,但8位是主流。
- 停止位:1位或2位。告诉接收方“这包数据结束了”。
- 校验位:奇校验、偶校验、或者无校验。我一般用无校验,省事。
关键点:串口是异步通信,没有时钟线。两边靠约定的波特率来同步。所以波特率不准,数据就全歪了。
1.2 CMS32的UART模块,有什么特别的?
中微CMS32系列单片机,内置了多个UART模块。我手头常用的CMS32M53xx系列,就有3路UART。嗯,这里要注意——不是所有引脚都能当UART用,得看数据手册的引脚复用表。
CMS32的UART模块特性,我列个表,你一看就明白:
| 特性 | 说明 |
|---|---|
| 支持波特率范围 | 300 ~ 115200 bps(实测可到230400,但稳定性看布线) |
| 数据位 | 7位或8位 |
| 停止位 | 1位或2位 |
| 校验模式 | 无校验、奇校验、偶校验 |
| FIFO深度 | 发送和接收各16字节硬件FIFO |
| 中断支持 | 发送完成、接收完成、接收超时、错误中断 |
| 自动波特率检测 | 部分型号支持,我一般不用,手动设更稳 |
我个人习惯,只要项目不要求极端省电,就把FIFO打开。16字节的FIFO能大大减少CPU中断频率,尤其在高波特率下,效果很明显。
小技巧:CMS32的UART模块,接收FIFO触发阈值可以设成1、4、8、14字节。我一般设成8字节,这样既不会太频繁进中断,也不会等太久才收到数据。
1.3 串口通信协议栈,不只是“发数据”
很多人以为串口通信就是“发什么收什么”。其实不然。裸的UART只保证字节级别的传输,但你要传一个“温度值25.3℃”,怎么知道哪几个字节是一包?哪几个字节是校验?
这就需要一个通信协议栈。说白了,就是在原始字节上,加一层“包装规则”。
我参与过一个项目,两个设备之间用串口传控制指令。一开始没做协议栈,结果偶尔出现粘包、丢字节,整个系统就乱套了。后来老老实实加了帧头、帧尾、校验,问题全解决。
一个典型的串口协议栈,通常包含这几层:
- 物理层:就是UART硬件,负责电平转换、波特率、字节收发。
- 数据链路层:定义帧结构——帧头、数据长度、数据体、校验、帧尾。
- 应用层:解析数据体里的具体含义,比如“0x01代表读取温度”。
避坑指南:我曾经在一个产品里,帧头用了0xAA 0x55,结果数据体里也出现了0xAA,导致接收方误判帧头。后来我改用“帧头+帧头取反”的方式,才彻底解决误判问题。
下面这张图,是我自己总结的串口协议栈分层结构,你看一眼就清楚了:
1.4 帧结构,到底长什么样?
我常用的帧结构,是这样的:
帧头(2字节) + 数据长度(1字节) + 命令字(1字节) + 数据体(N字节) + 校验(1字节) + 帧尾(2字节)
举个例子:
AA 55 05 01 25 03 E8 0F 0D 0A
│ │ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │ └─ 帧尾(0x0D 0x0A)
│ │ │ │ │ │ │ └─ 校验(累加和)
│ │ │ │ │ │ └─ 数据体(0x03 0xE8 = 1000)
│ │ │ │ │ └─ 数据体(0x25 = 37)
│ │ │ │ └─ 命令字(0x01 = 读取温度)
│ │ │ └─ 数据长度(0x05 = 5字节)
│ │ └─ 帧头(0x55)
│ └─ 帧头(0xAA)
这个结构,我在好几个项目里复用,稳定得很。你刚开始做串口协议,可以直接拿这个框架去改。
核心原则:帧头要足够特殊,帧尾要方便检测,校验要覆盖整个数据体。缺一个,就可能出问题。
1.5 波特率怎么选?我的经验
波特率的选择,其实是个权衡。我一般这么选:
- 9600:抗干扰强,线长能到十几米。适合传感器、工业现场。
- 115200:速度够快,但线长别超过2米。适合板级通信、调试。
- 460800以上:除非你布线很好、距离很短,否则别轻易用。我吃过亏。
为什么会这样?因为波特率越高,每个bit的时间越短,对信号上升沿、下降沿的要求就越高。线一长,信号就变形了。
建议:调试阶段用115200,速度快,省时间。产品定型后,根据实际线长和干扰环境,再决定要不要降速。
1.6 本章小结
串口通信,说难不难,说简单也不简单。CMS32的UART模块功能挺全的,FIFO、多种中断、可调参数,基本能满足大部分场景。关键是要把协议栈搭好,别裸着发数据。
嗯,这一章就聊到这儿。你先把这些基础概念消化掉,后面我们就要动手写代码了。