最近在寫一個通過手控器控制設備動作的程序,手控器按鍵較多,所以通過串口來和外設設備進行通信,由于命令較多,所以做了個小協議以后也能用到,可做主機可做從機,適合近距離單機通訊,第二位功能碼可做地址組成多機通訊,但最好加上校驗位。新手入門,大佬請多多指教
附上代碼
- //自定義串口發送協議 例: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標志位
- }
- }
復制代碼
|