STM32CubeMx+HAL库:USART串口收发数据的三种方式

上篇我们讲解了利用HAL库串口中断模式收发数据的教程,包括STM32CubeMx中串口的配置等,不清楚的小伙伴可以跳转链接学习查看。

STM32CubeMx+HAL库实现串口中断收发数据(STM32F103RCT6)新手小白必看的保姆级教程icon-default.png?t=N7T8https://blog.csdn.net/weixin_54015326/article/details/135683705?spm=1001.2014.3001.5501


串口收发数据的三种方式,分别是:阻塞模式(也叫轮询)、中断模式、DMA模式,以下是HAL库中串口发送和接收数据时所调用的函数。

汇总:

1.阻塞模式收发数据

        HAL_UART_Transmit():串口发送数据,使用超时管理机制
        HAL_UART_Receive(): 串口接收数据,使用超时管理机制

2.中断模式收发数据
        HAL_UART_Transmit_IT():串口中断模式发送
        HAL_UART_Receive_IT(): 串口中断模式接收

3.DMA模式收发数据
        HAL_UART_Transmit_DMA():串口DMA模式发送
        HAL_UART_Transmit_DMA():串口DMA模式接收

1.阻塞模式 

1.1 阻塞模式发送函数

HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);

该函数的作用是将数据通过UART发送到外部设备或其他设备。

参数说明:

  • huart: UART句柄,表示要使用的UART外设。
  • pData: 要发送的数据的指针,即数据的起始地址。
  • Size: 要发送的数据的大小,以字节为单位。用sizeof()函数获取发送缓冲区的长度
  • Timeout: 发送的超时时间,单位为毫秒。如果在指定的时间内发送完成,则函数返回 HAL_OK;否则,返回 HAL_TIMEOUT如果设置为HAL_MAX_DELAY,处理器就会一直等到数据发送完成再执行下一条语句。

1.2 阻塞模式接收函数

HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);

它的作用是从UART接收数据,并将接收到的数据存储到指定的缓冲区中。

参数说明:

  第一个参数是要使用的串口句柄地址
  第二个参数是要接收的数据缓冲区首地址
  第三个参数是接收的数据长度,这里可以直接用sizeof()函数获取接收缓冲区的长度
  第四个参数是超时时间,单位是ms,如果超过设置的时间,则函数返回HAL_TIMEOUT,如果设置为HAL_MAX_DELAY,处理器就会一直等到数据发送完成再执行下一条语句。

1.3 STM32CubeMX配置

 第一步:选择SYS的Debug-Serial Wire,开启SWD调试;

第二步: 时钟配置,选择RCC的 HSE -> Crystal/Ceramic Resonator(外部晶振)

紧接着配置时钟树  ?  ?  ?  ? 

 

第三步:配置USART,设置参数

配置完成,生成初始化代码(Project和Code Generator里的配置请参考之前那篇串口中断的贴子,熟悉之后就可以直接嘎嘎点)

1.4 代码编写

测试阻塞模式发送函数

在main.c里,定义一个发送数组缓冲区TxBuf数组;

在while(1)循环里添加阻塞发送函数和1s的延时,实现效果是每隔1s串口发送一次TxBuf数组里的“Hello World!!我爱单片机!!”在串口助手上显示

HAL_Delay(1000);
HAL_UART_Transmit(&huart1, TxBuf, sizeof(TxBuf), 100);

最终串口助手会显示: 

测试阻塞模式接收函数

首先定义一个接收缓冲区数组RXBuf[4],1个16进制数是4bit,两个16进制数是1byte(8bit),设置的缓冲区类型是uint8_t(8bit),数组大小是4字节,所以要发送8个16进制数正好填满缓冲区。

注意:接收缓冲区长度可以大于要接收数据的长度,但是不能小于要接收的数据长度。

while循环里添加如下代码: 

//从RxBuf接收缓冲区中接收数据,如果在1秒内没有接收完数据,函数将返回超时错误,接收完返回HAL_OK
if(HAL_UART_Receive(&huart1, RxBuf, sizeof(RxBuf), 1000) == HAL_OK)
{   // 如果成功接收到数据
    // 将接收到的数据原样发送回UART1,如果在1秒内没有发送完数据,函数将返回超时错误。
    HAL_UART_Transmit(&huart1, RxBuf, sizeof(RxBuf), 1000);
}

串口助手显示:

HEX模式是十六进制模式,当我们用电脑以HEX模式给单片机USART口发数据时,发的是十六进制,单片机接收的也是十六进制; 

注意:串口助手要打开HEX发送和HEX接收 

2.中断模式

2.1 中断模式发送函数

HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

参数说明:中断方式的收发函数只有三个参数
      第一个参数是要使用的串口句柄地址
      第二个参数是发送缓冲区的首地址,用于存放要发送的数据
      第三个参数是发送缓冲区长度

2.2 中断模式接收函数

HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

参数说明与发送函数类似,只是把第二个和第三个参数变为了接收缓冲区

        中断模式的前三个参数和阻塞方式完全一致,只是没有了超时时间管理,因为中断(IT)方式配置完成寄存器之后不需要再占用CPU,会在接收/发送数据完成后触发中断,因此不需要超时时间管理机制。

2.3 STM32CubeMX配置

在之间的基础上再选择 NVIC Settings,勾选Enable,再次生成代码

 2.4 代码编写

在开始的时候我们需要先启动一次异步接收 HAL_UART_Receive_IT();  

 之后添加串口回调函数,当串口接收到sizeof(RxBuf)大小的数据时,会产生串口接收中断,然后进入到中断服务函数中,执行对应的串口接收回调函数里面的代码。

 这段代码的意思是:判断串口是否为串口1,如果是的话,串口发送ACKBuf数组里面的数据,显示在串口助手的界面上

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart == &huart1)    // 判断串口号是否为 huart1
    {
        // 发送 ACKBuf 的缓冲区的数据到 UART1,使用中断模式发送
        HAL_UART_Transmit_IT(&huart1, ACKBuf, sizeof(ACKBuf));
    }
    // 重新启动 UART1 的中断接收,将接收到的数据存放到 RxBuf 的缓冲区中
    HAL_UART_Receive_IT(&huart1, RxBuf, sizeof(RxBuf));
}

 串口显示:

3.DMA模式

3.1 什么是DMA

DMA(Direct Memory Access,直接内存访问)是一种计算机系统中用于数据传输的机制。它允许数据在外设和内存之间直接传输,而不需要CPU的介入,从而减轻了CPU的负担,提高了数据传输的效率。

举个栗子:

        想象一下我们搬家的场景:你要把家里的一些东西从旧房子搬到新房子。在传统的情况下,你可能要亲自搬每一箱东西,把它们从旧房子搬到新房子。这就相当于CPU传统地处理数据传输的方式。

        现在,有一支搬家队,他们专门负责搬家。你只需要告诉他们从哪里搬,搬到哪里,然后他们就会自己完成这项任务。而你可以利用这段时间去做其他事情,不需要亲自动手。这就有点类似于DMA的工作原理。

        在计算机中,CPU通常会处理数据的传输工作,就像你亲自搬家一样。但有了DMA,就好比有了一支专门负责数据传输的队伍。CPU只需要告诉DMA从哪里搬,搬到哪里,然后就可以去处理其他任务了。DMA负责在外设和内存之间直接传输数据,而不需要CPU一直参与。

简而言之,DMA就像是一支搬家队伍,负责在不需要CPU亲自操劳的情况下完成数据传输任务,从而提高了系统的效率。

3.2 DMA模式发送函数

HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

参数类型和中断模式发送函数相同

3.3 DMA模式接收函数

HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

参数类型和中断模式接收函数相同 

3.4 STM32CubeMX配置

3.5 代码编写 

// 串口收到数据的回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    // 判断触发回调的 UART 句柄是否为 huart1
    if(huart == &huart1)    // 如果串口是 UART1
    {        
        // 使用 DMA 模式将 RxBuf 的缓冲区的数据原样发送回 UART1
        HAL_UART_Transmit_DMA(&huart1, RxBuf, sizeof(RxBuf));
    }
    // 使用 DMA 模式重新启动 UART1 的接收,将接收到的数据存放到 RxBuf 缓冲区中
    HAL_UART_Receive_DMA(&huart1, RxBuf, sizeof(RxBuf));
}

 串口显示:

完结!!!撒花!!      *,°*:.☆( ̄▽ ̄)/$:*.°*  


本篇完。

本人博客仅代表个人见解方便记录成长笔记。

若有不足,请指出,感谢您的阅读!