一、简介
串口采用DMA方式接收,MCU可以不用干预就实现外设到RAM传输,相较于中断方式大大提高MCU的运行效率,使得MCU可以腾出空来去处理其它重要事情。以下主要介绍HAL库关于串口DMA方式的配置以及代码实现,包括接收和发送。
二、CubeMx配置
首先将引脚配置为串口功能:
接着配置串口的参数:
点击ADD将UART5的接收设为DMA接收方式
开启串口和DMA中断:
三、代码实现
/*******数据结构定义*******/
typedef struct
{
uint8_t flg;
uint8_t buf[256];
uint16_t len
} DMA_PRO;
#define DMA_REC_LEN 100
DMA_PRO dmaTx = {0};
DMA_PRO dmaRx = {0};
/*******DMA使能/空闲中断使能*******/
//在串口初始化后加入
HAL_UART_Receive_DMA(&huart5, dmaRx.buf, DMA_REC_LEN);
__HAL_UART_ENABLE_IT(&huart5, UART_IT_IDLE);
/*******空闲中断处理*******/
void UsartReceive_IDLE(UART_HandleTypeDef *huart)
{
uint32_t tmpFlg = 0;
uint32_t temp;
tmpFlg =__HAL_UART_GET_FLAG(&huart5,UART_FLAG_IDLE); //获取IDLE标志位
if((tmpFlg != RESET))//idle标志被置位
{
__HAL_UART_CLEAR_IDLEFLAG(&huart5);//清除标志位
HAL_UART_DMAStop(&huart5);
temp = __HAL_DMA_GET_COUNTER(&hdma_huart5_rx);// 获取DMA中未传输的数据个数
dmaRx.len = 100 - temp; //总计数减去未传输的数据个数,得到已经接收的数据个数
dmaRx.flg = 1; // 接受完成标志位置1
}
}
/*******主循环打印接收内容*******/
/***main函数while循环*******/
while (1)
{
if (dmaRx.flg == 1)
{
dmaRx.flg = 0;
//避免其它异常触发空闲中断,误以为接收完成。如首次上电没收到数据空闲标志会被置位
if (dmaRx.len == 0)
{
if (HAL_UART_Receive_DMA(&huart5, dmaRx.buf, DMA_REC_LEN) != HAL_OK)
{
printf("DMA UART REC OPEN ERR\r\n");
}
}
else
{
//注DMA发送函数调完后,并没有完成发送,发送完成会触发DMA中断,调用串口中断回调函数
dmaTx.flg = 1;
memcpy(dmaTx.buf, dmaRx.buf, dmaRx.len);
dmaTx.len = dmaRx.len;
if (HAL_UART_Transmit_DMA(&huart5, dmaTx.buf, dmaTx.len) != HAL_OK)
{
printf("DMA UART TRANSFER OPEN ERR\r\n");
}
while (dmaTx.flg);
if (HAL_UART_Receive_DMA(&huart5, dmaRx.buf, DMA_REC_LEN) != HAL_OK)
{
printf("DMA OPEN ERR\r\n");
}
}
}
}
/*******发送回调函数复位发送标志*******/
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart == &huart5)
{
dmaTx.flg = 0;
}
}