切换时钟后仍有较长时间运行在原时钟频率上是怎么回事

2019-03-25 18:48发布

我是用PIC16F1937,功能上基本是AD采集数据然后处理并段码液晶显示,另外还要检测两个按键。
程序中是使用2个内部时钟,一个4M的HF,一个31K的LF,想法是根据LF来设定定时器0为20ms中断,中断函数中检测按键并计数25次(即定时500ms),500ms到了之后把标志位display_flag置1,然后禁止定时器0中断。
主函数中一直在检测display_flag是否为1,如果为1则切换时钟到4M,然后AD检测并处理然后显示,然后切换到低速时钟并把display_flag清零并允许定时器0中断,然后继续循环检测display_flag为1。
实际在中断服务函数中设置端口翻转并示波器检测发现有时候是20ms,有时候确是160us。而且us级的波形每次都出现十几次翻转,表明是在4M时钟的情况下多次进入中断。。。。
以下附上相关代码:
1.初始化
void Timer0Init(void)//内部时钟定时方式
{
        OPTION_REG = (OPTION_REG & 0xC0) | 0x10; // Fosc/4时钟,分频器 1/2
    TMR0 = 0xB2;// 178;
    timer0ReloadVal= 178;//定时时间=19.97ms
    INTCONbits.TMR0IF = 0;//清除中断标志位   
}

2.主函数中
        while(1)
        {
                CLRWDT();                                                                //看门狗复位(喂狗)               
                if((WorkOnFlag)&&(display_flag==1))        //延时结束,WorkOnFlag一般为1
                {
                   display_flag=0;       
LED2_SetHigh();   
                   SystemCrystalSet_H_Speed();        //切换到高速时钟
                   AD_deal_AND_Display();
                   Key_Deal();
                   Display();                                        //显示程序
                   SystemCrystalSet_L_Speed();        //切换到低速时钟
LED2_SetLow();
                   INTCONbits.TMR0IE=1;//开启TIM0中断                
                }       
      }
       

3.时钟切换函数
void SystemCrystalSet_H_Speed(void)
{
    OSCCON = 0b01101000;// 禁止 4x PLL; 0111 =500KHz HF;内部振荡器模块;//0x63;//2M  01011010  1101为4M
    OSCTUNE = 0x00;// 振荡器调节寄存器TUN<5:0>=00000:振荡器模块以厂家校准后的频率运行;
        while(!HFIOFR); //中频内部振荡器就绪位
}

void SystemCrystalSet_L_Speed(void)
{
    OSCCON = 0b00000000;// 禁止 4x PLL; 0111 =500KHz HF;内部振荡器模块;//0x63;//2M  01011010  1101为4M   
        while(HFIOFR); //中频内部振荡器就绪位
}


4.定时器0服务函数
void TMR0_ISR(void)
{           
        INTCONbits.TMR0IF = 0;                        //clear the TMR0 interrupt flag
        TMR0 += timer0ReloadVal;                //中断一次20MS
        //LED2_Toggle();                        //端口翻转
        ++AlarmNum;                                                //报警灯闪烁时间
        if(AlarmNum>=252)
        {AlarmNum = 0;}

        if((WorkOnFlag) && (!CheckStFlag))        //延时结束
        {KeyScan();        }
       
        if(++T0_Count > 25)                                //中断次数 0.5s执行一次
        {   
                T0_Count = 0;
                display_flag=1;       
                if((WorkOnFlag) && (!CheckStFlag))        //延时结束
                {INTCONbits.TMR0IE=0;}//关闭TIM0中断
        }       
}


5.端口控制相关代码
#define LED2_SetHigh()    do { LATD2 = 1; } while(0)
#define LED2_SetLow()   do { LATD2 = 0; } while(0)
#define LED2_Toggle()   do { LATD2 = ~LATD2; } while(0)


理论应该是一个高电平脉冲紧跟着500ms左右的低电平,然后再来一个高电平脉冲,然后再是500ms低电平才对。
下图是看不懂的示波器图像,在密集的脉冲之间的低电平大概是20ms左右,猜测应该是4M主频下中断25次的时间。。。
IMG_20170831_162822.jpg IMG_20170831_162833.jpg

请各位帮忙看看哪里不对的啊?
此帖出自小平头技术问答
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。