微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > MCU和单片机设计讨论 > 现在开发中遇到一个很棘手的问题,pic18f4520

现在开发中遇到一个很棘手的问题,pic18f4520

时间:10-02 整理:3721RD 点击:
4520的PORD4引脚控制一个三极管来 给ATT7022供电,当外部中断来的时候 启动7022采集电流数据,程序开始的一天都是好的,测量的电流也是对的,一天之后,采集的到数据就不对了全wei0
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个字节左右,也不知道这样可能解决这个问题

高手

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top