HAL库串口+DMA空闲中断接收不定长数据
时间: 2023-09-05 20:10:05 浏览: 218
使用DMA空闲中断接收不定长数据的步骤如下:
1. 初始化串口和DMA:配置串口为接收模式,启用DMA传输;配置DMA为循环模式,传输大小为1字节,传输方向为从串口接收数据到内存。
2. 开启DMA传输:调用DMA启动函数启动DMA传输。
3. 开启串口接收中断:调用串口中断使能函数,开启空闲中断。
4. 在空闲中断中处理数据:当DMA传输完成并且串口没有接收到新数据时,说明接收完成,可以在空闲中断中处理接收到的数据。
下面是一个简单的例子:
```c
#include "stm32f4xx_hal.h"
#define RX_BUF_SIZE 256
UART_HandleTypeDef huart1;
DMA_HandleTypeDef hdma_usart1_rx;
uint8_t rx_buf[RX_BUF_SIZE];
uint8_t rx_len = 0;
uint8_t rx_flag = 0;
void UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
hdma_usart1_rx.Instance = DMA2_Stream2;
hdma_usart1_rx.Init.Channel = DMA_CHANNEL_4;
hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart1_rx.Init.Mode = DMA_CIRCULAR;
hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;
hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(&huart1, hdmarx, hdma_usart1_rx);
HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
HAL_UART_Receive_DMA(&huart1, rx_buf, RX_BUF_SIZE);
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart == &huart1)
{
rx_len += RX_BUF_SIZE - hdma_usart1_rx.Instance->NDTR;
HAL_UART_Receive_DMA(huart, rx_buf, RX_BUF_SIZE);
}
}
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart)
{
if (huart == &huart1)
{
rx_len += RX_BUF_SIZE / 2 - hdma_usart1_rx.Instance->NDTR;
}
}
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
if (huart == &huart1)
{
__HAL_UART_CLEAR_PEFLAG(&huart1);
HAL_UART_Receive_DMA(huart, rx_buf, RX_BUF_SIZE);
}
}
void DMA2_Stream2_IRQHandler(void)
{
HAL_DMA_IRQHandler(&hdma_usart1_rx);
}
void HAL_UART_IdleCallback(UART_HandleTypeDef *huart)
{
if (huart == &huart1)
{
if (hdma_usart1_rx.Instance->NDTR == RX_BUF_SIZE)
{
rx_len = RX_BUF_SIZE;
rx_flag = 1;
}
else
{
rx_len = RX_BUF_SIZE - hdma_usart1_rx.Instance->NDTR;
}
}
}
int main(void)
{
HAL_Init();
UART_Init();
while (1)
{
if (rx_flag)
{
// 处理接收到的数据
rx_flag = 0;
}
}
}
```
在上面的例子中,我们使用了循环DMA传输模式,当接收到一定数量的数据后,将触发空闲中断,并在空闲中断中处理接收到的数据。同时,在DMA传输完成和空闲中断中,我们使用了两个不同的回调函数,分别处理DMA传输完成和空闲中断的事件。
阅读全文