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

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

https://blog.csdn.net/u014515202/article/details/73293917/

使用串口空闲中断和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.csdn.net/xukao5671927/article/details/78605022

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

更改为:

HAL_UART_AbortReceive(&huart2);

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

猜你喜欢

转载自blog.csdn.net/gongyuan073/article/details/81103011