STM32基于HAL库使用串口+DMA 不定长接收数据 学习记录

我这些博客都只是记录一下自己学习的内容,以及记录一些思考过的问题和疑惑的东西


这里的代码借鉴了一位博主的博客

地址:[]


这里cubemx串口基础配置部分参考这一篇博客
(只配置了串口中断接收和printf重定向)

这一篇博客我们需要开启串口DMA接收

首先先说说DMA是什么

DMA(Direct Memory Access)直接内存访问,是一种允许硬件子系统在不经过中央处理单元(CPU)的直接控制下,独立于CPU自行访问系统内存的技术。使用DMA,数据可以更高效地在内存和硬件之间传输,大大减轻了CPU的负担。

DMA主要用于处理大量的数据传输。在没有DMA的情况下,数据传输需要CPU介入,CPU必须从源读取数据,然后将其写入到目标位置,这个过程消耗了大量的CPU资源。DMA通过允许外设直接读写内存,使CPU能够在数据传输过程中执行其他任务或进入低功耗模式,从而提高了系统的效率。

为什么要使用串口DMA接收

 

串口通信经常涉及到连续的数据流传输。在没有使用DMA的情况下,CPU需要不断地检查接收缓冲区是否有数据,然后读取数据,或者检查发送缓冲区是否空闲,然后发送数据。这种方式称为轮询(Polling),它会占用大量的CPU资源,尤其是在高速率数据传输或大量数据传输的情况下。

使用DMA进行串口通信时,CPU初始化DMA传输后便可以执行其他任务,直到整批数据传输完成后,DMA控制器会通过中断通知CPU。这样,大大提高了CPU的使用效率,也提高了数据传输的速率。

什么情况下使用DMA更好
 

在以下几种情况下使用DMA进行串口通信通常会更好:

高速数据传输:当有大量数据需要快速传输时,DMA可以节省大量CPU资源。

多任务系统:在需要同时执行多个任务的系统中,使用DMA可以让CPU更好地管理和执行其他任务,提高系统的整体效率。

实时系统:对于需要快速响应的实时系统,使用DMA能够确保数据传输的同时,CPU可以及时处理其他更加紧急的任务。

举个栗子

假设您正在开发一个涉及图像处理的嵌入式系统,该系统需要通过串口接收来自外部相机模块的大量图像数据。如果不使用DMA,CPU需要不断地从串口接收缓冲区读取数据,并将其存储到内存中,这将极大地降低处理图像算法的效率。通过使用DMA,数据直接从串口传输到指定的内存区域,无需CPU参与数据的具体传输过程,CPU就可以专注于处理图像数据,提高了数据处理效率和系统响应速度。


打开cubemx,在之前配置串口中断接收重定向后


然后生成代码
这里我以使用多个串口为例(USART1 和 USART3)

usart.h中
 

/* USER CODE BEGIN Prototypes */

#define RX_BUFFER_SIZE 256

typedef struct {
    uint8_t RxBuffer[RX_BUFFER_SIZE];
    uint8_t RxData;
    uint16_t RxDataCnt;
}UART_RxTypeDef;

extern UART_RxTypeDef Uart1Rx;   // 为UART1声明外部结构体变量
extern UART_RxTypeDef Uart3Rx;   // 为UART3声明外部结构体变量

/* USER CODE END Prototypes */

usart.c中
 

/* USER CODE BEGIN 0 */

UART_RxTypeDef Uart1Rx = {{0}, 0, 0};  // 为UART1初始化结构体
UART_RxTypeDef Uart3Rx = {{0}, 0, 0};  // 为UART3初始化结构体
// 重定向c库函数printf到huart1
int fputc(int ch, FILE *f) {
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
    return ch;
}
int fgetc(FILE *f)
{
  uint8_t ch = 0;
  HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
  return ch;
}
/* USER CODE END 0 */

main.h中
 

/* USER CODE BEGIN Includes */
	
#include <stdio.h>
#include <string.h>

#include "usart.h"
/* USER CODE END Includes */

usart.c末尾处
 

/* USER CODE BEGIN 1 */

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	
    if (huart->Instance == USART1)
    {
        Uart1Rx.RxDataCnt = RX_BUFFER_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
		if(Uart1Rx.RxBuffer[Uart1Rx.RxDataCnt - 2] == '\r' && Uart1Rx.RxBuffer[Uart1Rx.RxDataCnt - 1] == '\n')
		{

			HAL_UART_Transmit(&huart1, Uart1Rx.RxBuffer, Uart1Rx.RxDataCnt,0xFFFF);
		}
    }
	
	if (huart->Instance == USART3)
    {
        Uart3Rx.RxDataCnt = RX_BUFFER_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart3_rx);
		if(Uart3Rx.RxBuffer[Uart3Rx.RxDataCnt - 2] == '\r' && Uart3Rx.RxBuffer[Uart3Rx.RxDataCnt - 1] == '\n')
		{
			
			HAL_UART_Transmit(&huart3, Uart3Rx.RxBuffer, Uart3Rx.RxDataCnt,0xFFFF);
		}
    }
}


/* USER CODE END 1 */

main.c 串口初始化后添加
 

HAL_UARTEx_ReceiveToIdle_DMA(&huart1,Uart1Rx.RxBuffer,RX_BUFFER_SIZE);
HAL_UARTEx_ReceiveToIdle_DMA(&huart3,Uart3Rx.RxBuffer,RX_BUFFER_SIZE);

在stm32f1xx_it.c中 

串口中断函数
usart1
添加
 

  /* USER CODE BEGIN USART1_IRQn 1 */
HAL_UARTEx_ReceiveToIdle_DMA(&huart1,Uart1Rx.RxBuffer,RX_BUFFER_SIZE);

  /* USER CODE END USART1_IRQn 1 */

usart3

添加

  /* USER CODE BEGIN USART3_IRQn 1 */
HAL_UARTEx_ReceiveToIdle_DMA(&huart3,Uart3Rx.RxBuffer,RX_BUFFER_SIZE);
  /* USER CODE END USART3_IRQn 1 */

如果还有其他的串口步骤与上面一致添加或者减少

烧录代码后测试成功:


实现接收不定长数据

利用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
发出的红包

打赏作者

送外卖的CV工程师

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

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

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

打赏作者

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

抵扣说明:

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

余额充值