单片机怎样才能不死机之串口Overrun

闲言少叙,先上code,大家看一下下面这段代码有没有问题?
// note: usart demo code runs on stm32f030#include “main.h”
static __io uint32_t timingdelay;
rcc_clockstypedef rcc_clocks;
uint8_t uart_buffer[100];
// gpio configurationvoid gpio_configuration(void){ gpio_inittypedef gpio_initstructure; gpio_pinafconfig(gpioa,gpio_pinsource9,gpio_af_1); // tx pa9 gpio_pinafconfig(gpioa,gpio_pinsource10,gpio_af_1); // rx pa10 gpio_initstructure.gpio_pin = gpio_pin_9 | gpio_pin_10; // usart1_tx | usart1_rx gpio_initstructure.gpio_mode = gpio_mode_af; gpio_initstructure.gpio_otype = gpio_otype_pp; gpio_initstructure.gpio_pupd = gpio_pupd_up; gpio_initstructure.gpio_speed = gpio_speed_level_1; gpio_init(gpioa, &gpio_initstructure); }
// usart configurationvoid usart_configuration(void){ usart_inittypedef usart_initstructure; usart_initstructure.usart_baudrate = 115200; //usart_initstructure.usart_baudrate = 9600; usart_initstructure.usart_wordlength = usart_wordlength_8b; usart_initstructure.usart_stopbits = usart_stopbits_1; usart_initstructure.usart_parity = usart_parity_no; usart_initstructure.usart_hardwareflowcontrol = usart_hardwareflowcontrol_none; usart_initstructure.usart_mode = usart_mode_tx | usart_mode_rx; usart_init(usart1,&usart_initstructure); usart_itconfig(usart1, usart_it_rxne, enable); usart_cmd(usart1,enable); }
// interrupt configurationvoid nvic_configuration(void){ nvic_inittypedef nvic_initstructure; // usart1 interrupt config nvic_initstructure.nvic_irqchannel = usart1_irqn; nvic_initstructure.nvic_irqchannelpriority = 0; nvic_initstructure.nvic_irqchannelcmd = enable; nvic_init(&nvic_initstructure);}
// usart1 interrupt handlervoid usart1_irqhandler (void){ static uint8_t i = 0;
if(usart_getitstatus(usart1,usart_it_rxne)!= reset) {// clear receive data register not empty flag usart_clearitpendingbit(usart1,usart_it_rxne); uart_buffer[i++] = usart_receivedata(usart1); if(i == 100) i = 0; }}
int main(void){ static uint8_t ch;
// init a 1ms timer interrupt, for delay function implementation. rcc_getclocksfreq(&rcc_clocks); systick_config(rcc_clocks.hclk_frequency / 1000); // enable usart1 and gpioa clock rcc_apb2periphclockcmd(rcc_apb2periph_usart1,enable); rcc_ahbperiphclockcmd(rcc_ahbperiph_gpioa,enable); gpio_configuration(); usart_configuration(); nvic_configuration(); ch = ‘a’; while(1) { delay(50); while(usart_getflagstatus(usart1, usart_flag_txe) == reset); usart_senddata(usart1, ch); ch++; }
}
/*** @brief inserts a delay time.* @param ntime: specifies the delay time length, in 1 ms.* @retval none*/void delay(__io uint32_t ntime){ timingdelay = ntime; while(timingdelay != 0);}
/*** @brief decrements the timingdelay variable.* @param none* @retval none*/void timingdelay_decrement(void){ if(timingdelay != 0x00) { timingdelay--; }}
它是可以在 stm32f030 上调试通过的串口收发测试程序,发送采用延时循环,接收采用中断,接收到的数据存入缓冲区。
有很多比较认真的实战派的同学估计会下载到板子上跑一跑,它确实能跑通,看起来也没什么问题。很多教程甚至官方的代码都是类似的处理方法。
但这确实有点儿像陷马坑,看似一马平川,跑着跑着突然连马带人 kucha 一声掉坑里了。这还真不是开玩笑,某知名楼宇自控公司的产品就在安装到客户现场后,经常莫名奇妙的死机。查来查去,查去查来,才发现问题。可是解决起来不容易啊,一个一个的去拆开,更新代码,想想都。。。
所以同学们不要轻视任何一段代码啊!
这段代码的问题是,如果接收数据之间间隔时间较长,可以正常收数据。但是如果对方发送数据非常快,或者偶尔在自己还没从串口接收寄存器取走数据的时候突然又来了数据,会导致 overrun 标志位的置位。这个标志位一置,串口基本上就罢工了。所以,在程序中一定要有对异常情况的处理。甚至觉得不会发生的异常也不要置之不理。(想一想为什么要填充flash的空白区域?在正常情况下代码永远不会跑到空白区域是吧。)
对串口异常的处理可以参考下面中断处理函数代码。当然也可以在主程序中定时处理,以便在中断失效的情况下还能恢复。
// usart1 interrupt handlervoid usart1_irqhandler (void){ static uint8_t i = 0;
if(usart_getflagstatus(usart1, usart_flag_ore) != reset) {// clear overrun error flag usart_clearflag(usart1, usart_flag_ore); } else if(usart_getflagstatus(usart1, usart_flag_ne) != reset) {// clear noise error flag usart_clearflag(usart1, usart_flag_ne); } else if(usart_getflagstatus(usart1, usart_flag_fe) != reset) {// clear framing error flag usart_clearflag(usart1, usart_flag_fe); } else if(usart_getflagstatus(usart1, usart_flag_pe) != reset) {// clear parity error flag usart_clearflag(usart1, usart_flag_pe); } else if(usart_getitstatus(usart1,usart_it_rxne)!= reset) {// clear receive data register not empty flag usart_clearitpendingbit(usart1,usart_it_rxne); uart_buffer[i++] = usart_receivedata(usart1); if(i == 100) i = 0; }}


在三频无线手机中给MAX2308 IF接收机IC使用三个IF滤波器
Intel:后10nm时代远景规划,着手7nm、5nm工艺研发工作
华为Mate和P系列提供专属服务,能否引起高端消费者的共鸣?
从几大知名芯片商看物联网技术生态系统
LGD 推出8寸360度折叠荧幕OLED
单片机怎样才能不死机之串口Overrun
飞凌FETMX6UL-C核心板的双主钟时间同步系统设计和实现
亚马逊卖家速看:亚马逊加拿大站要求在9月30之前提供ISED认证,否则面临下架风险!
华为荣耀或发布全新概念手机?海报“M”字样近期曝光
IR推出600V绝缘栅双极晶体管(IGBT)系列IRG7RC10FD
储气库双向计量设备流量计国产化现状
基于TI CC2541蓝牙(BLE)技术的心率监测方案
分析报告称2020年全球VR市场内容将增长128%
MAX2640低噪声放大器(LNA)的S参数测量和稳定性分析
单相电机的用途广泛,它可以分为哪几类
机器视觉检测中的图像预处理方法:平滑模糊处理,锐化
机器学习开发者想要打造一款App有多难?
物位传感器有哪些_物位传感器的实际应用
新通话如何化身“平台级”产品?
不锈钢螺旋板换热器焊缝泄露如何处理