![]() |
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)这句是不是应该用两个等于号== |