首页>>科技 >>内容

嵌入式串口调试连接,嵌入式开发之UART串口通信解析

发布时间:2023-10-14 17:37:13编辑:温柔的背包来源:

嵌入式串口调试连接,嵌入式开发之UART串口通信解析

很多朋友对嵌入式串口调试连接,嵌入式开发之UART串口通信解析不是很了解,每日小编刚好整理了这方面的知识,今天就来带大家一探究竟。

UART串口是嵌入式开发中常见的通信方式,但是很多人还不知道串口如何使用。

今天我们重点关注串口,简单分享一下几点:

串口接收方式

处理接收到的数据

通信协议分析

串口接收方式

从串口(通信的另一端)接收数据的常见方式是:

轮询(查询)接收寄存器

中断接收数据

轮询是指按照一定的时间间隔(通常是ms,甚至us)检查接收寄存器中是否有数据。如果有数据,则处理接收到的数据。

中断,当没有收到数据时,CPU做自己的事情。当接收到数据时,UART串口控制器会响应中断,通知CPU有事情要做。

您有没有想过轮询方式的缺点?

效率低:CPU大部分时间都在做查询工作;

响应不实时:如果短时间内有多个接收到的数据,CPU正在处理一件比较耗时的事情(例如:发送数据包),没有时间去查询接收到的数据数据。此时,数据可能会丢失。 (特别是早些年串口还没有FIFO功能)

因此,无论是UART串口,还是I2C、SPI、CAN等串行通信,最常用的是中断接收,很少使用轮询。

我曾经维护旧代码(一个陷阱)。 CLI串口采用轮询模式。出现了很多数据丢失、溢出错误等问题,让我加班了几个小时。

处理接收到的数据

中断数据来了,如何处理接收到的数据?

我见过一些小项目,有些应用是直接在中断函数中完成的。例如:串口中断接收来自传感器的数据,显示数据并执行一些响应动作。

对于中断函数来说,代码可以尽可能小,耗时也可以尽可能小,不能处理太多耗时且复杂的逻辑、应用程序等。

数据到来时的中断通常通过FIFO 进行处理。

1.简单的数组接收、应用解析和处理

例如:

static uint8_t gRxCnt=0;static uint8_t gRxBuf[10];void USART1_IRQHandler(void){ //. gDgus_RxBuf[gRxCnt]=(uint8_t)USART_ReceiveData(USART1); gRxCnt++; //. }void App(void) { //. if(0 gRxCnt) { //复制接收到的数据gRxCnt=0; //解析接收到的数据并进行处理}} 2、中断函数接收到完整的一帧数据,然后进行处理

例如:

无效USART1_IRQHandler(void){ 静态uint8_t RxCnt=0; //计数值static uint8_t RxNum=0; //数量if((USART1-SR USART_FLAG_RXNE)==USART_FLAG_RXNE) { gDgus_RxBuf[RxCnt]=(uint8_t)USART_ReceiveData(USART1) ; RxCnt++; if(gDgus_RxBuf[0] !=DGUS_FRAME_HEAD1) //接收到帧头1 { RxCnt=0;返回; } if((2==RxCnt) (gDgus_RxBuf[1] !=DGUS_FRAME_HEAD2)) { RxCnt=0;返回; } if(RxCnt==3) { RxNum=gDgus_RxBuf[2] + 3; } if(( 6=RxCnt) (RxNum=RxCnt)) { RxCnt=0; OSMboxPost(EventMBox_Touch, gDgus_RxBuf); //发送消息邮箱(执行触摸操作) } }}中断函数解析完一帧数据后,可以通过标志位通知应用程序(裸机),也可以通过消息队列发送给应用程序,邮箱等(RTOS)。

3. RTOS队列和邮箱接收

例如:

void DEBUG_COM_IRQHandler(void){ 静态uint8_t 数据; if(USART_GetITStatus(DEBUG_COM, USART_IT_RXNE) !=RESET) { Data=USART_ReceiveData(DEBUG_COM);CLI_RcvDateFromISR(Data);//下面将这个函数分开}}void CLI_RcvDateFromISR(uint8_t RcvData){ static portBASE_TYPE xHigherPriorityTaskWoken=pdFALSE; if(xCLIRcvQueue !=NULL) { xQueueSendFromISR(xCLIRcvQueue, RcvData, xHigherPriorityTaskWoken); }}如果一字节数据被中断,则通过消息队列发送一字节数据。如果没有及时发出,数据也会存储在队列中。

通信协议分析

像上面的第二种,简单的通讯协议,当项目比较小时,可以直接在中断函数中处理。

但如果项目比较大、比较复杂,协议也比较复杂,那么在函数内部就不建议使用上面的第二种方法了。

1. 裸机环境

裸机情况下,建议使用第一种方法:中断数组缓存数据(FIFO),应用解析通信协议。

2.RTOS环境

对于RTOS的情况,建议使用第三种方式:消息队列、邮箱等接收数据,然后发送(通知)应用解析协议。

当然,以上只是常用的方法,具体方法需要结合自己项目的实际情况。

同时,其他通信如I2C、CAN如果有协议分析也是类似的。

比如我在使用CAN之前就实现了我跟大家分享的MavLink:

无效CAN_RX_IRQHandler(void){ 静态CanRxMsg RxMessage;静态MAVRCV_QUEUE_TypeDef MAVRcvQueue_Union; CAN_Receive(CAN1, CAN_FIFO0, RxMessage); //复制长度、数据MAVRcvQueue_Union.MAVRcvStruct.MAVLink_Len=RxMessage.DLC; memcpy(MAVRcvQueue_Union.MAVRcvStruct.MAVLink_Buf[0],RxMessage.Data[0],RxMessage.DLC); MAVLink_RcvDateFromISR(MAVRcvQueue_Union.MAVLinkRcv_Queue[0]);} 最后,以上内容仅提供思路,代码可能并不适合项目。

黄飞

以上知识分享希望能够帮助到大家!