1、寄存器总结

1.1 常用 SFR 汇总表格

SFR汇总表格

1.2、TCON(定时器控制寄存器)

TCON的定义,描述,功能
TCON查询方式,中断方式

1.3、TMOD(定时器方式控制寄存器)

![TMOD的定义,描述,功能
工作方式

1.4 IE(中断允许寄存器)

1.5 IP(中断优先级寄存器)

1.6 SCON(串口行控制寄存器)

SCON简述

2、中断总结

下面是8051单片机中断处理流程的Mermaid流程图:

主程序正常执行

中断请求发生?

CPU响应中断

保护现场
(压栈保存PC、PSW等)

查找中断源
(硬件自动跳转到中断向量地址)

执行中断服务程序
(ISR)

恢复现场
(弹栈恢复PC、PSW等)

中断返回
(RETI指令)

CPU 正在执行主程序时,外部 / 内部突发事件向 CPU 发送请求,CPU 暂停当前主程序,跳转去执行专门的中断服务子程序,处理完事件后,自动回到断点继续执行原主程序。
作用:分时处理多任务、实时响应外部信号、定时控制、串口收发数据,避免 CPU 空循环等待。

2.1 外部中断

1)触发来源
单片机外部引脚电平 / 跳变信号触发:
INT0:P3.2 引脚,外部中断 0
INT1:P3.3 引脚,外部中断 1
2)两种触发方式(TCON 寄存器配置)
电平触发:引脚持续低电平就触发中断;
缺点:低电平一直存在会反复进中断,按键易卡死。
下降沿触发:引脚从高电平跳变到低电平的一瞬间触发一次,常用在按键、外部传感器触发。
3)典型应用
独立按键触发功能切换、外部传感器(红外、限位开关)信号检测、紧急停机触发。
4)关键寄存器
IT0/IT1:触发方式选择位,1 = 下降沿,0 = 低电平
EX0/EX1:外部中断允许开关
EA:总中断开关(所有中断必须打开 EA=1 才生效)

2.2 定时器中断

1)触发来源
单片机内部硬件定时器计数溢出,自动触发中断,不需要外部接线。
51 有 T0(定时器 0)、T1(定时器 1)两个独立定时器。
计数脉冲来源二选一:
定时模式:对系统机器周期计数,用来精准定时(ms/s 延时、秒表、时钟)
计数模式:对 T0/T1 外部引脚脉冲计数(统计脉冲个数、测速)
2)工作原理
给定时器 THx、TLx 赋初值,硬件自动累加计数;加满溢出后,硬件自动置中断标志位,申请定时器中断,进入中断服务函数重新装载初值,实现循环精准定时。
3)典型应用
LED 流水灯定时切换、数码管动态扫描、电子时钟秒分时计时、电机定时启停、按键消抖定时检测。
4)核心优势
不用软件循环空等延时,CPU 定时期间可以正常跑主程序,定时时间到自动进中断,不占用主程序运行资源。
5)关键寄存器
TMOD:设置 T0/T1 工作模式(定时 / 计数、16 位 / 8 位自动重装)
TH0、TL0、TH1、TL1:计数初值寄存器
ET0、ET1:定时器中断允许位
TR0、TR1:定时器启停控制位

6)定时器中断配置示例代码

以下是一个使用定时器0(T0)实现1ms定时中断的完整示例代码:

#include <reg51.h>

// 定义LED控制引脚
sbit LED = P1^0;

// 定义1ms计数值(假设晶振为12MHz)
// 机器周期 = 12 / 12MHz = 1μs
// 1ms需要计数次数 = 1000μs / 1μs = 1000次
// 定时器初值 = 65536 - 1000 = 64536 = 0xFC18
#define TIMER0_HIGH 0xFC  // 高8位
#define TIMER0_LOW  0x18   // 低8位

// 全局变量:中断计数
unsigned int timer0_count = 0;

/**
 * 定时器0中断服务函数
 * 中断号:1
 */
void timer0_isr() interrupt 1
{
    // 重新装载初值
    TH0 = TIMER0_HIGH;
    TL0 = TIMER0_LOW;
    
    // 中断计数
    timer0_count++;
    
    // 每1000次中断(1秒)翻转LED
    if (timer0_count >= 1000)
    {
        timer0_count = 0;
        LED = ~LED;  // LED状态翻转
    }
}

/**
 * 定时器0初始化函数
 * 模式1:16位定时器模式
 * 定时模式:对系统时钟计数
 */
void timer0_init()
{
    // 1. 设置TMOD寄存器:T0工作在模式1(16位定时器),定时模式
    // TMOD = 0000 0001 (GATE=0, C/T=0, M1=0, M0=1)
    TMOD &= 0xF0;  // 清零T0相关位
    TMOD |= 0x01;  // 设置T0为模式1
    
    // 2. 设置定时器初值
    TH0 = TIMER0_HIGH;
    TL0 = TIMER0_LOW;
    
    // 3. 开启定时器0中断
    ET0 = 1;  // 允许T0中断
    
    // 4. 开启总中断
    EA = 1;   // 总中断允许
    
    // 5. 启动定时器0
    TR0 = 1;  // 启动T0
}

/**
 * 主函数
 */
void main()
{
    // 初始化LED引脚
    LED = 0;
    
    // 初始化定时器0
    timer0_init();
    
    // 主循环
    while (1)
    {
        // 主程序可以执行其他任务
        // 定时器中断在后台自动运行
        // 这里可以添加其他功能代码
    }
}

7)代码说明

  • 定时器模式选择:使用TMOD寄存器设置T0为模式1(16位定时器),这是最常用的定时器模式。
  • 初值计算:根据晶振频率计算定时器初值,实现精确的定时时间。
  • 中断服务函数:使用interrupt 1关键字声明定时器0中断服务函数,中断号1对应T0中断。
  • 中断处理流程
    1. 定时器溢出触发中断
    2. 硬件自动跳转到中断服务函数
    3. 重新装载初值(保持定时精度)
    4. 更新中断计数器
    5. 根据计数结果执行相应操作
  • 主程序优势:主循环可以执行其他任务,定时功能由中断自动处理,实现多任务并行。

8)定时器中断配置步骤总结

  1. 选择定时器:T0或T1
  2. 设置工作模式:通过TMOD寄存器设置(模式0/1/2/3)
  3. 计算并设置初值:THx/TLx寄存器
  4. 开启中断允许:ETx = 1
  5. 开启总中断:EA = 1
  6. 启动定时器:TRx = 1
  7. 编写中断服务函数:使用interrupt关键字

9)常见定时器模式对比

模式 位数 自动重装 适用场景
模式0 13位 早期兼容,现已少用
模式1 16位 最常用,定时范围大
模式2 8位 需要精确重复定时
模式3 两个8位 T0分成两个独立8位定时器

2.3 串口中断

串口中断是51单片机中用于处理串行通信数据收发的重要中断类型。当串口完成一帧数据的发送或接收时,会触发串口中断,通知CPU进行相应处理。

串口中断相关寄存器

  1. SCON(串行控制寄存器)

    • RI(接收中断标志位):当串口接收到一帧完整数据时,硬件自动置1,需要软件清零
    • TI(发送中断标志位):当串口发送完一帧数据时,硬件自动置1,需要软件清零
  2. IE(中断允许寄存器)

    • ES(串口中断允许位):置1允许串口中断,置0禁止串口中断
  3. IP(中断优先级寄存器)

    • PS(串口中断优先级控制位):置1为高优先级,置0为低优先级

串口中断工作流程

  1. 初始化配置

    • 设置串口工作模式(模式1最常用)
    • 设置波特率(通过定时器1或定时器2)
    • 开启串口中断允许位(ES=1)
    • 开启总中断允许位(EA=1)
  2. 中断触发条件

    • 接收中断:当RI=1时触发,表示接收到一帧数据
    • 发送中断:当TI=1时触发,表示发送完成一帧数据
  3. 中断服务程序处理

    • 判断是RI还是TI触发的中断
    • 读取接收到的数据或准备下一帧发送数据
    • 清除中断标志位(RI=0或TI=0)

串口中断配置示例代码

#include <reg51.h>

// 串口初始化函数
void UART_Init() {
    // 设置串口工作模式1(8位UART,波特率可变)
    SCON = 0x50;  // 0101 0000:模式1,允许接收
    
    // 设置定时器1为波特率发生器,模式2
    TMOD &= 0x0F;  // 清除定时器1模式位
    TMOD |= 0x20;  // 设置定时器1为模式2
    
    // 设置波特率为9600(12MHz晶振)
    TH1 = 0xFD;    // 波特率重装值
    TL1 = 0xFD;
    
    // 启动定时器1
    TR1 = 1;
    
    // 允许串口中断
    ES = 1;
    
    // 允许总中断
    EA = 1;
}

// 串口发送一个字节
void UART_SendByte(unsigned char dat) {
    SBUF = dat;      // 将数据写入发送缓冲区
    while(!TI);      // 等待发送完成
    TI = 0;          // 清除发送中断标志
}

// 串口中断服务程序
void UART_ISR() interrupt 4 {
    if (RI == 1) {          // 接收中断
        RI = 0;             // 清除接收中断标志
        // 处理接收到的数据:SBUF中为接收到的数据
        unsigned char received_data = SBUF;
        // 这里可以添加数据处理代码
    }
    
    if (TI == 1) {          // 发送中断
        TI = 0;             // 清除发送中断标志
        // 发送完成处理
    }
}

// 主函数
void main() {
    UART_Init();           // 初始化串口
    
    // 发送测试数据
    UART_SendByte('H');
    UART_SendByte('e');
    UART_SendByte('l');
    UART_SendByte('l');
    UART_SendByte('o');
    
    while(1) {
        // 主循环
    }
}

串口中断的注意事项

  1. 中断标志位清除:RI和TI标志位必须由软件清零,硬件不会自动清除
  2. 数据缓冲区:发送和接收共用SBUF寄存器,但物理上是两个独立的寄存器
  3. 中断优先级:串口中断默认是低优先级,可通过PS位设置为高优先级
  4. 波特率匹配:发送和接收双方的波特率必须一致,否则会导致数据错误
  5. 中断嵌套:如果串口中断设置为高优先级,可以打断低优先级中断的执行

常见问题与解决方法

  1. 接收不到数据

    • 检查波特率设置是否正确
    • 确认ES和EA是否已置1
    • 检查硬件连接是否正常
  2. 数据发送不完整

    • 确保TI标志位在发送前已清零
    • 检查发送缓冲区是否被意外修改
  3. 中断响应不及时

    • 优化中断服务程序,减少执行时间
    • 考虑使用中断优先级设置

串口中断在51单片机串行通信中起着关键作用,合理使用串口中断可以实现高效的数据传输,同时释放CPU资源处理其他任务。

3、IO端口总结

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐