概要 STM32的串口接收不定长数据,最近在看超子说物联网,感觉太麻烦了不适合直接上手,然后我自己总结了两种方法: 1、不利用DMA 2、利用DMA方式
整体架构流程 这个HAL整起来是方便,但是HAL整体来说对于细节很到位就是逻辑很强逻辑,也就很繁琐,效率又不高,还缺胳膊少腿的。好用,就比如说这个串口接收,没有专门的方法调用。搞的就很麻烦,我第一次接触就是这感觉哈,大佬除外。
然后我看到超子说物联网可以用这个串口的空闲中断 来搞这个串口的不定长接收。
大致的原理是:在接收每一段数据帧之后就会放开这个串口,产生了这个串口的空闲中断(IDLE),然后我们可以捕捉这个UART_FLAG_IDLE这个标志位,然后这个标志位被置位了,我们就可以说这段数据被接收完成了。
我们使用STM32F407给大家做一下,大概流程
不用DMA的方式 先选择SYS
使能串口1 开启中断 配置时钟 生成工程 进入代码打开usart.c的MX_USART1_UART_Init这个函数在后面加上开启中断的代码
开启串口接收和串口的空闲中断之后就是一直等待 ,等待串口接收到数据,一旦接收数据就触发串口中断进入USART1_IRQHandler函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 void MX_USART1_UART_Init (void ) { huart1.Instance = USART1; huart1.Init.BaudRate = 115200 ; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; if (HAL_UART_Init(&huart1) != HAL_OK) { Error_Handler(); } __HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE); __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE); }
在stm32f4xx_it.c中,分别判断是否是接收中断还是空闲中断,如果是接收中断调用HAL_UART_Receive去接收一个数组,当一个数据帧接受完,就触发了空闲中断,以为串口接不到数据了,就直接放开串口,进入空闲中断后操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 uint8_t rx_buffer[100 ];uint8_t rx_len = 0 ; void USART1_IRQHandler (void ) { uint8_t res; HAL_UART_IRQHandler(&huart1); if (__HAL_UART_GET_FLAG(&huart1,UART_FLAG_RXNE) != RESET) { HAL_UART_Receive(&huart1,&res,1 ,1000 ); if (rx_len>=100 ) { rx_len = 0 ; } rx_buffer[rx_len++] = res; __HAL_UART_CLEAR_FLAG(&huart1,UART_FLAG_RXNE); } if (__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) != RESET) { HAL_UART_Transmit(&huart1,rx_buffer,rx_len,1000 ); rx_len = 0 ; __HAL_UART_CLEAR_IDLEFLAG(&huart1); } }
使用DMA方式 在创建工程的时候方法一样只需要在
还是在usart.c的MX_USART1_UART_Init这个函数在后面加上开启中断的代码,开启DMA的接收
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 void MX_USART1_UART_Init (void ) { huart1.Instance = USART1; huart1.Init.BaudRate = 115200 ; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; if (HAL_UART_Init(&huart1) != HAL_OK) { Error_Handler(); } HAL_UART_Receive_DMA(&huart1,rx_buffer,100 ); __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE); }
进入中断函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #define MAX 100 uint8_t rx_buffer[MAX];uint8_t rx_len = 0 ; void USART1_IRQHandler (void ) { HAL_UART_IRQHandler(&huart1); if (__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) != RESET) { HAL_UART_DMAStop(&huart1); rx_len = MAX - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx); HAL_UART_Transmit(&huart1,rx_buffer,rx_len,1000 ); HAL_UART_Receive_DMA(&huart1,rx_buffer,100 ); __HAL_UART_CLEAR_IDLEFLAG(&huart1); } }
小结 简单来说,就是利用接收数据后,数据的空闲时间来做有些事情把这些数据保存起来。