一、什么是中断
中断是单片机用来实时处理外部/内部随机事件的重要机制。
通俗理解:CPU正在做A任务,突然来了紧急事件B,CPU暂停A,转去处理B,B处理完毕,回到A任务断点继续执行。
生活类比:你正在洗衣服(主程序while循环),水壶烧开(中断事件),停下洗衣服,关火倒水(中断服务函数),处理完继续回去洗衣服。
轮询按键的痛点
如果主循环内部有长时间延时,例如delay_ms(20000);延时20秒。在延时期间按下按键,程序无法捕捉按键动作,按键信号直接丢失 。
中断可以解决这个痛点:无论CPU正在执行什么代码,只要中断事件触发,立刻跳转到中断服务函数处理。
二、硬件接线说明(P3.2‑INT0按键)
开发板硬件:
- INT0 → P3.2,外接独立按键KEY1
- 按键电路:4.7K上拉,松开:高电平;按下:低电平
- LED指示灯:
P2.7,低电平点亮
实验目标:按下P3.2按键触发外部中断0,翻转LED亮灭状态。
三、STC89C52RC中断源
STC89C5X一共有8个中断请求源:
- 外部中断0 INT0(P3.2)
- 外部中断1 INT1(P3.3)
- 外部中断2 INT2(P4.2)
- 外部中断3 INT3(P4.3)
- 定时器0中断T0
- 定时器1中断T1
- 定时器2中断T2
- 串口UART中断
分类:
- 外部中断:外部引脚电平变化触发
- 定时器中断:单片机内部定时器计数溢出触发
- 串口中断:串口完成接收/发送一帧数据触发
本章重点讲解外部中断0(P3.2/INT0)
四、中断相关寄存器
1.IE 中断允许寄存器(A8H)
| 位 | 符号 | 功能 |
|---|---|---|
| IE.7 | EA | 全局总中断开关,EA=1开启所有中断总开关 |
| IE.0 | EX0 | 外部中断0使能位,EX0=1开启INT0(P3.2) |
| IE.1 | ET0 | 定时器0中断使能 |
| IE.2 | EX1 | 外部中断1使能 |
| IE.3 | ET1 | 定时器1中断使能 |
| IE.4 | ES | 串口中断使能 |
✅开启外部中断0三步:
- 设置触发方式
IT0 - 打开INT0中断使能
EX0 = 1 - 打开全局总中断
EA = 1
2.TCON寄存器(88H)
IT0:外部中断0触发方式
IT0=0:低电平触发IT0=1:下降沿触发(推荐,按键首选)
下降沿含义:引脚电平 高 → 低 跳变,正好对应按键按下瞬间。
IE0:外部中断0中断请求标志,中断响应后硬件自动清零。
3.XICON辅助中断控制寄存器(C0H)
用于STC扩展的外部中断2、外部中断3(INT2、INT3)。标准reg52.h头文件没有定义该寄存器。
4.IP、IPH中断优先级寄存器
- IP:中断优先级低位
- IPH:中断优先级高位
⚠️IPH寄存器不可位寻址!不能写PX0H = 1;只能整体字节赋值
IPH = 0x01;
优先级规则:
- 高优先级中断可以打断低优先级中断,实现中断嵌套;
- 低优先级不能打断高优先级;
- 相同优先级同时触发,按照硬件查询次序响应。
五、中断服务函数语法
Keil C51扩展关键字interrupt,后面跟中断号,代表对应中断源。
c
void 函数名(void) interrupt 中断号
{
//中断处理逻辑
}
STC89C52RC中断号对照表
| 中断源 | 中断号 | 引脚 |
|---|---|---|
| INT0外部中断0 | 0 | P3.2 |
| T0定时器0 | 1 | --- |
| INT1外部中断1 | 2 | P3.3 |
| T1定时器1 | 3 | --- |
| UART串口 | 4 | --- |
| T2定时器2 | 5 | --- |
| INT2外部中断2 | 6 | P4.2 |
| INT3外部中断3 | 7 | P4.3 |
注意:中断服务函数不能有返回值,不能带形参。不要在中断里面写长延时、复杂运算。
六、完整可编译代码
版本1:最简版(基础功能,无消抖)
c
#include <reg52.h>
//STC扩展寄存器
sfr XICON = 0xC0;
sfr P4 = 0xE8;
sfr IPH = 0xB7;
sbit led1 = P2^7;
// KEY 直接硬件绑定 P3.2(INT0引脚),不需要额外sbit定义
// INT0硬件引脚固定 P3.2
//外部中断0初始化
void Int0_Init(void)
{
IT0 = 1; //下降沿触发 (高电平变低电平,按键按下)
EX0 = 1; //使能外部中断0(P3.2)
EA = 1; //打开全局总中断
}
//外部中断0中断服务函数,中断号0
void Int0_ISR(void) interrupt 0
{
led1 = ~led1; //翻转LED
}
void main(void)
{
Int0_Init();
while(1)
{
//主循环可以运行别的任务,不会阻塞按键
}
}
解释:INT0是硬件功能,P3.2引脚硬件默认绑定外部中断0 ,不需要
sbit key = P3^2读取电平;只要引脚检测到下降沿,自动触发中断。缺点:机械按键抖动,可能一次按下触发多次中断
版本2:工程可用版(中断内部软件消抖)
c
#include <reg52.h>
sfr XICON = 0xC0;
sfr P4 = 0xE8;
sfr IPH = 0xB7;
sbit led1 = P2^7;
sbit key_int0 = P3^2; //显式定义INT0按键引脚,代码可读性更好
//12M晶振毫秒延时
void delay_ms(unsigned int xms)
{
unsigned int i,j;
for(i = xms; i > 0; i--)
for(j = 124; j > 0; j--);
}
//外部中断0初始化
void Int0_Init(void)
{
IT0 = 1;
EX0 = 1;
EA = 1;
}
//中断服务函数
void Int0_ISR(void) interrupt 0
{
delay_ms(10); //延时消抖
if(key_int0 == 0) //再次确认引脚确实是低电平,按键按下
{
led1 = ~led1;
while(key_int0 == 0); //等待松开按键,避免长按反复触发
}
}
void main(void)
{
Int0_Init();
while(1)
{
}
}
✅这份代码完整体现P3.2按键:
sbit key_int0 = P3^2显式定义按键引脚- IT0=1配置下降沿触发(P3.2由高变低,按键按下)
- 中断进来之后再次读取
P3.2引脚电平做消抖校验
七、开发注意事项
- INT0硬件固定引脚为P3.2,INT1固定P3.3;不需要IO口手动轮询,硬件自动检测电平跳变。
- 机械按键抖动会导致单次按键多次进中断,实际项目必须增加软件消抖。
- 中断里面延时函数不宜过长,复杂业务逻辑尽量放主循环,中断内只做标志位。
- IPH寄存器不能位操作,只能直接字节赋值。
- 下降沿触发适合机械按键;电平触发容易重复触发。
八、本章小结
- INT0硬件引脚固定映射
P3.2,配置好寄存器之后引脚电平跳变自动触发中断。 - 使用外部中断0:开启全局中断EA,开启EX0,配置IT0触发方式。
- 中断函数
interrupt 0对应P3.2外部中断0。 - 机械按键必须消抖,否则会出现按一次LED翻转多次。