STM32F407 串口使用DMA方式通信

DMA的原理,就是利用寄存器方式进行读写,这样的好处就是相对于中断触发(往往一个字节字节的就中断一次),CPU中断次数大大降少,提高了效率,但也影响了实时性。总体来说,对于一般的应用,瑕不掩瑜,值得使用。

本文是基于串口1的,实际上串口1也是printf重定向接口,貌似没有什么冲突。

原则上:

  1. 串口接收采用DMA+空闲中断的方式

  2. 串口发送就是直接发送方式

这样的方式,符合一般项目需求。

也分两部分:STM32CubeMx端配置+代码的处理

STM32CubeMx端配置

CubeMX 这边在原先"串口"配置基础上,配置DMA方式,总体来说,跟网上大部分例子差不多。

在USART界面下选择 DMA Settings,如下图:

Mode选择Normal,一般都是。还有一种循环发送,大概意思就是开启后自动循环发送?

第4步骤,根据实际情况下选择,貌似没啥影响

RX:接收端配置

TX:发送端配置

在NVIC Settings。确认下是否中断开启?

Parameters Settings 跟常规串口配置一样,主要是一些波特率参数之类的

还要配置下DMA,在 System Core地方选择DMA

最后一项MEMTOMEM,默认是没有的,可通过下面的Add添加上去

其他都跟往常一样。

代码侧改动

好几个地方要改动:

直接上代码:

usart.h

复制代码
/* USER CODE BEGIN Private defines */

/* xxxx 的意思是 你自己取个好点名字*/

#define XXXX_BUFFER_SIZE  128 

extern volatile uint8_t g_xxxxRxLen; 			/*接收一帧数据的长度*/
extern volatile uint8_t g_xxxxRecvEndFlag; 		/*一帧数据接收完成标志*/
extern uint8_t g_xxxxRxbuffer[XXXX_BUFFER_SIZE]; /*接收数据缓存数组*/

/* USER CODE END Private defines */

usart.c

复制代码
/* USER CODE BEGIN 0 */

volatile uint8_t g_xxxxRxLen = 0;
volatile uint8_t g_xxxxRecvEndFlag = 0; 
uint8_t g_xxxxRxbuffer[XXXX_BUFFER_SIZE] = {0};

/* USER CODE END 0 */


在
void MX_USART1_UART_Init(void)
后面追加

/* USER CODE BEGIN USART1_Init 2 */
  __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); 
  __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); 

  /*DMA接收函数,此句一定要加,不加接收不到第一次传进来的实数据,*/
  /*是空的,且此时接收到的数据长度为缓存器的数据长度*/
  HAL_UART_Receive_DMA(&huart1,g_xxxxRxbuffer,XXXX_BUFFER_SIZE);


  /* USER CODE END USART1_Init 2 */

stm32f4xx_it.c 增加以下内容(10x系列,就是f1xx)

复制代码
void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
	
  uint32_t temp;
	
	if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) != RESET)
	{ 
可能是点个灯之类操作
		__HAL_UART_CLEAR_IDLEFLAG(&huart1);
		
		HAL_UART_DMAStop(&huart1); 
/* 获取DMA中未传输的数据个数 */
		temp = __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);   

/*总计数减去未传输的数据个数,得到已经接收的数据个数 */
/*  这里有风险的,BUFFER_SIZE 如果小于当前帧的话,就有问题*/

/* 正常情况下,要考虑下此情况 */
		g_xxxxRxLen = XXXX_BUFFER_SIZE - temp; 

		g_xxxxRecvEndFlag = 1;	/* 标志位置1	*/
	}

  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

  /* USER CODE END USART1_IRQn 1 */
}

应用侧,需要一个task去轮询(是否收到数据)

比如说,我是放在Task3里面

复制代码
void StartTask03(void const * argument)
{
  /* USER CODE BEGIN StartTask03 */
  /* Infinite loop */

	uint8_t dmaSend[] = "this is DMA\n";
		
	for(;;)
	{
		if(g_xxxxRecvEndFlag == 1)
		{
            /* 此demo 简单处理,就应答一个固定内容,实际要根据实际情况处理*/
			DMA_Usart1_Send(dmaSend,sizeof(dmaSend)-1);		
            
           // 此处增加协议处理之类的。可以复杂
			
			g_xxxxRxLen = 0;
			g_xxxxRecvEndFlag = 0;
			
			memset(g_xxxxRxbuffer,0,g_xxxxRxLen);
		}
		
		HAL_UART_Receive_DMA(&huart1,g_xxxxRxbuffer,XXXX_BUFFER_SIZE);
		
		osDelay(1);
	}
  /* USER CODE END StartTask03 */
}

/*
*********************************************************************************************************
* 函 数 名: DMA_Usart_Send
* 功能说明: 串口发送功能函数
* 形  参: buf,len
* 返 回 值: 无
*********************************************************************************************************
*/
void DMA_Usart1_Send(uint8_t *buf,uint8_t len)
{
	while(HAL_DMA_GetState(&hdma_usart1_tx) == HAL_DMA_STATE_BUSY)  
	{
		osDelay(1);
	}
    
	/* 关闭DMA */
    __HAL_DMA_DISABLE(&hdma_usart1_tx);

	if(HAL_UART_Transmit_DMA(&huart1, buf, len) != HAL_OK)
	{
		Error_Handler();
	}
}



/*
*********************************************************************************************************
* 函 数 名: DMA_Usart1_Read
* 功能说明: 串口接收功能函数
* 形  参: Data,len
* 返 回 值: 无
*********************************************************************************************************
*/
void DMA_Usart1_Read(uint8_t *Data,uint8_t len)
{
	HAL_UART_Receive_DMA(&huart1,Data,len);
}
相关推荐
得单片机的运1 小时前
STM32的以太网的搭建
stm32·单片机·嵌入式硬件·物联网·以太网·iot·w5500
酷飞飞2 小时前
RTC和看门狗基于GD32F407VE的天空星的配置
stm32·单片机·嵌入式硬件·mcu
qq_401700413 小时前
STM32的HardFault错误处理技巧
stm32
WD137298015573 小时前
WD5030A,24V降5V,15A 大电流,应用于手机、平板、笔记本充电器
stm32·单片机·嵌入式硬件·智能手机·汽车·电脑·51单片机
日更嵌入式的打工仔3 小时前
GPIO 中断通用配置指南
stm32·单片机·嵌入式硬件
平凡灵感码头4 小时前
基于 STM32 的智能门锁系统,系统界面设计
stm32·单片机·嵌入式硬件
Truffle7电子5 小时前
STM32理论 —— 存储、中断
stm32·嵌入式硬件·嵌入式·存储·中断
报错小能手5 小时前
linux学习笔记(32)网络编程——UDP
单片机·嵌入式硬件
XiangrongZ7 小时前
江协科技STM32课程笔记(四)—定时器TIM(输入捕获)
笔记·科技·stm32
xyx-3v7 小时前
SPI四种工作模式
stm32·单片机·嵌入式硬件·学习