51单片机基础-外部中断INT

第十三章 外部中断

1. 导入

在前几章中,我们通过轮询方式检测按键、控制电机等,但这种方式占用CPU资源,且响应不及时。为实现快速响应外部事件 (如紧急停止、按键触发),本章引入外部中断功能。

51单片机提供两个外部中断源:INT0 (P3.2)和 INT1(P3.3),当引脚电平发生变化时,可立即暂停当前程序,执行中断服务程序,处理完后再返回原任务。

本章目标:

  • 理解中断的基本概念与工作流程;
  • 掌握51单片机外部中断的触发方式;
  • 配置INT0和INT1为下降沿或低电平触发;
  • 实现按键通过中断控制LED或电机;
  • 为后续学习实时系统、事件驱动编程打下基础。

2. 硬件设计

2.1 中断引脚

中断源 对应引脚 特殊功能
INT0 P3.2 外部中断0
INT1 P3.3 外部中断1

2.2 典型电路(以INT0为例)

  • 按键K1一端接地;
  • 另一端接P3.2(INT0);
  • P3.2内部有上拉电阻,可省略外部上拉;
  • 按下按键时,P3.2变为低电平,触发中断。

建议添加100nF电容接地,进行硬件消抖(虽软件仍需处理)。


3. 软件设计

3.1 中断相关寄存器

51单片机通过以下寄存器控制中断:

寄存器 位 说明
TCON IT0(TCON.0) INT0触发方式:0=低电平触发,1=下降沿触发
IE0(TCON.1) INT0中断标志,自动置1,中断响应后自动清零
IT1(TCON.2) INT1触发方式
IE1(TCON.3) INT1中断标志
IE EX0(IE.0) 允许INT0中断
EX1(IE.1) 允许INT1中断
EA(IE.7) 总中断使能

3.2 中断初始化函数

c 复制代码
#include <reg52.h>

sbit LED = P1^0;

void exti0_init() {
    IT0 = 1;    // 下降沿触发(推荐,避免重复触发)
    EX0 = 1;    // 使能INT0中断
    EA  = 1;    // 开启总中断
}

// 外部中断0服务程序
void int0_isr() interrupt 0 {
    LED = ~LED;  // 每次中断翻转LED
}

interrupt 0 表示这是外部中断0的中断服务函数(INT0的中断号为0)。


3.3 完整示例:按键中断控制LED

c 复制代码
#include <reg52.h>

sbit LED = P1^0;

void delay_ms(unsigned int ms) {
    unsigned int i, j;
    for (i = 0; i < ms; i++)
        for (j = 0; j < 125; j++);
}

void exti0_init() {
    IT0 = 1;  // 下降沿触发
    EX0 = 1;  // 使能INT0
    EA  = 1;  // 全局中断开启
}

void main() {
    LED = 0;  // 初始LED亮
    exti0_init();
    while(1) {
        // 主程序可执行其他任务
        // 如:电机控制、显示刷新等
    }
}

// 外部中断0服务函数
void int0_isr() interrupt 0 {
    delay_ms(10);           // 软件消抖
    if (P3 & 0x04) == 0) {  // 再次确认P3.2为低(按键按下)
        LED = ~LED;
    }
    // IE0由硬件自动清零
}

3.4 外部中断1(INT1)示例

c 复制代码
void exti1_init() {
    IT1 = 1;  // 下降沿触发
    EX1 = 1;  // 使能INT1
    EA  = 1;
}

void main() {
    exti1_init();
    while(1);
}

// 外部中断1服务函数
void int1_isr() interrupt 2 {
    // INT1的中断号为2
    P1 = 0x00;  // 触发后关闭所有输出(如紧急停止)
}

3.5 中断触发方式对比

触发方式 配置 特点
低电平触发 IT0=0 只要为低就触发,可能重复触发
下降沿触发 IT0=1 仅在高→低跳变时触发一次,推荐使用

推荐使用下降沿触发,配合软件消抖,避免误触发。


3.6 应用:紧急停止电机

假设电机正在运行,通过INT1实现紧急停止:

c 复制代码
sbit IN1 = P2^0;
sbit IN2 = P2^1;
sbit ENA = P2^2;

void motor_stop() {
    IN1 = 0; IN2 = 0; ENA = 1;
}

void exti1_init() {
    IT1 = 1;
    EX1 = 1;
    EA  = 1;
}

void main() {
    // 启动电机正转
    IN1 = 1; IN2 = 0; ENA = 1;
    exti1_init();
    while(1);
}

void int1_isr() interrupt 2 {
    motor_stop();  // 紧急停止
}

按键接P3.3,按下后立即停止电机,响应速度快。


3.7 编译与下载

  • Keil中创建工程;
  • 确保按键接P3.2或P3.3;
  • 编译生成HEX;
  • 下载至单片机;
  • 按下按键,观察是否立即响应。

若中断不触发:

  • 检查EA、EX0/EX1是否开启;
  • 确认IT0/IT1设置正确;
  • 检查按键是否接地,引脚是否为低电平。

4. 小结

本章通过引入外部中断,掌握了事件驱动编程的核心技术,主要内容包括:

  • 中断机制:理解中断的触发、响应与返回过程;
  • 寄存器配置:掌握TCON、IE等关键寄存器的设置;
  • 软件实现:编写中断服务程序,实现快速响应;
  • 应用场景:用于按键检测、紧急停止、实时控制;
  • 系统优化:解放主程序,提高响应速度与系统稳定性。

4.1 常见问题与解决

问题 原因 解决方法
中断不响应 EA未开启或EX0=0 检查中断使能设置
多次触发 未消抖或使用低电平触发 改为下降沿触发 + 软件消抖
程序跑飞 中断函数中使用长延时或递归 中断函数应短小精悍
标志未清 一般由硬件自动清零 不建议手动清除IE0/IE1

4.2 下一步学习建议

  • 结合定时器中断实现多任务系统;
  • 使用外部中断实现计数功能(如转速测量);
  • 引入中断优先级(IP寄存器)管理多个中断;
  • 应用于工业控制 、智能报警等实时系统。

本章标志着你已掌握实时响应能力,下一章将进入定时器/计数器的深入学习,实现精准延时与周期性任务调度。


相关推荐
La Pulga3 小时前
【FreeRTOS源码学习笔记】任务切换
单片机·mcu·学习·嵌入式·freertos·实时操作系统
女神下凡7 小时前
芯参谋(85):Linux_PPI_NAND_驱动开发指南
linux·运维·arm开发·驱动开发·单片机·嵌入式硬件·设计规范
Zw-awa8 小时前
从 CH340 到 HC-05 和 HC-06:让小车脱离电脑
stm32
硅基手札9 小时前
【Linux 内核专栏 19】20 · 嵌入式子系统 — GPIO·pinctrl·clock·regulator
linux·运维·单片机·linux内核·嵌入式开发·调试定位
何粥学11 小时前
Vivado 2024.2 开发记录(AC820 Zynq-7020)——软件使用,点亮led灯
单片机·嵌入式硬件·zynq
Sakura_j_h_12 小时前
51 单片机驱动四位数码管:动态扫描、限流电阻与消影的取舍
单片机·嵌入式硬件·51单片机·嵌入式·数码管·动态扫描·限流电阻
HANDY0920013 小时前
从“不照人”到“剂量达标”:扇叶遮挡式UV-C空气消毒的工程边界与可验证评估框架
开发语言·人工智能·嵌入式硬件·智能家居
飞凌嵌入式15 小时前
千次静电放电试炼,守住飞凌嵌入式硬件可靠底线
嵌入式硬件
蹊黎1 天前
Linux 下用 C 语言实现进度条
linux·c语言·单片机
Zw-awa1 天前
从 CPU 搬运到自动搬运:DMA、空闲中断和两块缓冲
stm32