共计 1491 个字符,预计需要花费 4 分钟才能阅读完成。
背景痛点:为什么需要定时器控制 LED?
直接用 GPIO 控制 LED 闪烁时,我们需要手动编写延时循环。这种方式存在两个明显缺陷:

- CPU 资源浪费:执行延时循环时 CPU 无法处理其他任务
- 精度难以保证:延时受中断影响,不同时钟频率下需要重新计算
而使用 8253 定时器可以完美解决这些问题——它独立工作,能产生精确的时间间隔,解放 CPU 资源。
硬件设计:Proteus 电路连接详解
关键器件连接关系如下(端口地址80H-83H):
- 8086 CPU:通过地址总线 A0-A1 选择 8253 内部寄存器
- 8253 定时器:
- CLK1:连接 1MHz 时钟源(假设系统提供)
- GATE1:接 +5V 使能
- OUT1:连接 LED 阳极(阴极接地)
- 地址解码:
- 80H:计数器 1
- 81H:计数器 2(未使用)
- 82H:计数器 3(未使用)
- 83H:控制字寄存器
注:实际 Proteus 中需添加适当的上拉电阻和限流电阻(通常 220Ω)
核心实现:8253 初始化与工作原理
步骤 1:控制字设置(写入 83H)
需要配置的 控制字 =36H,其二进制含义为:
00110110
│││││││└─ 二进制模式(0)
│││││└── 读写低字节(01)
│││└─── 方式 3(方波)
│└──── 计数器 1
└───── 无特殊意义
步骤 2:计数初值计算(1Hz 方波)
已知条件:
- 输入时钟频率 =1MHz
- 目标频率 =1Hz
- 使用 BCD 码计数
计算公式:
计数初值 = 输入频率 / 输出频率 = 1,000,000 / 1 = 1,000,000
由于 8253 最大计数值 =65,535(FFFFH),需要分频处理。实际解决方案:
- 将 1,000,000 分解为 1000×1000
- 使用两个计数器级联(本文仅演示单个计数器实现)
简化方案:降低输入时钟频率(例如改为 100KHz),则初值 =100,000(需用 BCD 码表示为 0001 0000 0000)
完整代码实现(emu8086)
;============ 定义段 ============
.MODEL SMALL
.STACK 100H
.DATA
; 8253 端口地址定义
COUNTER1 EQU 80H
CONTROL EQU 83H
.CODE
START:
MOV AX, @DATA
MOV DS, AX
; 初始化 8253
MOV AL, 36H ; 控制字:计数器 1 + 方式 3 + 二进制
OUT CONTROL, AL ; 写入控制寄存器
; 写入计数初值(BCD 码示例)MOV AL, 10H ; 低字节 =10H(BCD 码 16)OUT COUNTER1, AL
MOV AL, 00H ; 高字节 =00H
OUT COUNTER1, AL
; 主循环(仅保持程序运行)MAIN_LOOP:
JMP MAIN_LOOP
MOV AH, 4CH
INT 21H
END START
避坑指南
硬件连接常见问题
- LED 不亮:
- 检查 OUT1 是否确实连接到 LED 阳极
- 测量 GATE1 是否为高电平
-
确认 8253 的 VCC 和 GND 正确连接
-
闪烁频率异常:
- 核对 CLK1 输入频率是否与代码预设值匹配
- 检查控制字是否误写为其他工作方式
软件调试技巧
- 在 emu8086 中使用单步执行,观察端口写入时序
- 在 Proteus 中右键 8253 选择 ”Debug” 查看内部寄存器值
进阶思考
尝试修改实现以下功能:
- 级联计数器 0 和计数器 1,实现精确的 1Hz 输出(初值 =1,000,000)
- 通过可变电阻调节输入时钟频率,实现 LED 闪烁频率手动调节
- 扩展控制多个 LED,形成流水灯效果
实现效果验证
在 Proteus 中运行仿真后,可以看到 LED 以稳定 1Hz 频率闪烁。用虚拟示波器观察 OUT1 引脚,会显示占空比 50% 的方波信号。这种方案相比软件延时,CPU 占用率几乎为 0,特别适合需要精确定时的嵌入式场景。
最佳实践建议:实际项目中,可将定时器初始化代码封装为独立函数,便于复用。
正文完
发表至: 未分类
近一天内
