目录:
1.MM32F0140简介
2.UART自动波特率校准应用场景
3.MM32F0140 UART自动波特率校准原理简介
4.MM32F0140 UART1 NVIC硬件自动波特率配置以及初始化
5.编写MM32F0140 UART1发送数据函数
6.编写MM32F0140 UART1中断接收函数以及自动波特率校准的实现
7.编写MM32F0140 UART1处理中断接收数据函数
8.验证MM32F0140 UART1自动波特率校准功能
提要:
学习MM32F0140 UART自动波特率校准功能的使用。例如:上位机串口调试助手UART通信波特率为19200,往下位机UART1波特率为9600的MM32F0140 发送一帧数据:
0xF8 0x55 0x2 0x03 0x04 0x05 0x06 0x07;下位机通过UART内部硬件自动检测接收到数据帧的首字节的位宽波特率时间来识别上位机的波特率,并重置下位机MCU的波特率寄
存器使得下位机MCU的波特率与上位机的通信波特率一致,从而实现数据帧的正常收发(注意:上位机与下位机的通信波特率不应相差太大,否则无法自动检测识别)。
本博客为原创文章,转载请注明出处!!!
内容:
1、MM32F0140简介:
(1)MM32F0140微控制器是基于Arm® Cortex®-M0内核,最高工作频率可达72MHz;
(2)供电电压支持:2.0V - 5.5V;
(3)多达64KB的Flash,8KB的SRAM;
(4)1个I2C;
(5)3个UART;
(6)1个12位共13通道的ADC;
(7)2个I2C或I2S;
(8)1个16位高级定时,1个16位和1个32位的通用定时器,3个16位的基本定时器;
(9)1个FlexCAN接口;
(10)1个IWDG和1个WWDG看门狗。
2.UART自动波特率校准应用场景
嵌入式软件工程师在开发产品时,经常会用到MCU的UART串口模块做产品功能方面的调试或主从机通信,当产品的主从机通信波特率有偏差时,或经过TTL电平转换电路转换后波特率出现
偏差或产品的工作环境相对比较恶劣时也会出现UART的主从机通信波特率偏差,这时如果MCU的UART内部集成了自动波特率检测校准功能,就能通过自动波特率检测校准从而维持MCU的UART
主从机的正常通信功能。
3.MM32F0140 UART自动波特率校准原理简介
MM32F0140系列MCU的UART内部集成了硬件自动波特率检测电路,自动检测接收到数据帧的首字节的位宽波特率时间来识别通信方的波特率参数,并重置MCU的UART波特率寄存器,使得通信双方保存通信波特率一致。
4.MM32F0140 UART1 NVIC硬件自动波特率配置以及初始化
MM32F0140 UART1的GPIO初始化,根据MM32F0140的DS数据手册选择PA9:UART1_TX,PA10:UART1_RX做为UART1的发送和接收数据的引脚,具体配置步骤,及其初始化如下所示:
(1)使能GPIOA外设时钟;
(2)配置IO管脚GPIO_AFx复用为UART1功能;
(3)配置UARTx IO的管脚;
(4)配置GPIO的输出速度;
(5)配置IO管脚的工作模式;
(6)根据GPIOA配置的参数整体初始化GPIO各管脚的成员参数。
static void Bsp_UART1_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; //Enable GPIOA Clock RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE); //PA9 AF UART1_TX GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1); //PA10 AF UART1_RX GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1); //PA9:UART1_TX GPIO_StructInit(&GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStruct); //PA10:UART1_RX GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOA, &GPIO_InitStruct); }
MM32F0140 UART1 NVIC硬件自动波特率配置以及初始化步骤如下所示:
(1)使能UART1外设时钟;
(2)调用之前配置的UART1GPIO初始化函数;
(3)配置UART1通信波特率为9600;
(4)配置UART1字长为8位;
(5)配置UART1收发数据为1位停止位;
(6)配置UART1收发数据为无奇偶校验位;
(7)配置UART1允许串口收发数据;
(8)根据以上配置参数初始化UART1结构体成员;
(9)配置UART1硬件自动波特率检测首字节的位宽(包含起始位宽)的长度和检测的边缘模式,可从UM手册UART_ABRCR自动波特率寄存器相关位查询到如下图1所示,本实例检测首字节的
边缘选择前一个边沿为下降沿(包含起始位)后一个边沿为上升沿,符合这个条件的字节为0xF8(b:1111 1000)等。
图1
(10)使能UART1接收数据中断、接收帧错误中断、自动波特率结束中断、自动波特率错误中断、空闲中断;
(11)配置UART1的NVIC中断优先级为0,并使能和初始化NVIC中断(优先级为0-3均可,参数越小优先级越高)。
MM32F0140 UART1 NVIC硬件自动波特率配置以及初始化代码如下所示:
void Bsp_UART1_NVIC_Init(u32 baudrate) { UART_InitTypeDef UART_InitStruct; NVIC_InitTypeDef NVIC_InitStruct; //Enable UART1 Clock RCC_APB2PeriphClockCmd(RCC_APB2ENR_UART1, ENABLE); //UART1 GPIO Init Bsp_UART1_GPIO_Init(); //Baud rate UART_StructInit(&UART_InitStruct); UART_InitStruct.BaudRate = baudrate; //The word length is in 8-bit data format. UART_InitStruct.WordLength = UART_WordLength_8b; UART_InitStruct.StopBits = UART_StopBits_1; //No even check bit. UART_InitStruct.Parity = UART_Parity_No; //No hardware data flow control. UART_InitStruct.HWFlowControl = UART_HWFlowControl_None; UART_InitStruct.Mode = UART_Mode_Rx | UART_Mode_Tx; UART_Init(UART1, &UART_InitStruct); //___ _______ // |_ _ _ _|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); //接收数据中断、接收帧错误中断、自动波特率结束中断、自动波特率错误中断、空闲中断、 //Enable Receive data interrupt、Receive frame error interrupt、Automatic baud rate end interrupt、 //Automatic baud rate error interrupt、Idle interrupt UART_ITConfig(UART1,UART_IT_RXIEN | UART_IER_RXFERR | UART_IER_ABREND_IEN | \ UART_IER_ABRERR_IEN | UART_IER_RXIDLE,ENABLE); //UART1 NVIC Interrupt NVIC_InitStruct.NVIC_IRQChannel = UART1_IRQn; NVIC_InitStruct.NVIC_IRQChannelPriority = 0; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStruct); //Enable UART1 UART_Cmd(UART1, ENABLE); }
5.编写MM32F0140 UART1发送数据函数
(1)MM32F0140 UART1发送字节函数如下所示:
void Bsp_UART_SendByte(UART_TypeDef* uart,u8 data) { UART_SendData(uart, data); while(!UART_GetFlagStatus(uart, UART_FLAG_TXEPT)); }
(2)MM32F0140 UART1发送多字节函数如下所示:
void Bsp_UART_SendBytes(UART_TypeDef* uart,u8* pbuf, u16 len) { while(len--) { Bsp_UART_SendByte(uart,*pbuf++); } }
(3)MM32F0140 UART1发送ASCII字符串函数如下所示:
void Bsp_UART_SendString(UART_TypeDef* uart,char* str) { while(*str) { Bsp_UART_SendByte(uart,(u8)(*str++)); } }
6.编写MM32F0140 UART1中断接收函数以及自动波特率校准的实现
(1)定义与MM32F0140 UART1先关的变量,缓存,以及头文件变量、函数声明,代码如下所示:
//UART1 Receive count u8 gUART1_Rx_Cnt; //UART1 Receive Buffer u8 gUART1_Rx_Buf[UART1_REC_LEN]; //UART1 Receiving Flag bool gUART1_Rx_Flag = false; //Hardware automatic baud rate error flag u8 Auto_BaudRate_FraErr_Flag = 0;
//注:上位机串口助手发送如下数据帧格式第1字节为波特率检测位宽,第2字节之后为可变字节方便观察收发数据帧 /*************************************************************************************************** --------------Falling edge to rising edge(including start bit)-------------------------------------- //The first byte is 0xF8 use test //___ _______ // |_ _ _ _|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 串口上位机发送数据格式: 0xF8 0x55 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0xF8 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0xF8 0x02 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0xF8 0x03 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 下位机分别给串口上位机原样回复收到的数据命令: 0xF8 0x55 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0xF8 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0xF8 0x02 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0xF8 0x03 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 ***************************************************************************************************/ //UART1 Baud Rate #define UART1_BAUDRATE (9600) //UART1 maximum receiving length 200 #define UART1_REC_LEN (200) //UART1 Receive Buffer extern u8 gUART1_Rx_Buf[UART1_REC_LEN]; //UART1 Receive count extern u8 gUART1_Rx_Cnt; //UART1 Receive Timing //extern u8 UART1_Rx_TimeCnt; //UART1 Receiving Flag extern bool gUART1_Rx_Flag; //UART1 Init void Bsp_UART1_NVIC_Init(u32 baudrate); //UART Send single byte data void Bsp_UART_SendByte(UART_TypeDef* uart,u8 data); //UART Send String void Bsp_UART_SendString(UART_TypeDef* uart,char* str); //UART Send multi-byte data void Bsp_UART_SendBytes(UART_TypeDef* uart,u8* pbuf, u16 len); //Test hardware automatic baud rate to send and receive data void Bsp_UART1_Recv_Task(void);
(2)MM32F0140 UART1中断接收函数以及自动波特率校准代码如下所示:
void UART1_IRQHandler(void) { u8 Recbyte; //UART1 receive interrupt,receive valid data interrupt flag bit if(UART_GetITStatus(UART1,UART_ISR_RX) != RESET) { //Clear UART1 receive interrupt flag UART_ClearITPendingBit(UART1,UART_ICR_RX); //Read the data received by UART1 Recbyte = UART_ReceiveData(UART1); //UART1 receive data buffered gUART1_Rx_Buf[gUART1_Rx_Cnt] = Recbyte; //Determine whether the received data of UART1 overflows if(gUART1_Rx_Cnt < UART1_REC_LEN-1) { //UART1 Receive count gUART1_Rx_Cnt++; } else { gUART1_Rx_Cnt = 0; } } //Receive data frame error interrupt flag if(UART_GetITStatus(UART1, UART_ISR_RXFERR_INTF) != RESET) { //Hardware automatic baud rate error flag Auto_BaudRate_FraErr_Flag = 1; UART_ClearITPendingBit(UART1,UART_ICR_RXFERRCLR); } //Idle interrupt hardware automatic baud rate self-calibration if(UART_GetITStatus(UART1, UART_ISR_RXIDLE) != RESET) { UART_ClearITPendingBit(UART1,UART_ICR_RXIDLE); //Hardware automatic baud rate error flag if(Auto_BaudRate_FraErr_Flag == 1) { Auto_BaudRate_FraErr_Flag = 0; //-------------------------------------Check MM32F0140 UART_AutoBaudRateHard--------------------------------------------------------- //Configure MM32F013x hardware automatic baud rate self-calibration,Falling edge to rising edge(including start bit) //___ _______ // |_ _ _ _|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); } //UART1 Receiving Flag gUART1_Rx_Flag = true; } //Automatic baud rate error clear bit if(UART_GetITStatus(UART1, UART_ISR_ABRERR_INTF) != RESET) { //Auto baud rate error clear bit UART_ClearITPendingBit(UART1,UART_ICR_ABRERRCLR); } //Automatic baud rate end interrupt clear bit if(UART_GetITStatus(UART1, UART_ISR_ABREND_INTF) != RESET) { //Auto baud rate end clear bit UART_ClearITPendingBit(UART1,UART_ICR_ABRENDCLR); } }
7.编写MM32F0140 UART1处理中断接收数据函数
MM32F0140 UART1处理中断接收数据函数代码如下所示:
void Bsp_UART1_Recv_Task(void) { //UART1 Rx Flag if(gUART1_Rx_Flag == true) { gUART1_Rx_Flag = false; //Send the received data as-is, for example:0x55 0x55 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 Bsp_UART_SendBytes(UART1,gUART1_Rx_Buf, gUART1_Rx_Cnt); //Receive data from the serial port of the host computer:0xF8 0x55 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 if((gUART1_Rx_Buf[0] == 0xF8) && (gUART1_Rx_Buf[1] == 0x55)) { LED1_TOGGLE(); } //Receive data from the serial port of the host computer:0xF8 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 else if((gUART1_Rx_Buf[0] == 0xF8) && (gUART1_Rx_Buf[1] == 0x01)) { LED1_TOGGLE(); } //Receive data from the serial port of the host computer:0xF8 0x02 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 else if((gUART1_Rx_Buf[0] == 0xF8) && (gUART1_Rx_Buf[1] == 0x02)) { LED1_TOGGLE(); } //Receive data from the serial port of the host computer:0xF8 0x03 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 else if((gUART1_Rx_Buf[0] == 0xF8) && (gUART1_Rx_Buf[1] == 0x03)) { LED1_TOGGLE(); } //Clear UART1 receiving count gUART1_Rx_Cnt = 0; //Clear the UART1 receiving buffer to facilitate receiving data next time memset(gUART1_Rx_Buf,0,sizeof(gUART1_Rx_Buf)); } }
8.验证MM32F0140 UART1自动波特率校准功能
(1)在main函数初始化中调用UART1 NVIC硬件自动波特率检测初始化函数即Bsp_UART1_NVIC_Init(UART1_BAUDRATE);调用LED初始化函数用于指示收到数据后做状态翻转,在while(1)
主循环中循环检测MM32F0140 UART1处理中断接收数据函数,代码如下所示:
int main(void) { //LED Init LED_Init(); //UART1 Hardware Automatic baud rate Init Baud rate:9600 Bsp_UART1_NVIC_Init(UART1_BAUDRATE); while(1) { //Test UART1 Recv IDLE Bsp_UART1_Recv_Task(); } }
(2)验证MM32F0140 UART1自动波特率校准功能
验证说明:
以上MCU的UART默认初始化的通信波特率为9600,通过改变上位机串口调试助手的通信波特率分别设置为:19200,38400,57600,115200并分别发送如下数据帧:
//注:上位机串口助手发送如下数据帧格式第1字节为波特率检测位宽,第2字节之后为可变字节方便观察收发数据帧 /*************************************************************************************************** --------------Falling edge to rising edge(including start bit)-------------------------------------- //The first byte is 0xF8 use test //___ _______ // |_ _ _ _|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 串口上位机发送数据格式: 0xF8 0x55 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0xF8 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0xF8 0x02 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0xF8 0x03 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 下位机分别给串口上位机原样回复收到的数据命令: 0xF8 0x55 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0xF8 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0xF8 0x02 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0xF8 0x03 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 ***************************************************************************************************/
如果下位机MCU检测到数据帧的首字节前一个边沿为下降沿,后一个边沿为上升沿的4个位宽的数据,例如0xF8(含起始位b:1111 1000)芯片内部波特率自动检测电路识别首字节的波特率位宽,
并重置MCU的UART波特率寄存器,以达到MCU的通信波特率与上位机的通信分别一致,并原样回复收到的数据给上位机串口助手显示出来,测试结果如下图2,图3,图4,图5所示:
图1 如上串口助手显示MM32F0140的UART1已自动检测到19200波特率并打印出收到的正确数据
图2 如上串口助手显示MM32F0140的UART1已自动检测到38400波特率并打印出收到的正确数据
图3 如上串口助手显示MM32F0140的UART1已自动检测到57600波特率并打印出收到的正确数据
图4 如上串口助手显示MM32F0140的UART1已自动检测到115200波特率并打印出收到的正确数据
总结:
学习MM32F0140 UART自动波特率校准功能的使用。例如:上位机串口调试助手UART通信波特率为19200,往下位机UART1波特率为9600的MM32F0140 发送一帧数据:
0xF8 0x55 0x2 0x03 0x04 0x05 0x06 0x07;下位机通过UART内部硬件自动检测接收到数据帧的首字节的位宽波特率时间来识别上位机的波特率,并重置下位机MCU的波特率寄
存器使得下位机MCU的波特率与上位机的通信波特率一致,从而实现数据帧的正常收发(注意:上位机与下位机的通信波特率不应相差太大,否则无法自动检测识别)。
注意事项:
(1)MM32F0140每个外设都有自己独立的时钟,需使能UART1 发送和接收引脚的GPIO时钟;
(2)使能UART1外设时钟;
(3)配置GPIOA的 PA9和PA10复用成UART1功能
(4)接收数据中断、接收帧错误中断、自动波特率结束中断、自动波特率错误中断、空闲中断;
(5)使能UART1自动波特率检测数据帧首字节的边缘模式前一个边沿为下降沿,后一个边沿为上升沿(具体组合可查看UM手册)并设置检测首字节的检测位宽(可设置1,2,4或8位宽)
本实例4位宽检测的首字节为0xF8;
(6)使能UART1 NVIC中断;
(7)验证MM32F0140 UART1自动波特率校准功能时记得切换上位机助手的通信波特率,记得设置首字节为0xF8(本实例);
(8)UART2和UART3的操作方法与UART1的方法一样,可参考以上UART1把对应的UART1参数改成UART2或UART3,使能相应外设时钟编写对应中断函即可。