主机每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);
}
楼主,你主机的串口发送部分代码不应该在定时器里面做,而是在定时器里面立个标志,主循环里循环判断这个标志,成立了,在主循环里发送串口数据。因为定时器中断要尽量简洁,但是你发送数据本来要很多时间,按照你的波特率,发送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;
}
楼主先这样改,试试效果如何。顺便理解下查询和中断方式区别在哪里!
先让从机接收一个发一个,不要判断数据接收有没有错误
引用: 引用 4 楼 great_bug 的回复:
你两次访问TMOD寄存器,两次的操作互相冲突.
正解,楼主还可以 去网上 搜索下,网上应该有很多类似的代码啊。
问题解决了,一个是TMOD重载的问题,一个是定时器0中断程序里代码太多,一个是串口中断代码没有写对,