stm32串口发送数据包进行解析,实现人机交互 您所在的位置:网站首页 人机如何交互 stm32串口发送数据包进行解析,实现人机交互

stm32串口发送数据包进行解析,实现人机交互

2024-07-14 22:44| 来源: 网络整理| 查看: 265

串口收发解析数据包

学过stm32的同学都知道,利用串口与32进行通讯非常的方便,在正点原子的官方历程中我们就可以看到,在串口中断服务函数里面,对接受的数据用一个十六位的数据来判断是否接受完成(即是否在数据包的末尾接收到0x0D,0x0A,他们分别对应的是\r \n),利用高位处理状态,低位则将数据包数量储存下来,

u16 USART_RX_STA

请添加图片描述

那么既然可以判断是否接受到了数据,那么我们是不是可以将数据进行拆分处理,进行储存,然后对程序中的一些变量进行赋值,然后实现人机交互的功能,通过串口;

例如说,我们发送 X90 Y90 Z90那么就会对后面的数据进行接受处理;

在这里我们发送的数据包主要分为2中类型:

HEX数据包:

用于原始数据的接受,比如陀螺仪,以及温度传感器;

请添加图片描述

文本数据包:

常见的使用场景有CNC,以及3D打印使用的G代码;

请添加图片描述

然后在处理的时候,相信你也看到,需要用到状态机的知识;进行逐层判别,

例如正点原子用的是定义一个变量:

u16 USART_RX_STA

当然我们也可以通过将一个变量置0,1,2,3,,等等来表示不同的状态;

数据包为例的话:

请添加图片描述 请添加图片描述

你可能会有一个疑问就是,为什么HEX的包头包尾设置为0xFF与0xFE,这是因为,如果在数据包中存在一样的数值,可能会导致接受混乱的时候,这两个数据是影响比较小的,毕竟接受的数据不可能一直为很大的值;或者说出现为0xFF与0xFE的可能性比较小;通过这样的设置就极大程度的减小了数据包紊乱的问题;

针对文本数据包就比较好表示了,这了用到的是 @ 这个用的不是很多的字符作为包头,然后 \n 回车为包尾;

这里以文本数据包为例,简要讨论一下实现所需要的步骤:

1,串口的中断处理函数,在接受到数据中断以后,根据之前提到的状态机的知识判断数据的有效性;然后储存到char类型的数组中;

2,清空空格这种多余符号,使数据紧凑

3,数据包大体分为两大类:比如说,类似于这个"LED_ON"与"G 91"这么两种数据,处理起来肯定是不一样的;这里他们分为a,b两种类型:

​ a:字符串类型的话,调用strcmp(A,B)//if ture return 0把接受数据与事先定义好的字符串进行比较,然后类似于蓝牙的编程方式一样,进入相应的 if 语句,执行相关操作;

​ b:CNC,G代码类型的:在数组中寻找特定字母,然后标记位置,最后取出该字母与下一个字母之间的数据;注意一点的是,这些数据是 char 类型的单个数字,需要转化为 int 类型以后乘以每一位相应的位权,得到数据;

字符串类型的数据包,控制LED的开关:

int main(void) { OLED_Init(); LED_Init(); Serial_Init(); OLED_ShowString(1, 1, "TxPacket"); OLED_ShowString(3, 1, "RxPacket"); while (1) { if (Serial_RxFlag == 1) { OLED_ShowString(4, 1, " "); OLED_ShowString(4, 1, Serial_RxPacket); if (strcmp(Serial_RxPacket, "LED_ON") == 0) { LED1_ON(); Serial_SendString("LED_ON_OK\r\n"); OLED_ShowString(2, 1, " "); OLED_ShowString(2, 1, "LED_ON_OK"); } else if (strcmp(Serial_RxPacket, "LED_OFF") == 0) { LED1_OFF(); Serial_SendString("LED_OFF_OK\r\n"); OLED_ShowString(2, 1, " "); OLED_ShowString(2, 1, "LED_OFF_OK"); } else { Serial_SendString("ERROR_COMMAND\r\n"); OLED_ShowString(2, 1, " "); OLED_ShowString(2, 1, "ERROR_COMMAND"); } Serial_RxFlag = 0; } } }

然后这里放几个我写过的函数,适用于G代码,和CNC代码解析;

串口中断处理函数:

void USART1_IRQHandler(void)//Êý¾Ý°üÒÔ@¿ªÍ·\0(»Ø³µ)½áβ { static uint8_t RxState = 0; static uint8_t pRxPacket = 0; if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET) { uint8_t RxData = USART_ReceiveData(USART1); if (RxState == 0) { if (RxData == '@' && Serial_RxFlag == 0)//ûÓÐÓöÁÈ¡±ê־λÁ¢¿ÌÇåÁãµÄº¯Êý£¬Ä¿µÄÊDZÜÃâÁ¬Ðø·¢Ë͵Äʱºò£¬±¾´ÎûÓд¦ÀíÍê¾Í¿ªÊ¼ÏÂÒ»´ÎÊý¾ÝµÄ´¦Àí£¬µ¼Ö½ÓÊÜ´íÎó { //Ö¤Ã÷ÉÏÒ»´Î½ÓÊÜÒѾ­ÔÚmainº¯ÊýÖд¦ÀíÍê±ÏÁË RxState = 1; pRxPacket = 0;//¾²Ì¬¾Ö²¿±äÁ¿£¬ËùÒÔÿ´Îµ÷ÓõÄʱºò£¬²»Ò»¶¨Îª0 } } else if (RxState == 1) { if (RxData == '\r') { RxState = 2; } else { Serial_RxPacket[pRxPacket] = RxData; pRxPacket ++; } } else if (RxState == 2) { if (RxData == '\n') { RxState = 0; Serial_RxPacket[pRxPacket] = '\0';//×¢ÒâCÓïÑÔµÄÊý×é½áβΪ\0 Serial_RxFlag = 1; //Êý¾Ý½ÓÊÜÍê³É£¬¿ÉÒÔ½øÈëmainº¯ÊýÖÐ } } USART_ClearITPendingBit(USART1, USART_IT_RXNE); } }

清除空格:

void clear_blank(char *a) { int i=0, j=0; for (i = 0; i a[j++] = a[i]; } else if(a[i]==' '){ continue; } } a[j] = '\0'; //ÔÚÊý×éµÄĩβÌí¼ÓÒ»¸ö'\0'//ÕâÀïºÍ֮ǰµÄÖжϴ¦Àíº¯Êý²»³åÍ»£¬ //Ò»¸öÊǽӽÓÊÕÍêÒÔºó¼Ó£¬Ò»¸öÊÇÈ¥³ý¿Õ°×¼Ó }

查找(搜索)特殊字符在数组中的位置:

int search_array( char *a, int n, char x ) { int i,x_Tab_dowm; int flag=-1; x_Tab_dowm=x+32;//ÒÑÖªÔÚASCLL´úÂëÖУ¬´óд×ÖĸºÍСд×ÖĸÏà²î32 for(i=0;i flag=1; break;//Ò»µ©¼ì²âµ½×ÖĸµÄ»°£¬¾Í²»ÐèÒª½øÐÐforÑ­»·ÁË£¬ËùÒÔÕâÀïÓÃbreakÀ´Ð´; } else if(a[i]==x_Tab_dowm) { flag=1; break; } } if(flag==1) return i; else return flag; }

读取特定字符后面的数据,然后转换成 int 类型:

int get_array_number( char *a, int start , int place)//Êý×éa,ÆðʼλÖÃ(×ÖĸXYZËùÔÚµÄλÖÃ),ÐèÒªÌáÈ¡Êý×ֵĴóС { int mi = 0, di = 0; int temp = 0, result = 0, real_place = 0, i = 0, j = 0;//ÉùÃ÷±äÁ¿ºóÒ»¶¨Òª¼°Ê±³õʼ»¯±äÁ¿ for (i = 0; i real_place++; }//´ÓÐèÒªÅжϵÄ×Öĸ¿ªÊ¼£¬µ½ÏÂÒ»¸ö×Öĸ½áÊø if ( ('A' break; } } for (j = 0; j if (Serial_RxFlag == 1) { clear_blank(Serial_RxPacket); x_place=search_array(Serial_RxPacket,Serial_RxPacket_Size,'X'); y_place=search_array(Serial_RxPacket,Serial_RxPacket_Size,'Y'); z_place=search_array(Serial_RxPacket,Serial_RxPacket_Size,'Z'); x_num = get_array_number(Serial_RxPacket, x_place, Serial_RxPacket_Size); y_num = get_array_number(Serial_RxPacket, y_place, Serial_RxPacket_Size); z_num = get_array_number(Serial_RxPacket, z_place, Serial_RxPacket_Size); Serial_RxFlag = 0; } }

主函数:

int main(void) { OLED_Init(); LED_Init(); Serial_Init(); // OLED_ShowString(1, 1, "TxPacket"); OLED_ShowString(1, 1, "RxPacket"); while (1) { Data_Handler(); OLED_ShowString(2, 1, "X_num:"); OLED_ShowString(3, 1, "Y_num:"); OLED_ShowString(4, 1, "Z_num:"); OLED_ShowNum(2,7,x_num,5); OLED_ShowNum(3,7,y_num,5); OLED_ShowNum(4,7,z_num,5); } }

Serial.h:

Serial.c:



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有