请各位帮我修改下串口程序的错误

小美   2010-4-30 18:41 楼主

  1. #include
  2. #define uchar unsigned char
  3. #define uint unsigned int
  4. unsigned char flag,a,i;
  5. uchar b[4];
  6. uchar code table[]="I get ";
  7. void init()
  8. {
  9.         TMOD=0x20;     //确定T1的工作方式
  10.         TH1=0xfd;                //计算T1的初值,装载TH1,TL1
  11.         TL1=0xfd;
  12.         TR1=1;                        //启动T1
  13.         REN=1;                        //确定串行口的工作方式
  14.         SM0=0;
  15.         SM1=1;
  16.         EA=1;
  17.         ES=1;
  18. }

  19. void main()
  20. {
  21.         init();
  22.         while(1)
  23.         {
  24.                 if(flag==1)
  25.                 {
  26.                         ES=0;                        //关闭串口中断,否则发送数据时同样申请中断,程序进入死循环
  27.                         for(i=0;i<6;i++)
  28.                         {
  29.                                 SBUF=table[i];
  30.                                 while(!TI);
  31.                                 TI=0;
  32.                         }
  33.                         for(i=0;i<4;i++)
  34.                         {
  35.                                 SBUF=b[i];
  36.                                 while(!TI);                //发送完毕后,TI会被硬件置1,跳出循环,说明数据发送完毕
  37.                                 TI=0;        //
  38.                         }
  39.                         ES=1;
  40.                         flag=0;
  41.                 }
  42.         }
  43. }

  44. void ser() interrupt 4
  45. {
  46.         uchar j;
  47.         for(j=0;j<4;j++)
  48.         {
  49.                 while(!RI);
  50.                 RI=0;                                //接受数据完成后,内部硬件置1,进入串口中断函数后
  51.                 b[j]=SBUF;       
  52.         }                                    //必须有软件清0
  53.         flag=1;                                //将flag置1,方便在主程序中检测
  54. }


    现在用串口助手发送字符的时候,如果一次输入正好是4个字符,那么程序时没有错误的
但如果每次输入了2个字符,那么点击发送键后,串口助手是没有显示的,因为中断函数里的j还没有到4,
这样就需要发送2次,串口助手才会收到字符

但如果每次发送3个字符的话,第一次依然没有显示,但第二次发送后会保留多余的字符到b[j],这样以后再一次发送4个字符的话,串口助手以后收到的字符就会和发送的有点出入

求修改!
    如果输入少于4个字符,下次发送的时候,可以把b[]里保存的字符清空
    如果输入大于4个字符,下子发送的事业,也可以把b[]里多保存的字符清空

最好在中断函数里修改后发出来

回复评论 (10)

  1. void ser() interrupt 4
  2. {
  3.     uchar j;
  4.     for(j=0;j<4;j++)
  5.     {
  6.         while(!RI);
  7.         RI=0;                //接受数据完成后,内部硬件置1,进入串口中断函数后
  8.         b[j]=SBUF;   
  9.     }                        //必须有软件清0
  10.     flag=1;                //将flag置1,方便在主程序中检测
  11. }

这里j是局部变量 ,生存周期只是在函数内。这样写太容易出问题了
点赞  2010-4-30 19:36
1.你给一个数据接受中断就进入了,然后进入了那个for循环,如果你输入的不满4个字符,由于 while(!RI);你的中断程序总是 处于等待状态,根本就没有从接收中断跳出来,所以不会返回的数据的,
2.而当你给的字符一旦满4个立刻回从接收中断跳出,并执行串口发送,所以你会看到发的字符多于4个的时候,能够显示前4个字符,至于多余的部分,由于你第五发送的数据引起中断前,你就在主函数里关闭了中断,进行串行发送,所以第五个数据及其以后的就进入等待状态,等到你给pc发送完毕之后重新打开串口中断,又把第五个及其以后的数据写入你那个字符数组b[]了。但是这时候再次进入接收中断,重新进行初始化,j在for循环被赋初值0,所以你发的4个以后的多余数据存储在b[0]b[1]。。。。。当中了,当然了你多余的数据如果不足4个又回到了第一种情况,只有等到4个才会从中断跳出来了。。多余四个就是第二种情况,多余的等到下次从头开始存入。。。。
点赞  2010-4-30 20:15
楼主可以加一个接收超时,如果超过一定时间还没接收到4个字符,就将接收清空;
如果超过四个接不保存,超时并且接收到大于等于4个时就将表明,接收完毕。
点赞  2010-5-1 00:20
先谢谢上面各位的回复。

引用: 引用 3 楼 stude 的回复:

楼主可以加一个接收超时,如果超过一定时间还没接收到4个字符,就将接收清空;
如果超过四个接不保存,超时并且接收到大于等于4个时就将表明,接收完毕。

我也想这么改,可是不知道这么改,郁闷死了
点赞  2010-5-1 10:04
没人帮下忙了吗?
点赞  2010-5-1 19:21

#include
#define uchar unsigned char
#define uint unsigned int
unsigned char flag,a,i;
uchar b[4];
uchar code table[]="I get ";
void init()
{
    TMOD=0x20;     //确定T1的工作方式
    TH1=0xfd;        //计算T1的初值,装载TH1,TL1
    TL1=0xfd;
    TR1=1;            //启动T1
    REN=1;            //确定串行口的工作方式
    SM0=0;
    SM1=1;
    EA=1;
    ES=1;
}

void main()
{
    init();
    while(1)
    {
        if(flag==1)
        {
            ES=0;            //关闭串口中断,否则发送数据时同样申请中断,程序进入死循环
            for(i=0;i<6;i++)
            {
                SBUF=table;
                while(!TI);
                TI=0;
            }
            for(i=0;i<4;i++)
            {
                SBUF=b;
                while(!TI);        //发送完毕后,TI会被硬件置1,跳出循环,说明数据发送完毕
                TI=0;    //
            }
            ES=1;
            flag=0;
        }
    }
}

void ser() interrupt 4
{  long int i=0,p=0;
   uchar a[100];
    uchar j;
    for(j=0;j<100;j++)
    {   
        while(!RI){i++;if(i==10000) return;}
        RI=0;                //接受数据完成后,内部硬件置1,进入串口中断函数后
        p++;
                if (p<4)
            b[j]=SBUF;  
                else
              a[j]=SBUF;
    }                        //必须有软件清0
    flag=1;                //将flag置1,方便在主程序中检测
}
点赞  2010-5-1 20:29
改动在中断函数里:如下:
void ser() interrupt 4
{ long int i=0,p=0;
  uchar a[100];
  uchar j;
  for(j=0;j<100;j++)
  {   
  while(!RI){i++;if(i==10000) return;}
  RI=0; //接受数据完成后,内部硬件置1,进入串口中断函数后
  p++;
if (p<4)
b[j]=SBUF;   
else  
  a[j]=SBUF;

  } //必须有软件清0
  flag=1; //将flag置1,方便在主程序中检测
}
我的做法是:由于前面我已经说过如果你的数据少于4个你那个中断里的while根本就跳不出来。如果多余4个会跳出中断,但是pc端与单片机并没有握手程序代码,所以pc那边有可能仍然在发送4个以后的数据,但是单片机主函数已经关闭中断不予理会,所以等到再次开中断的时候pc那边第4个以后的数据可能发送完了,也就是说单片机的SBUF中的数据在单片机主程序发送给pc机数据的时候可能被刷新,当然了在单片机给pc发送数据的时候pc的接收函数会相应,可能不会继续发送多余的数据,但是从单片机先关中断,然后发送数据,再到开中断这个期间,pc那边可能不同步,可能pc那边提前接受完毕了,没等单片机再次开中断准备接受呢就pc就开始发送了。
基于以上想法:我想,因为楼主只想发送四个数据,这四个数据按照9600的波特率也就需要几毫秒吧。我这里用一个i不断地累加,按常规来说发送4个数据应该不会是i累加的数太大,如果太大的话说明pc发送端发送不组4个数据,总是在while这里循环跳不出来了,那么就直接返回,这时候能能是pc显示2个数据。当然了你要是不想要这两个数据还可以做适当的修改,
再来说说多于4个的情况,我这里用了一个辅助变量p,由于楼主担心4个以后的数据会在你下次发送的时候仍然存在于b[]里面,所以我们索性把4个以后的数据也一块接了,只是不放在b[]里面,放在另一数据a[]里面,而a[]是局部变量,根本就不返回,这样做无非是把数据全部接受,不影响下次发送,下次仍然可以从b[0]开始存放数据。。。。。
以上只是个人的一点想法,由于电脑总是蓝屏就懒得检验了,仅供楼主参考。。。
点赞  2010-5-1 20:47
[quote]引用楼主 wangjun403 的回复:
当接收到第一个字节的串口数据后启动一个定时器(定时间隔由串口波特率和收发的数据量来确定),定时器到时后检查是否收到所需的字节数。如果没有,则清除接收缓冲区、关闭定时器,等待下一次接收。

另:为什么非要在单片机处理接收超时的问题?不能在PC上做吗?
在单片机一帧数据接收完整后,可以给PC发送一个接收成功的标志。PC端接收到后就可以发送下一帧数据,如果PC端在超时时间内没有接收到单片机的接收成功标志,则给单片机发送一个重发标志,然后重新发送上一帧数据。

因为PC上的资源较多,使用定时器判断超时也方便。换个思路,一样可以解决问题。
点赞  2010-5-1 22:58
对于8楼的说法,我感觉靠谱。呵呵,pc那边不是不能做,而是一般来说pc那边我们是用的网上某个地方下载的串口调试工具,而那个上位机软件根本就没有“握手”程序,所以。要想让pc那边检验标志那除非你自己去编一个适用于自己的上位机发送接收程序,但一般来说我们是不专注于上位机的,,而且那样检验是否超时的工作和在单片机上做是一样的。。。pc资源固然丰富,不过那不是做单片机的人所擅长的吧。。。。
点赞  2010-5-2 12:35
通讯这种东西需要定义一个简单的协议,这样才能有保证的。
点赞  2010-5-5 12:16
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复