串口接收数据, 用DMA搬运数据, 而且想在串口接收遇到空闲的时候读取DMA接收到的数据.
事实上这么做很麻烦.
根本原因在于, 串口接收空闲是串口触发的. 默认进入的Handler函数是
void USART2_IRQHandler(void)
{
}
DMA则不是, DMA没有搬运空闲 IDLE 的中断触发功能. 只有
- 搬运一半时触发的中断
- 搬运完成时触发中断.
- 搬运错误中断.
HAL库又引入了一个自己定义的回调函数HAL_UARTEx_RxEventCallback. 最坑的是这个函数并非每次必然会进入的中断. 经常是进入不了的.
// 接收完成回调函数
// void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
// {
// }
在研究了很久的情况下, 终于找到了串口如何通过DMA搬运数据, 又不需要通过中断高频占用CPU的方法.
一遍情况下,使用串口,只有3种情况,
1. 第1种是低频率的串口命令通信, 间歇性的通信. 我称之为 命令通信模式 , 不允许命令丢失
2. 第2种是低频率的串口命令通信, 间歇性的通信. 我称之为 重复命令通信模式 , 允许命令丢失,发送方会重复不间断的发送当前命令. 例如航模遥控器.(实际情况下, 大多数是这种情况)
3.第3种情况是高频率的使用串口传输大量的数据. 我称之为 数据传输模式
针对第1种情况命令通信模式, 如果要保证每个命令都收到则不建议使用DMA, 而是全部用串口中断来获取命令数据. 写入到缓存中, 使用循环缓冲队列存储接收到的命令.
针对第2种情况命令通信模式,命令通信模式下, 如果不太注重每个命令都收到, (一遍是发送方会重复一直发命令) 这种模式下.建议用串口空闲中断加DMA搬运. 这种情况下. 当串口空闲时(一般是一个命令发送完会空闲一会.) 这个时候从DMA中取到所有的字符命令, 然后解析. 此时的DMA搬运模式建议是手动模式, 只搬运1次, 搬运满所有的缓存后就停止搬运, 在命令处理完之后再开启DMA搬运下一个. 此时的DMA不要开启任何中断.
针对第3种情况数据传输模式, 例如ADC数据采集
传输大量数据则将DMA的目标 BufferSize设置的大一点, 不要开启串口空闲中断. 用DMA的传输完成中断和半完成中断进行数据处理.
重点在于
传输空闲中断只是串口触发的, 不是DMA触发的.
传输空闲中断只是串口触发的, 不是DMA触发的.
传输空闲中断只是串口触发的, 不是DMA触发的.
传输空闲中断只是串口触发的, 不是DMA触发的.
传输空闲中断只是串口触发的, 不是DMA触发的.
第2种情况最好自己用底层的中断函数, 不要用HAL提供的中断函数.