|
傻孩子大侠书中【实例七】中断唤醒的键盘扫描,P109页,说到 “这个实例还有一个遗留的问题需要大家注意:如果去掉中断服务函数中“PCMSK1&=(~((1<<PCINT11)|(1<<PCINT10)|(1<<PCINT9)));”一句,键盘将只能被唤醒1次。据说DA895在这个问题上找了半天,在这里我们不打算详细分析,把这个问题留给读者思考。”
pragma interrupt_handler pcint1_isr: iv_PCINT1
void pcint1_isr(void) //引脚电平变化中断PCINT1中断服务函数
{
SMCR&=0xFE; //禁止休眠功能,以免误触发
//PCMSK1&=(~((1<<PCINT11)|(1<<PCINT10)|(1<<PCINT9))); //禁止引脚电平变化中断,以免影响键盘扫描程序的运行 (把这一行注释掉)
PCICR&=(~(1<<PCIE1));
}
void main (void)
{
unsigned char KeyValue=NoKey;
unsigned int SleepTimer=0;
DDRC=0xF1; //将键盘的"行"设置为输出,键盘的"列"设置为输入并开启了输入端的内部上拉电阻
DDRB=0xFF;
DDRD=0xFF;
PORTC=0xFF;
PORTB=0xFF;
PORTD=0xFF;
SEI(); //允许全局中断
LedDisPort=DisTab[0]; //上电后初始化显示"0"
while(1)
{
KeyValue=Key_Scan_Ant_Dither();
if (KeyValue!=NoKey) //当有按键按下时,显示该键的键值
{
LedDisPort=DisTab[KeyValue];
SleepTimer=0; //并清0休眠计时器
}
else //当没有按键按下时,计算连续未操作的时间
{
SleepTimer++; //休眠计时器自加以实现计时
if (SleepTimer >= 1500) //当连续3秒钟(近似值)没有按任何按键时,将进入休眠状态
{
SleepTimer=0; //清0休眠计时器,以便唤醒后继续计时
PORTC=0b11001111; //将键盘的行(PC5,PC4)设置为输出"0"状态
PORTD=0x00; //关闭数码管显示驱动以节省电能
PCMSK1|=((1<<PCINT11)|(1<<PCINT10)|(1<<PCINT9)); //使能PCINT9..11
PCICR|=(1<<PCIE1); //使能第一组引脚电平变化中断
SMCR=0x05; //设置掉电状态并使能休眠功能
asm("SLEEP"); //休眠单片机,进入掉电状态
PORTC=0xFF; //休眠唤醒后将PC端口重置回初始化状态
}
} //End Of Else
} //End Of While
}
键盘只能唤醒一次?我感觉有点疑问:
1. 在第一次中断唤醒后,虽然PCMSK1中的电平变化中断没有被屏蔽掉,但是在 PCICR&=(~(1<<PCIE1)) 后, PCIE1(PCINT8-14端口的总开关)是掉的,故即使唤醒后的,键盘操作(PC1,PC2,PC3输入)或端口(PORT PC4,PC5输出变化)引起的电平也不会使得再次进入电平变化中断服务程序。
除非把 PCICR&=(~(1<<PCIE1));也去掉,每次按键或PORTC的电平变化都将引起中断,从而影响程序的正常运行而已。
2.我在Protues中仿真试过,后续唤醒仍然是有效的。(并不是只能唤醒一次) |
|