搜索

PICC+ICD程序乱跑咋回事?附上了简洁的源程序,大侠看看

[复制链接]
4416|32
 楼主 | 2011-8-5 11:23 | 显示全部楼层 |阅读模式
本帖最后由 秋雨 于 2011-8-6 00:24 编辑

16F886+MAPLAB+PICC+ICD2仿真

采用内部4M晶体,中断开了TMR0 TMR1 和RB口中断

程序总是跑飞或乱跑,差了很多遍找不到问题。。。然后我在程序里面随便加了一个判断语句,发现总是不对

定义了一个无用的变量
unsigned char ERR_CODE;

加的语句如下

  ERR_CODE=1;
  if(ERR_CODE>100)
  {
   asm("nop");
  }

这个变量别的地方都没有用到。结果ICD2仿真发现,程序居然能跑到asm("nop")这一句。。。此时发现STATUS不对。。为00011011或者 0001111。。。
差了3天,找不到问题,以前数组超限会出乱跑的问题,这次查了没有发现超数组容量的。

请教一下,各位遇到的程序乱跑的问题大都由什么原因引起的呢?
| 2011-8-5 14:16 | 显示全部楼层
如果程序中其他地方存在nop,则在编译器优化的作用下,该nop可能会统一到一个地址,此时可能出现从别的地方转移而来。
所以,并不一定是执行了这个条件判断。

PC乱飞,多数是因为代码中出现错误或者临界代码。

贴出你的中断函数看看。

使用特权

评论回复
 楼主 | 2011-8-5 16:46 | 显示全部楼层
中断函数很长。。。
#include "MAIN.H"

//0-9,nul,H,L
const unsigned char Tab_Code[14]=
{
        0X48,0X7E,0X8C,0X1C,0X3A,0X19,0X09,0X7C,0X08,0X18,0XFF,0X61,0X3D,0x43
};
//数码管显示对应表
//bit7 6 5 4   3 2 1 0
//         E D P C   G B F A
//         C G D E   P F A B
//0         0 1 0 0   1 0 0 0        48               
//1         0 1 1 1   1 1 1 0        7E
//2  1 0 0 0   1 1 0 0        8C
//3  0 0 0 1   1 1 0 0        1C
//4  0 0 1 1   1 0 1 0        3A
//5  0 0 0 1   1 0 0 1        19
//6  0 0 0 0   1 0 0 1        09
//7  0 1 1 1   1 1 0 0        7C
//8  0 0 0 0   1 0 0 0        08
//9  0 0 0 1   1 0 0 0  18
//NUL1 1 1 1   1 1 1 1  FF
//H  0 1 1 0   0 0 0 1  61
//L  0 0 1 1   1 1 0 1  3D
//d  0 1 0 0   0 0 1 1  43
unsigned char zTemp;

void interrupt zint(void)
{
        static unsigned char cHang;
        static unsigned char cKey_Old;
        static bit bKey_Keep;
        static unsigned char cZero;
        static unsigned char cFlash_Time;
        unsigned char cTemp1,cTemp2;

       
    di();
        zTemp=STATUS;
       
        if(T0IF&&T0IE)
        {       
                T0IF=0;
                bMs_1=1;
        }
        //***********************************************************
        //5Ms
    if(TMR1IF)
    {
                TMR1IF=0;
                TMR1H=0XEC;
                 TMR1L=0X78;


                PORTC&=0XF4;        //关闭显示
                RB5=0;//PORTB&=0xDF;
                PORTA=0xFF;

                //=====================================================================
                //在显示前进行按键扫描
                if(cHang==2)
                {
                        RB5=1;//PORTB|=0x20;
                }
                else
                        PORTC|=(1<<cHang);

                cTemp1=(PORTC>>4);
       
                if(cTemp1)
                {
                        cZero=0;
                        if(!bKey_Keep)
                        {
                                for(cTemp2=0;cTemp2<4;cTemp2++)
                                {
                                        if(cTemp1&(1<<cTemp2))
                                        {
                                                break;
                                        }
                                }

                                cTemp1=(cHang<<2)|cTemp2;

                                if(cTemp1==cKey_Old)
                                {
                                        bKey_Ok=1;
                                        bKey_Keep=1;
                                        cKey_Val=cKey_Old;
                                }
                                else
                                {
                                        cKey_Old=cTemp1;
                                }
                        }
                }
                else
                {
                        cZero|=(1<<cHang);
                        if(cZero==0x0F)
                        {
                                cKey_Old=0;
                                bKey_Keep=0;
                        }
                }


                //-----------------------------------------------------------
                //显示数据
                if(cHang==0)
                {
                        if((cSys_State==0)&&(cFlash_Time>=FLASH_BRIGHT))
                        {
                                PORTA=0XFF;
                        }
       
                        else
                        {
                                if(bM_S)
                                        PORTA=Tab_Code[Led_Buf[cHang]]&0xF7;
                                else
                                        PORTA=Tab_Code[Led_Buf[cHang]];       
                        }
                }
                else
                {
                        if((bFlash==1)&&(cFlash_Time>=FLASH_BRIGHT))
                        {
                                PORTA=0XFF;
                        }
                        else
                        {
                                PORTA=Tab_Code[Led_Buf[cHang]];
                        }                               
                }
                //闪烁时间计数
                if((cSys_State==0)||(bFlash))
                {
                        cFlash_Time++;
                        if(cFlash_Time>=FLASH_LONG)
                        {
                                cFlash_Time=0;
                        }
                }


                //行扫描+1
                cHang++;
                if(cHang==4)
                {
                        cHang=0;
                        bMs_20=1;
                }
        }

        if((RBIF)&&(RBIE))
        {
                bRB_Ok=1;
                cRead_Portb=(~PORTB)&0X0F;
                RBIF=0;
                RBIE=0;
        }
    STATUS=zTemp;
        ei();
}

使用特权

评论回复
 楼主 | 2011-8-5 16:55 | 显示全部楼层
我用的是PICC9.8,请问这个版本的PICC不需要设置什么编译选项吧?晶振选择什么的那些都设置了。Compiler,linker,Global 都用的默认的

使用特权

评论回复
| 2011-8-5 17:26 | 显示全部楼层
中断程序问题很严重。

if(TMR1IF)


很奇怪你用了这么多年PIC,竟然不知道PIC16的中断不能这么写吗?
if(TMR1IE&&TMR1IF){}

使用特权

评论回复
 楼主 | 2011-8-5 21:17 | 显示全部楼层
因为TMR1IE一直是打开的,就不需要判断TMRIE了吧?
这个改了也不管用,不过总算找到一点规律。我的TMR0改为256uS中断一次时,上电就跑到asm("nop"),
当把TMR0的分频器改为1:32时,就是8MS中断一次时,跑飞的概率低了点,当关闭TMR0时,跑飞的概率更低,估计是与中断有关,难道是因为中断程序所占时间太长?我的系统4M晶体,我的TMR1为5MS中断一次,RB大约为20MS中断一次,时间够长了呀?主程序也没有大运算量的程序,咋能造成STATUS出错呢?

使用特权

评论回复
 楼主 | 2011-8-5 21:21 | 显示全部楼层
另外再请教一点,ICD2仿真时,TMR0不是按照程序运行的时间增加吗?比如运行一条单周期指令+1,
咋乱变呢。。

使用特权

评论回复
 楼主 | 2011-8-5 21:29 | 显示全部楼层
另外,关闭RB口中断发现程序不跑飞了。RB1是检测一个脉冲的,频率大约50HZ,在中断中读B口、做标记并且关闭RBIE,在主程序中判断标志进行计数工作,并且处理完了后打开RBIE。

使用特权

评论回复
 楼主 | 2011-8-5 21:35 | 显示全部楼层
如果B口不用中断而在主程序中检测RB1的话,程序还是跑到asm("nop")中。。。

主程序中检测RB1程序如下
                if(cSys_State<=2)
                {       
                        if(RB1!=bOld_RB1)
                        {
                                bOld_RB1=RB1;
                                if(!RB1)
                                {
                                        if(!bDir)
                                                bFor_Step=1;
                                        else
                                                bRev_Step=1;
                                }
                        }
                }

使用特权

评论回复
 楼主 | 2011-8-5 22:23 | 显示全部楼层
没办法,关掉B口中断,然后把脉冲输入到RA3口进行计数,程序还是会进入asm("nop")中。。。,看来不是RB口中断的事,改后的检测程序如下
        难道是计数程序的问题?然后去掉计数程序,单单保留检测程序,还是不行。。
检测程序如下:
        if(cSys_State<=2)
                {       
                        if(RA3!=bOld_RB1)
                        {
                                bOld_RB1=RA3;
                                if(!RA3)
                                {
                                        if(!bDir)
                                                bFor_Step=1;
                                        else
                                                bRev_Step=1;
                                }
                        }
                }

使用特权

评论回复
| 2011-8-5 23:57 | 显示全部楼层
di();
        zTemp=STATUS;


STATUS=zTemp;
        ei();

加这几句就杯具了,删掉试一试!!!!保管灵。

使用特权

评论回复
 楼主 | 2011-8-6 00:15 | 显示全部楼层
楼上的,这两句只是为了测试用的,系统保存STATUS在这之前。

反复试验,删程序,删到最后只有几句了,还是不行。程序运行不到几秒钟就进入主程序中的这一句:PORTA=0X55;//asm("nop");
我全贴出大家看看

主程序:

main.c

#include "MAIN.H"
#include "INIT.H"

bit bMs_20;

bit bRB_Ok;                                                                //RB口0-3变化中断
unsigned char cRead_Portb;                                //RB口读取值

//下面3个变量只是为了测试用,分别在TMR0 TMR1(现在关闭了)和RB口中断中+1,为了看看经过多少次中断后出错,结果发现没有什么规律。
unsigned int ERR_TMR0=0;
unsigned char ERR_TMR1=0;
unsigned char ERR_RB=0;
unsigned char ERR_T;

//void Led_Refresh(unsigned char cType,unsigned int iNum);
//*****************************************************************************
void main(void)
{
        unsigned char cTemp;
        initial();  

        ei();

        while(1)
        {
                ERR_T=1;          //ERR_T这个变量在别的函数中根本没用
                if(ERR_T>=3)
                {       
                        PORTA=0X55;//asm("nop");   //错误的进入这里
                        ERR_T=2;
                }
                ERR_T=0;

                if(bMs_20)
                {       
                        bMs_20=0;

                }
        }
}

中断程序:

#include "MAIN.H"

//0-9,nul,H,L
const unsigned char Tab_Code[14]=
{
        0X48,0X7E,0X8C,0X1C,0X3A,0X19,0X09,0X7C,0X08,0X18,0XFF,0X61,0X3D,0x43
};

void interrupt zint(void)
{
        static unsigned char cHang;

        static unsigned char cFlash_Time;


    di();

        if(T0IF&T0IE)
        {       
                T0IF=0;
                TMR0=0X0;
                if(ERR_TMR0<65535)
                ERR_TMR0++;
        }
        else if((RBIF&RBIE))
        {
                bRB_Ok=1;
                cRead_Portb=(~PORTB)&0X0F;
                RBIF=0;
                //RBIE=0;

                if(ERR_RB<255)
                ERR_RB++;
        }

        ei();
}

初始化程序:

#include "MAIN.H"

void initial(void)
{
        OPTION=0X08;    //bit.7=0 PORTB弱上拉使能
                 //BIT.6=0 RB.INT引脚下降沿触发
                 //BIT.5=0(T0CS) TMR0内部时钟
                 //BIT.4=0(T0SE) TMR0计数脉冲信号边沿选择
                 //BIT.3(PSA)=0  预分频器用于TMR0
                 //BIT.2-BIT.0 预分频器比例1:4

//        WDTCON=0x0C;
        //OSCCON=0X70;                //8M晶体设置
        /*==================================================*/
        /*输出输入端口设置*/

        /*AD管脚关闭*/
        ANSEL=0x0;         //
        ANSELH=0;

        TRISA=0X08;        //数码管段控
        PORTA=0XFF;   
       
        //        RB0-2为电机转速信号输入,RB3为脚踏开关,RB4为停止信号输出,高停止
        //        RB5为数码管位控,RB6 RB7为调试,RB6还输出蜂鸣器       
        TRISB=0X0F;                   
        PORTB=0X1F;                    //RB6 RB7 --ICD
        WPUB=0X0F;                                //RB0-RB3 按键输入弱上拉使能
        //========================================================
        //RB口变化中断
        //========================================================
        IOCB=0X0F;
        RBIF=0;
        RBIE=1;


        //RC0、1、3 为数码管位控兼按键扫描输出,
        //RC2-PWM,RC4-7按键输入
        TRISC=0XF4;//            
        PORTC=0XF4;            

        //***************************************************************
        //1ms定时,用于计算转速
        //***************************************************************
        TMR0=0;
        T0IF=0;
        T0IE=1;
       
       
        //定时扫描,5Ms定时,利用TIME1
        //***************************************************************
        T1CON=0X01; //定时模式  预分频1:1
      
        TMR1H=0XEC;
        TMR1L=0X78;

        TMR1IF=0;           //清标识位
//        TMR1IE=1;           //中断使能



        //==========================================
        PEIE=1;             //外围中断使能


}

使用特权

评论回复
 楼主 | 2011-8-6 00:16 | 显示全部楼层
还有,上面的程序当RB口没有脉冲式就不会出错。。

使用特权

评论回复
 楼主 | 2011-8-6 10:17 | 显示全部楼层
完整程序附上

V11.rar (164.51 KB, 下载次数: 18)

使用特权

评论回复
| 2011-8-6 16:04 | 显示全部楼层
都告诉你不要在中断服务代码中人工禁止或使能全局中断使能,硬件相应中断或退出中断后会自动禁止或使能全局中断,中断现场保护编译器会帮你实现,重要的寄存器如:W,STATUS。。等都会进行保护,你碰到的问题就是因为中断现场被破坏导致的!
删掉di(); 和 ei();

使用特权

评论回复
 楼主 | 2011-8-6 17:29 | 显示全部楼层
:victory:asspeed大侠。。。貌似真的好的耶!

我明天再接电机反复试验一下。。。

我都不知道我从啥时候开始中断里面加di(),ei()了,我查了查以前的程序,从06年开始用picc就这样用了。。。
以前也遇到过程序有时候乱跑的事情,最后也没找到原因。。。哎,估计真是这个原因。。。

听君一句话,胜读十年书呀!

回头研究研究为啥这两句能破坏中断现场??

使用特权

评论回复
 楼主 | 2011-8-6 17:31 | 显示全部楼层
随便补充一句,我这6年至少开发过上百款程序。。。。估计都有这个BUG。。。。但是出问题的很少,大侠知不知道何种情况下才会出问题?

使用特权

评论回复
| 2011-8-6 21:23 | 显示全部楼层
你自己想一想:
如果在中断服务函数里,当在恢复现场前,你使能了全局中断使能位,而这时又产生了一个中断,会发生什么事情呢?想明白了就清楚了。

使用特权

评论回复
 楼主 | 2011-8-6 22:19 | 显示全部楼层
哦,明白了。。。。

使用特权

评论回复
| 2011-8-7 08:21 | 显示全部楼层
picc中断里是不用再加中断禁止和打开,不过可能还有其他原因啊

使用特权

评论回复
扫描二维码,随时随地手机跟帖
您需要登录后才可以回帖 登录 | 注册

本版积分规则

我要发帖 投诉建议 创建版块 申请版主

快速回复

您需要登录后才可以回帖
登录 | 注册
高级模式

论坛热帖

在线客服 快速回复 返回顶部 返回列表