这个双机通信为什么有问题?

thingwind   2010-5-28 21:54 楼主
主机每200ms向从机发送一次数据,从机接收到后,如果判断数据接收没有错误,就将数据返回到主机使主机的LED1灯亮。但是现在发送和接收都实现不了,我看到SBUF里没有数据。好像一用定时器定时发送数据就有问题,不知道是怎么回事。
1,主机程序:
#include
sbit                LED1=P0^0;
unsigned char data1[6]; //发送协议
unsigned char data2[6]; //接收协议
void init_serial0();         //定时器0初始化
void init_serial1();    // 串口初始化
unsigned char ecc=0x00;
int i,a=0;

/****************** 发送数据 **********************/
void send_data(unsigned char *data1)
{
        /* 发送数据 */
        for(i=0; i<5; i++)
        {
                TI = 0;
                SBUF = data1;    // 发送数据                                                                               
                while(!TI);
                TI = 0;
        }
}          
  /****************初始化串口 ********************/
void init_serial1()
{
        TMOD = 0x20;        //定时器T1使用工作方式2
        TH1 = 250;    // 设置定时器T1初值250,是波特率为4800bps,
        TL1 = 250;       
        TR1 = 1;    // T1开始计时
        PCON = 0x80;    // SMOD = 1        ,波特率4800加倍
        SCON = 0x50;        //工作方式1,波特率9600bps,允许接收
}
/* *****************定时器0 **********************/
void init_serial0()
{
        TMOD = 0x10;        //定时器T0使用工作方式1
        TH0 = 0xB8;    // 设置定时器T0初值20ms,
        TL0 = 0x00;       
        TR0 = 1;    // T0开始计时       
        ET0=1;        //允许定时器0中断
        EA=1;        //CPU开放中断  
}
/*************** T0溢出中断,使用工作模式1,每20ms发送一次数据*********** */
void timer0_int () interrupt 1 //using 0                // T0溢出中断,使用工作模式1
{                                                  
        TH0 = 0xB8;    // 重新装入初值
        TL0 = 0x00;
        a++;
        if(a==10)
         {
         send_data(data1);//发送数据
         a=0;                
         }
/* **********************主程序******************** */
void main(void)
{
  
        data1[0]=0xC5;//包头
        data1[1]=0x08;//数据内容
        data1[2]=0xF6;
        data1[3]=0xC8;
        data1[4]=0xC5+ data1[1]+ 0xF6+0xC8;//校验字节,和自动溢出取最低8位                                                 
    init_serial1();   // 串口初始化
    init_serial0();   //定时器0初始化
          TI=0;
        RI=0;       
        IE=0x9A;  //开所有中断
        IP=0x01;  //定时器0中断优先

while(1)        //循环等待
    {
                       
    }
}

void Serial_INT() interrupt 4        //串口中断服务程序
{        int i;         
        /* 接收数据 */
        for(i=0; i<5; i++)
        {         RI=0;
                while(!RI);
                data2 = SBUF;    // 接收数据
                RI = 0;               
        }
                ecc=0xC5+ data1[1]+ 0xF6+0xC8;//校验字节,和自动溢出取最低8位
                data2[5]=0;           // 表示数据结束
         
/* 进行数据校验《若正确则控制相对应的指示灯 */
if((data2[0]==0xC5)&&(data2[4]==ecc))       
         {
   if((data2[1]&0x80)==0x80)           //高电平灭
            LED1=1;
   else
      LED1=0;                                          //低电平亮   
         }          
}

2,从机程序:
#include
sbit                LED1=P0^0;
unsigned char data2[6]; //接收协议
void init_serial0();         //定时器0初始化
void init_serial1();    // 串口初始化
unsigned char ecc=0x00;
int i;

/****************** 发送数据 **********************/
void send_data(unsigned char *data1)
{
        int i;       
        /* 发送数据 */
        for(i=0; i<5; i++)
        {
                TI = 0;
                SBUF = data1;    // 发送数据                                                        while(!TI);
                TI = 0;
        }
}          
  /****************初始化串口 ********************/
void init_serial1()
{
        TMOD = 0x20;        //定时器T1使用工作方式2
        TH1 = 250;    // 设置定时器T1初值250,是波特率为4800bps,
        TL1 = 250;       
        TR1 = 1;    // T1开始计时
        PCON = 0x80;    // SMOD = 1        ,波特率4800加倍
        SCON = 0x50;        //工作方式1,波特率9600bps,允许接收
}
/* **********************主程序******************** */
void main(void)
{                                                 
    init_serial1();   // 串口初始化
          TI=0;
        RI=0;       
        IE=0x98;  //开所有中断(除过定时器0)
        IP=0x10;  //串口中断优先

while(1)        //循环等待
    {
                       
    }
}

void Serial_INT() interrupt 4        //串口中断服务程序
{                 
        /* 接收数据 */
        for(i=0; i<5; i++)
        {         RI=0;
                while(!RI);
                data2 = SBUF;    // 接收数据
                RI = 0;               
        }
                ecc=0xC5+ data2[1]+ 0xF6+0xC8;//校验字节,和自动溢出取最低8位
                data2[5]=0;           // 表示数据结束         
/* 进行数据校验,若正确则返回到主机 */
if((data2[0]==0xC5)&&(data2[4]==ecc))                 
         send_data(data2);
            
}

回复评论 (8)

楼主,你主机的串口发送部分代码不应该在定时器里面做,而是在定时器里面立个标志,主循环里循环判断这个标志,成立了,在主循环里发送串口数据。因为定时器中断要尽量简洁,但是你发送数据本来要很多时间,按照你的波特率,发送1byte数据至少都要1.5ms。很长了。

其次,无论从机还是主机,你的串口接收中断函数的处理流程也有问题:
for(i=0; i<5; i++)
{ RI=0;
while(!RI);
data2 = SBUF; // 接收数据
RI = 0;
}
每次中断后,RI肯定为1,此时你应该先读取了数据再清标志位,其实既然你用了中断方式,也没必要查询RI了。改为:


for(i=0; i<5; i++)
{
data2 = SBUF; // 接收数据
RI = 0;
}


楼主先这样改,试试效果如何。顺便理解下查询和中断方式区别在哪里!
点赞  2010-5-28 22:24
顶楼上的~~~~~~~~~
点赞  2010-5-29 00:20
先让从机接收一个发一个,不要判断数据接收有没有错误
点赞  2010-5-29 10:12
你两次访问TMOD寄存器,两次的操作互相冲突.
点赞  2010-5-29 10:26
引用: 引用 4 楼 great_bug 的回复:
你两次访问TMOD寄存器,两次的操作互相冲突.


正解,楼主还可以 去网上 搜索下,网上应该有很多类似的代码啊。
点赞  2010-5-29 17:04
你不会debug吗?
点赞  2010-5-30 09:24
keil有debug,可以跟踪仿真调试
点赞  2010-5-30 10:09
问题解决了,一个是TMOD重载的问题,一个是定时器0中断程序里代码太多,一个是串口中断代码没有写对,
点赞  2010-5-31 18:37
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复