大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是嵌入式里串口(UART)自动波特率识别程序设计与实现。
本篇是 《串口(UART)自动波特率识别程序设计与实现(中断)》 的续集,上一篇我们利用 GPIO 模块自带的下降沿中断功能实现了 RXD 电平跳变捕捉与计时,今天我们再试试古老的轮询 RXD 管脚电平的方法去实现同样的功能。
轮询法最大的缺点是会阻塞系统(不考虑 RTOS 调度),但是它也有中断法所没有的特点(或者说不太方便做到的),在做轮询时,我们可以采取一些经典的管脚电平软件消抖措施,从而降低误识别率。
- 程序主页: https://github.com/JayHeng/cortex-m-apps/tree/master/components/autobaud
一、串口(UART)自动波特率识别程序设计
1.1 函数接口定义
轮询法与中断法函数接口保持一致,详见 《串口(UART)自动波特率识别程序设计与实现(中断)》 1.1 小节,两者共享头文件:autobaud.h,这样方便项目设计时自由切换自动波特率识别方法。
1.2 识别设计思想
关于识别的思路,轮询法与中断法也是一致的,详见 《串口(UART)自动波特率识别程序设计与实现(中断)》 1.2 小节,但是轮询法里多了手动检测 RXD 引脚电平下降沿跳变的过程。
引脚电平跳变检测其实也很简单,就是不断读取引脚输入电平值,并比较相邻两次输入电平值,如果发现不一致,则是跳变发生之时。如果前一次电平值是高,那么此时便是下降沿。

1.3 主代码实现
根据上一小节描述的设计思想,我们很容易写出下面的主代码(autobaud_poll_v2.1.c),代码里痞子衡都做了详细注释。相比中断法源代码,我们其实只需要修改 autobaud_get_rate() 函数实现如下:
//! @brief 读取GPIO管脚输入电平 extern uint32_t read_autobaud_pin(void); bool autobaud_get_rate(uint32_t *rate) { // 仅当电平为低(非空闲态)时才开始识别 uint32_t currentEdge = read_autobaud_pin(); if (currentEdge != 1) { pin_transition_callback(); uint32_t previousEdge = currentEdge; while (s_transitionCount < kFirstByteRequiredFallingEdges + kSecondByteRequiredFallingEdges) { // 检查是否有电平翻转 currentEdge = read_autobaud_pin(); if (currentEdge != previousEdge) { // 仅当电平翻转是下降沿时 if (previousEdge == 1) { pin_transition_callback(); } previousEdge = currentEdge; } } // 计算出实际检测到的波特率值 uint32_t calculatedBaud = (microseconds_get_clock() * (kNumberOfBitsForFirstByteMeasured + kNumberOfBitsForSecondByteMeasured)) / (uint32_t)(s_firstByteTotalTicks + s_secondByteTotalTicks); // 对实际检测出的波特率值做对齐处理 // 公式:rounded = stepSize * (value/stepSize + .5) *rate = ((((calculatedBaud * 10) / kAutobaudStepSize) + 5) / 10) * kAutobaudStepSize; return true; } else { return false; } }
二、串口(UART)自动波特率识别程序实现
前面讲的都是硬件无关设计,但最终还是要落实到具体 MCU 平台上的,其中 GPIO 读取部分是跟 MCU 紧相关的。我们以恩智浦 i.MXRT1011 为例来介绍硬件实现。
2.1 软件消抖实现
恩智浦 MIMXRT1010-EVK 有板载调试器 DAPLink,这个 DAPLink 中也集成了 USB 转串口的功能,对应的 UART 引脚是 IOMUXC_GPIO_09_LPUART1_RXD 和 IOMUXC_GPIO_10_LPUART1_TXD,我们就选用这个管脚 GPIO1[9] 做自动波特率检测,引脚电平读取函数代码如下:
#define AUTOBAUD_PIN_DEBOUNCE_READ_COUNT (20U) uint32_t read_autobaud_pin(void) { // 多次读取管脚输入电平值 uint32_t readCount = 0; for (uint32_t i = 0; i < AUTOBAUD_PIN_DEBOUNCE_READ_COUNT; i++) { readCount += GPIO_PinRead(GPIO1, 9); } // 如某电平值出现几率超过半数,则认定为有效电平 return (readCount < (AUTOBAUD_PIN_DEBOUNCE_READ_COUNT / 2)) ? 0 : 1; }
关于 I/O 软件消抖,一般有两种实现:一、是两次 I/O 读取之间加一定延时(us级别),如两次值一样,则认定有效,否则重复此过程;二、是多次读取 I/O 值,取其中出现几率超过一半的那个电平值。前者主要适用按键的场景,后者更适用本文轮询法自动波特率识别场景。
2.2 在MIMXRT1010-EVK上实测
最后就是在板子上实测,因为在设计上轮询法与中断法接口是一致的,因此测试主函数代码完全不用修改,详见 《串口(UART)自动波特率识别程序设计与实现(中断)》 2.2 小节。测试结果同样达到了预期效果。
至此,嵌入式里串口(UART)自动波特率识别程序设计与实现痞子衡便介绍完毕了,掌声在哪里~~~
欢迎订阅
文章会同时发布到我的 博客园主页、CSDN主页、知乎主页、微信公众号 平台上。
微信搜索"痞子衡嵌入式"或者扫描下面二维码,就可以在手机上第一时间看了哦。
最后欢迎关注痞子衡个人微信公众号【痞子衡嵌入式】,一个专注嵌入式技术的公众号,跟着痞子衡一起玩转嵌入式。
衡杰(痞子衡),目前就职于恩智浦MCU系统部门,担任嵌入式系统应用工程师。
专栏内所有文章的转载请注明出处:http://www.cnblogs.com/henjay724/
与痞子衡进一步交流或咨询业务合作请发邮件至 [email protected]
可以关注痞子衡的Github主页 https://github.com/JayHeng,有很多好玩的嵌入式项目。
关于专栏文章有任何疑问请直接在博客下面留言,痞子衡会及时回复免费(划重点)答疑。
痞子衡邮箱已被私信挤爆,技术问题不推荐私信,坚持私信请先扫码付款(5元起步)再发。