0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于灵动微电子MM32F013x 系列的UART硬件自适应波特率

电子设计 来源:灵动MM32MCU 作者:灵动MM32MCU 2021-02-15 09:09 次阅读

嵌入式工程师在开发产品中经常会用到MCU的片上UART和其它模块进行通信,为了在某些非正常的恶劣环境下能正常使用串口通信,可能需要对UART通信波特率进行自适应校准,在我们之前的微课堂中讲解过关于MM32通用MCU的UART串口通信方面的基础知识,这里我们增加基于灵动微电子MM32F013x 系列UART硬件自适应波特率的使用。

1、原理

UART硬件波特率自适应检测首个通信字节的位宽(1bit、2bit、4bit、8bit),检测前一个边沿和后一个边沿之间的位长,即检测前一个边沿为下降沿,后一个边沿为上升沿或前一个边沿为下降沿,后一个边沿为下降沿,可通过软件灵活配置。

本实例以串口工具作为上位机,MM32F013x的UART1作为下位机,MCU端初始化为非标准波特率9200,使能空闲中断及其他状态标志位,上位机切换不同的波特率,由于上位机和MCU端的波特率不同,可能出现通信失败的情况,启动UART硬件波特率自适应功能,即检测上位机发的首个字节位宽来识别上位机的波特率,MCU端通过硬件波特率自适应切换到对应的波特率,与上位机维持后续正常的通信。

如下图所示,以首字节0XF8为例,首字节位宽为4bit的原理说明:

o4YBAF_8C3aAf1jtAADJl_q1Dqc572.png

2、程序配置

2.1 初始化MM32F013x UART1串口

从官网下载MM32F013x例程,这里我们在MM32F0133C7P的样例程序中添加注释并对代码修改。

#include "bsp_UART.h"
#include "led.h"
/*******************************************************************************
* 函数名称:void bsp_UART1_Init(u32 baudrate)
* 函数功能:初始化UART1 PA9/PA10分别作为UART1的TX/RX
* 输入参数:无
* 返回数值:无
******************************************************************************/
void bsp_UART1_Init(u32 baudrate)
{
    //GPIO初始化结构体
    GPIO_InitTypeDef GPIO_InitStructure;
    //UART初始化结构体
    UART_InitTypeDef UART_InitStructure;    
    //NVIC初始化结构体
    NVIC_InitTypeDef NVIC_InitStructure;

    //使能UART1时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_UART1, ENABLE);        
    //使能GPIOA时钟
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);  

    //开启GPIOA PA9复用于UART1_TX功能 
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_1);    
    //开启GPIOA PA10复用于UART1_RX功能 
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_1);   

    //UART1_TX   GPIOA.9
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;     
    //配置GPIOA.9 速度为高速50MHz
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    
    //配置GPIOA.9为复用推挽输出
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        
    //根据GPIO结构体初始化UART1_TX GPIOA.9
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    //UART1_RX GPIOA.10
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;    
    //配置UART1_RX GPIOA.10为上拉输入
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;    
    //根据GPIO结构体初始化UART1_RX GPIOA.10
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    //串口波特率
    UART_InitStructure.UART_BaudRate = baudrate;    
    //字长为8位数据格式
    UART_InitStructure.UART_WordLength = UART_WordLength_8b;    
    //一位停止位
    UART_InitStructure.UART_StopBits = UART_StopBits_1;    
    //无奇偶校验位
    UART_InitStructure.UART_Parity = UART_Parity_No;    
    //无硬件数据流控
    UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None;    
    //允许收发模式
    UART_InitStructure.UART_Mode = UART_Mode_Rx | UART_Mode_Tx;
    //根据UART结构体初始化串口UART1
    UART_Init(UART1, &UART_InitStructure);

    //硬件自动波特率检测第1个字节位的位宽前一个边沿为下降沿,后一个边沿为上升沿
    //___              _______
    //   |_ _ _ _|1 x x x x|        = Binary:xxxx 1000  Fall to Rise -> 1 start bit 
    //AutoBaudRate Mode Fall to Rise 4bit width,the first byte is 0xF8 use test

    UART_AutoBaudRateSet(UART1, ABRMODE_FALLING_TO_RISINGEDGE4BIT, ENABLE);

    //接收数据中断、接收帧错误中断、自动波特率结束中断、自动波特率错误中断、空闲中断
    UART_ITConfig(UART1, UART_IT_RXIEN | UART_ICR_RXFERRCLR | UART_ICR_ABRENDCLR |\ UART_ICR_ABRERRCLR | UART_ICR_RXIDLE | UART_IT_ERR, ENABLE);
    //使能UART1
    UART_Cmd(UART1, ENABLE);

    //UART1 NVIC中断优先级设置
    NVIC_InitStructure.NVIC_IRQChannel = UART1_IRQn;
    //UART通道优先级0
    NVIC_InitStructure.NVIC_IRQChannelPriority = 0;          
    //IRQ通道使能
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;        
    //根据指定的参数初始化NVIC寄存器
    NVIC_Init(&NVIC_InitStructure);    
}

2.2 编写MM32F013x UART1串口中断服务函数

继续在bsp_UART.c文件中编写MM32F013x UART1串口中断服务函数如下所示。

/*******************************************************************************
* 函数名称:void UART1_IRQHandler(void)
* 函数功能:串口1 UART1中断服务程序
* 输入参数:无
* 返回数值:无
*******************************************************************************/
//自动波特率帧错误标志
u8 Auto_BaudRate_FraErr_Flag = 0;
void UART1_IRQHandler(void)                    
{
    u8 Res;

    //UART1接收中断
    if(UART_GetITStatus(UART1, UART_IT_RXIEN) != RESET)  
    {
        //清UART1接收中断标志
        UART_ClearITPendingBit(UART1,UART_IT_RXIEN);            
        //读取UART1接收到的数据
        Res = UART_ReceiveData(UART1);        
        //UART1接收数据缓存起来,最大接收UART1_REC_LEN个字节 
        UART1_Rx_Buf[UART1_Rx_Cnt] = Res;        
        //UART1作接收缓存溢出判断,最大接收UART1_REC_LEN个字节
        if(UART1_Rx_Cnt < UART1_REC_LEN-1)
        {
            //还有数据要接收,接收计数变量自加
            UART1_Rx_Cnt++;
        }
        else
        {
            UART1_Rx_Cnt = 0;
        }
    }

    //帧错误中断标志位
    if(UART_GetITStatus(UART1, UART_IER_RXFERR) != RESET)
    {
        //自动波特率帧错误标志置1
        Auto_BaudRate_FraErr_Flag = 1;
        //清帧错误中断标志位
        UART_ClearITPendingBit(UART1,UART_IER_RXFERR);
    }

    //接收数据帧错误中断
    if(UART_GetITStatus(UART1, UART_ICR_RXFERRCLR) != RESET)
    {     
        UART_ClearITPendingBit(UART1,UART_ICR_RXFERRCLR);
    }

    //空闲中断硬件波特率自校准
    if(UART_GetITStatus(UART1, UART_ICR_RXIDLE) != RESET)
    {
        UART_ClearITPendingBit(UART1,UART_ICR_RXIDLE);

        //自动波特率帧错误标志
        if(Auto_BaudRate_FraErr_Flag == 1)
        {
            Auto_BaudRate_FraErr_Flag = 0;

    //----------------Check MM32F013x UART_AutoBaudRateHard----------
    //___              _______
    //   |_ _ _ _|1 x x x x|  = Binary:xxxx 1000  Fall to Rise -> 1 start bit 
    //AutoBaudRate Mode Fall to Rise 4bit width,the first byte is 0xF8 use test

        UART_AutoBaudRateSet(UART1, ABRMODE_FALLING_TO_RISINGEDGE4BIT, ENABLE);    
        }
    }

    //自动波特率错误中断清除位
    if(UART_GetITStatus(UART1, UART_ICR_ABRERRCLR) != RESET)
    {      
        UART_ClearITPendingBit(UART1,UART_ICR_ABRERRCLR);  
    }

    //自动波特率结束中断清除位
    if(UART_GetITStatus(UART1, UART_ICR_ABRENDCLR) != RESET)
    {
        UART_ClearITPendingBit(UART1,UART_ICR_ABRENDCLR);
    }
}

2.3 MM32F013x UART1串口接收函数

在bsp_UART.h文件中宏定义UART1波特率、接收字节长度,变量声明以及UART1接收数据函数和发送数据函数声明。

 void UART1_Recv_Task(void)
{   
   //收到的数据原样返回到串口上位机
   UART_SendBytes(UART1,UART1_Rx_Buf, UART1_Rx_Cnt);
}

2.4 MM32F013x UART串口发送函数

在bsp_UART.c文件中编写MM32F013x UART1发送数据函数,发送单字节数据和发送多字节数据函数分别如下所示:

/*******************************************************************************
* 函数名称:void UART_SendByte(UART_TypeDef* UARTx,u8 dat)
* 函数功能:UART发送单字节数据
* 输入参数:UARTx:UART1/UART2;dat:待发送的数据
* 返回数值:无
*******************************************************************************/
void UART_SendByte(UART_TypeDef* UARTx,u8 dat)
{
    UART_SendData(UARTx, dat);

    while(!UART_GetFlagStatus(UARTx, UART_FLAG_TXEPT));
}

/*******************************************************************************
* 函数名称:void UART_SendBytes(UART_TypeDef* UARTx,u8* buf, u16 len)
* 函数功能:UART发送多字节数据
* 输入参数:UARTx:UART1/UART2;buf:待发送的数据;len:待发送数据的长度
* 返回数值:无
*******************************************************************************/
void UART_SendBytes(UART_TypeDef* UARTx,u8* buf, u16 len)
{
    while(len--)
    {
        UART_SendByte(UARTx,*buf++);       
    }
}

3、MM32F013x UART硬件 自适应波特率的功能演示

在main.c文件的main函数里初始化bsp_UART1_Init(9200)串口初始化函数,在while(1)大循环里调用测试UART1硬件自动波特率收发数据函数:UART1_Recv_Task();这里以检测UART1通信首字节为4bit宽为例,模式为前一个边沿为下降沿,后一个边沿为上升沿。

MCU端设置非标准波特率9200,我们通过上位机以不同的波特率发送F8进行硬件波特率自适应,自适应完成后UART1就切换到对应的波特率,MCU端收到数据后直接返回给上位机。

o4YBAF_8C4mAVXorAAHgpS9Jm6M455.png

编辑:hfy

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • mcu
    mcu
    +关注

    关注

    146

    文章

    16011

    浏览量

    343536
  • uart
    +关注

    关注

    22

    文章

    1158

    浏览量

    99947
  • 串口通信
    +关注

    关注

    32

    文章

    1577

    浏览量

    54859
收藏 人收藏

    评论

    相关推荐

    请问STM32F407 SPI如何设置不同的波特率

    请教下大家F407 SPI1(Master)的波特率,因为读取TI ADS1274,需要将SPI波特率设置成某些特殊值,比如 51200 * 256 = 13107200,请问是否能做到? 目前我
    发表于 03-13 08:23

    XMC4200如何更改UART波特率

    我想让波特率在检测到不匹配的波特率时可以改变。 但我遇到了新问题。 从下面的代码中可以看到,函数\"XMC_UART_CH_SetBaudrate\" 中的第一个参数在库源代码
    发表于 03-05 06:28

    XMC4000怎样才能将波特率设置为非恒定值?

    我们怎样才能将波特率设置为非恒定值? 在我的应用程序中,我需要根据某些情况更改UART波特率。 因此,波特率设置不能保持恒定。 但是,如果我添加UA
    发表于 01-23 06:26

    什么是串口波特率?串口通信为什么要设置波特率

    什么是串口波特率?串口通信为什么要设置波特率波特率与比特率的关系 如何选择串口波特率?  串口波特率是在串行通信中,传输速率的衡量单位。它
    的头像 发表于 01-22 16:10 522次阅读

    什么是串口波特率?串口通信为什么要设置波特率

    电子设备的世界中,数据是通过各种方式进行传输的。其中,串口通信是一种常见的数据传输方式,它以其简单、可靠和广泛的特性,成为了电子设备间通信的重要手段。而在串口通信中,有一个非常重要的参数——波特率
    的头像 发表于 11-03 08:21 1571次阅读
    什么是串口<b class='flag-5'>波特率</b>?串口通信为什么要设置<b class='flag-5'>波特率</b>?

    51单片机编程什么时候要用到波特率倍速?波特率倍速有什么用处?

    51单片机串口波特率倍速问题,51单片机编程什么时候要用到波特率倍速,波特率倍速有什么用处啊,不太明白,会不会因为串口波特率倍速影响到串口下载程序,可是程序又是怎么影响到
    发表于 10-27 07:34

    CW32单片机UART波特率设置介绍

    CW32单片机UART波特率设置介绍
    的头像 发表于 10-24 17:35 488次阅读
    CW32单片机<b class='flag-5'>UART</b><b class='flag-5'>波特率</b>设置介绍

    GPS模块修改波特率重启之后还是原来波特率要如何解决?

    GPS模块修改波特率重启之后还是原来波特率如何解决?是模块本身问题么
    发表于 10-17 06:28

    关于NUC029波特率设置问题

    关于NUC029的波特率设置一直有个疑问,在手册中详细描述了波特率的计算公式和设置方法,但是如果我使用固件库进行设置,是库函数自动给我设置到我需要的波特率吗? 比如我在UART_Ope
    发表于 08-21 07:38

    什么是串口波特率?串口波特率的分类及应用详解

    什么是串口波特率串口波特率是指串口通信系统中传输数据的速率。在UART串口通信中,数据以位(bit)的形式传输,波特率是指每秒钟传输的位数。在串口通信中,
    的头像 发表于 08-08 10:09 3244次阅读
    什么是串口<b class='flag-5'>波特率</b>?串口<b class='flag-5'>波特率</b>的分类及应用详解

    NUC029的UART比特设置,是库函数自动给我设置到我需要的波特率吗?

    关于NUC029的波特率设置一直有个疑问,在手册中详细描述了波特率的计算公式和设置方法,但是如果我使用固件库进行设置,是库函数自动给我设置到我需要的波特率吗? 比如我在UART_Ope
    发表于 06-28 07:53

    1Mhz主频下UART波特率9600无法使用4800是怎么回事?

    分频到1Mhz ,UART波特率9600无法使用收到的和发送的数据不一致,4800收到的数据正常 官方例程代码如下: CKDIV=0x0C;//分频到1Mhz MFP_P31_UART
    发表于 06-16 07:16

    波特率是什么?波特率设计

    从宏观理解,波特率表征了串口的传输速度。
    的头像 发表于 06-05 15:19 1.1w次阅读
    <b class='flag-5'>波特率</b>是什么?<b class='flag-5'>波特率</b>设计

    uart1进行数据接收/输出波特率一直是115200,设置不了其它波特率

    rt-thread用uart1进行数据接收和输出,波特率一直是115200,设置不了其它波特率串口1初始化如下,数据输入和输出的波特率还是115200: void
    发表于 05-12 15:20

    S32K312安全启动并尝试查找和调整uart波特率

    我正在研究 S32K312 安全启动并尝试查找和调整 uart 波特率? 我应该在哪里调整它?
    发表于 05-04 08:19