STM32USART+DMA实现不定长数据接收
这一期的内容是一篇代码分享,CubeMX配置介绍,关于基础的内容可以往期内容
CubeMX配置
其余部分配置这里不做介绍,这里只展示串口+DMA部分
代码分享
- main函数
c
/* USER CODE BEGIN PTD */
uint8_t Usart1_Send_Buffer[] = "公主王子请点赞!!!\r\n";
uint8_t Recv_Buff[BUFFER_SIZE]; //接收数据缓存
volatile uint8_t Recv_Length; //接收一帧数据的长度
volatile uint8_t Recv_DndFlag; //一帧数据接收完成标志
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //使能串口空闲中断
HAL_UART_Receive_DMA(&huart1,Recv_Buff,BUFFER_SIZE); //开启DMA串口接收,最大接收长度为 BUFFER_SIZE
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
//通过串口1使用DMA的方式发送数据
// HAL_UART_Transmit_DMA(&huart1, (uint8_t *)Usart1_Send_Buffer, sizeof(Usart1_Send_Buffer));
// HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/* USER CODE END PTD */
在main函数定义的数据,需要在mian.h里面声明外部变量
c
#define BUFFER_SIZE 256
extern uint8_t Recv_Buff[BUFFER_SIZE]; //接收数据缓存
extern volatile uint8_t Recv_Length; //接收一帧数据的长度
extern volatile uint8_t Recv_DndFlag; //一帧数据接收完成标志
- USART1_IRQHandler中断函数
c
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
//注意要在USART1_IRQHandler函数内判断串口空闲中断idle的状态,而不是到串口接收完成回调函数里面,
//由于接收长度的限制,所以大概率是不会接收完成的
// uint32_t temp;
if((__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) != RESET))//idle标志被置位为1,则说明接收完成,串口处于空闲状态
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位
HAL_UART_DMAStop(&huart1); //接收完成,关闭DMA串口接收
Recv_Length = BUFFER_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx); //总计数减去未传输的数据个数,得到已经接收的数据个数
//__HAL_DMA_GET_COUNTER(&hdma_usart1_rx);用于获取本次DMA传输中为传输的数据个数。
Recv_DndFlag = 1; // 接受完成标志位置1
HAL_UART_Transmit_DMA(&huart1, Recv_Buff, Recv_Length);
Recv_Length = 0;//清除计数
Recv_DndFlag = 0;//清除接收结束标志位 ,也可以在其他地方判断,执行相应步骤后清除。
memset(Recv_Buff,0,Recv_Length);
HAL_UART_Receive_DMA(&huart1, Recv_Buff, BUFFER_SIZE);//重新打开DMA接收,不然只能接收一次数据
}
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
USART1_IRQHandler中断函数在stm32f4xx_it.c文件中,代码实现原理具体如下:
- 开启串口1的空闲中断
- 开启DMA串口1的接收数据,接收数据长度为BUFFER_SIZE(需要确保BUFFER_SIZE >正常的数据长度)
- 在数据的接收过程中,串口处于忙碌状态,当接收完成时,串口空闲,发送中断。
- 判断是空闲中断标志位置位,读取未完成传输的数据,计算接收的数据长度
- 将计算数据长度的发送会串口,检验数据正确性
- 清空接收的数据,再次开启DMA接收,重复以上过程。
实践结果
发送数据
接收数据