STM32F4使用DMA串口空闲中断接受数据


前言

STM32使用USART串口接受数据有多种模式,其中一种是直接使用串口中断,来一个数据就处理一个数组,当很多数据传过来时候,频繁进入中断会占用CPU太多时间。这是我们可以使用DMA(直接存储器访问),将接受到的数据先放到DMA中,等传送完全了再去处理数据。而使用DMA接收也有多种方式,其中就有DMA定长中断接收和串口空闲中断接收。

一、DMA串口空闲中断接收

头文件:usart.h

#ifndef __USART_H__
#define __USART_H__

#define usart3_RX_BUFF_SIZE 128
#define DMA_UsART3_SIZE          128
void MX_USART3_UART_Init(void);

#endif

配置函数:

#include "usart.h"
UART_HandleTypeDef huart3;
DMA_HandleTypeDef hdma_usart3_rx;
DMA_HandleTypeDef hdma_usart3_tx;
/* USART3 init function */
void MX_USART3_UART_Init(void)
{
  huart3.Instance = USART3;
  huart3.Init.BaudRate = 115200;
  huart3.Init.WordLength = UART_WORDLENGTH_8B;
  huart3.Init.StopBits = UART_STOPBITS_1;
  huart3.Init.Parity = UART_PARITY_NONE;
  huart3.Init.Mode = UART_MODE_TX_RX;
  huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart3.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart3) != HAL_OK)
  {
    Error_Handler();
  }
}
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	if(uartHandle->Instance==USART3)
	{
		__HAL_RCC_USART3_CLK_ENABLE();
		__HAL_RCC_GPIOD_CLK_ENABLE();
		/**USART3 GPIO Configuration
		PD9     ------> USART3_RX
		PD8     ------> USART3_TX
		*/
		GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_8;
		GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
		GPIO_InitStruct.Pull = GPIO_NOPULL;
		GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
		GPIO_InitStruct.Alternate = GPIO_AF7_USART3;
		HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
		/* USART3_RX Init */
		hdma_usart3_rx.Instance = DMA1_Stream1;
		hdma_usart3_rx.Init.Channel = DMA_CHANNEL_4;
		hdma_usart3_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
		hdma_usart3_rx.Init.PeriphInc = DMA_PINC_DISABLE;
		hdma_usart3_rx.Init.MemInc = DMA_MINC_ENABLE;
		hdma_usart3_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
		hdma_usart3_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
		hdma_usart3_rx.Init.Mode = DMA_CIRCULAR;
		hdma_usart3_rx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
		hdma_usart3_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
		if (HAL_DMA_Init(&hdma_usart3_rx) != HAL_OK)
		{
			Error_Handler();
		}
		__HAL_LINKDMA(uartHandle,hdmarx,hdma_usart3_rx);
		/* USART3_TX Init */
		hdma_usart3_tx.Instance = DMA1_Stream3;
		hdma_usart3_tx.Init.Channel = DMA_CHANNEL_4;
		hdma_usart3_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
		hdma_usart3_tx.Init.PeriphInc = DMA_PINC_DISABLE;
		hdma_usart3_tx.Init.MemInc = DMA_MINC_ENABLE;
		hdma_usart3_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
		hdma_usart3_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
		hdma_usart3_tx.Init.Mode = DMA_CIRCULAR;
		hdma_usart3_tx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
		hdma_usart3_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
		if (HAL_DMA_Init(&hdma_usart3_tx) != HAL_OK)
		{
			Error_Handler();
		}
		__HAL_LINKDMA(uartHandle,hdmatx,hdma_usart3_tx);
		/* USART3 interrupt Init */
		HAL_NVIC_SetPriority(USART3_IRQn, 5, 0);
		HAL_NVIC_EnableIRQ(USART3_IRQn);
		/* USER CODE BEGIN USART3_MspInit 1 */
		__HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);
		/* USER CODE END USART3_MspInit 1 */
	}
}
void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{
	if(uartHandle->Instance==USART3)
	{
		/* USER CODE BEGIN USART3_MspDeInit 0 */
		/* USER CODE END USART3_MspDeInit 0 */
		/* Peripheral clock disable */
		__HAL_RCC_USART3_CLK_DISABLE();
		/**USART3 GPIO Configuration
		PD9     ------> USART3_RX
		PD8     ------> USART3_TX
		*/
		HAL_GPIO_DeInit(GPIOD, GPIO_PIN_9|GPIO_PIN_8);
		HAL_DMA_DeInit(uartHandle->hdmarx);
		HAL_DMA_DeInit(uartHandle->hdmatx);
		HAL_NVIC_DisableIRQ(USART3_IRQn);
	}
}

中断接受处理函数

uint8_t usart3_rx_data[usart3_RX_BUFF_SIZE];
void USAR_UART_IDLECallback(UART_HandleTypeDef *huart3)
{
	if(__HAL_UART_GET_FLAG(huart3, UART_FLAG_IDLE)!=RESET)   //判断是否是空闲中断
    {
		__HAL_UART_CLEAR_IDLEFLAG(huart3);
		HAL_UART_DMAStop(huart3);                            //停止本次DMA传输
		uint8_t data_length  = DMA_UsART3_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart3_tx);   //计算接收到的数据长度
		process_judge_message( usart3_rx_data );
		memset(usart3_rx_data,0,data_length);             //清零接收缓冲区
		HAL_UART_Receive_DMA(huart3, usart3_rx_data, DMA_UsART3_SIZE);   //重启开始DMA传输 每次最长255字节数据
	}
} 
void USART3_IRQHandler(void)
{
  HAL_UART_IRQHandler(&huart3);
  USAR_UART_IDLECallback(&huart3);
}

二、DMA定长中断接收

本例的定长设置为30个字节

头文件:

#ifndef USART1_H
#define USART1_H
#include "stm32f4xx_hal.h"

#define CALI_DATA_PACKAGE_SIZE (40u)

void usart1_configuration(uint32_t bound);

#endif

配置函数:

DMA_HandleTypeDef  dma2_handler;      //DMA句柄
UART_HandleTypeDef usart1_handler;    //UART句柄
uint8_t usart1_rx_cali_data[CALI_DATA_PACKAGE_SIZE];
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
	GPIO_InitTypeDef gpio_init;
	if(huart->Instance == USART1)
	{
		__HAL_RCC_GPIOA_CLK_ENABLE();           
		__HAL_RCC_GPIOB_CLK_ENABLE();           //开启GPIOH时钟
		__HAL_RCC_USART1_CLK_ENABLE();			//使能USART1时钟
		gpio_init.Pin = GPIO_PIN_9;
		gpio_init.Alternate = GPIO_AF7_USART1;
		gpio_init.Mode = GPIO_MODE_AF_PP;       //输出
		gpio_init.Pull = GPIO_PULLUP;        	//上拉
		gpio_init.Speed = GPIO_SPEED_FREQ_HIGH;
		HAL_GPIO_Init(GPIOA, &gpio_init);
		gpio_init.Pin = GPIO_PIN_7;
		HAL_GPIO_Init(GPIOB, &gpio_init);
	}
}
void usart1_configuration(uint32_t bound)
{
    __HAL_RCC_DMA1_CLK_ENABLE();//DMA1时钟使能 
    __HAL_RCC_DMA2_CLK_ENABLE();//DMA1时钟使能 
	__HAL_LINKDMA(&usart1_handler, hdmarx, dma2_handler);    //将DMA与USART1联系起来(接收DMA)
	dma2_handler.Instance = DMA2_Stream5;    //dma2 数据流5(可查表)
	dma2_handler.Init.Channel = DMA_CHANNEL_4;//通道4(可查表)
	dma2_handler.Init.Direction = DMA_PERIPH_TO_MEMORY;//从外设到存储器
	dma2_handler.Init.MemInc = DMA_MINC_ENABLE;    //存储器增量模式
	dma2_handler.Init.PeriphInc = DMA_PINC_DISABLE; //外设非增量模式
	dma2_handler.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
	dma2_handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
	dma2_handler.Init.FIFOMode = DMA_FIFOMODE_DISABLE;  //关闭
	dma2_handler.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;//无
	dma2_handler.Init.MemBurst = DMA_MBURST_SINGLE;
	dma2_handler.Init.PeriphBurst = DMA_PBURST_SINGLE;
	dma2_handler.Init.Mode = DMA_CIRCULAR;//循环模式
	dma2_handler.Init.Priority = DMA_PRIORITY_MEDIUM;//优先级设置
	HAL_DMA_DeInit(&dma2_handler);//复位寄存器
	HAL_DMA_Init(&dma2_handler); 
    //usart1 初始化
	usart1_handler.Instance=USART1;					    //USART1
	usart1_handler.Init.BaudRate=bound;				    //波特率
	usart1_handler.Init.WordLength=UART_WORDLENGTH_8B;  //字长为8位数据格式
	usart1_handler.Init.StopBits=UART_STOPBITS_1;	    //一个停止位
	usart1_handler.Init.Parity=UART_PARITY_NONE; 
	usart1_handler.Init.HwFlowCtl=UART_HWCONTROL_NONE;  //无硬件流控
	usart1_handler.Init.Mode=UART_MODE_TX_RX;		    //收发模式
	HAL_UART_Init(&usart1_handler);					    //HAL_UART_Init()会使能UART1
	HAL_UART_Receive_DMA(&usart1_handler, usart1_rx_cali_data, 30);//开启usart1 rx dma接收中断
	HAL_NVIC_SetPriority(DMA2_Stream5_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(DMA2_Stream5_IRQn);
}

中断处理函数

void DMA2_Stream5_IRQHandler(void)
{
	HAL_DMA_IRQHandler(&dma2_handler);
	get_pc_cali_data(&pc_cali, usart1_rx_cali_data);	//回调
}

以上就是串口配置DMA的基本流程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值