STM32实用应用系列:串口接收不定长数据(HAL库 UART + DMA)

目录

一、串口接收不定长数据的实现思路

二、具体实现代码

1、USART 的配置

2、DMA的配置(放在 HAL_UART_MspInit 中)

3、USART 中断处理函数


一、串口接收不定长数据的实现思路

在串口通信中,我们很多时候是需要接收不定长的数据,并且对接收到数据放入到缓存中,等待接下来的处理。

整一个流程大致如下:

实现方法:

  • 串口 空闲中断;
  • 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);
}

 

利用STM32 HAL库实现串口DMA发送和不定数据接收的方法如下: 1. 串口DMA发送: 首先,需要初始化串口和DMA相关的参数。通过HAL_UART_Init()函数初始化串口,设置波特率、数据位、停止位等参数。然后使用HAL_UART_Transmit_DMA()函数启动DMA发送,将发送数据缓冲区的指针和数据度传入该函数。 2. 不定数据接收: 在接收数据时,我们可以使用DMA模式配合中断来实现不定度的数据接收。首先,需要初始化串口和DMA相关的参数,与串口DMA发送相同。然后,使用HAL_UART_Receive_DMA()函数启动DMA接收,将接收数据存放到接收缓冲区中。 在接收数据的过程中,可以通过中断方式来判断数据是否接收完成。在中断处理函数中,可以读取接收数据缓冲区的数据,并根据接收到的数据进行处理。在处理完数据之后,可以继续启动DMA接收,以进行下一次的数据接收。 需要注意的是,在中断处理函数中,需要判断DMA接收是否完成,可以通过检查DMA接收状态寄存器的标志位来判断。如果DMA接收完成,则可以执行相应的操作,比如解析接收到的数据。 总结: 利用STM32 HAL库,可以方便地实现串口DMA发送和不定数据接收。通过初始化相关参数,并启动串口DMA发送和接收,可以实现高效的数据传输。在中断处理函数中,可以对接收到的数据进行处理,并根据需要继续启动DMA接收。这种方法适用于需要在接收端实时处理不定度的数据的场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不吃鱼的猫丿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值