微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > MCU和单片机设计讨论 > 单片机通讯程序问题

单片机通讯程序问题

时间:10-02 整理:3721RD 点击:
最近做一个单片机的通讯程序,问题很怪!求解!
1.晶振采用12MHZ,初始化为4800的波特率,有大概0.16%误差!
2.接收采用中断接收,发送采用查询方式,放在主程序里面。
3.如果没有中断,则发送A代码,接受数据正确返回B代码,接受错误返回C代码,分别置有标志位。
4.另外还有一个定时器中断作为显示输出。
5.主程序中增加了I2C的读写程序。
目前的现象为:
在程序测试的时候,有接近一半的几率返回的数据不对,如果没有通讯中断的时候,所有返回的数据是正确的。一旦通讯中断,会返回错误的数据(错误的数据一般由A数据的一部分和B(或者C)数据的一部分组成。)如果将数据发送频率加快以后,所有数据又会恢复正常。如果硬件重新上电,则又会错误?
调试完成后DATA 115. 用的stc90C51.  A,B,C发送代码放在一个数组里面。
求解!

错误发生了以后,采用原有的代码单独测试了通讯的接收和发送程序,不会出现错误!
但是一旦加入了其它的读写程序,则会出现问题。
是否程序占用空间太大了的原因,数据存储读取不正常了?

那肯定是读写操作出错了,可能是读写时序不对

“定时器中断作为显示输出”这部分移到主程序

//----------------------------------------------------------------------------------
void main()                        //主程序
{
value humi_val,temp_val;
unsigned char num=105,num1=300;
  unsigned char error,checksum,n;
   
init_uart();         //定义时钟启动
UsartConfiguration(); //串行口
s_connectionreset();          //连接复位
  Delay10ms(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
   TR1=1;
    while(1)
  {     
        num=At24c02Read(2);
        Delay10ms(2);
        num1=At24c02Read(4);
        Delay10ms(2);
             if(K1==0)
          {Delay10ms(1);
          if(K1==0)
            
                    num=At24c02Read(2);
            Delay10ms(2);
                    num++;       
                        if(num>=70)num=70;
                     DisplayData[0] = GPIO_DIG_CODE[10*num/1000];//千位
                    DisplayData[1] = GPIO_DIG_CODE[10*num%1000/100];//百位   
                    DisplayData[2] = GPIO_DIG_CODE[10*num%1000%100/10]|0X80;//十位 加小数点程序
                     DisplayData[3] = GPIO_DIG_CODE[10*num%1000%100%10];//个位
                        At24c02Write(2,num);
                        Delay10ms(1);
                }


                //------------------------------------------------------------------------
        else if(K2==0)
          {Delay10ms(1);
            if (K2==0)
            num=At24c02Read(2);
            Delay10ms(1);     
                        num--;
                        if(num<=20)num=20;
                    DisplayData[0] = GPIO_DIG_CODE[10*num/1000];//千位
                    DisplayData[1] = GPIO_DIG_CODE[10*num%1000/100];//百位   
                    DisplayData[2] = GPIO_DIG_CODE[10*num%1000%100/10]|0X80;//十位 加小数点程序
                     DisplayData[3] = GPIO_DIG_CODE[10*num%1000%100%10];//个位
                        At24c02Write(2,num);
                        Delay10ms(1);
                }
               
               
                ///--------------------------------------------------------------------------------
           else if(K3==0)
          {Delay10ms(1);
            if (K3==0)
            num1=At24c02Read(4);
        Delay10ms(1);
                    num1++;
                        if(num1>=40)num1=40;
                    DisplayData[4] = GPIO_DIG_CODE[10*num1/1000];//千位
                    DisplayData[5] = GPIO_DIG_CODE[10*num1%1000/100];//百位   
                    DisplayData[6] = GPIO_DIG_CODE[10*num1%1000%100/10]|0X80;//十位 加小数点程序
                     DisplayData[7] = GPIO_DIG_CODE[10*num1%1000%100%10];//个位
                        At24c02Write(4,num1);
                        Delay10ms(1);
                }
       
       
                //--------------------------------------------------------------------------------------
           else if(K4==0)
          {Delay10ms(1);
            if (K4==0)
                num1=At24c02Read(4);
            Delay10ms(1);
                    num1--;
                        if(num1<=20)num1=20;
                    DisplayData[4] = GPIO_DIG_CODE[10*num1/1000];//千位
                    DisplayData[5] = GPIO_DIG_CODE[10*num1%1000/100];//百位   
                    DisplayData[6] = GPIO_DIG_CODE[10*num1%1000%100/10]|0X80;//十位 加小数点程序
                     DisplayData[7] = GPIO_DIG_CODE[10*num1%1000%100%10];//个位
                        At24c02Write(4,num1);
                        Delay10ms(1);
               
                }
       
       
       
                //----------------------------------------------------------------------------
        else //无键盘操作时候的扫描程序
        {                  
                        //-------------------------------------
                        //ES=0;
                   error=0;        //初始化error=0,即使当前没有错误
            error+=s_measure((unsigned char*) &humi_val.i,&checksum,HUMI);  //         测量湿度
            error+=s_measure((unsigned char*) &temp_val.i,&checksum,TEMP);  //         测量温度
           if(error!=0) s_connectionreset();           //如果系统发生错误,系统连接复位        
             else
           { humi_val.f=(float)humi_val.i;                   //        整形数变浮点数
            temp_val.f=(float)temp_val.i;                   //         整形数变浮点数
            calc_sth11(&humi_val.f, &temp_val.f);            //         修正相对湿度及温度
                    humi_val.f=humi_val.f*10;                   //        整形数变浮点数
            temp_val.f=temp_val.f*10;
                    temp_val.i=(int)temp_val.f;
                    humi_val.i=(int)humi_val.f;
                     DisplayData[0] = GPIO_DIG_CODE[humi_val.i/1000];//千位
                    DisplayData[1] = GPIO_DIG_CODE[humi_val.i%1000/100];//百位   
                    DisplayData[2] = GPIO_DIG_CODE[humi_val.i%1000%100/10]|0X80;//十位 加小数点程序
                     DisplayData[3] = GPIO_DIG_CODE[humi_val.i%1000%100%10];//个位
                     DisplayData[4] = GPIO_DIG_CODE[temp_val.i/1000];//千位
                     DisplayData[5] = GPIO_DIG_CODE[temp_val.i%1000/100];//百位
                       DisplayData[6] = GPIO_DIG_CODE[temp_val.i%1000%100/10]|0X80;//十位
                      DisplayData[7] = GPIO_DIG_CODE[temp_val.i%1000%100%10];       
                         
              // ES=1;
                    }
     
           if(flag==0)//有数据过来
                   {         outdata[34]=outdata[34]+0x01;
                 ES=0;
           outdata[0]=0x55;         //帧头
           outdata[1]=0xAA;         //帧头
           outdata[2]=0x1E;         //数据长度
           outdata[3]=outdata[34];        //帧序号
           outdata[4]=0x10;         //版本号
           outdata[5]=0x00;         //服务器地址
           outdata[6]=0x00;        //服务器地址
           outdata[7]=0x00;         //服务器地址
           outdata[8]=0x00;         //服务器地址
           outdata[9]=0x08;        //储藏柜地址
           outdata[10]=0x00;   //储藏柜地址
           outdata[11]=0x00; //储藏柜地址
           outdata[12]=0x00;  //储藏柜地址
           outdata[13]=0xC1;//定时上传指令
           outdata[14]=0x00;
           outdata[15]=0x00;
           outdata[16]=0x00;
           outdata[17]=0x00;//数据上传时间
           outdata[18]=0x02; //参数总数
           outdata[19]=0x21;//表示温度
           outdata[20]=0x00;
           outdata[21]=num1; //温度设置值
           outdata[22]=temp_val.i/10; //温度实际值
           outdata[23]=temp_val.i%10; //温度实际值
           outdata[24]=0x20;//表示湿度
           outdata[25]=0x00;
           outdata[26]=num; //湿度设置值
           outdata[27]=humi_val.i/10;
           outdata[28]=humi_val.i%10; //温度实际值
           outdata[29]=0x00; //校验
                for(n=0;n<29;n++)
                {outdata[29]=outdata[n]+outdata[29];} //数据发送的时候是否要把中断关闭,以免在数据发送的时候引起不必要的错误;
              for(n=0;n<30;n++)
                        {
                                SBUF = outdata[n];
                                while(!TI);
                                TI = 0;
                      }
                        ES=1;
                  Delay10ms(50);
                }
        else if(flag==1)
         {//检测数据写入是否正确
           ES=0;
         outdata[34]=outdata[34]+0x01;
           flag=0;
         At24c02Write(2, outdata[28]);
         Delay10ms(1);
         num=At24c02Read(2);
     Delay10ms(1);  
                       for(n=0;n<20;n++)
                        {
                                outdata[n]=0X00;
                        }
         if(num== outdata[28])
    {        ES=0;
       outdata[0]=0x66;         //帧头
           outdata[1]=0xAA;         //帧头
           outdata[2]=0x0F;         //数据长度
           outdata[3]=outdata[34];        //帧序号
           outdata[4]=0x10;         //版本号
           outdata[5]=0x00;         //服务器地址
           outdata[6]=0x00;        //服务器地址
           outdata[7]=0x00;         //服务器地址
           outdata[8]=0x00;         //服务器地址
           outdata[9]=0x08;        //储藏柜地址
           outdata[10]=0x00;   //储藏柜地址
           outdata[11]=0x00; //储藏柜地址
           outdata[12]=0x00;  //储藏柜地址
           outdata[13]=0x31;//定时上传指令
           outdata[14]=0x00;
           outdata[15]=0x00; //校验
                for(n=0;n<15;n++)
                {outdata[15]=outdata[n]+outdata[15];} //数据发送的时候是否要把中断关闭,以免在数据发送的时候引起不必要的错误;
              for(n=0;n<16;n++)
                        {
                                SBUF = outdata[n];
                                while(!TI);
                                TI = 0;
                        }
               
                //需要加入输出继电器的控制,设置控制阈值等。
                  ES=1;
                  Delay10ms(50);
          }
                else
                {       
        //        ES=0;
           outdata[0]=0x77;         //帧头
           outdata[1]=0xAA;         //帧头
           outdata[2]=0x0F;         //数据长度
           outdata[3]=outdata[34];        //帧序号
           outdata[4]=0x10;         //版本号
           outdata[5]=0x00;         //服务器地址
           outdata[6]=0x00;        //服务器地址
           outdata[7]=0x00;         //服务器地址
           outdata[8]=0x00;         //服务器地址
           outdata[9]=0x08;        //储藏柜地址
           outdata[10]=0x00;   //储藏柜地址
           outdata[11]=0x00; //储藏柜地址
           outdata[12]=0x00;  //储藏柜地址
           outdata[13]=0x31;//定时上传指令
           outdata[14]=0x01;
           outdata[15]=0x00;
                 for(n=0;n<15;n++)
                {outdata[15]=outdata[n]+outdata[15];} //数据发送的时候是否要把中断关闭,以免在数据发送的时候引起不必要的错误;
              for(n=0;n<16;n++)
                        {
                        SBUF = outdata[n];
                                while(!TI);
                                TI = 0;
                        }
                        ES=1;
                        Delay10ms(50);
               
                }
                 }
                  
         else if(flag==2)
          {          ES=0;
          outdata[34]=outdata[34]+0x01;
                                 for(n=0;n<20;n++)
                        {
                                outdata[n]=0X00;
                        }          
          
          flag=0;
           outdata[0]=0x88;         //帧头
           outdata[1]=0xAA;         //帧头
           outdata[2]=0x0F;         //数据长度
           outdata[3]=outdata[34];        //帧序号
           outdata[4]=0x10;         //版本号
           outdata[5]=0x00;         //服务器地址
           outdata[6]=0x00;        //服务器地址
           outdata[7]=0x00;         //服务器地址
           outdata[8]=0x00;         //服务器地址
           outdata[9]=0x08;        //储藏柜地址
           outdata[10]=0x00;   //储藏柜地址
           outdata[11]=0x00; //储藏柜地址
           outdata[12]=0x00;  //储藏柜地址
           outdata[13]=0x31;//定时上传指令
           outdata[14]=0x01;
           outdata[15]=0x00;
                   for(n=0;n<15;n++)
                {outdata[15]=outdata[n]+outdata[15];} //数据发送的时候是否要把中断关闭,以免在数据发送的时候引起不必要的错误;
              for(n=0;n<16;n++)
                        {
                                SBUF =outdata[n];
                                while(!TI);
                                TI = 0;
                        }
                        ES=1;
                        Delay10ms(50);
            }
          }   
//执行加湿和除湿的动作
//程序需要增加一个延时动作的功能,等待湿度稳定下来以后进行控制。
if(humi_val.i/10==num)          //误差值在0.5以内的时候 ,加湿除湿停止工作
{JS=1;
CS=1;}
else if        (humi_val.i/10>num&& humi_val.i/10-num>4) //实际湿度大于设定湿度
{JS=1;
CS=0;}
else if(humi_val.i/10<num&& num-humi_val.i/10>4)         //实际湿度小于设定湿度
{JS=0;
CS=1;}
else
{}

   }
   
   
}
//
void GPIO_DIGDisplayDatalay() interrupt 1  //定时器0中断,自动重装赋值
{
//定时器在工作方式二会自动重装初,所以不用在赋值。
               
        GPIO_DIG=0; //消隐
        switch(Num)         //位选,选择点亮的数码管,
        {
                case(0):
                     LSA=0;LSB=0;LSC=0; break;//显示第0位           //把这一段程序去掉以后,该数码管不显示。
             case(1):
                        LSA=1;LSB=0;LSC=0; break;//显示第1位
                case(2):
                        LSA=0;LSB=1;LSC=0; break;//显示第2位
                case(3):
                        LSA=1;LSB=1;LSC=0; break;//显示第3位
                case(4):
                        LSA=0;LSB=0;LSC=1; break;//显示第4位
                case(5):
                        LSA=1;LSB=0;LSC=1; break;//显示第5位
                case(6):
                        LSA=0;LSB=1;LSC=1; break;//显示第6位
                case(7):
                        LSA=1;LSB=1;LSC=1; break;//显示第7位               
        }
        GPIO_DIG = DisplayData[Num]; //段选,选择显示的数字。
        Num++;
        if(Num>7)
        {
                Num=0;
        }

}
//------------------------
//---------------------------
void Usart() interrupt 4         //只判断接收标志位,如果是接收标志引起的中断时候则运行程序。
  //中断里面引用其他程序,会导致程序重复导入,因此中断采集到数据以后只需要附一个数据输入标志位,放到主程序中去判断即可。
  {
          if(RI)
        {        RI=0;
                outdata[i]=SBUF;         
    if(i==0&&outdata[i]==0x55)//判断帧头字符0X55AA
        { outdata[35]=outdata[35]+ outdata[i];
        i=1;
       }
    else if(i==1&&outdata[i]==0xAA)        //判断帧头字符
      { outdata[35]=outdata[35]+outdata[i];
      i=2;
      }
    else if(i>=2&&i<33)
      { outdata[35]=outdata[35]+ outdata[i]; //中间接收字符
       i++;
      }
    else if(i==33&&outdata[i]== outdata[35]&&outdata[5]==0x08&&outdata[6]==0x00&&outdata[7]==0x00&&outdata[8]==0x00)  //检测校验数据是否正确 而且地址正确
          {
               if(outdata[24]==0x20&&outdata[28]==outdata[32]&&outdata[28]>=0x14&&outdata[28]<=0x46)//参数是否设置正确
               {i=0;
                   flag=1;        //数据命令正确
                   ES=0;
                   outdata[35]=0;         
                                }
               else
               {i=0;
                   flag=2;        //数据命令错误
                   ES=0;
               outdata[35]=0;}
           }
         else
         {i=0;
         outdata[35]=0;}

}
}
//----------------------------------------------------------------------------------
void init_uart()         //时钟初始化         定时器0
//----------------------------------------------------------------------------------
  {
        TMOD=0X02;  //选择为定时器模式,工作方式2,仅用TRX打开启动。
        TH0=0X9C;        //给定时器赋初值,定时100us
        TL0=0X9C;       
        ET0=1;      //打开定时器0中断允许
        EA=1;       //打开总中断
        TR0=1;      //打开定时器
}
/*******************************************************************************
* 函 数 名         :UsartConfiguration()
* 函数功能                   :设置串口
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void UsartConfiguration() //定时器1
{
        SCON=0X50;                        //设置为工作方式1
        TMOD=0X22;                        //设置计数器工作方式2 TMOD=0X22 将定时器1的值需要重复设定
        PCON=0X80;                        //波特率加倍
        TH1=0XF3;                    //计数器初始值设置,注意波特率是4800的
        TL1=0XF3;
   // ES=1;
        EA=1;
   //        TR1=1;                            //打开计数器
}

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top