现在开发中遇到一个很棘手的问题,pic18f4520
if(sendok_flag==0)
{
uchar i;
if(Action_flag==1)
{ i=0;
for(;(i<5)&&(sendok_flag==0);i++)
{ asm("CLRWDT");
Delay_ms(50);
Send_Action_data();
Delay_ms(1500);
}
}
if(work_flag==1)
{ i=0;
for(;(i<5)&&(sendok_flag==0);i++)
{
Delay_ms(50);
Send_work_data();
Delay_ms(1500);
}
之前发送的函数在中断里就执行了,这段代码是我加在WHILE(1)循环里的,没加这段代码的时候,程序工作几个月都不会有问题,这段代码主要是防止通讯不成功,重复发送的,有没有大神帮忙看看,这段代码有什么问题吗
程序信息太少,无法分析出问题原因,要确定数据采集的方式,是否中断方式,确定是采集的数据错误,还是发送数据部分错误,Action_flag,sendok_flag,work_flag这几个标志什么情况下会变更
if(RCIF==1) //UART中断程序
{ asm("CLRWDT"); //看门狗喂狗
TMR0H=0xAB; //开启定时器,用于控制UART_Index清零,定时0.5s
TMR0L=0xA0; //设置初值0xABA0,在16位定时器64分频情况下精确定时0.5s
TMR0ON=1; //开定时器0
if(OERR) //如果接收溢出,则通过CREN重置OERR标志
{
CREN=0;
Delay_us(10);
CREN=1;
}
ReBuffer[UART_Index++]=RCREG;
if((UART_Index==10)&&(ReBuffer[0]==0x11))
{
asm("CLRWDT"); //看门狗喂狗
UART_Index=0; //对报文接收索引清零
Connection(); //按照报文进行通讯
Delay_us(10);
}
if((UART_Index==8)&&(ReBuffer[0]==0x10)&&(ReBuffer[1]==0x5A)&&(ReBuffer[2]==Code_Number/16777216)&&(ReBuffer[3]==(Code_Number%16777216)/65536)&&(ReBuffer[4]==(Code_Number%65536)/256)&&(ReBuffer[5]==Code_Number%256))
{
asm("CLRWDT"); //看门狗喂狗
UART_Index=0; //对报文接收索引清零
sendok_flag=1;// 中继器返回标志位
}
}
if(INT0IF==1)
{ asm("CLRWDT"); //看门狗喂狗
INT0IF=0;
Action_flag=1;
if(Action<99)
{
LED=1;
Action++;
asm("CLRWDT"); //看门狗喂狗
AT24C256_I2C_ByteWrite(0x0000,Action);
AT24C256_I2C_ByteWrite(Action*7,Action); //次
AT24C256_I2C_ByteWrite(Action*7+1,BCD_Num(DS3231_I2C_ByteRead(0x06))); //年
AT24C256_I2C_ByteWrite(Action*7+2,BCD_Num(DS3231_I2C_ByteRead(0x05))); //月
AT24C256_I2C_ByteWrite(Action*7+3,BCD_Num(DS3231_I2C_ByteRead(0x04))); //日
AT24C256_I2C_ByteWrite(Action*7+4,BCD_Num(DS3231_I2C_ByteRead(0x02))); //时
AT24C256_I2C_ByteWrite(Action*7+5,BCD_Num(DS3231_I2C_ByteRead(0x01))); //分
AT24C256_I2C_ByteWrite(Action*7+6,BCD_Num(DS3231_I2C_ByteRead(0x00))); //秒
Send_Action_data();
asm("CLRWDT"); //看门狗喂狗
LED=0; //连续雷击灯灭 20170306
}
else
{ asm("CLRWDT"); //看门狗喂狗
LED=1;
Action=99;
Send_Action_data();
LED=0; //连续雷击灯灭 20170306
}
}
if(INT1IF==1)
{
INT1IF=0;
if((BCD_Num(DS3231_I2C_ByteRead(0x02))%4)==0) //小时为4的倍数
{ asm("CLRWDT"); //看门狗喂狗
Get_Data();
if(Record_Index[1]<=1080) //6个月记录
{
Record_Index[1]++;
}
else
{ asm("CLRWDT"); //看门狗喂狗
Record_Index[1]=1; //重新循环覆盖
Record_Index[0]++;
AT24C256_I2C_ByteWrite(0x0001,Record_Index[0]);
}
AT24C256_I2C_ByteWrite(0x0002,Record_Index[1]/256);
AT24C256_I2C_ByteWrite(0x0003,Record_Index[1]%256);
AT24C256_I2C_ByteWrite(0x1000+6*Record_Index[1],BCD_Num(DS3231_I2C_ByteRead(0x06))); //年
AT24C256_I2C_ByteWrite(0x1000+6*Record_Index[1]+1,BCD_Num(DS3231_I2C_ByteRead(0x05))); //月
AT24C256_I2C_ByteWrite(0x1000+6*Record_Index[1]+2,BCD_Num(DS3231_I2C_ByteRead(0x04))); //日
AT24C256_I2C_ByteWrite(0x1000+6*Record_Index[1]+3,BCD_Num(DS3231_I2C_ByteRead(0x02))); //时
AT24C256_I2C_ByteWrite(0x1000+6*Record_Index[1]+4,I/256);
AT24C256_I2C_ByteWrite(0x1000+6*Record_Index[1]+5,I%256);
}
if((BCD_Num(DS3231_I2C_ByteRead(0x0F))&0x02)!=0)
{ asm("CLRWDT"); //看门狗喂狗
LED=1;
work_flag=1;
Send_work_data();
// Delay_ms(1000);
asm("CLRWDT"); //看门狗喂狗
LED=0;
数据的采集是在外部中断来了以后 ,开始采集的,Action_flag(外部中断),sendok_flag(发送成功的标志,也就是本机收到返回后),work_flag,之前中断里发送的actiondata,第一次发程序是我加的,之前while里面只有一句休眠
这几个标志都是在中断里变的,之前这几个标志没加在主循环里的话,在中断里执行,程序都是正常的
程序只有这些,就这些程序来讲,假定几个条件,一,数据的采集已经完成,该保存的数据也已经保存,二,数据已经发送了,但认为不成功。
这样有几个问题,一,其他两个标志先不管,也不确定是否正确,但是sendok_flag标志只看到两种状态,而两种状态不能满足你现在功能的需要。二,sendok_flag标志在重发过程中没有变更,也就是重发成功后并没有置一。三,虽然限定了重发次数,但是没限定重发不成功的操作。四,看现在第一段程序,因为sendok_flag标志没有变更,那假如重发是否成功,将会不停的进行重发操作,那对采样是否用影响就不确定了。五,看到了发送中断程序,但是没看到Send_Action_data();和Send_work_data();,所以现在只能假定在发送中断程序里,发送成功了会sendok_flag=1,但是不知道什么时候sendok_flag会等于0。
真谢谢你的耐心解答,我第一段程序没有贴完全下面还有一段
if(sendok_flag==1)
{ sendok_flag=0;
work_flag=0;
Action_flag=0;
}
如果发送成功的话,接收中断里的sendok-flag置1,试验我做过,如果发送成功的话,就只会发送一次,如果不成功就会重发直到发送成功,但最多只有限定的次数,程序也能能跑起来,大概一天左右,在这一天之中,所测量的数据也都是对的,之后就不对了数据,而且在数据不对的时候,我可以通过中断唤醒MCU,MCU上传出来的数据除了采集的数据不对之外,其他的诸如 设备号之类的信息都是对的,就只有测量的数据不对,还有一个情况,重新上电之后,采集的数据又都对了,Send_Action_data( ) //
{
uchar i=0;
E30M1=0;//设置为唤醒模式
E30M0=1;
Delay_ms(50);
SeBuffer[17]=0; //清0校验和
SeBuffer[0]=0x68;
SeBuffer[1]=0x0d; //事件标志位
SeBuffer[2]=0x0b;
SeBuffer[3]=Myaddr;
SeBuffer[4]=Code_Number/16777216;
SeBuffer[5]=(Code_Number%16777216)/65536;
SeBuffer[6]=(Code_Number%65536)/256;
SeBuffer[7]=Code_Number%256;
SeBuffer[8]= Action;
SeBuffer[9]= AT24C256_I2C_ByteRead(Action*7+1);
SeBuffer[10]= AT24C256_I2C_ByteRead(Action*7+2);
SeBuffer[11]= AT24C256_I2C_ByteRead(Action*7+3);
SeBuffer[12]= AT24C256_I2C_ByteRead(Action*7+4);
SeBuffer[13]= AT24C256_I2C_ByteRead(Action*7+5);
SeBuffer[14]= AT24C256_I2C_ByteRead(Action*7+6);
Get_Data();
SeBuffer[15]=I/256;
SeBuffer[16]=I%256;
for(i=1;i<17;i++)
SeBuffer[17]=SeBuffer[17]+SeBuffer;
SeBuffer[18]=0x16;
TXEN=1;
for(i=0;i<19;i++)
{
TXREG=SeBuffer;
while(TRMT==0);
Delay_us(1);
SeBuffer=0;
}
TXEN=0;
Delay_ms(50); //等待模块发送完毕
E30M1=1;
E30M0=0;//进入省电模式
Delay_ms(50); //等待模块下次发送
}
还有一个情况 所有的数据采集都是在需要的时候才会采集,一个是action—flag另一个是work-flag,这两个状态来了才会采集数据,还有一个是主动召测的时候,奇怪的是所有的功能刚开始都是正常的
没用过这个芯片,需要确定几个问题,
一,在能正常工作的一天里有没有通讯中断的情况。
二,通讯中断的情况下,其他功能是否正常。
三,通讯中断的情况下,看程序应该是无限重发,直到发送正常,不会是有限的次数,for(;(i<5)&&(sendok_flag==0);i++),虽然是重发5次就退出,但sendok_flag仍然等于0,主程序应该会不断判断sendok_flag==0这个条件,所以似乎应该是无限重发。
四,重发的情况下,是否还能正确采集数据。
五,sendok_flag是这次为了重发功能而加的吗。
六,if(RCIF==1) , if(INT0IF==1),if(INT1IF==1)是在中断里执行,还是在中断里设标志,退出中断后再以查询方式执行。
七,如果采集是在中断里执行,有可能会对重发过程中的一些参数进行修改。
八,每天里采集的次数是否一样,是否有固定次数后设备失灵的情况。
九,看程序sendok_flag是放在接收程序里的,是否可以理解为PC会返回一个确认收到数据的数据包。
十,如果通讯中断超过一天,恢复通讯后,是否能正常。
十一,去除休眠模式,是否能正常。
十二,看门狗是否起作用了,如果没有,可以查查喂狗的部分是否死循环了。
感觉是程序跑飞了,可能是有些变量被多处同时修改,判断条件无法处理,死循环了。
这个重发只会在INT0,INT1的时候才会有重发一说,因为我主程序里用到了这两个中断里action_flag 和work_flag
这两个中断来的时候会置1,
if(sendok_flag==0)
{
uchar i;
if(Action_flag==1)
{ i=0;
for(;(i<5)&&(sendok_flag==0);i++)
{
Delay_ms(50);
RE_Send_Action_data();
Delay_ms(1500);
}
}
if(work_flag==1)
{ i=0;
for(;(i<5)&&(sendok_flag==0);i++)
{
Delay_ms(50);
RE_Send_work_data();
Delay_ms(1500);
}
}
sendok_flag=0;
work_flag=0;
Action_flag=0;
}
if(sendok_flag==1)
{ sendok_flag=0;
work_flag=0;
Action_flag=0;
}
我里面加了这两个标志位的清零,
这样看似乎也没什么问题,那看看是否能在数据包里增加一些判断信息,比如一些相关的寄存器数值,一些变量数值等。
理一理程序结构,看看有没有会误判断的地方。
看看模式转换时单片机的状态如何,E30M1=1;E30M0=0;,在单片机手册里没找到,或许不在芯片手册里,看看模式转换的设置位置是否合适。
另外建议设置一个类似resend_flag的标志,和sendok_flag区分一下,如果问题解决了和这个无关,可以再合并成一个。
你分析的真实透彻,给的建议很好,E30M1=1;E30M0=0; 是我的一个模块信息,配置模块的工作方式,为了省电,今天上午看程序的编译,看到了数据空间占了188个字节,我在变量定义的时候没有区分bank,而每个bank最大128字节,所以我把部分变量的定义放在了bank1,其他的都默认在bank0,让bank0默认的在90个字节左右,也不知道这样可能解决这个问题
高手