找回密码
 立即注册
查看: 621|回复: 1

分享个自己写的自定义串口协议

[复制链接]
  • 打卡等级:以坛为家I
  • 打卡总天数:204
  • 最近打卡:2025-04-02 13:56:58

19

主题

37

回帖

236

积分

中级会员

积分
236
发表于 2024-6-13 08:36:50 | 显示全部楼层 |阅读模式
最近在写一个通过手控器控制设备动作的程序,手控器按键较多,所以通过串口来和外设设备进行通信,由于命令较多,所以做了个小协议以后也能用到,可做主机可做从机,适合近距离单机通讯,第二位功能码可做地址组成多机通讯,但最好加上校验位。新手入门,大佬请多多指教
附上代码
  • //自定义串口发送协议 例:68 01 00 03 FF ,除去包头包尾,中间为 功能码,数据1,数据2
  • // 发送数据包函数  功能码,第一位数据,第二位数据
  • void SendDataPacket(uint8_t function, uint8_t data1, uint8_t data2) {
  •     // 发送包头
  •     USART1_SendData(PACKET_HEADER);
  •     // 发送功能码
  •     USART1_SendData(function);
  •     // 发送数据1和数据2
  •     USART1_SendData(data1);
  •     USART1_SendData(data2);
  •     // 发送包尾
  •     USART1_SendData(PACKET_TAILER);
  • }
  • void Anlsy_Data(uint8_t function, uint8_t data1, uint8_t data2)//所有按键接收解析在这里写
  • {
  •     if(function == KEY_STAUS)
  •     {
  •         SysChenyuan.mark = QX_MARK;
  •     switch(data2)
  •         {
  •         case KEY1:
  •             SysChenyuan.Uart_Comd = QX1;
  •             printf("清洗1按键按下,data2 = %02d,function = %02d", data2, function);
  •             break;
  •         case KEY2:
  •                         SysChenyuan.Uart_Comd = QX2;
  •             printf("清洗2按键按下,data2 = %02d,function = %02d", data2, function);
  •             break;
  •         case KEY3:
  •                         SysChenyuan.Uart_Comd = QX3;
  •             printf("清洗3按键按下,data2 = %02d,function = %02d", data2, function);
  •             break;
  •                 case KEY_STOP:
  •                         SysChenyuan.all_stopped = YES;//停止标志
  •             printf("停止按键按下,data2 = %02d,function = %02d", data2, function);
  •             break;
  •                 case KEY_CHONGSHUI:
  •                         SysChenyuan.QiTa = CHONGSHUI;//冲水标志
  •             printf("冲水按键按下,data2 = %02d,function = %02d", data2, function);
  •             break;
  •                 case KEY_HONGGAN:
  •                         SysChenyuan.QiTa = HONGGAN;//烘干标志
  •             printf("烘干按键按下,data2 = %02d,function = %02d", data2, function);
  •             break;
  •         default:
  •             // 处理未知按键情况
  •             break;
  •     }
  •     }
  • }
  • extern uint8_t Serial_Rx3Flag,time_out3,time_out3_flag;
  • // 解析数据包的函数
  • int ParseDataPacket(void) {
  •     static uint8_t expectingHeader = 1; // 标记是否正在等待包头
  •     static uint8_t packetIndex = 0, i = 0; // 当前数据包内的索引
  •     uint8_t function, data1, data2;
  •         if(Serial_Rx3Flag == 1)
  •         {
  •             time_out3 = 0;
  •             time_out3_flag = 0;
  •             // 遍历缓冲区中的所有数据(在实际情况中,你可能只处理新接收到的数据)
  •             for ( i = 0; i < rxIndex; ++i) {
  •                     if (expectingHeader) {
  •                             if (rxBuffer == PACKET_HEADER) {
  •                                     expectingHeader = 0; // 找到了包头,开始解析数据包
  •                                     packetIndex = 0; // 重置数据包索引
  •                             }
  •                             // 如果不是包头,则忽略该字节或进行错误处理
  •                     } else {
  •                             switch (packetIndex) {
  •                                     case 0: // 功能码
  •                                             function = rxBuffer;
  •                                             break;
  •                                     case 1: // 数据1
  •                                             data1 = rxBuffer;
  •                                             break;
  •                                     case 2: // 数据2
  •                                             data2 = rxBuffer;
  •                                             // 检查包尾
  •                                             if (rxBuffer[i+1] == PACKET_TAILER) {
  •                                                     // 完整的数据包已接收,可以处理数据
  •                                                 Anlsy_Data(function, data1, data2);
  •                                                     // processPacket(function, data1, data2);
  •                                                     // 重置状态以接收下一个数据包
  •                                                     expectingHeader = 1;
  •                                                     packetIndex = 0;
  •                                                     rxIndex = 0; // 清除缓冲区(或者只清除已处理的部分)
  •                                             } else {
  •                                                     // 没有找到包尾,可能是数据损坏或丢失,进行错误处理
  •                                                     // TODO: 错误处理代码
  •                                                     expectingHeader = 1; // 重置状态以接收下一个数据包
  •                                                     packetIndex = 0;
  •                                             }
  •                                             break;
  •                                     default:
  •                                             // 无效的数据包索引,进行错误处理
  •                                             expectingHeader = 1; // 重置状态以接收下一个数据包
  •                                             packetIndex = 0;
  •                                             break;
  •                             }
  •                             if (packetIndex < 3) { // 还未到达包尾,递增索引
  •                                     packetIndex++;
  •                             }
  •                     }
  •             }
  •             rxIndex = 0;// 清除已处理的数据(如果rxIndex不是自动管理的)
  •             Serial_Rx3Flag = 0;
  •     }
  •     return 0; // 返回值可以根据需要来定义,例如表示是否成功解析了一个数据包
  • }
  • //下面是串口超时代码,我放在了10ms定时器里,看需要。
  • // 定时器回调函数 10ms
  • void vTimerCallback( TimerHandle_t xTimer )
  • {
  •     if(time_out3 < 10 && time_out3_flag == 1) {
  •             time_out3++;
  •     }
  •     // 检查是否超时
  •     if(time_out3 >= 10) {
  •         time_out3 = 0;
  •         time_out3_flag = 0;
  •             // 执行超时处理,例如发送确认信息或者进行数据处理
  •         Serial_Rx3Flag = 1;
  •     }
  • }
  • //串口中断
  • void USART1_IRQHandler(void)
  • {
  •     if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET)   //RXNE 标志位为1 表示可以接收数据
  •     {
  •         uint8_t ucReceivedChar;
  •          // 读取接收到的字符
  •         ucReceivedChar = USART_ReceiveData(USART1);
  •                 if (rxIndex < RX_BUFFER_SIZE) {
  •                     rxBuffer[rxIndex++] = ucReceivedChar;
  •                     time_out3 = 0;
  •                     time_out3_flag = 1;
  •                 }
  • //                if(Serial_Rx3Flag == 1)
  • //                {
  • //                    rxIndex  = 0;
  • //                }
  •         USART_ClearITPendingBit(USART1,USART_IT_RXNE);  //清除RXNE标志位
  •     }
  • }


回复

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:55
  • 最近打卡:2025-05-02 08:32:59

718

主题

1万

回帖

1万

积分

管理员

积分
15630
发表于 2024-6-13 08:42:15 | 显示全部楼层
回复 支持 反对

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-2 20:21 , Processed in 0.274748 second(s), 54 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表