找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 170|回复: 11
打印 上一主题 下一主题
收起左侧

51单片机串口收发代码排错

[复制链接]
跳转到指定楼层
楼主
ID:705846 发表于 2024-9-14 18:28 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式


PC发送hex  5A A5 03 01 02 03;解析出03(数据包的长度),第一次解析正常,03改变后解析还是03,
哪位帮忙分析一下代码出错


void main(){
        UartInit();
        EA=1;

while(1){Uart_send_data();};
}


void Uart() interrupt 4
{
        static unsigned char ccnt,bufccnt,sendccnt;      //接收计数
        if(RI && REC_COMPLETED==0){        
                        RI=0; //清除RI接收完成标记
                if(ccnt<3){
                                RECD_TEMP[ccnt++]=SBUF;
                                
                }else{                                       
                                        if(RECD_TEMP[0]==0x5A && RECD_TEMP[1]==0xA5){
                                //ccnt=3
                                                DATA_LENGTH= RECD_TEMP[2];
                                                USART_RX_BUF[bufccnt++]=SBUF;
                                                
                                                if(bufccnt=DATA_LENGTH){
                                                        REC_COMPLETED=1;               
                                                        bufccnt=0;
                                                        ES=0;
                                                }else{
                                                        REC_COMPLETED=0;
                                                }
                                        }else{
                                                ES=1;
                                                ccnt=0;
                                                REC_COMPLETED=0;
                                                }        
                                }         
                        }
}
void Uart_send_data(){
    //        static unsignged char sendccnt;
        if(REC_COMPLETED){
        //                ES=0;
        //                for(sendccnt=0;sendccnt<DATA_LENGTH;sendccnt++)
      //                {
                                SBUF= DATA_LENGTH; //一次只能发送8位
                                while(!TI);
                                TI = 0;                
//                        }        
                        REC_COMPLETED=0;
                        DATA_LENGTH=0;
        //                sendccnt=0;        
                        ES=1;
        }
}


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:878061 发表于 2024-9-15 09:51 | 只看该作者
if(bufccnt=DATA_LENGTH)这句是不是应该用两个等于号==
回复

使用道具 举报

板凳
ID:705846 发表于 2024-9-15 12:20 | 只看该作者
发表于 2024-9-15 09:51
if(bufccnt=DATA_LENGTH)这句是不是应该用两个等于号==

修正,情况依旧,可能还是数组上面的问题。但没有排查的思路
回复

使用道具 举报

地板
ID:705846 发表于 2024-9-15 15:17 | 只看该作者

冷启动,发两次后收到正确的一次,之后再也收不到了。继续排错中.........

void Uart() interrupt 4
{
        static unsigned char ccnt,bufccnt;
        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){
                                                REC_COMPLETED=1;
                                                bufccnt=0;
                                                ccnt=0;
                                                ES=0;
                                        }else{
                                                REC_COMPLETED=0;
                                        }                       
                        }       
                }
        }       
        if(TI){
        //TI=0;
        }
}
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;
                }
                REC_COMPLETED=0;
                DATA_LENGTH=0;
                m=0;
                ES=1;
        }
}




回复

使用道具 举报

5#
ID:705846 发表于 2024-9-16 09:31 | 只看该作者


感谢坛子高工,问题已经解决,增加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;
        }
}

回复

使用道具 举报

6#
ID:1073939 发表于 2024-9-16 15:35 | 只看该作者
samxon 发表于 2024-9-16 09:31
感谢坛子高工,问题已经解决,增加else条件。
void Uart() interrupt 4
{

这段代码还有问题。
1.串口是可以同时收发的。 if(RI && REC_COMPLETED==0)会使发送期间数据接收出错。
2.错误检查有漏洞。数据长度要做范围检查。
3.浪费了太多全局变量,51的ram资源又比较少。

请参考我的代码。
  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. }
复制代码
回复

使用道具 举报

7#
ID:705846 发表于 2024-9-16 22:17 来自手机 | 只看该作者
ydatou 发表于 2024-9-16 15:35
这段代码还有问题。
1.串口是可以同时收发的。 if(RI && REC_COMPLETED==0)会使发送期间数据接收出错。
...

非常感谢,这个是状态机的思想写的代码。当然最好。值得拥有。
回复

使用道具 举报

8#
ID:705846 发表于 2024-9-17 08:18 来自手机 | 只看该作者
ydatou 发表于 2024-9-16 15:35
这段代码还有问题。
1.串口是可以同时收发的。 if(RI && REC_COMPLETED==0)会使发送期间数据接收出错。
...

能不等讲一下,我看到很多都是用指针传送接收数组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;//多余状态,正常情况下不可能出现
        }
}
回复

使用道具 举报

9#
ID:287147 发表于 2024-9-17 23:18 | 只看该作者



感谢坛子高工,问题已经解决,增加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;
        }
}
回复

使用道具 举报

10#
ID:1073939 发表于 2024-9-18 11:08 | 只看该作者
samxon 发表于 2024-9-17 08:18
能不等讲一下,我看到很多都是用指针传送接收数组uartx_Rx_buf的值。直接传递和用指针传区别在哪里。直接 ...

这段代码不能在51下工作。
51的ram最多只有256字节,单Buf[300]都不够。
51的临时变量不是分配在堆栈上,函数一般不支持再入。一个函数假如在某个中断中有调用,那么它就不适合在其它中断中和非中断中调用。
用指针传递更灵活方便,但占用ram资源多些。用全局变量传递,占用ram资源少,使用限制多。
回复

使用道具 举报

11#
ID:1073939 发表于 2024-9-18 12:00 | 只看该作者
  1. /*
  2. 和楼主代码比优点如下:
  3. 占用ram资源少。
  4. 可连续多帧处理,不会掉帧。
  5. 多帧之间掺杂其他数据,不会掉帧。
  6. */
  7. #define MAX_LENGTH 32//最大数据长度
  8. idata unsigned char USART_RX_BUF[MAX_LENGTH];//xdata
  9. unsigned char DATA_LENGTH;//当前数据长度,只有REC_COMPLETED为1时才有效
  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)//连续多个5A也能正常接收,不掉帧。
  29.                                 ccnt = 0;
  30.                 }
  31.                 else if (ccnt == 2)
  32.                 {
  33.                         if (d > 0 && d <= MAX_LENGTH)//数据长度检查,防止溢出。
  34.                         {
  35.                                 DATA_LENGTH = d;
  36.                                 ccnt = 3;
  37.                         }
  38.                         else if (d == 0x5A)//连续多个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个字符时间)处理使REC_COMPLETED = 0
  54.                                         //9600波特率下,2个字符时间约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. }
复制代码
回复

使用道具 举报

12#
ID:705846 发表于 2024-9-18 17:16 | 只看该作者

谢谢你热情给力的解析,还把代码增加了注释。非常感谢。希望占用您宝贵时间帮我看看下面的代码。给点思路和办法我。谢谢。

遇到的难点:
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;
                ........
                }
        }
}

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表