相信大家很多初学者都会遇到串口接收不定长数据的情况。
对于初学者可能看着有点难理解,多看几遍就好,亲测能用。
话不多说上菜上菜!!!!
此代码是本人在具体工程应用,实测稳定。
有不足之处还请发现问题的小伙伴指出,大家共同进步。
此处省略stm32CubeIDE 配置过程*********************************
串口配置过程如下:
其他几个串口也是如下进行配置(正常使用的话只使能DMA接收即可)
新建usr_uart_rec.h头文件,内容如下:
#ifndef USR_UART_REC_USR_UART_REC_H_
#define USR_UART_REC_USR_UART_REC_H_
#include "main.h"
#define MAX_REC_COUNT 36//可随根据实际使用情况进行调整
typedef struct
{
uint8_t ReciveBuff[MAX_REC_COUNT];//接收缓冲区
uint8_t uartRecCount;//接收数据的计数器
uint8_t RecFlag:1;//接收标志位 主要用于数据处理
}DMAuartReciveBuff;
typedef struct
{
DMAuartReciveBuff userUart1;
DMAuartReciveBuff userUart2;
DMAuartReciveBuff userUart3;
DMAuartReciveBuff userUart4;
DMAuartReciveBuff userUart5;
DMAuartReciveBuff userUart6;
}UART_REC;
typedef struct
{
uint8_t DMAbuff[MAX_REC_COUNT];
}uBbuffer;
typedef struct
{
uBbuffer usr_uart1;
uBbuffer usr_uart2;
uBbuffer usr_uart3;
uBbuffer usr_uart4;
uBbuffer usr_uart5;
uBbuffer usr_uart6;
}UART_MEMCPY_BUFF;//复制DMA的数据 用于解析
extern UART_MEMCPY_BUFF usr_dma_Data;
extern UART_REC userUart;
void USR_UART_Init();//串口初始化函数
void UART1_IRQ_DataGet();//在串口中断服务函数中添加此函数用于缓存数据
void UART2_IRQ_DataGet();
void UART3_IRQ_DataGet();
void UART4_IRQ_DataGet();
void UART5_IRQ_DataGet();
void UART6_IRQ_DataGet();
#endif /* USR_UART_REC_USR_UART_REC_H_ */
新建usr_uart_rec.c头文件,内容如下:
#include "main.h"
#include "usart.h"
#include "usr_uart_rec.h"
#include "string.h"
UART_REC userUart;
UART_MEMCPY_BUFF usr_dma_Data;
void USR_UART_Init()//串口初始化函数
{
__HAL_UART_ENABLE_IT(&huart2,UART_IT_IDLE);//启动IDLE中断
__HAL_UART_ENABLE_IT(&huart3,UART_IT_IDLE);//启动IDLE中断
__HAL_UART_ENABLE_IT(&huart4,UART_IT_IDLE);//启动IDLE中断
__HAL_UART_ENABLE_IT(&huart5,UART_IT_IDLE);//启动IDLE中断
__HAL_UART_ENABLE_IT(&huart6,UART_IT_IDLE);//启动IDLE中断
__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);//启动IDLE中断
userUart.userUart1.uartRecCount = 0;
// 注意串口DMA 发送时候应该如下顺序初始化DMA 和串口
// MX_DMA_Init();
// MX_USART1_UART_Init();
// MX_UART4_Init();
// MX_UART5_Init();
// MX_USART2_UART_Init();
// MX_USART3_UART_Init();
// MX_USART6_UART_Init();
HAL_UART_Receive_DMA(&huart1, (uint8_t *)&userUart.userUart1.ReciveBuff, sizeof(userUart.userUart1.ReciveBuff));
HAL_UART_Receive_DMA(&huart2, (uint8_t *)&userUart.userUart2.ReciveBuff, sizeof(userUart.userUart2.ReciveBuff));
HAL_UART_Receive_DMA(&huart3, (uint8_t *)&userUart.userUart3.ReciveBuff, sizeof(userUart.userUart3.ReciveBuff));
HAL_UART_Receive_DMA(&huart4, (uint8_t *)&userUart.userUart4.ReciveBuff, sizeof(userUart.userUart4.ReciveBuff));
HAL_UART_Receive_DMA(&huart5, (uint8_t *)&userUart.userUart5.ReciveBuff, sizeof(userUart.userUart5.ReciveBuff));
HAL_UART_Receive_DMA(&huart6, (uint8_t *)&userUart.userUart6.ReciveBuff, sizeof(userUart.userUart6.ReciveBuff));
}
void UART1_IRQ_DataGet()//在串口1的中断服务函数中添加此函数用于缓存数据
{
if(USART1 == huart1.Instance)
{
if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE))
{
HAL_UART_DMAStop(&huart1);
userUart.userUart1.uartRecCount = MAX_REC_COUNT - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);//用于统计DMA接收到了多少数据
userUart.userUart1.RecFlag = true;
// printf("userUart.userUart1.uartRecCount is %d",userUart.userUart1.uartRecCount);
// memcpy(&usr_dma_Data.usr_uart1.DMAbuff,&userUart.userUart1.ReciveBuff,userUart.userUart1.uartRecCount);
// memset((uint8_t *)&userUart.userUart1.ReciveBuff,0,sizeof(userUart.userUart1.ReciveBuff));
// userUart.userUart1.uartRecCount = 0;
HAL_UART_Receive_DMA(&huart1, (uint8_t *)&userUart.userUart1.ReciveBuff, sizeof(userUart.userUart1.ReciveBuff));
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
}
}
}
void UART2_IRQ_DataGet()//在串口1的中断服务函数中添加此函数用于缓存数据
{
if(USART2 == huart2.Instance)
{
if(__HAL_UART_GET_FLAG(&huart2,UART_FLAG_IDLE))
{
HAL_UART_DMAStop(&huart2);
userUart.userUart2.uartRecCount = MAX_REC_COUNT - __HAL_DMA_GET_COUNTER(&hdma_usart2_rx);//用于统计DMA接收到了多少数据
userUart.userUart2.RecFlag = true;
// printf("userUart.userUart2.uartRecCount is %d",userUart.userUart2.uartRecCount);
// memcpy(&usr_dma_Data.usr_uart2.DMAbuff,&userUart.userUart2.ReciveBuff,userUart.userUart2.uartRecCount);
// memset((uint8_t *)&userUart.userUart2.ReciveBuff,0,sizeof(userUart.userUart2.ReciveBuff));
// userUart.userUart2.uartRecCount = 0;
HAL_UART_Receive_DMA(&huart2, (uint8_t *)&userUart.userUart2.ReciveBuff, sizeof(userUart.userUart2.ReciveBuff));
__HAL_UART_CLEAR_IDLEFLAG(&huart2);
}
}
}
void UART3_IRQ_DataGet()//在串口1的中断服务函数中添加此函数用于缓存数据
{
if(USART3 == huart3.Instance)
{
if(__HAL_UART_GET_FLAG(&huart3,UART_FLAG_IDLE))
{
HAL_UART_DMAStop(&huart3);
userUart.userUart3.uartRecCount = MAX_REC_COUNT - __HAL_DMA_GET_COUNTER(&hdma_usart3_rx);//用于统计DMA接收到了多少数据
userUart.userUart3.RecFlag = true;
// printf("userUart.userUart3.uartRecCount is %d",userUart.userUart3.uartRecCount);
// memcpy(&usr_dma_Data.usr_uart3.DMAbuff,&userUart.userUart3.ReciveBuff,userUart.userUart3.uartRecCount);
// memset((uint8_t *)&userUart.userUart3.ReciveBuff,0,sizeof(userUart.userUart3.ReciveBuff));
// userUart.userUart3.uartRecCount = 0;
HAL_UART_Receive_DMA(&huart3, (uint8_t *)&userUart.userUart3.ReciveBuff, sizeof(userUart.userUart3.ReciveBuff));
__HAL_UART_CLEAR_IDLEFLAG(&huart3);
}
}
}
void UART4_IRQ_DataGet()//在串口1的中断服务函数中添加此函数用于缓存数据
{
if(UART4 == huart4.Instance)
{
if(__HAL_UART_GET_FLAG(&huart4,UART_FLAG_IDLE))
{
HAL_UART_DMAStop(&huart4);
userUart.userUart4.uartRecCount = MAX_REC_COUNT - __HAL_DMA_GET_COUNTER(&hdma_uart4_rx);//用于统计DMA接收到了多少数据
userUart.userUart4.RecFlag = true;
// printf("userUart.userUart1.uartRecCount is %d",userUart.userUart1.uartRecCount);
// memcpy(&usr_dma_Data.usr_uart4.DMAbuff,&userUart.userUart4.ReciveBuff,userUart.userUart4.uartRecCount);
// memset((uint8_t *)&userUart.userUart4.ReciveBuff,0,sizeof(userUart.userUart4.ReciveBuff));
// userUart.userUart4.uartRecCount = 0;
HAL_UART_Receive_DMA(&huart4, (uint8_t *)&userUart.userUart4.ReciveBuff, sizeof(userUart.userUart4.ReciveBuff));
__HAL_UART_CLEAR_IDLEFLAG(&huart4);
//顺便处理收到的数据
}
}
}
void UART5_IRQ_DataGet()//在串口1的中断服务函数中添加此函数用于缓存数据
{
if(UART5 == huart5.Instance)
{
if(__HAL_UART_GET_FLAG(&huart5,UART_FLAG_IDLE))
{
HAL_UART_DMAStop(&huart5);
userUart.userUart5.uartRecCount = MAX_REC_COUNT - __HAL_DMA_GET_COUNTER(&hdma_uart5_rx);//用于统计DMA接收到了多少数据
userUart.userUart5.RecFlag = true;
// printf("userUart.userUart1.uartRecCount is %d",userUart.userUart1.uartRecCount);
// memcpy(&usr_dma_Data.usr_uart5.DMAbuff,&userUart.userUart5.ReciveBuff,userUart.userUart5.uartRecCount);
// memset((uint8_t *)&userUart.userUart5.ReciveBuff,0,sizeof(userUart.userUart5.ReciveBuff));
// userUart.userUart5.uartRecCount = 0;
HAL_UART_Receive_DMA(&huart5, (uint8_t *)&userUart.userUart5.ReciveBuff, sizeof(userUart.userUart5.ReciveBuff));
__HAL_UART_CLEAR_IDLEFLAG(&huart5);
}
}
}
void UART6_IRQ_DataGet()//在串口1的中断服务函数中添加此函数用于缓存数据
{
if(USART6 == huart6.Instance)
{
if(__HAL_UART_GET_FLAG(&huart6,UART_FLAG_IDLE))
{
HAL_UART_DMAStop(&huart6);
userUart.userUart6.uartRecCount = MAX_REC_COUNT - __HAL_DMA_GET_COUNTER(&hdma_usart6_rx);//用于统计DMA接收到了多少数据
userUart.userUart6.RecFlag = true;
// printf("userUart.userUart1.uartRecCount is %d",userUart.userUart1.uartRecCount);
// memcpy(&usr_dma_Data.usr_uart6.DMAbuff,&userUart.userUart6.ReciveBuff,userUart.userUart6.uartRecCount);
// memset((uint8_t *)&userUart.userUart6.ReciveBuff,0,sizeof(userUart.userUart6.ReciveBuff));
// userUart.userUart1.uartRecCount = 0;
HAL_UART_Receive_DMA(&huart6, (uint8_t *)&userUart.userUart6.ReciveBuff, sizeof(userUart.userUart6.ReciveBuff));
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
}
}
}
注释掉的部分可用于调试,本人不建议在中断中处理大量数据,因为容易死机哦。
在使用串口DMA的时候需要注意以下问题:
在使用 stm32CubeIDE生成代码之后,按照官方的初始化流程有点点问题,会导致串口接收不到数据,所以要稍作修改,改变初始化流程:如下所示(最主要的是先初始化DMA 再初始化相关串口)这是一位博主针对DMA串口接收数据失败写的文章
MX_DMA_Init();
MX_USART1_UART_Init();
MX_UART4_Init();
MX_UART5_Init();
MX_USART2_UART_Init();
MX_USART3_UART_Init();
MX_USART6_UART_Init();
最后在stm32f4xx_it.c 如下,将自定义的函数加到中断服务函数中即可 例如:
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 */
UART1_IRQ_DataGet();
/* USER CODE END USART1_IRQn 1 */
}
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 */
UART2_IRQ_DataGet();
/* USER CODE END USART2_IRQn 1 */
}
void USART3_IRQHandler(void)
{
/* USER CODE BEGIN USART3_IRQn 0 */
/* USER CODE END USART3_IRQn 0 */
HAL_UART_IRQHandler(&huart3);
/* USER CODE BEGIN USART3_IRQn 1 */
UART3_IRQ_DataGet();
/* USER CODE END USART3_IRQn 1 */
}
void UART4_IRQHandler(void)
{
/* USER CODE BEGIN UART4_IRQn 0 */
/* USER CODE END UART4_IRQn 0 */
HAL_UART_IRQHandler(&huart4);
/* USER CODE BEGIN UART4_IRQn 1 */
UART4_IRQ_DataGet();
/* USER CODE END UART4_IRQn 1 */
}
void UART5_IRQHandler(void)
{
/* USER CODE BEGIN UART5_IRQn 0 */
/* USER CODE END UART5_IRQn 0 */
HAL_UART_IRQHandler(&huart5);
/* USER CODE BEGIN UART5_IRQn 1 */
UART5_IRQ_DataGet();
/* USER CODE END UART5_IRQn 1 */
}
void USART6_IRQHandler(void)
{
/* USER CODE BEGIN USART6_IRQn 0 */
/* USER CODE END USART6_IRQn 0 */
HAL_UART_IRQHandler(&huart6);
/* USER CODE BEGIN USART6_IRQn 1 */
UART6_IRQ_DataGet();
/* USER CODE END USART6_IRQn 1 */
}
需要注意的是 此代码在接收完成后会有一个软件标志位被置1,使用完数据之后需要用户手动清零。
userUart.userUart1.RecFlag = true;//串口1接收完成的中断标志
userUart.userUart1.uartRecCount = MAX_REC_COUNT - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);//用于统计DMA接收到了多少数据
具体如何使用呢,举个例子(串口1):
uint8_t PowerRecBuff[23];
void PowerDataAnalyze()//解析电池的数据
{
if(userUart.userUart1.RecFlag )
{
userUart.userUart1.RecFlag = false;//清除标志位
memcpy((uint8_t *)&PowerRecBuff,(uint8_t *)&userUart.userUart1.ReciveBuff, userUart.userUart1.uartRecCount);
RSOC = PowerRecBuff[23];
/*
使用者亦可在此处进行数据处理
具体怎么处理不用我多说了吧---哈哈 加油。
*/
userUart.userUart1.uartRecCount = 0;
memset((uint8_t *)&userUart.userUart1.ReciveBuff,0, sizeof(userUart.userUart1.ReciveBuff));
}
}
自此完结。此代码亲测可用,对于初学者可能有点难理解,加油!共勉。