一、先前知识
使用到的74HC138译码器、74HC573锁存器、LED灯模块和独立按键模块等,在前面的基础模块的介绍中都有简单介绍,这里就不再介绍了。
按键之外部中断
蓝桥杯板子上按键部分的右下角有个J5模块,用跳帽来进行独立按键和矩阵键盘之间的切换。此次使用矩阵键盘的时候需要把跳帽接到2~3引脚。
蓝桥杯板子上外部中断的引脚是P3^2(INT0)和P3^1(INT1),因此需要把按键部分的跳帽接到2~3引脚来构成独立按键。
![](https://img-blog.csdnimg.cn/img_convert/3bda1f7415d14c548d849aa6e7caa494.png)
图一、按键模块
中断的相关基础概念的简单介绍
内核与外设之间的主要交互方式有两种:轮询和中断。轮询的方式看似很公平,所有的都兼顾到,但是实际工作效率很低,且不能及时响应紧急事件;而中断系统使得内核具备了应对突发事件的能力。比如:你正在家里做饭,这时突然有电话打了过来,如果按照轮询来说,那么你就必须炒完菜之后再去接电话;按照中断来说,那么你这时遇到了有电话进来的紧急情况,就先去处理完电话的事务再继续按照计划炒菜。
在执行CPU当前程序时,由于系统中出现了某种急需处理的情况,CPU暂停正在执行的程序,转而去执行另外一段特殊程序来处理出现的紧急事务,处理结束之后,CPU自动返回到原来暂停的程序中去继续执行。这种程序在执行过程中由于外界的原因而被中间打断的情况,称之为中断。
中断服务函数:内核响应中断后执行的相应处理程序。
中断向量:中断服务程序的入口地址。每个中断源都对应一个固定的入口地址。当内核响应中断请求时,就会暂停当前的程序执行,然后跳转到该入口地址执行代码。注意,请求不一定能够进中断,必须要打开中断之后,请求才能响应。
外部中断用到的寄存器
每个中断源都对应着一个固定的入口地址,也就是中断向量,它们分别是:
0 0x0003: INT0
1 0x000B: TF0
2 0x0013: INT1
3 0x001B: TF1
4 0x0023: RI/TI
![](https://img-blog.csdnimg.cn/img_convert/6c8693c3fc6d4cb9a1105ca0a3a9c8a0.png)
图二、IE寄存器
![](https://img-blog.csdnimg.cn/img_convert/f836f80293674ad29b0c78a6d0df452c.png)
图三、IP寄存器
![](https://img-blog.csdnimg.cn/img_convert/5d3404addb5d4641af65037a14d5b993.png)
图四、TCON寄存器
![](https://img-blog.csdnimg.cn/img_convert/5f0750af09cd43ad9b20a90d5aee2d3f.png)
图五、SCON寄存器
总开关,总中断EA,只有当总中断EA接上之后,同时相应的中断EX0、ET0等也接上,外部中断才能控制内核。
![](https://img-blog.csdnimg.cn/img_convert/265909f5c39f47a7891bb93a3ef97939.jpeg)
图六、中断寄存器的顺序
关于中断服务函数程序的编写
一般情况下,中断的处理函数有两个,其一为中断初始化函数,其二为中断服务函数。并且初始化函数要放在主函数的里面while(1)的外面,服务函数不需要放在主函数里,需要用到时会直接跳转到中断服务函数。
初始化函数就是一个普通的函数,而中断服务函数有着特殊的格式:
①中断函数没有返回值,也不能对其输入参数;
②函数名后面要跟一个关键字“interrupt”,说明这是一个中断服务函数;
③在关键字“interrupt”后面要跟上中断号,说明这个中断服务函数是为哪个中断服务的。
例如:void 函数名() interrupt 中断号
以上关于中断的介绍并不像书上以及老师们讲的那么专业,都只是本人学习过程中的理解总结而已。如果读者想要了解的更完整、更精细,可以查看相关方面的书和资料。也欢迎各位给我提出意见。
二、模块控制实现过程简述
先把按键的跳帽接到2~3引脚上,然后定义所用到的引脚,再进行控制。要控制LED模块,就需要先往74HC138译码器中写入二进制数100(十进制数为4),输出就是Y4为低电平,经过一个或非门输出的Y4C就为高电平,再输入74HC573锁存器。然后控制LED灯的点亮。
三、所要实现的功能
L1指示灯不停闪烁,按键S5(外部中断INT0引脚所接)按下后会产生外部中断信号,响应后L8指示灯点亮延时一段时间后再熄灭。程序循环实现上述功能。
四、代码实现
①引脚定义
// 引脚定义
sbit INT0 = P3^2;
②138译码器通道选择函数
// 通道选择函数
void HC138_Init( unsigned char channel )
{
switch( channel )
{
case 0:
P2 = ( P2 & 0x1f ) | 0x00; // 0
break;
case 4:
P2 = ( P2 & 0x1f ) | 0x80; // Y4C
break;
case 5:
P2 = ( P2 & 0x1f ) | 0xa0; // Y5C
break;
case 6:
P2 = ( P2 & 0x1f ) | 0xc0; // Y6C
break;
case 7:
P2 = ( P2 & 0x1f ) | 0xe0; // Y7C
break;
}
}
③初始化系统-关闭目前不需要的蜂鸣器和继电器
// 系统初始化
void Init_System(void)
{
// 关闭LED灯
HC138_Init( 4 );
P0 = 0xff;
// 关闭蜂鸣器和继电器
HC138_Init( 5 );
P0 = 0xaf; // 1010 1111
HC138_Init( 0 ); // 关闭通道选择
P0 = 0xff;
}
④外部中断0初始化函数
// 外部中断0初始化函数
void INT0_Init(void)
{
IT0 = 1; // 下降沿有效
EX0 = 1; // 打开IE中断控制寄存器
EA = 1; // 打开总中断开关
}
⑤外部中断0服务函数
// 外部中断0服务函数
void INT0_Service() interrupt 0
{
P0 = ( P0 & 0x7f ) | 0x00; // L8亮
Delay_tms( 10000 );
P0 = ( P0 & 0x7f ) | 0x80; // L8灭
Delay_tms( 10000 );
}
⑥控制L1闪烁的函数
// 控制L1闪烁
void LED_Control(void)
{
HC138_Init( 4 );
P0 = ( P0 & 0xfe ) | 0x00; // 亮
Delay_tms( 2000 );
P0 = ( P0 & 0xfe ) | 0x01; // 灭
Delay_tms( 2000 );
}
⑦延时函数
void Delay_tms( unsigned int t )
{
int i;
while( t-- )
{
for( i=115 ; i>0 ; i-- )
{
}
}
}
⑧整个函数展示
#include <STC15F2K60S2.H>
#include "Delay_ms.h"
// 引脚定义
sbit INT0 = P3^2;
// 通道选择函数
void HC138_Init( unsigned char channel )
{
switch( channel )
{
case 0:
P2 = ( P2 & 0x1f ) | 0x00; // 0
break;
case 4:
P2 = ( P2 & 0x1f ) | 0x80; // Y4C
break;
case 5:
P2 = ( P2 & 0x1f ) | 0xa0; // Y5C
break;
case 6:
P2 = ( P2 & 0x1f ) | 0xc0; // Y6C
break;
case 7:
P2 = ( P2 & 0x1f ) | 0xe0; // Y7C
break;
}
}
// 系统初始化
void Init_System(void)
{
// 关闭LED灯
HC138_Init( 4 );
P0 = 0xff;
// 关闭蜂鸣器和继电器
HC138_Init( 5 );
P0 = 0xaf; // 1010 1111
HC138_Init( 0 ); // 关闭通道选择
P0 = 0xff;
}
// 外部中断0初始化函数
void INT0_Init(void)
{
IT0 = 1; // 下降沿有效
EX0 = 1; // 打开IE中断控制寄存器
EA = 1; // 打开总中断开关
}
// 外部中断0服务函数
void INT0_Service() interrupt 0
{
P0 = ( P0 & 0x7f ) | 0x00; // L8亮
Delay_tms( 10000 );
P0 = ( P0 & 0x7f ) | 0x80; // L8灭
Delay_tms( 10000 );
}
// 控制L1闪烁
void LED_Control(void)
{
HC138_Init( 4 );
P0 = ( P0 & 0xfe ) | 0x00; // 亮
Delay_tms( 2000 );
P0 = ( P0 & 0xfe ) | 0x01; // 灭
Delay_tms( 2000 );
}
int main(void)
{
Init_System(); // 系统初始化
INT0_Init(); // 外部中断0初始化
while(1)
{
LED_Control(); // 控制L1点亮
}
}
五、运行图片
![](https://img-blog.csdnimg.cn/img_convert/2982db65dcdd41449cd1b3d6eaa43ccc.jpeg)