目录
2、DMA的配置(放在 HAL_UART_MspInit 中)
一、串口接收不定长数据的实现思路
在串口通信中,我们很多时候是需要接收不定长的数据,并且对接收到数据放入到缓存中,等待接下来的处理。
整一个流程大致如下:
实现方法:
- 串口 空闲中断;
- DMA接收数据:(循环模式、不使用中断)
1、可以得知已经的数据长度: BuffSize - DMA.Instanc->NDTR 【进而可以通过两次数据长度相减,得到本次传输的数据长度】
2、数据处理:可以将接收到的数据从DMA缓存中存入到自定义的 队列缓存 中(队列结构体),后续要处理的时候再从队列中出队进行处理
二、具体实现代码
首先,大家可以先参考官方库的USART DMA的例程,里面演示了USART DMA的最基本的使用方法
1、USART 的配置
void vUart1Init(void)
{
ex_Uart1Handle.Instance = USART1;
ex_Uart1Handle.Init.BaudRate = UART1_BAUNDRATE;
ex_Uart1Handle.Init.WordLength = UART_WORDLENGTH_8B;
ex_Uart1Handle.Init.StopBits = UART_STOPBITS_1;
ex_Uart1Handle.Init.Parity = UART_PARITY_NONE;
ex_Uart1Handle.Init.Mode = UART_MODE_TX_RX;
ex_Uart1Handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
ex_Uart1Handle.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&ex_Uart1Handle);
/* 请在下方添加开启中断 以及 DMA 等操作 */
__HAL_USART_ENABLE_IT(&ex_Uart1Handle, USART_IT_IDLE);
HAL_NVIC_SetPriority(USART1_IRQn, 6, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
}
2、DMA的配置(放在 HAL_UART_MspInit 中)
注意:
- DMA 需要配置为 DMA_CIRCULAR(若是 DMA_Normal的情况的话将DMA的缓存写满后,将不再写入;DMA_CIRCULAR则是从头覆盖新的数据)
- 需要通过 HAL_DMA_Start 来开启DMA传输
- SET_BIT(USART1->CR3, USART_CR3_DMAR) 使能USART的接收或者发送DMA
void HAL_UART_MspInit(UART_HandleTypeDef *uartHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(uartHandle->Instance == USART1)
{
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = UART1_PIN_TX | UART1_PIN_RX;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
HAL_GPIO_Init(UART1_PORT, &GPIO_InitStruct);
/* 下面添加对DMA初始化、链接DMA等内容 */
__HAL_RCC_DMA2_CLK_ENABLE();
ex_Uart1DMATxHandle.Instance = DMA2_Stream7;
ex_Uart1DMATxHandle.Init.Channel = DMA_CHANNEL_4;
ex_Uart1DMATxHandle.Init.Direction = DMA_MEMORY_TO_PERIPH;
ex_Uart1DMATxHandle.Init.PeriphInc = DMA_PINC_DISABLE;
ex_Uart1DMATxHandle.Init.MemInc = DMA_MINC_ENABLE;
ex_Uart1DMATxHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
ex_Uart1DMATxHandle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
ex_Uart1DMATxHandle.Init.Mode = DMA_CIRCULAR;
ex_Uart1DMATxHandle.Init.Priority = DMA_PRIORITY_LOW;
ex_Uart1DMATxHandle.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
ex_Uart1DMATxHandle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
ex_Uart1DMATxHandle.Init.MemBurst = DMA_MBURST_INC4;
ex_Uart1DMATxHandle.Init.PeriphBurst = DMA_PBURST_INC4;
HAL_DMA_Init(&ex_Uart1DMATxHandle);
/* Associate the initialized DMA handle to the UART handle */
__HAL_LINKDMA(uartHandle, hdmatx, ex_Uart1DMATxHandle);
/* Configure the DMA handler for reception process */
ex_Uart1DMARxHandle.Instance = DMA2_Stream5;
ex_Uart1DMARxHandle.Init.Channel = DMA_CHANNEL_4;
ex_Uart1DMARxHandle.Init.Direction = DMA_PERIPH_TO_MEMORY;
ex_Uart1DMARxHandle.Init.PeriphInc = DMA_PINC_DISABLE;
ex_Uart1DMARxHandle.Init.MemInc = DMA_MINC_ENABLE;
ex_Uart1DMARxHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
ex_Uart1DMARxHandle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
ex_Uart1DMARxHandle.Init.Mode = DMA_CIRCULAR;
ex_Uart1DMARxHandle.Init.Priority = DMA_PRIORITY_HIGH;
ex_Uart1DMARxHandle.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
ex_Uart1DMARxHandle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
ex_Uart1DMARxHandle.Init.MemBurst = DMA_MBURST_INC4;
ex_Uart1DMARxHandle.Init.PeriphBurst = DMA_PBURST_INC4;
HAL_DMA_Init(&ex_Uart1DMARxHandle);
/* Associate the initialized DMA handle to the the UART handle */
__HAL_LINKDMA(uartHandle, hdmarx, ex_Uart1DMARxHandle);
HAL_DMA_Start(&ex_Uart1DMARxHandle, (uint32_t)(&(USART1->DR)), (uint32_t)ucUart1RxBuffer, USART1_RX_LENGTH);
SET_BIT(USART1->CR3, USART_CR3_DMAR);
}
}
3、USART 中断处理函数
void USART1_IRQHandler(void)
{
static uint16_t usLengthOld = 0, usLengthNew = 0;
uint16_t usDataLength = 0;
/* 本次数据长度获取 */
if(usLengthOld < (usLengthNew = (USART1_RX_LENGTH - ex_Uart1DMARxHandle.Instance->NDTR)))
{
usDataLength = usLengthNew - usLengthOld;
/* 数据处理 */
}
else
{
usDataLength = USART1_RX_LENGTH - usLengthOld + usLengthNew;
/* 数据处理 */
}
usLengthOld = usLengthNew;
__HAL_UART_CLEAR_IDLEFLAG(&ex_Uart1Handle);
}