注:板子:MSP430F5529 开发环境:CCSv5
上一篇博文发了按键中断的例程和详细的注释,但是好像把程序烧进单片机之后执行效果并不是很好:每按一次按键灯的状态不一定只改变一次,有时灯本来是亮的,按一次后还是亮的;或者按下去之后灯灭了,按键抬起来之后灯又亮了。
造成该现象的原因就是按键的抖动问题。
按键的抖动一般是机械性抖动,当开关断开或闭合时接触点处不会一下子接通也不会一下子断开,而是会产生轻微的抖动导致电路的多次接通和断开,这个过程大致会持续5ms-10ms。想像一下如果中断程序是瞬间完成的,那么接触点每抖动一下都会引起一次中断,所以就会引起按下按键后灯的状态改变次数是不确定的,也就是效果和我们的预期不一致;由于按下和抬起时都会有抖动产生,所以就会出现按下去灯灭,抬起来灯亮的情况。
知道了抖动产生的原因,我们就可以思考解决的办法了。
1、延时消抖
很显然如果中断的反应不要那么快,是不是就可以避免这个问题了呢?那么有一个办法就是把中断程序的执行时间延长,让中断执行的慢一点,这样在第一次触发中断后cpu去执行中断程序,当抖动引发的中断请求发出时中断标志位IFG已经被置位所以这些中断请求相当于被覆盖掉了,从而达到消抖的目的。
于是我们的中断程序为
#pragma vector = PORT2_VECTOR
__interrupt void Port_2 () {
__delay_cycles(10000); //延时消抖 所传递参数为cpu周期
P1OUT |= BIT0;
}
似乎是可以的,设置按键下降沿触发中断,按下后避过抖动时间然后改变灯的状态,但是还有按键抬起呢?抬起时的抖动一样会触发中断,这时我们可以加一条语句
#pragma vector = PORT2_VECTOR
__interrupt void Port_2 () {
__delay_cycles(10000); //延时消抖 所传递参数为cpu周期
if((P2IN & BIT1)==0) {
P1OUT ^= BIT0;
}
P2IFG &= ~BIT1;
}
判断延时后按键处于按下状态时才改变灯的状态,否则就不变。
如果想上升沿触发中断的话就改一下判断条件就好了。
2、利用定时器
还有一个办法,就是不用按键去触发中断,而是定时检测按键的状态。
当按键按下后,电平状态为 高—低—高,那么我们就去不停的检测按键的电平状态,若发现电平由高变低,那么改变灯的状态就好了。
利用定时器,每隔10ms左右(可调整)去检测按键电平,用两个变量分别记录上一次的状态和本次的状态,发现符合条件就改变灯的状态。
具体实现如下:
#include
int main(void) {
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
P1DIR |= BIT0;
P2DIR &= ~BIT1;
P2OUT |= BIT1;
P2REN |= BIT1;
TA0CTL |= TASSEL_1 + MC_1 + TAIE + TACLR;
TA0CCR0 = 32;
__bis_SR_register(LPM4_bits + GIE);
return 0;
}
#pragma vector=TIMER0_A1_VECTOR
__interrupt void TIMER0_A1_ISR() {
static unsigned char key_now=0;
unsigned char key_past=0;
key_past=key_now;
if(P2IN & BIT1) key_now=1;
else key_now=0;
if(key_now==0&&key_past==1) P1OUT ^= BIT0;
TA0CTL &= ~TAIFG;
}
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』