stm32串口不定长数据接收(hal库)的若干问题

http://www.stmcu.org/module/forum/thread-606385-1-1.html

https://blog.youkuaiyun.com/u014515202/article/details/73293917/

https://blog.youkuaiyun.com/qq_24376681/article/details/78729946

使用串口空闲中断和DMA配合时出现的问题:

问题1.串口接收一旦溢出就会丢数据。
例如串口接收满了,稍等几秒再启动新的DMA接收函数HAL_UART_Receive_DMA时,就丢失数据了,而且是再也收不到串口数据。如果接满后马上启动就没这个问题。
看官方示例代码,停止DMA接收后似乎要DeInit后重新初始化Init和启动DMA接收

解答:

当接收DMA关闭后,此时串口还是激活的,若此时串口来数据,无法触发DMA传输,此时产生上溢错误(ORE),由于串口数据寄存器里的数据不能及时转移走,后面来的数据就进不来。一旦出现这种错误后,就不会再触发DMA请求,即使再开启DMA也不行。要恢复正常的话就只有Deinit后再重新初始化串口,或者直接将数据寄存器中的数据读走后,后面的数据才能正常进入,从而正常产生DMA请求,这个DMA请求是指硬件请求。
其实在STM32官网公众号有文章介绍了该问题,主要是先启动了串口再启动DMA就会容易引起该问题。因此为了防止该问题要不每次开DMA都清ORE寄存器;要不按规矩先开DMA再开串口,不用了先关串口再关DMA

2.接收不完全

空闲中断最大的一个问题,就是发送方的一帧数据不能被打断。不然stm32就会触发空闲中断,只接收到一帧的一部分数据。假如两个单片机通信,任意一个串口发送的过程被其他中断打断之后再回来继续发送就会导致帧被截断.

解答:

没有FIFO 无解

 

3.串口DMA接收不能单独停止。
例如串口同时在DMA发送和DMA接收,DMA接收到一半我要终止DMA的话,只能调用HAL_UART_DMAStop把接收DMA和串口DMA都停止。
换言之,不能单独停止DMA接收。
我理解的接收DMA和发送DMA是两个独立的操作,为什么不能单独停止?

解答:

HAL_UART_DMAStop()是同时关收发DMA,

只关闭接收的函数: HAL_UART_AbortReceive(); 该函数的两个工作内容:

1. 先关闭接收DMA,HAL_DMA_Abort(huart->hdmarx);
2. 置位RX ready状态,huart->RxState = HAL_UART_STATE_READY;
忽略了错误标志和IT标志处理,最保险的方式还是使用HAL_UART_AbortReceive()函数。

 

 

 

一种笨办法::直接利用stm32的RXNE和IDLE中断进行接收不定字节数据。 
基本知识: 
IDLE中断什么时候发生? 
IDLE就是串口收到一帧数据后,发生的中断。什么是一帧数据呢?比如说给单片机一次发来1个字节,或者一次发来8个字节,这些一次发来的数据,就称为一帧数据,也可以叫做一包数据。 
如何判断一帧数据结束,就是我们今天讨论的问题。因为很多项目中都要用到这个,因为只有接收到一帧数据以后,你才可以判断这次收了几个字节和每个字节的内容是否符合协议要求。 
看了前面IDLE中断的定义,你就会明白了,一帧数据结束后,就会产生IDLE中断。

如何配置好IDLE中断? 
下面我们就配置好串口IDLE中断吧。 

USART_CR

Bit4是 : IDLEIE      寄存器                 Bit5是: RXNEIE

对Bit4写1开启IDLE中断,对Bit5写1开启接收数据中断。(注意:不同系列的STM32,对应的寄存器位可能不同)

RXNE中断和IDLE中断的区别? 
当接收到1个字节,就会产生RXNE中断,当接收到一帧数据,就会产生IDLE中断。比如给单片机一次性发送了8个字节,就会产生8次RXNE中断,1次IDLE中断。 

USART_ISR 状态寄存器

Bit4是 : IDLE      寄存器                 Bit5是: RXNE

这是状态寄存器,当串口接收到数据时,bit5就会自动变成1,当接收完一帧数据后,bit4就会变成1. 
需要注意的是,在中断函数里面,需要把对应的位清0,否则会影响下一次数据的接收。

比如RXNE接收数据中断,只要把接收到的一个字节读出来,就会清除这个中断。

IDLE中断,如何是F0系列的单片机,需要用ICR寄存器来清除,如果是F1系列的单片机,清除方法是“先读SR寄存器,再读DR寄存器”。

串口初始化中开启两个中断:

USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);

USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

中断处理函数如下:

 

 

当然你也可以先不管各种问题,调试通了再说。

按照以下教程即可正常收发

https://blog.youkuaiyun.com/xukao5671927/article/details/78605022

中断里的
//HAL_UART_DMAStop(&huart2);

更改为:

HAL_UART_AbortReceive(&huart2);

即可修复收取数据的时候关闭了DMA导致不能发送得问题。

### 使用STM32 CubeMX配置串口进行不定长数据接收与发送 #### 配置环境准备 为了实现基于STM32CubeMX的串口DMA和空闲中断功能,需先准备好开发环境。确保安装了最新版本的STM32CubeMX以及相应的IDE工具链(如Keil MDK或TrueSTUDIO)。此外,还需下载并熟悉官方提供的示例工程[^1]。 #### STM32CubeMX初始化设置 打开STM32CubeMX软件,在项目创建向导中选择目标MCU型号。进入主界面后,找到`Connectivity`标签页下的UART外设模块,并双击开启其配置窗口。在此处勾选启用DMA控制器选项,并指定用于接收操作的具体通道号;对于发送部分同样如此处理。接着切换到NVIC中断优先级管理页面,激活USART全局中断事件以便后续能够响应外部信号触发的动作[^2]。 #### 定义结构体变量存储接收到的信息 在应用程序源码文件内声明一个自定义类型的全局对象实例UsartType1,该类型包含了若干成员属性用来追踪当前状态机的工作情况,比如是否有新的帧到达标志位receive_flag、缓冲区实际占用字节数rx_len等字段。这些信息将在ISR服务例程内部被更新维护以反映最新的硬件活动状况[^3]: ```c /* usart.h */ typedef struct { uint8_t receive_flag : 1; uint8_t dmaSend_flag : 1; uint16_t rx_len; uint8_t usartDMA_rxBuf[RECEIVELEN]; } USART_RECEIVETYPE; extern USART_RECEIVETYPE UsartType1; ``` #### 编写回调函数处理逻辑流程控制 当检测到线路处于低电平超过一定时间间隔即认为一帧结束,则会调用对应的IDLE线程入口点执行相应动作序列。此时应重置计数器并将捕获到的有效载荷复制给上层协议栈进一步解析处理。同时也要注意防止溢出错误的发生,因此建议设定合理的最大允许长度限制值以免造成不必要的麻烦: ```c void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){ if(huart->Instance==USARTx){ // Replace with your actual instance name. __HAL_DMA_DISABLE(&hdma_usart_rx); UsartType1.receive_flag = 1; UsartType1.rx_len = huart->RxXferSize - __HAL_DMA_GET_COUNTER(&hdma_usart_rx); /* Process received data here */ __HAL_UART_FLUSH_DRREGISTER(huart); __HAL_UART_ENABLE_IT(huart, UART_IT_IDLE); __HAL_DMA_CLEAR_FLAG(&hdma_usart_rx,DMA_FLAG_TCIF4|DMA_FLAG_HTIF4|DMA_FLAG_TEIF4); __HAL_DMA_ENABLE(&hdma_usart_rx); } } ``` #### 发送过程中的注意事项 针对消息传递环节而言,考虑到可能存在的并发访问冲突风险因素影响整体性能表现,所以在每次发起新请求之前务必确认前一次事务已经顺利完成再继续下一步骤的操作。可以通过轮询方式查询特定寄存器的状态位得知确切的结果反馈,或者借助于前面提到过的dmaSend_flag布尔量来进行同步协调工作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值