最近在写一个通过手控器控制设备动作的程序,手控器按键较多,所以通过串口来和外设设备进行通信,由于命令较多,所以做了个小协议以后也能用到,可做主机可做从机,适合近距离单机通讯,第二位功能码可做地址组成多机通讯,但最好加上校验位。新手入门,大佬请多多指教
附上代码
- //自定义串口发送协议 例: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[i] == PACKET_HEADER) {
- expectingHeader = 0; // 找到了包头,开始解析数据包
- packetIndex = 0; // 重置数据包索引
- }
- // 如果不是包头,则忽略该字节或进行错误处理
- } else {
- switch (packetIndex) {
- case 0: // 功能码
- function = rxBuffer[i];
- break;
- case 1: // 数据1
- data1 = rxBuffer[i];
- break;
- case 2: // 数据2
- data2 = rxBuffer[i];
-
- // 检查包尾
- 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标志位
- }
- }
复制代码
|