STM32 HAL库 串口DMA接收不定长数据
整体思路:我是用的CUBEMX软件生成的工程,使能了两个串口,串口2用来接收不定长的数据,串口1用来发送串口2接收到的数据;串口2我找了一个UBLOX卫星模块,每秒输出不定长的定位信息数据;
首先肯定要先打开串口空闲中断,cubemx里面没有这个空闲中断的开启图形界面,需要自己敲代码打开。
然后开启DMA接收;
最后串口接收到空闲中断标志后会跳进中断函数,然后再进行处理就可以了。
NVIC也顺便改一下,默认是0的话有时候用库自带延时函数会卡死。
main函数
在你的串口初始化后加入两行代码
__HAL_UART_ENABLE_IT(&huart2,UART_IT_IDLE);
使能串口空闲中断
HAL_UART_Receive_DMA(&huart2, temp, BUFF_SIZE);
这个是把dma接收到的数据放到temp里面,BUFF_SIZE是空间大小,可以在前面宏定义(#define BUFF_SIZE 1024),由于ublox每秒输出的信息比较多,所以缓存开的比较大;
完成上面的步骤,串口接收到数据就进入中断了。由于中断函数里没有空闲中断的处理函数,所以我们要自己在stm32f4xx_it.c文件中加
void USART2_IRQHandler(void)
{
/* USER CODE BEGIN USART2_IRQn 0 */
/* USER CODE END USART2_IRQn 0 /
HAL_UART_IRQHandler(&huart2);
/ USER CODE BEGIN USART2_IRQn 1 /
MY_UART_IDLE_IRQHandler(&huart2);//这个是我们自己定义的空闲中断服务函数
/ USER CODE END USART2_IRQn 1 */
}
然后在main文件里把空闲中断服务函数写出来
void MY_UART_IDLE_IRQHandler(UART_HandleTypeDef *huart)
{
if(huart->Instance==USART2)
{
if(__HAL_UART_GET_FLAG(&huart2,UART_FLAG_IDLE)!=RESET)
{
__HAL_UART_CLEAR_IDLEFLAG(&huart2);
//清除中断标志
HAL_UART_DMAStop(&huart2);
//停止dma接收
uint16_t DMA_RECEIVE = BUFF_SIZE -__HAL_DMA_GET_COUNTER(&hdma_usart2_rx);
计算出接收到的字节数
HAL_UART_Transmit(&huart1, temp, DMA_RECEIVE, 1000);//从串口1将收到的数据发出
memset(temp,0,DMA_RECEIVE);
将缓存区重新初始化
HAL_UART_Receive_DMA(&huart2, temp,BUFF_SIZE);
重新开启DMA接收
}
}
}
需要注意的是,__HAL_DMA_GET_COUNTER(&hdma_usart2_rx)这个函数是表示DMA接收剩余的字节数;我们刚开始的时候开启DMA接收的时候是1024个字节,然后进入空闲中断后,这个函数统计到我们内存还剩XX个字节,也就是说我们实际收到的字节是1024减去内存剩下的字节数。
DMA_RECEIVE这个要根据你实际字节去定义大小,我开始定义的是uint8_t,输出结果怎么都不对,最后发现1024-x这个肯定要大于uint8_t,所以改成了uint16_t。
本人也是刚学习没几天,所以写的很基础,希望能帮到正在学习的人。