找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索

51單片機(jī)串口收發(fā)代碼排錯(cuò)

查看數(shù): 1191 | 評(píng)論數(shù): 14 | 收藏 1
關(guān)燈 | 提示:支持鍵盤翻頁(yè)<-左 右->
    組圖打開中,請(qǐng)稍候......
發(fā)布時(shí)間: 2024-9-14 18:28

正文摘要:

PC發(fā)送hex  5A A5 03 01 02 03;解析出03(數(shù)據(jù)包的長(zhǎng)度),第一次解析正常,03改變后解析還是03, 哪位幫忙分析一下代碼出錯(cuò) void main(){         UartInit(); ...

回復(fù)

ID:1073939 發(fā)表于 2024-9-19 10:01
samxon 發(fā)表于 2024-9-18 17:16
謝謝你熱情給力的解析,還把代碼增加了注釋。非常感謝。希望占用您寶貴時(shí)間幫我看看下面的代碼。給點(diǎn)思路 ...

感覺協(xié)議制定得不太合理,putCmd()應(yīng)該能解決你的第3個(gè)難點(diǎn)。
  1. char putchar(char c) // 發(fā)1個(gè)
  2. {
  3.         while (!TI)
  4.                 ; // 注意uart初始化時(shí)要TI = 1;
  5.         TI = 0;
  6.         SBUF = c;
  7.         return c;
  8. }
  9. void putBuff(unsigned char *buf, unsigned char len) // 發(fā)多個(gè)
  10. {
  11.         while (len--)
  12.                 putchar(*buf++);
  13. }
  14. /*
  15. */
  16. void putCmd(unsigned char cmd, unsigned short var_add, const unsigned char *dat, unsigned char len)
  17. {
  18.         putchar(Pack_Head >> 8);
  19.         putchar(Pack_Head);
  20.         putchar(len + 3);
  21.         putchar(cmd);
  22.         putchar(var_add >> 8);
  23.         putchar(var_add);
  24.         putBuff(dat, len);
  25. }
復(fù)制代碼


putCmd()使用示范
  1. #define CMD_1_ADD 0x1200
  2. #define CMD_2_ADD 0x1350
  3. #define CMD_3_ADD 0x1400
  4. code unsigned char CMD_1[] = {0x06, 0x1b};                                         // 寫入電壓
  5. code unsigned char CMD_2[] = {0x34, 0x35, 0x57, 0x00};                 // 寫入測(cè)試標(biāo)識(shí)
  6. code unsigned char CMD_3[] = {0x50, 0x41, 0x53, 0x53, 0x00}; // 寫入測(cè)試結(jié)果(pass或fail)
  7. void putCmd_demo()
  8. {
  9.         putCmd(WriteCmd, CMD_1_ADD, CMD_1, sizeof(CMD_1));
  10.         putCmd(WriteCmd, CMD_2_ADD, CMD_2, sizeof(CMD_2));
  11.         putCmd(WriteCmd, CMD_3_ADD, CMD_3, sizeof(CMD_3));
  12.         putCmd(WriteCmd, 1234, "1234567890", sizeof("1234567890")-1);
  13. }
復(fù)制代碼


簡(jiǎn)化你之前的Uart_send_data()
  1. void Uart_send_data()
  2. {
  3.         // unsigned char m;
  4.         if (REC_COMPLETED)
  5.         {
  6.                 REC_COMPLETED = 0;
  7.                 putBuff(USART_RX_BUF, DATA_LENGTH);
  8.                 // for (m = 0; m < DATA_LENGTH; m++)
  9.                 // {
  10.                 //         SBUF = USART_RX_BUF[m];
  11.                 //         while (!TI)
  12.                 //                 ;
  13.                 //         TI = 0;
  14.                 // }
  15.         }
  16. }
復(fù)制代碼



ID:705846 發(fā)表于 2024-9-19 09:41
samxon 發(fā)表于 2024-9-18 17:16
謝謝你熱情給力的解析,還把代碼增加了注釋。非常感謝。希望占用您寶貴時(shí)間幫我看看下面的代碼。給點(diǎn)思路 ...

一個(gè)一個(gè)來(lái)搞,請(qǐng)各位幫忙把關(guān)代碼。如有更好優(yōu)化,請(qǐng)賜教。
添加數(shù)據(jù)包長(zhǎng)度代碼
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; //將長(zhǎng)度直接添加到數(shù)組下標(biāo)2的位置。
                }else{
                        par_buf=temp_buf[i-1];
                }       
        }
        Send_Test_Parameter(par_buf,cnt+1);
}
ID:705846 發(fā)表于 2024-9-18 17:16

謝謝你熱情給力的解析,還把代碼增加了注釋。非常感謝。希望占用您寶貴時(shí)間幫我看看下面的代碼。給點(diǎn)思路和辦法我。謝謝。

遇到的難點(diǎn):
1) 如何把len這個(gè)長(zhǎng)度字段插入到數(shù)據(jù)包的第3個(gè)字節(jié)。
2)由于有效數(shù)據(jù)部分是不確定的?赡苡袝r(shí)是3個(gè)字節(jié),也有可能是四個(gè)字節(jié)。如何把這些直接傳遞給Join_Test_Parameter函數(shù)來(lái)正確的產(chǎn)生一個(gè)數(shù)據(jù)包。
3)也許可用一個(gè)數(shù)組把想要的參數(shù)一次全部打包丟給Join_Test_Parameter這個(gè)函數(shù)處理吧?墒俏也恢涝趺磳(shí)現(xiàn)。
謝謝大家,特別是謝謝這個(gè)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); //寫入測(cè)試標(biāo)識(shí)
                Join_Test_Parameter(0x08,WriteCmd,0x1400,0x50 0x41 0x53 0x53 0x00);        //寫入測(cè)試結(jié)果(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;
                ........
                }
        }
}

ID:1073939 發(fā)表于 2024-9-18 12:00
  1. /*
  2. 和樓主代碼比優(yōu)點(diǎn)如下:
  3. 占用ram資源少。
  4. 可連續(xù)多幀處理,不會(huì)掉幀。
  5. 多幀之間摻雜其他數(shù)據(jù),不會(huì)掉幀。
  6. */
  7. #define MAX_LENGTH 32//最大數(shù)據(jù)長(zhǎng)度
  8. idata unsigned char USART_RX_BUF[MAX_LENGTH];//xdata
  9. unsigned char DATA_LENGTH;//當(dāng)前數(shù)據(jù)長(zhǎng)度,只有REC_COMPLETED為1時(shí)才有效
  10. bit REC_COMPLETED;

  11. void Uart() interrupt 4
  12. {
  13.         unsigned char d;
  14.         static unsigned char ccnt = 0;
  15.         if (RI)
  16.         {
  17.                 RI = 0;
  18.                 d = SBUF;

  19.                 if (ccnt == 0)
  20.                 {
  21.                         if (d == 0x5A)
  22.                                 ccnt = 1;
  23.                 }
  24.                 else if (ccnt == 1)
  25.                 {
  26.                         if (d == 0xA5)
  27.                                 ccnt = 2;
  28.                         else if (d != 0x5A)//連續(xù)多個(gè)5A也能正常接收,不掉幀。
  29.                                 ccnt = 0;
  30.                 }
  31.                 else if (ccnt == 2)
  32.                 {
  33.                         if (d > 0 && d <= MAX_LENGTH)//數(shù)據(jù)長(zhǎng)度檢查,防止溢出。
  34.                         {
  35.                                 DATA_LENGTH = d;
  36.                                 ccnt = 3;
  37.                         }
  38.                         else if (d == 0x5A)//連續(xù)多個(gè)5A也能正常接收,不掉幀。
  39.                                 ccnt = 1;
  40.                         else
  41.                                 ccnt = 0;
  42.                 }
  43.                 else
  44.                 {
  45.                         unsigned char i = ccnt - 3;
  46.                         if (i < MAX_LENGTH)
  47.                         {
  48.                                 USART_RX_BUF[i] = d;
  49.                                 ccnt++;
  50.                                 if (i == DATA_LENGTH - 1)
  51.                                 {
  52.                                         REC_COMPLETED = 1;
  53.                                         //要盡快(<=2個(gè)字符時(shí)間)處理使REC_COMPLETED = 0
  54.                                         //9600波特率下,2個(gè)字符時(shí)間約2ms。
  55.                                         ccnt = 0;
  56.                                 }
  57.                         }
  58.                         else
  59.                                 ccnt = 0;
  60.                 }
  61.         }
  62.         if (TI)
  63.         {
  64.                 // TI=0;
  65.         }
  66. }
  67. void Uart_send_data()
  68. {
  69.         unsigned char m;
  70.         if (REC_COMPLETED)
  71.         {
  72.                 REC_COMPLETED = 0;
  73.                 for (m = 0; m < DATA_LENGTH; m++)
  74.                 {
  75.                         SBUF = USART_RX_BUF[m];
  76.                         while (!TI)
  77.                                 ;
  78.                         TI = 0;
  79.                 }
  80.         }
  81. }
復(fù)制代碼
ID:1073939 發(fā)表于 2024-9-18 11:08
samxon 發(fā)表于 2024-9-17 08:18
能不等講一下,我看到很多都是用指針傳送接收數(shù)組uartx_Rx_buf的值。直接傳遞和用指針傳區(qū)別在哪里。直接 ...

這段代碼不能在51下工作。
51的ram最多只有256字節(jié),單Buf[300]都不夠。
51的臨時(shí)變量不是分配在堆棧上,函數(shù)一般不支持再入。一個(gè)函數(shù)假如在某個(gè)中斷中有調(diào)用,那么它就不適合在其它中斷中和非中斷中調(diào)用。
用指針傳遞更靈活方便,但占用ram資源多些。用全局變量傳遞,占用ram資源少,使用限制多。
ID:287147 發(fā)表于 2024-9-17 23:18



感謝壇子高工,問題已經(jīng)解決,增加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;
        }
}
ID:705846 發(fā)表于 2024-9-17 08:18
ydatou 發(fā)表于 2024-9-16 15:35
這段代碼還有問題。
1.串口是可以同時(shí)收發(fā)的。 if(RI && REC_COMPLETED==0)會(huì)使發(fā)送期間數(shù)據(jù)接收出錯(cuò)。
...

能不等講一下,我看到很多都是用指針傳送接收數(shù)組uartx_Rx_buf的值。直接傳遞和用指針傳區(qū)別在哪里。直接傳程序看起來(lái)不是更好清晰嗎。謝謝解答。

void Encode_Receive(uint8_t bytedata)
{
        static uint8_t step=0;//狀態(tài)變量初始化為0 在函數(shù)中必須為靜態(tài)變量
        static uint8_t cnt=0,Buf[300],len,cmd,*data_ptr;
        static uint16_t crc16;
        //進(jìn)行數(shù)據(jù)解析 狀態(tài)機(jī)
        switch(step)
        {
            case 0://接收幀頭1狀態(tài)
                if(bytedata== 0xAF)
                {
                    step++;
                    cnt = 0;
                    Buf[cnt++] = bytedata;
                }break;
            case 1://接收幀頭2狀態(tài)
                if(bytedata== 0xFA)
                {
                    step++;
                    Buf[cnt++] = bytedata;
                }
                else if(bytedata== 0XAF)
                {
                    step = 1;
                }
                else
                {
                    step = 0;
                }
                break;
            case 2://接收數(shù)據(jù)長(zhǎng)度字節(jié)狀態(tài)
                step++;
                Buf[cnt++] = bytedata;
                len = bytedata;
                break;
            case 3://接收命令字節(jié)狀態(tài)
                step++;
                Buf[cnt++] = bytedata;
                cmd = bytedata;
                data_ptr = &Buf[cnt];//記錄數(shù)據(jù)指針首地址
                if(len == 0)step++;//數(shù)據(jù)字節(jié)長(zhǎng)度為0則跳過(guò)數(shù)據(jù)接收狀態(tài)
                break;
            case 4://接收l(shuí)en字節(jié)數(shù)據(jù)狀態(tài)
                Buf[cnt++] = bytedata;
                if(data_ptr + len == &Buf[cnt])//利用指針地址偏移判斷是否接收完len位數(shù)據(jù)
                {
                    step++;
                }
                break;
            case 5://接收crc16校驗(yàn)高8位字節(jié)
                step++;
                crc16 = bytedata;
                break;
            case 6://接收crc16校驗(yàn)低8位字節(jié)
                crc16 <<= 8;
                crc16 += bytedata;
                if(crc16 == CRC16_Check(Buf,cnt))//校驗(yàn)正確進(jìn)入下一狀態(tài)
                {
                    step ++;
                }
                else if(bytedata == 0xAF)
                {
                    step = 1;
                }
                else
                {
                    step = 0;
                }
                break;
            case 7://接收幀尾
                if(bytedata== 0xFF)//幀尾接收正確
                {
                        Encode_Handle(cmd,data_ptr,len);//數(shù)據(jù)解析
                    step = 0;
                }
                else if(bytedata == 0xAF)
                {
                    step = 1;
                }
                else
                {
                    step = 0;
                }
                break;
            default:step=0;break;//多余狀態(tài),正常情況下不可能出現(xiàn)
        }
}
ID:705846 發(fā)表于 2024-9-16 22:17
ydatou 發(fā)表于 2024-9-16 15:35
這段代碼還有問題。
1.串口是可以同時(shí)收發(fā)的。 if(RI && REC_COMPLETED==0)會(huì)使發(fā)送期間數(shù)據(jù)接收出錯(cuò)。
...

非常感謝,這個(gè)是狀態(tài)機(jī)的思想寫的代碼。當(dāng)然最好。值得擁有。
ID:1073939 發(fā)表于 2024-9-16 15:35
samxon 發(fā)表于 2024-9-16 09:31
感謝壇子高工,問題已經(jīng)解決,增加else條件。
void Uart() interrupt 4
{

這段代碼還有問題。
1.串口是可以同時(shí)收發(fā)的。 if(RI && REC_COMPLETED==0)會(huì)使發(fā)送期間數(shù)據(jù)接收出錯(cuò)。
2.錯(cuò)誤檢查有漏洞。數(shù)據(jù)長(zhǎng)度要做范圍檢查。
3.浪費(fèi)了太多全局變量,51的ram資源又比較少。

請(qǐng)參考我的代碼。
  1. #define MAX_LENGTH 32
  2. unsigned char USART_RX_BUF[MAX_LENGTH];
  3. unsigned char DATA_LENGTH;
  4. bit REC_COMPLETED;

  5. void Uart() interrupt 4
  6. {
  7.         unsigned char d;
  8.         static unsigned char ccnt=0;
  9.         if (RI)
  10.         {
  11.                 RI = 0;
  12.                 d = SBUF;

  13.                 if (ccnt==0){
  14.                         if(d==0x5A)
  15.                                 ccnt=1;
  16.                 }
  17.                 else if (ccnt==1){
  18.                         if(d==0xA5)
  19.                                 ccnt=2;
  20.                         else
  21.                                 ccnt=0;
  22.                 }
  23.                 else if (ccnt==2){
  24.                         if(d>0 && d<=MAX_LENGTH){
  25.                                 DATA_LENGTH=d;
  26.                                 ccnt=3;
  27.                         }
  28.                         else
  29.                                 ccnt=0;
  30.                 }
  31.                 else {
  32.                         unsigned char i=ccnt-3;
  33.                         if(i<MAX_LENGTH){
  34.                                 USART_RX_BUF[i] = d;
  35.                                 ccnt++;
  36.                                 if(i==DATA_LENGTH-1) {
  37.                                         REC_COMPLETED = 1;
  38.                                         ccnt=0;
  39.                                 }
  40.                         }
  41.                         else
  42.                                 ccnt=0;
  43.                 }
  44.         }
  45.         if (TI)
  46.         {
  47.                 // TI=0;
  48.         }
  49. }
  50. void Uart_send_data()
  51. {
  52.         unsigned char m;
  53.         if (REC_COMPLETED)
  54.         {
  55.                 REC_COMPLETED = 0;
  56.                 for (m = 0; m < DATA_LENGTH; m++)
  57.                 {
  58.                         SBUF = USART_RX_BUF[m];
  59.                         while (!TI)
  60.                                 ;
  61.                         TI = 0;
  62.                 }
  63.         }
  64. }
復(fù)制代碼
ID:705846 發(fā)表于 2024-9-16 09:31


感謝壇子高工,問題已經(jīng)解決,增加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;
        }
}

ID:705846 發(fā)表于 2024-9-15 12:20
發(fā)表于 2024-9-15 09:51
if(bufccnt=DATA_LENGTH)這句是不是應(yīng)該用兩個(gè)等于號(hào)==

修正,情況依舊,可能還是數(shù)組上面的問題。但沒有排查的思路
ID:878061 發(fā)表于 2024-9-15 09:51
if(bufccnt=DATA_LENGTH)這句是不是應(yīng)該用兩個(gè)等于號(hào)==

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表