串口非阻塞式收发数据的重要性
提升系统响应效率
非阻塞模式允许程序在等待串口数据时继续执行其他任务,避免因长时间等待导致系统卡顿。这种方式特别适合需要同时处理多任务的场景,如嵌入式系统中的实时数据采集与用户交互并行处理。
避免资源浪费
在阻塞模式下,线程会持续占用CPU资源等待数据到达,而非阻塞模式下通过轮询或事件驱动机制(如中断)释放CPU资源,减少无意义的空转,提高整体资源利用率。
增强实时性
非阻塞操作结合超时机制可快速响应多个串口或外设事件。例如,工业控制系统中需同时监控多个传感器数据,非阻塞模式能确保每个数据通道的及时处理,避免因单个通道阻塞导致整体延迟。
简化错误处理
非阻塞读取可通过返回值(如EAGAIN或EWOULDBLOCK)立即判断数据是否就绪,而非等待超时。这种机制使得程序能更灵活地处理异常,如数据丢失或通信中断。
适应低速设备
低速串口设备(如GPS模块)数据传输间隔较长,非阻塞模式允许在此期间执行其他高优先级任务(如界面刷新或网络通信),优化系统吞吐量。
配置CubeMX

第一步:配置下载器接口

第二步:配置外部高速晶振

第三步:修改主频为72MHZ

第四步:打开串口USART1,注意波特率为115200

第五步:配置串口中断(global interrupt:全局中断)

第六步:打开DMA,默认参数即可,后面我们会用到使用DMA来进行定长数据的收发。(DMA是一种不用CPU进行介入就能把数据传输完成的一种工具(属于一种接口),后期我还会对DMA进行单独的介绍,现在小伙伴们知道DMA就是一种高效的传输数据的接口就OK了!)

使用中断实现非阻塞试收发数据
首先我们来介绍串口中断接收函数:
HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
各参数详细解释:第一个参数是句柄,第二个参数是接收到的数据(是一个指针类型的变量),第三个参数则是每次接收的字节长度(1字节 = 1byte)
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
这个是串口接收中断回调函数,这个函数具体什么时候被调用呢???(当开启了串口中断后,当串口数据接收完毕,就会触发一次这个串口回调函数,串口回调函数)。
举个例子:单片机接收到电脑给单片机发送一个数据‘a',然后当单片机接收完这个数据’a'后,就会触发串口接收回调函数(前提是开启了串口中断)。

该串口中断是一个带有__weak的定义的函数,所以他可以被重新定义!!!!!!!!!详细小伙伴可以去网上搜搜关于__weak这个函数的定义

上图:我们需要先开启接收中断,当开启后,只要单片机发现有数据需要接收的时候,就会从其他任务中跳出,来进行数据的接收,这样相当于当没有数据的时候,单片机也不用一直等待数据的到来了,极大的提高了单片机的运行效率。

上图:则是我们前面介绍的串口接收回调函数(好好体会为什么这个函数名字加以理解为什么要这个名字????)。为什么要加if判断???(如果不加if判断,加入我们开启了串口1中断和串口2中断,我们如何判断进入中断的到底是哪个串口的中断呢?所以我们用每个串口句柄的不同来判断具体是哪个串口的操作!!!!!(为什么要取地址?因为huart定义就是个指针变量,huart就是一个地址而不是一个值,要*huart才是去huart所在地址的值!!!!))。
到此我们已经实现了非阻塞试的串口收发,但小伙伴们有没有发现,这样的串口收发,依然还是固定长度的数据收发,那我们该如何进行不定长数据的收发呢?无论我们发送什么长度的值,单片机都会返回相应的值。
不定长数据收发
首先我们先来认识两个函数:
HAL_UARTEx_ReceiveToIdle_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
这个函数叫做DMA空闲中断接收函数,当单片机使用DMA传输数据完成时候就会触发下面这个弱定义函数(__weak),前文已经对weak做了简单的解释。
__weak void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)

在uart.h文件中加入extern UART——HandleTypeDef huart1;如果不加在main函数中则会找不到DMA接收的句柄从而导致报错!!!

上图:代码表示开启接收空闲DMA,关闭DMA的过半中断(可能是因为开启接收空闲DMA同时把过半中断也打开了,所以我们需要关闭他,不然当DMA传输数据到一半的时候就会触发中断导致数据接收异常!!!!)

上图:使用UARTEx(串口扩展库里的函数,接收事件中断回调函数),当接收完数据后,我们该函数会计算出相应的Size。这样就达到了实现定长数据收发的目的!!!!!
注意:当每次发送完后,都必须重新开启接收!!!(如果接收函数在while循环里那就不用管,因为接收函数不在while循环里,所以我们在接收完触发中断,要再次的开启!!!!(别忘记关闭DMA过半中断))
还有就是图中的Data数组大小可以给大一些比如Data[100];
299

被折叠的 条评论
为什么被折叠?



