[STM32 HAL]一种可能不错的DMA处理串口数据方案

发布时间 2023-07-09 20:42:30作者: Akasa

[STM32 HAL]一种可能不错的DMA处理数据方案

原文链接:https://blog.csdn.net/youmeichifan/article/details/51750435?spm=1001.2014.3001.5506

本文配置稍有不同,大体类似。

MX配置

开启USART1,使能USART1全局中断,打开RX,TX的DMA通道,均为normal模式,内存地址自增,使能TX对应DMA的中断,RX不需要。

代码部分

  • 在main.c里将MX_DMA的初始化放在MX_UART的初始化之前

usart.h:

/* USER CODE BEGIN Prototypes */

#define RECEIVELEN 1024
#define USART_DMA_SENDING 1//发鿁未完成
#define USART_DMA_SENDOVER 0//发鿁完房
typedef struct
{
uint8_t receive_flag:1;	// 空闲接收标记
uint8_t dmaSend_flag:1;	// 发鿁完成标访
uint16_t rx_len;	// 接收长度
uint8_t usartDMA_rxBuf[RECEIVELEN];	// DMA接收缓存
}USART_RECEIVETYPE;

extern USART_RECEIVETYPE usartType1;

void __USART_Receive_IDLE(UART_HandleTypeDef *huart);
void __USART_SendData_DMA(uint8_t *pdata, uint16_t Length);

/* USER CODE END Prototypes */

usart.c:

/* USER CODE BEGIN 0 */
#include "string.h"
#include "main.h"

USART_RECEIVETYPE usartType1;

/* USER CODE END 0 */
/* USER CODE BEGIN 1 */

void __USART_SendData_DMA(uint8_t *pdata, uint16_t Length)
{
	while(usartType1.dmaSend_flag == USART_DMA_SENDING);
	usartType1.dmaSend_flag = USART_DMA_SENDING;
	HAL_UART_Transmit_DMA(&huart1, pdata, Length);
}
 
//DMA发鿁完成中断回调函敿
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
	//HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, 1);
	__HAL_DMA_DISABLE(huart->hdmatx);
	usartType1.dmaSend_flag = USART_DMA_SENDOVER;
	//HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, 0);
}
 
//串口接收空闲中断
void __USART_Receive_IDLE(UART_HandleTypeDef *huart)
{
	uint32_t temp;
 
	if((__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != RESET))
	{ 
		__HAL_UART_CLEAR_IDLEFLAG(&huart1);
		HAL_UART_DMAStop(huart);
		temp = huart1.hdmarx->Instance->NDTR;
		usartType1.rx_len =  RECEIVELEN - temp; 
		usartType1.receive_flag=1;
		HAL_UART_Receive_DMA(&huart1,usartType1.usartDMA_rxBuf,RECEIVELEN);
	}
}

/* USER CODE END 1 */

stm32f4xxit.c:

/**
  * @brief This function handles USART1 global interrupt.
  */
void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
	__USART_Receive_IDLE(&huart1);     // 这段代码是自己加进去的
  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

  /* USER CODE END USART1_IRQn 1 */
}

main.c:

/* USER CODE BEGIN PV */
char rxStr[256];

char drawBuffer1[256];
char drawBuffer2[256];
char drawBuffer3[256];
/* USER CODE END PV */


/* USER CODE BEGIN 2 */
HAL_UART_Receive_DMA(&huart1, usartType1.usartDMA_rxBuf, RECEIVELEN);
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
/* USER CODE END 2 */


while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		if(usartType1.receive_flag)
		{
			usartType1.receive_flag = 0;
			//printf("%s\r\n", (char*)usartType1.usartDMA_rxBuf);
			strcpy(rxStr, (char*)usartType1.usartDMA_rxBuf);
            // 处理数据
			get_Data(rxStr, drawBuffer1, 'a', 'b');
   			get_Data(rxStr, drawBuffer2, 'b', 'c');
			get_Data(rxStr, drawBuffer3, 'c', 'd');
            
			memset(usartType1.usartDMA_rxBuf, 0x00, sizeof(usartType1.usartDMA_rxBuf));
		}
		
		//__USART_SendData_DMA((uint8_t*)sendBuffer1, sizeof(sendBuffer1));
		u8g2_FirstPage(&u8g2);
		do
		{
     		u8g2_DrawStr(&u8g2, 0, 15, drawBuffer1);
			u8g2_DrawStr(&u8g2, 0, 30, drawBuffer2);
			u8g2_DrawStr(&u8g2, 0, 45, drawBuffer3);
		}while(u8g2_NextPage(&u8g2));
  }
  /* USER CODE END 3 */

然后基本就可以了

但这个方案好像有点小问题,具体还没有搞清楚,大体是可以用的,至少可以接收电脑发送的数据并处理且显示,等有空再好好研究一下啦~