HAL库串口中断RX中的Overrun Error解决方案

1. ORE触发条件

首先简单研究一下什么时候会出现overrun的问题,配置正常的HAL串口中断接收如下

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{/* judge interrupt source */if(huart ->Instance == USART2){//send data to huart1 from huart2HAL_UART_Transmit(&huart1, (uint8_t*)recv_buf, 3,0xFFFF);//enable RX ITHAL_UART_Receive_IT(huart, (uint8_t*)recv_buf, 3);}
}

可以看出,分三种情况:

  • 发送数据=接收缓存,正常
  • 发送数据<接收缓存,BUF未满,要等待下一次数据到来填满缓存才会触发中断
  • 发送数据>接收缓存,BUF已满,多余部分被截断,和下一次数据一起触发中断

其中,触发两次接收缓存溢出的时候,就会进入Overrun Error。

比如说BUF长度为3,连续发两次长度为4的数据,就会进入ORE。或者说第一次发送长度为2的数据,然后接着发送两次长度为3的数据,也是会触发ORE的,后续的两次长度为3的数据因为有之前一条长度为2的铺垫,都是视作BUF溢出的数据。但是如果发送一次长度为4的数据之后,后续发长度一条长度为2的数据,就会进入正常状态,是有弹性的。弹性限度为BUF长度的两倍,也就是说发送一次长度为6的数据,会立即进入ORE。

ORE状态下,串口进入ORE溢出中断,无法继续接收数据,但是可以发送数据,相当于接收数据不会触发中断了。

2.ORE解决方案

对于ORE溢出常用解决方案有下:

  • 关闭ORE中断
  • 采取双重缓存

无论哪一种方法都要理解HAL_UART_RxCpltCallback的实现原理:

  1. HAL_UART_IRQHandler(UART_HandleTypeDef *huart)(中断处理函数)
  2. UART_Receive_IT(UART_HandleTypeDef *huart) (接收函数)
  3. HAL_UART_RxCpltCallback(huart)(中断回调函数)

从上到下,层层封装和调用。

void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{uint32_t isrflags   = READ_REG(huart->Instance->SR);uint32_t cr1its     = READ_REG(huart->Instance->CR1);uint32_t cr3its     = READ_REG(huart->Instance->CR3);uint32_t errorflags = 0x00U;uint32_t dmarequest = 0x00U;/* If no error occurs */errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));//close ORE check//errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_NE));if (errorflags == RESET){/* UART in mode Receiver -------------------------------------------------*/if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET)){UART_Receive_IT(huart);return;}}

​想要关闭ORE中断,将errorflags中的USART_SR_ORE 这一位去掉即可,相当于对ORE错误不予检查,经过实际的测试是可行的,实际的表现就是出现ORE溢出之后,串口只接受固定BUF长度的数据,对于溢出的数据直接丢弃,但是还需要考虑ORE溢出之后,那个时刻中BUF肯定是有数据,但是由于没有清除BUF,后续的数据直接进来会导致错位,因此想要真正实现完美的溢出数据丢弃处理且不影响后续的数据,是要在程序中加入清除BUF的指令的。但是这些方法都会影响HAL库的底层代码,包括去掉USART_SR_ORE 这一位,这也是STM32IDE的一点的不好的地方,底层文件是没有用户代码入口的,修改IOC文件之后,一切都会回到最初的起点。

其次就是双重缓存,具体的就是将BUF长度设置为1,这样子每一次收到一个字节的话都会调用回调函数,为什么长度长度大于1的时候会发生ORE,而1的时候可以接受很长的数据而不ORE呢,我猜是因为1的时候将某些位置位了,间接关闭了ORE,然后用户自己定义BUF区,一个一个去读取写入,这个方法还可以实现不定长的接收,设置数据结束帧位就可以了。缺点也很明显,当数据很长的时候,中断要进入很多次,有点占资源了。

用户回调函数HAL_UART_RxCpltCallback只有接收到设定的BUF的长度才会调用一次,而不是有字节就调用,实现的方法在UART_Receive_IT函数中:

    if (--huart->RxXferCount == 0U){/* Disable the UART Data Register not empty Interrupt */__HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);/* Disable the UART Parity Error Interrupt */__HAL_UART_DISABLE_IT(huart, UART_IT_PE);/* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */__HAL_UART_DISABLE_IT(huart, UART_IT_ERR);/* Rx process is completed, restore huart->RxState to Ready */huart->RxState = HAL_UART_STATE_READY;#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)/*Call registered Rx complete callback*/huart->RxCpltCallback(huart);
#else/*Call legacy weak Rx complete callback*/HAL_UART_RxCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */

if (–huart->RxXferCount == 0U)这一句,每次字节来都会调用UART_Receive_IT,然后RxXferCount减1,这个变量就是一开始设置的BUF接收长度,只有等这个到零了,才会调用HAL_UART_RxCpltCallback(huart)

最终,因为在项目中串口是需要来高频率接收固定长度的测量数据的,但是在之前要用串口发送上电指令,这个指令会返回一个和测量数据长度不同的ASK信号,处理方法就是在上电之后,再开启串口接收,这样子就可以设置BUF长度为固定长度,同时稍微降低测量的频率,让串口接收有足够的时间,避免ORE的产生。

HAL库串口中断RX中的Overrun Error问题相关推荐

  1. STM32 HAL库 串口DMA(收发)和STM32串口中断接收(接收时间管理机制)+ESP8266 wifi模组通信问题

    一.HAL库 串口 DMA+ESP8266模组通信问题 用STM32 HAL库串口的DMA发送和空闲中断接收处理数据,单片机发送AT指令给ESP8266 wifi模组问题:单片机连续几次给wifi模组 ...

  2. STM32 hal库串口空闲中断最新用法

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一.串口空闲中断是什么? 二.使用步骤 1.hal库空闲中断接收函数 2.使用方法 3.最终效果 实际效果 总结 前言 ...

  3. STM32 HAL库串口同时收发,接收卡死?

    STM32 使用 HAL库串口同时收发,使用踩坑史 = =!......by 矜辰所致 目录 前言 一. HAL 库串口收发 1.1 串口发送 1.2 串口接收 1.2.1 标准库接收 1.2.1 H ...

  4. 【STM32】基于HAL库的中断详细学习

    目录 1.中断概述 1.1中断相关概念 1.2 STM32中断系统 2 .HAL库的中断处理 2.1 HAL 库的中断封装 2.2 外部中断处理流程 3.外部中断的HAL库定义 3.1. 外部中断的数 ...

  5. STM32 HAL库 串口DMA接收不定长数据

    STM32 HAL库 串口DMA接收不定长数据 整体思路:我是用的CUBEMX软件生成的工程,使能了两个串口,串口2用来接收不定长的数据,串口1用来发送串口2接收到的数据:串口2我找了一个UBLOX卫 ...

  6. STM32 HAL库串口收发数据

    STM32 HAL库串口收发数据 许多传感器的使用方法是:单片机给传感器发送一帧数据,然后传感器返回单片机一帧有用数据,所以串口的收发功能十分重要. STM32cubeMX的配置 时钟和下载方式就不讲 ...

  7. hal库开启中断关中断_STM32 HAL库学习系列第9篇---NVIC按键外部中断函数

    原文首发于同名微信公号「Allen5G」,欢迎大家搜索关注! **针对HAL库的中断操作,使用按键实例进行说下,以供参考---------------------------**void HAL_GP ...

  8. hal库开启中断关中断_(2)STM32使用HAL库操作外部中断——理论讲解

    1.中断触发过程 对主程序压栈--把中断服务函数的地址写入到程序计数器(PC)--执行中断服务函数 2.中断向量表 中断服务函数的地址在STM32的手册上的中断向量表中(如下是一部分): 如上表所示, ...

  9. STM32控制步进电机:基于HAL库定时器中断的闭环步进电机驱动+精准控制脉冲数

    STM32控制步进电机:基于HAL库定时器中断的闭环步进电机驱动+精准控制脉冲数 一.步进电机闭环驱动器 二.CubeMx配置 1.Clock Configuration 2.脉冲端 定时器配置 3. ...

最新文章

  1. 利用Travis CI 让你的github项目持续构建(Node.js为例)
  2. Tensorflow利用函数修饰符@tf.custom_gradients自定义函数梯度
  3. Blue-Red Permutation 贪心,思维
  4. Django框架深入了解_05 (Django中的缓存、Django解决跨域流程(非简单请求,简单请求)、自动生成接口文档)(一)
  5. wxWidgets:wxArrayString类用法
  6. ntnub原理怎么看_老电工由浅入深带你入门学PLC的工作原理和梯形图的编程规则...
  7. nginx 80端口重定向到443端口
  8. 数字化风控全流程 实操课程V2.0 第三期
  9. easyui 改变单元格背景颜色
  10. 6678-GPIO基础(1)
  11. matlab仿真动力学方程的几种方法,总结,以范德波振子为例
  12. Java转Ruby【快速入门】
  13. CodeMeter服务不能启动的解决方法,rslogix5000,无法启动,codemeter服务没有启动,
  14. 计算机右键 管理,鼠标右键菜单管理方法?
  15. 三维激光雷达路沿检测
  16. 计算机课程表怎么制作,制作我的课程表(教案)
  17. Bio.Entrez下载PubMed中的文献
  18. 高效记忆/形象记忆(06)英语单词记忆-字母编码
  19. 小程序支付:appid和mch_id不匹配采坑实录
  20. mysql Error 1412: Table definition has changed, please retry transaction

热门文章

  1. 最短路径问题之广度优先算法BFS(C语言)
  2. 聊一聊在软件测试过程中如何保障产品质量
  3. 16种常用的数据分析方法-信度分析
  4. Linux下压力测试工具-stress
  5. 什么耳机长时间戴比较舒服,推荐五款开放式耳机
  6. 截屏完整的重新设计(在Kickstarter上获得访问权限!)
  7. 老鱼的-kuangbin专题题解
  8. R语言如何求函数的偏导数?
  9. ArcEngine介绍
  10. CSS学习笔记之PS切图 3.1