在图3-12所示电路中用4位集成式七段数码管显示按键计数值(实际仅用后3位),其中清零按键为单独定义,但连接在RB0/INT引脚的计数键未作任何定义,其识别与响应使用外部中断实现。
图3-12 INT中断计数
(一)PIC16F877A中断逻辑
PIC16F877A能够识别的中断有15个,中断内部逻辑结构如图3-13所示,其中以“F”或“IF”结尾的为中断标志位(interrupt flag bit),以“E”或“IE”结尾的为中断使能位(interrupt enable bit)。
图3-13 PIC16F877A中断逻辑示意图
由中断逻辑示意图中的“与门”与“或门”可知,要使能RB0/INT中断,需要设置INTE=1与GIE=1;如果要使能TIMER1中断,需要设置TMR1IE=1、PEIE=1及GIE=1。
(二)计数键中断响应程序设计
仿真电路中的计数按键连接在单片机RB0/INT引脚,根据PIC单片机中断逻辑,主程序中有如下核心代码:
前两行设置RB0、RB4为输入,内部上拉,其中RB0为外部中断输入。
后两句设置中断控制寄存器INTCON的GIE与INTE位,其中INTE=1使能RB0/INT外部中断,GIE=1使能所有未屏蔽中断。
OPTION_REG寄存器中的INTEDG(Interrupt Edge Select bit,中断沿选择位)用于设置上升沿触发或下降沿触发,默认值取值为0,对应于下降沿触发(源程序略去了该行代码)。
通过以上设置,RB0/INT引脚上由高到低的跳变将触发RB0/INT中断,如果按键按下后未释放,中断不会持续触发,只有释放按键后再次按下,才会因为再次出现高电平到低电平的跳变而再次触发中断,计数值仅在计数键每次重新按下时累加。
XC8编译器支持的中断服务例程格式为:
关键字interrupt表示该函数为中断函数,中断函数不能有返回值,最后面的ISR_XXX为自定义的中断函数名称。根据PIC16F877A技术手册:The Reset vector is at 0000h and the interrupt vector is at 0004h,其中断向量地址为0004H,也就是说它的所有中断共用一个中断入口地址,故而PIC单片机的中断处理函数也只有一个。在进入中断处理函数后,再通过判断中断标志位来进入不同的执行分支,例如本例中的中断函数通过if(INTF= = 1)判断“外部中断”是否被触发。
源程序对两个按键的检测与处理完全不同,具体如下。
(1)计数键:通过中断触发来识别。每次中断触发时即表示计数键按下,中断例程INT_Control_Count被自动调用,计数变量Count随之累加。
(2)清零键:通过主程序轮询判断。主程序循环调用if(KEY_CLEAR_DOWN())查看RB4引脚是否变为低电平,如果为低电平则表示清零键按下。
仿真运行时,即使按键中断例程内没有延时消抖处理,程序也能很好地运行,但在实际应用中却可能出现异常,因此要注意加入延时来消除按键抖动的影响,另外注意将中断标志位软件清零语句INTF=0放在延时语句之后,以免先清零INTF,延时期间的按键抖动再次置位INTF,使得中断程序刚完成一次处理后又旋即再次进入,导致程序运行不稳定。
对于清零按键的判断宏定义KEY_CLEAR_DOWN(),其延时消抖处理可以省略,该按键的抖动不影响清零操作。
① 修改电路和代码,用查询方式判断计数键,用中断方式控制清零键,实现相同的运行效果。
② 修改代码,测试RB0/INT上升沿触发中断的计数效果。
③ 添加4只三极管驱动数码管刷新显示。