上篇我们讲解了利用HAL库串口中断模式收发数据的教程,包括STM32CubeMx中串口的配置等,不清楚的小伙伴可以跳转链接学习查看。
STM32CubeMx+HAL库实现串口中断收发数据(STM32F103RCT6)新手小白必看的保姆级教程https://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模式接收
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,处理器就会一直等到数据发送完成再执行下一条语句。
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,处理器就会一直等到数据发送完成再执行下一条语句。
第一步:选择SYS的Debug-Serial Wire,开启SWD调试;
第二步: 时钟配置,选择RCC的 HSE -> Crystal/Ceramic Resonator(外部晶振)
紧接着配置时钟树 ⬇ ⬇ ⬇ ⬇
第三步:配置USART,设置参数
配置完成,生成初始化代码(Project和Code Generator里的配置请参考之前那篇串口中断的贴子,熟悉之后就可以直接嘎嘎点)
在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模式给单片机发送数据时,发的是十六进制,单片机接收的也是十六进制;
注意:串口助手要打开HEX发送和HEX接收
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
这个函数的目的是启动UART传输并以非阻塞的方式发送一定数量的数据。
参数说明:中断方式的收发函数只有三个参数
第一个参数是要使用的串口句柄地址
第二个参数是发送缓冲区的首地址,用于存放要发送的数据
第三个参数是发送缓冲区长度
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
参数说明与发送函数类似,只是把第二个和第三个参数变为了接收缓冲区
中断模式的前三个参数和阻塞方式完全一致,只是没有了超时时间管理,因为中断(IT)方式配置完成寄存器之后不需要再占用CPU,会在接收/发送数据完成后触发中断,因此不需要超时时间管理机制。
在之间的基础上再选择 NVIC Settings,勾选Enable,再次生成代码
在开始的时候我们需要先启动一次异步接收 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));
}
串口显示:
DMA(Direct Memory Access,直接内存访问)是一种计算机系统中用于数据传输的机制。它允许数据在外设和内存之间直接传输,而不需要CPU的介入,从而减轻了CPU的负担,提高了数据传输的效率。
举个栗子:
想象一下我们搬家的场景:你要把家里的一些东西从旧房子搬到新房子。在传统的情况下,你可能要亲自搬每一箱东西,把它们从旧房子搬到新房子。这就相当于CPU传统地处理数据传输的方式。
现在,有一支搬家队,他们专门负责搬家。你只需要告诉他们从哪里搬,搬到哪里,然后他们就会自己完成这项任务。而你可以利用这段时间去做其他事情,不需要亲自动手。这就有点类似于DMA的工作原理。
在计算机中,CPU通常会处理数据的传输工作,就像你亲自搬家一样。但有了DMA,就好比有了一支专门负责数据传输的队伍。CPU只需要告诉DMA从哪里搬,搬到哪里,然后就可以去处理其他任务了。DMA负责在外设和内存之间直接传输数据,而不需要CPU一直参与。
简而言之,DMA就像是一支搬家队伍,负责在不需要CPU亲自操劳的情况下完成数据传输任务,从而提高了系统的效率。
HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
参数类型和中断模式发送函数相同
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
参数类型和中断模式接收函数相同
使用DMA时必须开启中断!!
优先级选择:
DMA配置:
同理也要先开启一次DMA接收;
// 串口收到数据的回调函数
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));
}
串口显示:
串口助手接收区显示的数据,就是通过 HAL_UART_Transmit、HAL_UART_Transmit_IT、HAL_UART_Transmit_DMA这三个之一的发送函数,把发送缓冲区数组里的数据发送到外面。
发送区用户输入的数据,通过接收函数,存到接收缓冲区数组中,以便与发送函数发送。
中断模式和DMA(normal)模式下接收数据,都需要在初始化时开启一次中断/DMA接收,并且在接收回调函数中重启一次中断/DMA接收,才能实现循环发送。
以上就是初步探索HAL库实现串口接收和发送的三种方式,继续进步!!
完结!!!撒花!! *★,°*:.☆( ̄▽ ̄)/$:*.°★*
本篇完。
本人博客仅代表个人见解方便记录成长笔记。
若有不足,请指出,感谢您的阅读!