STM32 串口 DMA 接收任意长度数据
这里是转变了一个思路,单纯从 DMA 角度解决问题貌似找不到很好的答案,那就转换到串口上来。因为本身的工作是串口 DMA 接收任意长度数据。
DMA 局限性
DMA 传输完成会产生中断告知 CPU,这对于固定长度的数据是没什么问题的。但是对于不定长的数据就不行了,DMA 一定要接收到足够多(设定的长度)的数据时才产生完成中断,如果接收到的数据量小于设定的长度,这个时候 CPU 就无法通过中断方式取处理这点数据了。那 CPU 怎样优化这个缺陷呢?那就是使用轮询的方式,主动获取 DMA 当前收到了多少字节数据,然后决定要不要处理这些数据。但是,一旦使用轮询方式就背离了 DMA 原有的设计意图(为 CPU 减负)。
那还有什么办法可以优雅地解决这个问题吗?那就是使用串口空闲中断。
串口空闲中断
这里是转变了一个思路,单纯从 DMA 角度解决问题貌似找不到很好的答案,那就转换到串口上来。因为本身的工作是串口 DMA 接收任意长度数据。
串口有个空闲中断,大概是串口总线在一个字节的时间内没有再接收到数据,认为一帧数据传输完毕了,就会产生串口空闲中断。
这样我们就不使用 DMA 中断了,只使用串口空闲中断,即在串口空闲中断中获取 DMA 接收的数据并处理,然后再开启下次 DMA 接收。
关键代码
使能串口空闲中断
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
添加串口空闲中断处理函数
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
UART_IRQHandler_IDLE(&huart1); // 串口空闲中断处理函数
/* USER CODE END USART1_IRQn 1 */
}
/* USER CODE BEGIN 1 */
void UART_IRQHandler_IDLE(UART_HandleTypeDef *huart)
{
if(huart == &huart1)
{
if(__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE) != RESET)
{
HAL_UART_DMAStop(&huart1);
uint8_t data_length = sizeof(recv_buf) - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
HAL_UART_Transmit(&huart1, recv_buf, data_length, 100);
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
__HAL_UART_CLEAR_OREFLAG(&huart1);
HAL_UART_Receive_DMA(&huart1, recv_buf, sizeof(recv_buf));
}
}
}
/* USER CODE END 1 */
避坑
在使用串口中断时,一定记得要清除 ORE flag,不然中断会出各种意想不到的异常,比如串口发送数据会触发串口接收中断。
__HAL_UART_CLEAR_OREFLAG(&huart1);
测试
完整代码
https://download.csdn.net/download/lyndon_li/88054148
对应硬件:STM32F107VCT6

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐
所有评论(0)