痞子衡嵌入式:嵌入式里串口(UART)自动波特率识别程序设计与实现(轮询)


  大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是嵌入式里串口(UART)自动波特率识别程序设计与实现

  本篇是 《串口(UART)自动波特率识别程序设计与实现(中断)》 的续集,上一篇我们利用 GPIO 模块自带的下降沿中断功能实现了 RXD 电平跳变捕捉与计时,今天我们再试试古老的轮询 RXD 管脚电平的方法去实现同样的功能。

  轮询法最大的缺点是会阻塞系统(不考虑 RTOS 调度),但是它也有中断法所没有的特点(或者说不太方便做到的),在做轮询时,我们可以采取一些经典的管脚电平软件消抖措施,从而降低误识别率。

一、串口(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主页知乎主页微信公众号 平台上。

微信搜索"痞子衡嵌入式"或者扫描下面二维码,就可以在手机上第一时间看了哦。

posted @ 2021-06-14 17:57  痞子衡  阅读(770)  评论(0编辑  收藏  举报