STM32 HAL 使用串口IDLE中断+DMA实现收发

发布时间 2023-11-13 23:56:03作者: Akasa

STM32 HAL 使用串口IDLE中断+DMA实现收发

cubeMX配置

mx配置如下(省去系统时钟,烧录口,工程属性配置)

注意:这里关闭 Force DMA channels Interrupts

image

然后按下面配置即可(TX和RX的DMA都是normal模式)

image

image

代码部分

uart_com.h:

#ifndef __UART_COM_H__
#define __UART_COM_H__

#include "main.h"
#include "string.h"
#include "stdarg.h"
#include "stdio.h"

#define DATA_SIZE 255

typedef struct UART_Data_T 
{
	UART_HandleTypeDef * phuart;
	uint8_t pRxData[DATA_SIZE];
	uint8_t rxData[DATA_SIZE];
	uint16_t rxDataSize;
	uint8_t txBuffer[DATA_SIZE];
}UART_Data_T;

extern UART_Data_T myUART1;

void myUART_Init(UART_HandleTypeDef * huart, UART_Data_T * myUART);
void myUART_send_DMA(UART_Data_T * myUART, uint8_t * buffer, uint16_t size);
void myUART_debug_printf(UART_Data_T * myUART, const char * format, ...);
static inline void myUART_copyData(UART_Data_T * myUART, uint16_t size);
static inline void myUART_resumeReceive(UART_Data_T * myUART);

#endif

uart_com.h:

#include "uart_com.h"

UART_Data_T myUART1;

void myUART_Init(UART_HandleTypeDef * huart, UART_Data_T * myUART)
{
	myUART->phuart = huart;
	HAL_UARTEx_ReceiveToIdle_DMA(huart, myUART->pRxData, sizeof(myUART->pRxData));
}

static inline void myUART_copyData(UART_Data_T * myUART, uint16_t size)
{
	strcpy((char*)myUART->rxData, (char*)myUART->pRxData);
	myUART->rxDataSize = size;
}

static inline void myUART_resumeReceive(UART_Data_T * myUART)
{
	memset(myUART->pRxData, 0x00, sizeof(myUART->pRxData));
	HAL_UARTEx_ReceiveToIdle_DMA(myUART->phuart, myUART->pRxData, sizeof(myUART->pRxData));
}

void myUART_send_DMA(UART_Data_T * myUART, uint8_t * buffer, uint16_t size) 
{
	while(HAL_DMA_GetState(myUART->phuart->hdmatx) != HAL_DMA_STATE_READY);
	__HAL_DMA_DISABLE(myUART->phuart->hdmatx);
	HAL_UART_Transmit_DMA(myUART->phuart, buffer, size);
}

void myUART_debug_printf(UART_Data_T * myUART, const char * format, ...)
{
	uint16_t length = 0;
	va_list args;
	va_start(args, format);
	length = vsnprintf((char*)myUART->txBuffer, sizeof(myUART->txBuffer), (char*)format, args);
	myUART_send_DMA(myUART, myUART->txBuffer, length);
}

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	if(huart->Instance==myUART1.phuart->Instance)
	{
		/*Deal with the data*/
	  myUART_copyData(&myUART1, Size);
		//myUART_send_DMA(&myUART1, myUART1.rxData, myUART1.rxDataSize);	// This sentence is used for testing.
		//myUART_debug_printf(&myUART1, "%s", myUART1.rxData);	// This sentence is used for testing.
		
		/*Clear data and restart DMA receive*/
		myUART_resumeReceive(&myUART1);
	}
}

使用

以uart1为例,进行初始化:

myUART_Init(&huart1, &myUART1);
myUART_debug_printf(&myUART1, "Init OK!\n");

然后就可以在代码里调用发送函数了。