![]() |
發布時間: 2024-9-14 18:28
正文摘要:PC發送hex 5A A5 03 01 02 03;解析出03(數據包的長度),第一次解析正常,03改變后解析還是03, 哪位幫忙分析一下代碼出錯 void main(){ UartInit(); ... |
samxon 發表于 2024-9-18 17:16 感覺協議制定得不太合理,putCmd()應該能解決你的第3個難點。
putCmd()使用示范
簡化你之前的Uart_send_data()
|
samxon 發表于 2024-9-18 17:16 一個一個來搞,請各位幫忙把關代碼。如有更好優化,請賜教。 添加數據包長度代碼 void Join_Test_Parameter(unsigned char cmd,unsigned short var_add,unsigned short jdata){ unsigned char temp_buf[15],par_buf[16],i,par_buf_size,cnt=0; temp_buf[cnt++]= (Pack_Head&0xFF00)>>8; //0 temp_buf[cnt++]= Pack_Head&0xFF; //1 temp_buf[cnt++]= cmd; //2 temp_buf[cnt++]=(var_add&0xFF00)>>8; //3 temp_buf[cnt++]=var_add&0xFF; //4 temp_buf[cnt++]=(jdata&0xFF00)>>8; //5 temp_buf[cnt++]=jdata&0xFF; //6 for(i=0;i<10;i++){ if(i<2){ par_buf=temp_buf; }else if(i==2){ par_buf=cnt-3; //將長度直接添加到數組下標2的位置。 }else{ par_buf=temp_buf[i-1]; } } Send_Test_Parameter(par_buf,cnt+1); } |
謝謝你熱情給力的解析,還把代碼增加了注釋。非常感謝。希望占用您寶貴時間幫我看看下面的代碼。給點思路和辦法我。謝謝。 遇到的難點: 1) 如何把len這個長度字段插入到數據包的第3個字節。 2)由于有效數據部分是不確定的。可能有時是3個字節,也有可能是四個字節。如何把這些直接傳遞給Join_Test_Parameter函數來正確的產生一個數據包。 3)也許可用一個數組把想要的參數一次全部打包丟給Join_Test_Parameter這個函數處理吧。可是我不知道怎么實現。 謝謝大家,特別是謝謝這個ydatou友情幫忙 void Join_Test_Parameter(unsigned char len,unsigned char cmd,unsigned short var_add,unsigned short jdata){ unsigned char par_buf[15],cnt=0; par_buf[cnt++]= (Pack_Head&0xFF00)>>8; par_buf[cnt++]= Pack_Head&0xFF; par_buf[cnt++]=len; par_buf[cnt++]= cmd; par_buf[cnt++]=(var_add&0xFF00)>>8; par_buf[cnt++]=var_add&0xFF; par_buf[cnt++]=(jdata&0xFF00)>>8; par_buf[cnt++]=jdata&0xFF; Send_Test_Parameter(par_buf,cnt); } void Get_Test_Gear(){ if(REC_COMPLETED){ REC_COMPLETED=0; if(USART_RX_BUF[1]==0x31){ switch(USART_RX_BUF[2]){ case 0x00: TEST_GEAR=0; Join_Test_Parameter(0x05,WriteCmd,0x1200,0x61B); //寫入電壓 Join_Test_Parameter(0x05,WriteCmd,0x1250,0x145); //寫入電流 Join_Test_Parameter(0x05,WriteCmd,0x1300,0x1fb); //寫入功率 Join_Test_Parameter(0x07,WriteCmd,0x1350,0x34 0x35 0x57 0x00); //寫入測試標識 Join_Test_Parameter(0x08,WriteCmd,0x1400,0x50 0x41 0x53 0x53 0x00); //寫入測試結果(pass或fail) Join_Test_Parameter(0x05,WriteCmd,0x1653,0x0400); //改變字體顏色 Join_Test_Parameter(0x05,WriteCmd,0x1500,0x1455); //寫入最大值 Join_Test_Parameter(0x05,WriteCmd,0x1200,0x13F1); //寫入平均值 Join_Test_Parameter(0x05,WriteCmd,0x1200,0x1389); //寫入最小值 break; case 0x10: TEST_GEAR=1; ........ } } } |
|
samxon 發表于 2024-9-17 08:18 這段代碼不能在51下工作。 51的ram最多只有256字節,單Buf[300]都不夠。 51的臨時變量不是分配在堆棧上,函數一般不支持再入。一個函數假如在某個中斷中有調用,那么它就不適合在其它中斷中和非中斷中調用。 用指針傳遞更靈活方便,但占用ram資源多些。用全局變量傳遞,占用ram資源少,使用限制多。 |
感謝壇子高工,問題已經解決,增加else條件。 void Uart() interrupt 4 { static unsigned char ccnt,bufccnt,recd_temp[5]; if(RI && REC_COMPLETED==0){ RI=0; if(ccnt<3){ recd_temp[ccnt++]=SBUF; }else{ if(recd_temp[0]==0x5A && recd_temp[1]==0xA5){ DATA_LENGTH=recd_temp[2]; USART_RX_BUF[bufccnt++]=SBUF; if(bufccnt==DATA_LENGTH){ //5A A5 02 03 04 0>03,1;1>04,2 REC_COMPLETED=1; bufccnt=0; ccnt=0; ES=0; } }else{ ccnt=0; } } } if(TI){} } void Uart_send_data(){ static unsigned char m; if(REC_COMPLETED){ for(m=0;m<DATA_LENGTH;m++){ SBUF=USART_RX_BUF[m]; while(!TI); TI=0; } DATA_LENGTH=0; REC_COMPLETED=0; m=0; ES=1; } } |
ydatou 發表于 2024-9-16 15:35 能不等講一下,我看到很多都是用指針傳送接收數組uartx_Rx_buf的值。直接傳遞和用指針傳區別在哪里。直接傳程序看起來不是更好清晰嗎。謝謝解答。 void Encode_Receive(uint8_t bytedata) { static uint8_t step=0;//狀態變量初始化為0 在函數中必須為靜態變量 static uint8_t cnt=0,Buf[300],len,cmd,*data_ptr; static uint16_t crc16; //進行數據解析 狀態機 switch(step) { case 0://接收幀頭1狀態 if(bytedata== 0xAF) { step++; cnt = 0; Buf[cnt++] = bytedata; }break; case 1://接收幀頭2狀態 if(bytedata== 0xFA) { step++; Buf[cnt++] = bytedata; } else if(bytedata== 0XAF) { step = 1; } else { step = 0; } break; case 2://接收數據長度字節狀態 step++; Buf[cnt++] = bytedata; len = bytedata; break; case 3://接收命令字節狀態 step++; Buf[cnt++] = bytedata; cmd = bytedata; data_ptr = &Buf[cnt];//記錄數據指針首地址 if(len == 0)step++;//數據字節長度為0則跳過數據接收狀態 break; case 4://接收len字節數據狀態 Buf[cnt++] = bytedata; if(data_ptr + len == &Buf[cnt])//利用指針地址偏移判斷是否接收完len位數據 { step++; } break; case 5://接收crc16校驗高8位字節 step++; crc16 = bytedata; break; case 6://接收crc16校驗低8位字節 crc16 <<= 8; crc16 += bytedata; if(crc16 == CRC16_Check(Buf,cnt))//校驗正確進入下一狀態 { step ++; } else if(bytedata == 0xAF) { step = 1; } else { step = 0; } break; case 7://接收幀尾 if(bytedata== 0xFF)//幀尾接收正確 { Encode_Handle(cmd,data_ptr,len);//數據解析 step = 0; } else if(bytedata == 0xAF) { step = 1; } else { step = 0; } break; default:step=0;break;//多余狀態,正常情況下不可能出現 } } |
ydatou 發表于 2024-9-16 15:35 非常感謝,這個是狀態機的思想寫的代碼。當然最好。值得擁有。 |
samxon 發表于 2024-9-16 09:31 這段代碼還有問題。 1.串口是可以同時收發的。 if(RI && REC_COMPLETED==0)會使發送期間數據接收出錯。 2.錯誤檢查有漏洞。數據長度要做范圍檢查。 3.浪費了太多全局變量,51的ram資源又比較少。 請參考我的代碼。
|
感謝壇子高工,問題已經解決,增加else條件。 void Uart() interrupt 4 { static unsigned char ccnt,bufccnt,recd_temp[5]; if(RI && REC_COMPLETED==0){ RI=0; if(ccnt<3){ recd_temp[ccnt++]=SBUF; }else{ if(recd_temp[0]==0x5A && recd_temp[1]==0xA5){ DATA_LENGTH=recd_temp[2]; USART_RX_BUF[bufccnt++]=SBUF; if(bufccnt==DATA_LENGTH){ //5A A5 02 03 04 0>03,1;1>04,2 REC_COMPLETED=1; bufccnt=0; ccnt=0; ES=0; } }else{ ccnt=0; } } } if(TI){} } void Uart_send_data(){ static unsigned char m; if(REC_COMPLETED){ for(m=0;m<DATA_LENGTH;m++){ SBUF=USART_RX_BUF[m]; while(!TI); TI=0; } DATA_LENGTH=0; REC_COMPLETED=0; m=0; ES=1; } } |
發表于 2024-9-15 09:51 修正,情況依舊,可能還是數組上面的問題。但沒有排查的思路 |
if(bufccnt=DATA_LENGTH)這句是不是應該用兩個等于號== |