|

大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是嵌入式里串口(UART)自动波特率识别程序设计与实现。
9 d2 Y5 k4 c% h7 u- M! Z2 o串口(UART)是嵌入式里最基础最常用也最简单的一种通讯(数据传输)方式,可以说是工程师入门通讯领域的启蒙老师,同时串口打印也是嵌入式项目里非常经典的调试与交互方式。! i- l+ V y% z; Z! W
最精简的串口仅使用两根单向信号线:TXD、RXD,这两根信号线是独立工作的,因此数据收发既可分开也可同时进行,这就是所谓的全双工。串口没有主从机概念,并且没有专门的时钟信号 SCK,所以串口通信也属于异步传输。
6 h1 N( j9 E; J5 V* o0 ^5 P' m0 u说到异步传输,这就不得不提波特率(每秒钟传输bit数)的问题了,通信双方必须使用一致的波特率才能完成正确的数据传输。正常情况下,我们都是为两个串口设备事先约定好波特率,比如 MCU 与上位机通信,在 MCU 程序里按 115200 的波特率去初始化 UART 外设,然后上位机串口调试助手也设置 115200 波特率,双方再联合工作。0 o! P7 _7 V+ j5 M7 @2 d! j
有时候,我们也希望能有一种灵活的波特率约定方式,比如建立通信前,在上位机串口调试助手里随意设置一种波特率,然后按这个波特率发送数据,MCU 端能自动识别出这个波特率,并用识别出来的波特率去初始化 UART 外设,然后再进行后续数据传输,这种方式就叫自动波特率识别。痞子衡今天要分享的就是在 MCU 里实现自动波特率识别的程序设计:
& c" ?. e+ w$ i$ ~" K& w程序主页:https://github.com/JayHeng/cortex-m-apps/tree/master/components/autobaud一、串口(UART)自动波特率识别程序设计1.1 函数接口定义首先是设计自动波特率识别程序头文件:autobaud.h ,这个头文件里直接定义如下 3 个接口函数原型。涵盖必备的初始化流程 init()、deinit(),以及最核心的波特率识别功能 get_rate()。
% t, A7 I: Y G, W X//! @brief 初始化波特率识别, S7 H0 h, O8 y3 @! A
void autobaud_init(void);
0 X* \7 }7 k" L$ I6 [+ Y//! @brief 检测波特率识别是否已完成,并获取波特率值
! U; @! i3 M. X! w* Ebool autobaud_get_rate(uint32_t *rate);
4 u( ^- @' q$ q0 g0 l- c+ W7 e! U//! @brief 关闭波特率识别
+ F: D; }6 p1 A& Ivoid autobaud_deinit(void);' s6 M: g F+ F# Z
1.2 识别设计思想关于识别,因为上位机数据是从 RXD 引脚过来的,所以在 MCU 里需要先将 RXD 引脚配置成普通数字输入 GPIO(这个引脚需要上拉,默认保持高电平),然后检测这个 GPIO 的电平跳变(一般用下降沿)并计时。
8 u* t5 r q3 ~# N- K3 A% e5 S& g下图是典型的 UART 单字节传输时序,I/O 空闲状态是高电平,传输时总是由 1bit 低电平起始位开启,然后是从 LSB 到 MSB 的 8bit 数据位,校验位是可选项(我们暂不开启),最后由 1bit 高电平停止位结束,I/O 回归高电平空闲状态。
. Q. w7 n" M$ o0 K7 u! ` U6 i7 _Note 1:检测下降沿跳变,是因为 I/O 空闲为高,起始位的存在保证了每 Byte 传输周期总是从下降沿开始。Note 2:起始位和停止位两个 bit 的存在还兼有波特率容错的功能,通信双方波特率在 3% 的误差内数据传输均可以正常进行。 |
|