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

stc89c52串口问题

时间:10-02 整理:3721RD 点击:
还是郭老师的那个题目:以16进制发送一个0-65536之间的任一数,当单片机收到后在数码管上动态显示出来,波特率自定。我的问题是,我在串口助手上输入任何数,五个数码管只显示11366,代码如下:
#include<reg52.h>
#define uchar unsigned char
uchar flag;
int a,ge,shi,bai,qian,wan;        //个位、十位、百位、千位、万位
sbit dula=P2^6;
sbit wela=P2^7;
uchar code table[]={
0x06,0x5b,0x4f,
0x66,0x6d,0x7d};  
void init()
{
        EA=1;
        ES=1;
        TMOD=0x20;//定时器1工作方式2
        TH1=0xfd;
        TL1=0xfd;
        TR1=1;
        REN=1;
        SM0=0;
        SM1=1;
        dula=0;
}
void delay(uchar y)
{
        uchar i,j;
        for(i=y;i>0;i--)
                for(j=118;j>0;j--);
}
void display(int x)
{
        wan=x/10000;
        qian=x%10000/1000;
        bai=x%10000%1000/100;
        shi=x%100/10;
        ge=x%10;
                                                    //从左到右,第1个数码管
        dula=1;
        P0=table[wan];
        dula=0;
        P0=0xff;                         
        wela=1;
        P0=0xfe;
        wela=0;
        delay(5);
        dula=1;                                         //第2个数码管
        P0=table[qian];
        dula=0;
        P0=0xff;
        wela=1;
        P0=0xfd;
        wela=0;
        delay(5);
                                                          //第3        个数码管
        dula=1;
        P0=table[bai];
        dula=0;
        P0=0xff;
        wela=1;
        P0=0xfb;
        wela=0;
        delay(5);
     dula=1;
        P0=table[shi];
        dula=0;
        P0=0xff;
        wela=1;
        P0=0xf7;
        wela=0;
        delay(5);
        dula=1;
        P0=table[ge];
        dula=0;
        P0=0xff;
        wela=1;
        P0=0xef;
        wela=0;       
        delay(5);         
}
void main()
{       
        init();
        while(1)
        {
                if(flag==1)
                {       
                        ES=0  ;               
                        SBUF=a;                  //向PC端返回要显示的值
                        while(!TI);
                        TI=0;
                        display(a);
                        ES=1;
                }
        }
}
void serial() interrupt 4
{
        RI=0;
        a=SBUF;                                   //将接受到的值给a
        flag=1;
}

@一抹阳光 @爱我别走 麻烦你们了


纠正你几个错误。
其一:变量分配问题,flag只用到了0,1两个状态51可以定义成bit型节省空间,ge、shi……应该放在display()函数中定义成局部变量。
其二:段码数组不完整。0~9显示码不管共阴共阳有10个的(0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07共阴)
其三:flag变量赋值以后没有清零,main函数不断执行if(flag)条件下的语句块。失去flag的意义了。display函数正常应该放在while(1)第一层下只做显示用。
其四:串口信息帧中,一次接受、发送一个字符。怎么能赋值给5位数呢?思路:定义一个接收缓冲区,buf[5]类似的,开拓出5个字节的空间保存你的5位数数据。当然你也可以简单的一个变量用算法把接受的二进制数据组合到两个字节的int型中。
其五:串口助手发送字符一般用字符型发送,接收的时候,buf=SBUF&0X0F;去低位,例如:发送2,数据形式为0x32;取低位,为2保存在缓存中,再进行处理。
有问题再交流。先解决以上的。

在楼下  

    在尽量保证你原有程序结构不变的情况下,对你的程序进行了改正,所有存在问题隐患,或错误的语句前均加有注释并已修改,可以对照你原有程序查看,如有疑问可以继续交流。
      另外对于串口调试助手,你在发送数据的时候,如果选择的是16进制发送就应该输入十六进制的数,比如你要发送65534的时候就输入FF FE,而不是65534,如果你输入的是"65534",并以16进制发送,实际单片机收到的是0X65 0x53,这不符合你的初衷,对于此程序如果你需要让数码管显示65535,那么必须在串口调试助手输入对应的16进制数FF FF再以16进制形式发送,否则出错,同理其他数字先应转换为16进制,而如果你以字符型发送那么单片机收到的则是每个字符对应的ASCII值,比如你已字符型发送123,实际发出的则是0x31 0x32 0x33,这样的数据与我定的数据格式不符,因而也无法正常显示,当然你如果想输入字符数字,数码管直接显示,这也是可以做到的,需要另外定义数据格式,更改程序,或者对上位机串口助手进行修改。但对于你们这道作业题实际上题意是让发送16进制数而不是字符。
      这里我将串口接收数据的格式定为:两个字节为一段数据,前者为高8位,无数据校验。

  1. /******************************修改版*********************************/

  2. #include<reg52.h>
  3. #define uchar unsigned char

  4. /*标志位定义成bit型即可*/
  5. bit flag;

  6. /*你既然要显示0-65535,int型显然不满足要求*/
  7. unsigned int a;
  8. sbit dula=P2^6;
  9. sbit wela=P2^7;

  10. /*之前段码表有误,0x3f不能漏,表示0,漏掉产生的结果就是使得每位显示的数比原来大1*/
  11. uchar code table[]={0X3F,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0X07,0X7F,0X6F};  
  12. void init()
  13. {
  14.   /*不管是中断还是定时器,配置的时候均应该按照一定的寄存器配置顺序,切记不要随意*/        
  15.                TMOD=0x20;        //定时器1工作方式2                       
  16.                 SM0=0;        
  17.                 SM1=1;
  18.                 REN=1;
  19.                 TH1=0xFD;
  20.                 TL1=0xFD;
  21.                 EA=1;
  22.                 ES=1;
  23.                 TR1=1;
  24.                 dula=0;
  25. }
  26. void delay(uchar y)
  27. {
  28.         uchar i,j;
  29.         for(i=y;i>0;i--)
  30.                 for(j=118;j>0;j--);
  31. }

  32. /*你既然要显示0-65535,这里形参x类型为int肯定是不行的,改为了unsigned int*/
  33. void display(unsigned int x)            
  34. {

  35. /*这里的ge,shi,bai,qian,wan,定义在函数内部即可,定义成全局,变量将常驻内存,对于这里
  36. 定义局部即可,函数运行完将释放空间,因而不必浪费*/
  37.         unsigned char ge,shi,bai,qian,wan;        //个位、十位、百位、千位、万位
  38.         wan=x/10000;
  39.         qian=x%10000/1000;
  40.         bai=x%10000%1000/100;
  41.         shi=x%100/10;
  42.         ge=x%10;
  43.                                                     //从左到右,第1个数码管
  44.         dula=1;
  45.         P0=table[wan];
  46.         dula=0;
  47.         P0=0xff;                        
  48.         wela=1;
  49.         P0=0xfe;
  50.         wela=0;
  51.         delay(5);
  52. /*此句P0=0X00作用为消影,你在前面考虑到了段码对下面位码的影响,从而写上了P0=0XFF
  53. 但是这里却忽略了下一次的位码对段码的影响,加上P0=0X00便解决此问题,以下类似语句后
  54. 均已加上*/
  55.         P0=0x00;


  56.         dula=1;                                         //第2个数码管
  57.         P0=table[qian];
  58.         dula=0;
  59.         P0=0xff;
  60.         wela=1;
  61.         P0=0xfd;
  62.         wela=0;
  63.         delay(5);
  64.         P0=0x00;
  65.                                                           //第3个数码管
  66.         dula=1;
  67.         P0=table[bai];
  68.         dula=0;
  69.         P0=0xff;
  70.         wela=1;
  71.         P0=0xfb;
  72.         wela=0;
  73.         delay(5);
  74.         P0=0x00;                           

  75.         dula=1;
  76.         P0=table[shi];
  77.         dula=0;
  78.         P0=0xff;
  79.         wela=1;
  80.         P0=0xf7;
  81.         wela=0;
  82.         delay(5);
  83.         P0=0x00;

  84.         dula=1;
  85.         P0=table[ge];
  86.         dula=0;
  87.         P0=0xff;
  88.         wela=1;
  89.         P0=0xef;
  90.         wela=0;        
  91.         delay(5);
  92.         P0=0x00;         

  93. }
  94. void main()
  95. {        
  96.         init();        
  97.         while(1)
  98.         {
  99.               /*显示置于if语句之外,保证一直刷新显示*/
  100.                  display(a);
  101.              /*flag==1即标志着串口数据接收完成,将收到的数据发送至PC端*/
  102.                 if(flag==1)
  103.                 {
  104.                        /*标志位需清零*/      
  105.                         flag=0;     
  106.                         ES=0;
  107.                         /*先发送高八位*/               
  108.                         SBUF=a/256;                  //向PC端返回要显示的值
  109.                         while(!TI);
  110.                         TI=0;
  111.                        /*发送低八位*/
  112.                         SBUF=a%256;                  //向PC端返回要显示的值
  113.                         while(!TI);
  114.                         TI=0;
  115.                         ES=1;
  116.                                                 
  117.                 }
  118.         }
  119. }
  120. void serial() interrupt 4
  121. {

  122. /*由于待接收的数据是16位,而串口每次中断只能接收8位的数据,因此需要接收完两个字节做一次数据转换
  123. 这里由于恰好是接收两次,利用a变量本身保存上次的值,从而不需要再定义变量用作两次接收数据,当然如果
  124. 接收的数据较多,建议定义buf[]数组进行储存,接收完成进行统一数据转换。*/
  125.         static unsigned char i=0;         //静态局部变量,计数收到数据的个数
  126.         RI=0;
  127.         if(++i==2)                        //共收到两个字节的数据,此时收到第八位
  128.         {
  129.                 i=0;
  130.                 a=a*256+SBUF;             //组合成16位
  131.                 flag=1;                   //标志置位,主函数中将收到的两个字节发送出去
  132.         }
  133.         else                              //收到高八位
  134.         {
  135.                 a=SBUF;               
  136.         }      
  137.         
  138. }

复制代码

首先,很感谢@一抹阳光 耐心地给我修改冗长的代码,通过你的注释,我对串口通信又多了一些理解.接下来就讲一下一个细节问题吧,我用你改好的的代码测试的时候,发现,如果我第一次发送"ff",数码管显示"255",但第二次发送"ff"时,数码管却显示"65535",所以,我就修改了一下串口接受中断:
/*这里我定义了两个全局变量 i 和 j ,根据小编的的说法,我也定义了  uint buf[2]   作为缓存*/
void serial() interrupt 4
{
       
                                                  //变量i计数收到数据的个数,j作为标志
        if(RI==1)
                {
                        RI=0;
                        if(j==2)                //第三次发送的数据,放到高8位
                                j=0;
                        buf[j]=SBUF;
                        i++;
                        j++;
                        if(i==3) i=1;         //第三个字节做为第一个字节处理
                }
              
                        if(i==1) a=buf[0];
                        if(i==2)   a=buf[0]*256+buf[1];
                        flag=1 ;
}
一开始,我是在中断中对 i,j 清零的,但是这样做还是有问题,所以我就将其改在main中进行:
void main()
{
        init();
        while(1)
        {
                display(a);
         if(flag==1)
                {
                        flag=0;      
                        ES=0;         
                        SBUF=a/256;         
                        while(!TI);
                        TI=0;
                        SBUF=a%256;                 
                        while(!TI);
                        TI=0;
                        ES=1;
                        i=0;j=0;   //发送结束后,对i,j清零
                }
        }       
}


谢谢小编的建议,我已经做了修改,问题基本解决

@dongyumin 为什么我对@一抹阳光 的回复还没通过?

受益匪浅,谢谢大神解析

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

网站地图

Top