2501_94369262 2025-12-07 20:46 采纳率: 55.6%
浏览 3

At89c51单片机定时中断

设计一个15秒定时器,若时间到,则进行声明期报警计数器规定若按钮按下,则重新15秒计时。
硬件设计与软件设计

  • 写回答

2条回答 默认 最新

  • 檀越@新空间 2025-12-07 20:52
    关注

    晚上好🌙🌙🌙
    本答案参考通义千问

    设计一个基于 AT89C51 单片机15秒定时器,功能如下:

    • 按下按钮后,重新开始 15 秒倒计时;
    • 当时间到(即 15 秒结束)后,触发报警(如 LED 点亮、蜂鸣器响等);
    • 使用 定时中断 实现定时功能。

    一、硬件设计

    1.1 所需硬件组件

    | 名称 | 功能说明 | |--------------|----------------------------------| | AT89C51 单片机 | 核心控制器 | | 按钮开关 | 用于重置定时器 | | LED | 报警指示灯 | | 蜂鸣器 | 报警声音输出 | | 电阻、电容 | 用于电路稳定与滤波 |

    1.2 硬件连接图(简要描述)

    • 按钮:连接至 P3.2 引脚(外部中断 0),低电平有效;
    • LED:连接至 P1.0 引脚,高电平点亮;
    • 蜂鸣器:连接至 P1.1 引脚,控制其发声;
    • 晶振:使用 12MHz 晶振,配置为内部时钟;
    • 复位电路:使用上拉电阻 + 按钮实现复位功能。

    二、软件设计

    2.1 系统流程图

    开始
    │
    ├─ 初始化定时器、中断、IO
    │
    ├─ 等待按钮按下(或进入中断)
    │
    ├─ 启动定时器,开始 15 秒倒计时
    │
    ├─ 定时中断发生,计数器减 1
    │
    └─ 若计数器为 0 → 触发报警 → 停止定时器
    

    2.2 关键代码逻辑

    2.2.1 定时器设置(使用定时器 0,方式 1)

    void Timer0_Init() {
        TMOD = 0x01;      // 定时器 0 工作方式 1(16 位)
        TH0 = 0x3C;       // 设置初值,1ms 中断(12MHz 晶振)
        TL0 = 0x0B;
        ET0 = 1;          // 开启定时器 0 中断
        EA = 1;           // 全局中断开启
        TR0 = 1;          // 启动定时器 0
    }
    

    注意: 在 12MHz 晶振下,定时器初值计算公式为:

    初值 = 65536 - (12e6 / 12 / 1000) = 65536 - 1000 = 64536 = 0xFFD8
    

    但为了简化,我们采用每 1ms 中断一次的方式,通过 计数 15000 次 来实现 15 秒。

    2.2.2 定时器中断服务程序

    unsigned int count = 0;
    
    void Timer0_ISR() interrupt 1 {
        TH0 = 0x3C;       // 重新加载初值
        TL0 = 0x0B;
        count++;          // 计数器加 1
    
        if (count == 15000) {  // 15 秒到
            P1_0 = 0;       // LED 点亮
            P1_1 = 0;       // 蜂鸣器响
            TR0 = 0;        // 停止定时器
        }
    }
    

    2.2.3 按钮中断处理(外部中断 0)

    void External0_Init() {
        EX0 = 1;          // 开启外部中断 0
        IT0 = 1;          // 下降沿触发
        EA = 1;
    }
    
    void External0_ISR() interrupt 0 {
        count = 0;        // 重置计数器
        TR0 = 1;          // 重新启动定时器
    }
    

    三、完整 C 语言代码示例

    #include <reg51.h>
    
    #define LED P1_0
    #define BUZZER P1_1
    
    unsigned int count = 0;
    
    void Timer0_Init() {
        TMOD = 0x01;      // 定时器 0 方式 1
        TH0 = 0x3C;       // 1ms 中断
        TL0 = 0x0B;
        ET0 = 1;
        EA = 1;
        TR0 = 1;
    }
    
    void External0_Init() {
        EX0 = 1;
        IT0 = 1;
        EA = 1;
    }
    
    void Timer0_ISR() interrupt 1 {
        TH0 = 0x3C;
        TL0 = 0x0B;
        count++;
    
        if (count == 15000) {
            LED = 0;      // 报警
            BUZZER = 0;
            TR0 = 0;
        }
    }
    
    void External0_ISR() interrupt 0 {
        count = 0;
        TR0 = 1;
    }
    
    void main() {
        LED = 1;          // 初始状态关闭
        BUZZER = 1;
        Timer0_Init();
        External0_Init();
    
        while(1);
    }
    

    四、解决方案步骤总结

    1. 初始化定时器和中断

      • 配置定时器 0 为方式 1,设置初值以实现 1ms 中断
      • 开启全局中断和定时器中断
    2. 设置外部中断

      • 配置 P3.2 为外部中断 0,下降沿触发
      • 编写中断服务程序,用于重置计数器并重启定时器
    3. 编写定时器中断服务程序

      • 每次中断将计数器 count 加 1
      • count == 15000(即 15 秒)时,触发报警(LED 和蜂鸣器)
      • 停止定时器,防止重复触发
    4. 主函数中运行循环

      • 保持程序在等待中断状态

    五、注意事项

    • 定时器初值计算:根据晶振频率调整初值,确保精度;
    • 中断优先级:如果有多中断,需合理设置中断优先级;
    • 去抖动处理:按钮可能产生抖动,建议在软件或硬件中做消抖处理;
    • 报警恢复:报警后需手动复位或通过其他方式重新启动定时器。

    如有需要,我也可以提供 Proteus 仿真图Keil 编译环境配置。是否需要?

    评论

报告相同问题?

问题事件

  • 创建了问题 12月7日