当发生电平变化中断(外部中断)产生一个中断触发标志。然后去定时器中进行处理。
因为我当前所做的项目对运行时间要求不高,我将按键的处理放置在定时器中断中处理,如果对运行时间有要求,可以把对按键的判断放置在主程序中。例: 按键长按开关机,单击功能切换
按键长按开关机,单击功能切换
中断中处理
void isr(void) __interrupt(0)
{
if(INTFbits.PBIF) //电平变化中断与睡眠唤醒中断
{
PBIF_Trigger = 1; //中断触发标志
Flag_Time=0; //消抖清零
INTFbits.PBIF=0; //中断标志位清零
}
if(INTFbits.T0IF) //1MS定时器
{
Flag_Time++; //消抖累加
if(PBIF_Trigger)
{
if(Flag_Time>=30) //30ms消抖
{
if(!KEY_DOWN) //按键触发判断
{
Flag_Time=0; //消抖清零
Hold_Time++; //按键按下持续时间
if(Hold_Time>=60) //持续时间超过1.8S
{
Hold_Time=0; //清零
//Long_Press=1; //长按标志位,在主程序中处理
}
}
else
{
if(Hold_Time) //保持时间小于1.8S,算为单击
{
//Function_M1++; //功能切换
}
Hold_Time=0;
PBIF_Trigger=0; //中断触发标志清零
}
}
}
TMR0 = 0XC4;
INTFbits.T0IF=0;
}
}
主程序中处理
void isr(void) __interrupt(0)
{
if(INTFbits.PBIF) //电平变化中断与睡眠唤醒中断
{
PBIF_Trigger = 1; //中断触发标志
Flag_Time=0; //消抖清零
INTFbits.PBIF=0; //中断标志位清零
}
if(INTFbits.T0IF) //1MS定时器
{
Flag_Time++; //消抖累加
TMR0 = 0XC4;
INTFbits.T0IF=0;
}
}
void main()
{
Systen_Initial();
while(1)
{
if(PBIF_Trigger)
{
if(Flag_Time>=30) //30ms消抖
{
if(!KEY_DOWN) //按键触发判断
{
Flag_Time=0; //消抖清零
Hold_Time++; //按键按下持续时间
if(Hold_Time>=60) //持续时间超过1.8S
{
Hold_Time=0; //清零
if(Flag_Run_Sleep == 1)
{
Flag_Run_Sleep=0;
LED=0;
Flag_ON_OFF=0;
}
else
{
Inital_Sleep();
LED=1;
}
PBIF_Trigger=0;
}
}
else
{
if(Hold_Time) //保持时间小于1.8S,算为单击
{
//Function_M1++; //功能切换
}
Hold_Time=0;
PBIF_Trigger=0; //中断触发标志清零
}
}
}
else
Flag_Time = 0;
}
}
双击开关机
if(INTFbits.PABIF)
{
Delay_Time = 0;
// 消抖清零
Key_Delay_Time = 0;
User_Flag.PABIF_Trigger = 1;
// 中断触发标志,在定时器中断中进行处理
// 需要与进入睡眠互锁,标志不清除,进入不了睡眠,不然可能有BUG
INTFbits.PABIF = 0;
}
if(INTFbits.T0IF) // 1MS定时器
{
TMR0 = 0x09;
// 无自动重载寄存器 需要软件置位
if(User_Flag.PABIF_Trigger) //电平变化产生标志
{
Delay_Time++;
if( (Input_Key) || (User_Flag.Key_Trigger) )
// 按键按下与按键松开可进
Key_Delay_Time++;
// 只有关于按键的标志才会自增
if(Delay_Time >= 40)
// 防止充电器插拔与电池充满产生的中断,导致进入,产生误触发
{
if(Key_Delay_Time>30) // 30MS
{
if(Input_Key) // 按键按下,高有效
{
User_Flag.Key_Trigger = 1;
// 防止当按键松开时,进入不了
if(User_Flag.Key_Up_Trigger) // 是否第二次按下
{
if(User_Flag.System_Sleep)// 系统现在是在休眠还是工作
{
User_Flag.System_Sleep = 0; // 清除睡眠标志,去工作
}
else
{
User_Flag.System_Sleep = 1; // 在工作,去睡觉
}
User_Flag.Key_Up_Trigger = 0;
// 标志触发过,清除
User_Flag.System_Stuta_Change = 1;
// 防止系统把第二次按键松开,判断为第一次按键松开
// 需要与进入睡眠互锁,标志不清除,进入不了睡眠,不然可能有BUG
}
}
else
{
if(User_Flag.System_Stuta_Change)
// 第二次按键松开 跳过
User_Flag.System_Stuta_Change=0;
else
{
User_Flag.Key_Up_Trigger = 1;
// 第一次按键松开标志
// 需要与进入睡眠互锁,标志不清除,进入不了睡眠,不然可能有BUG
Double_Click_Waiting = 0;
// 开始计数 第一次按键松开400MS内,无再触发,判断为无效
}
User_Flag.Key_Trigger = 0;
// 按下一次置一一次,松开一次执行一次清零一次
}
}
User_Flag.PABIF_Trigger = 0;
// 程序执行完毕,清零
Key_Delay_Time = 0; // 清零,等待下次计时
Delay_Time = 0;
}
}
if(User_Flag.Key_Up_Trigger) // 按键第一次松开后,等待第二次按键按下
{
Double_Click_Waiting++;
if(Double_Click_Waiting >= 400) // 标志位有效时间400ms
{
Double_Click_Waiting = 0;
User_Flag.Key_Up_Trigger = 0;
}
}
INTFbits.T0IF = 0; // 中断标志位软件清零
}
单击开关机,功能切换
void isr(void) __interrupt(0)
{
if(INTFbits.PBIF)
{
User_Flag.PBIF_Trigger=1; //中断触发标志
Key_Delay_Time=0; //消抖清零
INTFbits.PBIF = 0; // Clear PBIF(PortB input change interrupt flag bit)
}
if(INTFbits.T0IF) //2ms定时器中断
{
//PWM_Standard++; //模拟PWM
Key_Delay_Time++;
if(User_Flag.PBIF_Trigger)
{
if(Key_Delay_Time>12) //24ms消抖
{
if(!KEY_DOWN_Input) //按键低有效
{
//User_Flag.System_Standby=0; //退出睡眠模式
//User_Flag.Function_Switch++; //功能切换
//PWM_Duty_Cycle=0; //可能可以不写
//PWM_Standard=0; //基准清零,不写会导致第一个周期偏短
//User_Flag.Variate_ADD=1; //循环周期增加标志
//User_Flag.Sound_Trigger=1; //咪头触发标志,切换到模式3时,自动触发一次输出
}
Key_Delay_Time=0; //消抖清零
User_Flag.PBIF_Trigger=0; //清除中断触发标志
}
}
TMR0 = 0X81;
INTFbits.T0IF = 0; // 清除定时器0中断标志位
}
}
两个按键控制同一个LED
KEY_1: 0:空 1:声控模式 2~n:进入睡眠模式 KEY_2: 0:空 1:常亮 2:炫彩呼吸灯 3~n:进入睡眠模式
单击唤醒 单击切换功能
屏蔽一个按键按下不松开,导致当另一个按键按下产生误触发。
void isr(void) __interrupt(0)
{
if(INTFbits.PABIF) //电平变化中断与睡眠唤醒中断
{
Key_Delay_Time=0; //按键消抖时间清零
PABIF_Trigger=1; //中断触发标志
INTFbits.PABIF = 0; // 清除中断标志位
}
if(INTFbits.T0IF) //4ms定时器中断
{
if(PABIF_Trigger) //如果不在中断,可以换成按键输入引脚
{
Key_Delay_Time++;
if(Key_Delay_Time>5) //20ms消抖
{
if(!Input_KEY_2) //KEY_2是否按下 正常模式
{
if((KEY_1_FLAG)&&(KEY_2_FLAG)) //任意一个按键是否按下后未松开
{
//System_Standby=0; //退出睡眠模式,防止程序未处理完,就进入睡眠模式,使程序卡死
//Function_Switch_1=0; //声控模式不执行
//Function_Switch++; //模式切换 0:空 1:常亮 2:炫彩呼吸灯 3~n:进入睡眠模式
}
KEY_2_FLAG=0; //按键按下标志
}
else
KEY_2_FLAG=1; //按键松开
}
if(Key_Delay_Time>5) //消抖。在我这个编译器中,不能和上面消抖合并。会导致程序出错 {
if(!Input_KEY_1) //KEY_1 声控模式
{
if((KEY_1_FLAG)&&(KEY_2_FLAG)) //任意一个按键是否按下后未松开
{
//System_Standby=0; //退出睡眠模式
//Mic_Trigger=0; //声音触发标志位清零
//Function_Switch=0; //正常模式不执行
//Function_Switch_1++; //模式切换 0:空 1:声控模式 2~n:进入睡眠模式
}
KEY_1_FLAG=0; //按键按下
}
else
KEY_1_FLAG=1; //按键松开
Key_Delay_Time=0; //消抖清零
PABIF_Trigger=0; //清除电平变化触发标志
}
}
TMR0 = 0X00;
INTFbits.T0IF = 0; // Clear PBIF(PortB input change interrupt flag bit)
}
}