单片机通讯程序问题
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; //打开计数器
}