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