目录
[1. 硬件材料](#1. 硬件材料)
[2. 开发软件](#2. 开发软件)
[二、方案 1:基础延时实现 LED 闪烁(入门级)](#二、方案 1:基础延时实现 LED 闪烁(入门级))
[1. 硬件接线](#1. 硬件接线)
[2. 完整代码(Keil C51)](#2. 完整代码(Keil C51))
[3. 代码解析](#3. 代码解析)
[4. 编译与下载](#4. 编译与下载)
[三、方案 2:定时器中断实现 LED 闪烁(进阶版)](#三、方案 2:定时器中断实现 LED 闪烁(进阶版))
[1. 硬件接线](#1. 硬件接线)
[2. 完整代码(晶振 12MHz)](#2. 完整代码(晶振 12MHz))
[3. 代码核心解析](#3. 代码核心解析)
[(1)定时器初值计算(晶振 12MHz)](#(1)定时器初值计算(晶振 12MHz))
[1. LED 不亮](#1. LED 不亮)
[2. LED 常亮 / 常灭](#2. LED 常亮 / 常灭)
[3. 闪烁频率不准](#3. 闪烁频率不准)
一、基础准备
1. 硬件材料
| 元件 | 数量 | 备注 |
|---|---|---|
| STC89C52 单片机最小系统板 | 1 块 | 核心控制单元 |
| LED 发光二极管 | 1 个 | 任意颜色(红 / 绿 / 蓝) |
| 限流电阻 | 1 个 | 220Ω~330Ω(保护 LED,防止过流烧坏) |
| 杜邦线 | 若干 | 连接电路 |
| USB 转 TTL 模块 | 1 个 | 下载程序 + 供电 |
| 5V 电源 | 1 个 | 也可通过 USB 转 TTL 给最小系统供电 |
2. 开发软件
- 编译器:Keil uVision4/5(需安装 C51 编译器);
- 下载工具:STC-ISP(STC 单片机专用下载软件)。
二、方案 1:基础延时实现 LED 闪烁(入门级)
1. 硬件接线
以控制 P1.0 引脚为例,接线逻辑(灌电流驱动,51 单片机推荐方式):
- LED 负极(短脚)→ 串联 220Ω 限流电阻 → 单片机 P1.0 引脚;
- LED 正极(长脚)→ 5V 电源(VCC);
- 单片机 GND → 电源 GND(共地)。
⚠️ 若用拉电流驱动(LED 正极接 P1.0,负极接 GND),亮度会稍低,因为 51 拉电流能力弱,优先推荐灌电流方式。
2. 完整代码(Keil C51)
c
运行
// 头文件:51单片机寄存器定义
#include <reg52.h>
// 引脚定义:将P1.0定义为LED_PIN,方便修改
sbit LED_PIN = P1^0;
// 延时函数:软件延时约1秒(晶振12MHz)
void Delay1s() {
unsigned int i, j, k;
for(i=15; i>0; i--)
for(j=200; j>0; j--)
for(k=200; k>0; k--);
}
// 主函数:程序入口
void main() {
while(1) { // 死循环,持续执行
LED_PIN = 0; // P1.0输出低电平,LED导通亮
Delay1s(); // 延时1秒
LED_PIN = 1; // P1.0输出高电平,LED截止灭
Delay1s(); // 延时1秒
}
}
3. 代码解析
sbit LED_PIN = P1^0;:位定义,将 P1 口的第 0 位命名为 LED_PIN,可直接操作该引脚电平;Delay1s():三层嵌套循环实现软件延时,晶振 12MHz 时,1 个机器周期 = 1μs,循环次数决定延时时间(可根据实际需求调整);while(1):死循环保证 LED 持续闪烁,不会执行一次就停止;- 电平逻辑:灌电流驱动下,引脚低电平(0)→ LED 亮,高电平(1)→ LED 灭。
4. 编译与下载
- Keil 中新建工程,选择器件为
Atmel → AT89C52(STC89C52 兼容此型号); - 添加上述代码文件(.c),勾选 "Options for Target → Output → Create HEX File";
- 编译生成
.hex文件; - 打开 STC-ISP,选择单片机型号
STC89C52RC,导入.hex文件,选择正确串口,点击 "下载 / 编程",给单片机上电即可。
三、方案 2:定时器中断实现 LED 闪烁(进阶版)
软件延时的缺点是占用 CPU 资源(延时期间 CPU 无法做其他事),定时器中断 是更高效的方式,CPU 可在定时期间处理其他任务。
1. 硬件接线
与方案 1 完全相同(P1.0 接 LED)。
2. 完整代码(晶振 12MHz)
c
运行
#include <reg52.h>
sbit LED_PIN = P1^0;
unsigned int count = 0; // 中断计数变量
// 定时器0初始化函数:配置10ms定时
void Timer0_Init() {
TMOD &= 0xF0; // 清空定时器0模式位
TMOD |= 0x01; // 定时器0模式1(16位定时)
TH0 = 0xDC; // 高8位初值:65536 - 10000 = 55536 → 0xDC00
TL0 = 0x00; // 低8位初值
ET0 = 1; // 开启定时器0中断
EA = 1; // 开启总中断(必须)
TR0 = 1; // 启动定时器0
}
// 定时器0中断服务函数
void Timer0_ISR() interrupt 1 {
TH0 = 0xDC; // 重装初值(16位定时器溢出后需手动重装)
TL0 = 0x00;
count++; // 每10ms计数+1
if(count == 100) { // 10ms×100=1000ms=1秒
count = 0; // 计数清零
LED_PIN = ~LED_PIN; // 翻转LED电平(亮→灭/灭→亮)
}
}
void main() {
Timer0_Init(); // 初始化定时器
while(1) {
// 此处可添加其他任务,如按键检测、串口通信等
// 定时器中断会自动触发,不影响主函数执行
}
}
3. 代码核心解析
(1)定时器初值计算(晶振 12MHz)
- 机器周期 = 12 / 晶振频率 = 12/12MHz = 1μs;
- 定时 10ms 需要计数次数 = 10ms / 1μs = 10000 次;
- 16 位定时器最大计数 65536 次,因此初值 = 65536 - 10000 = 55536 → 十六进制
0xDC00(TH0=0xDC,TL0=0x00)。
(2)中断配置关键
interrupt 1:中断号,定时器 0 中断对应中断号 1(外部中断 0=0,定时器 1=3,串口 = 4);ET0=1:开启定时器 0 中断,EA=1:开启总中断(51 所有中断必须先开总中断);- 中断服务函数中需重装初值:16 位定时器模式 1 溢出后,TH0/TL0 会清零,需手动重新赋值才能保证下次定时准确。
(3)闪烁逻辑
- 每 10ms 进入一次中断,
count加 1; - 当
count=100时(累计 1 秒),翻转 LED 引脚电平,实现 1 秒闪烁。
四、常见问题与调试技巧
1. LED 不亮
- 接线错误:检查 LED 正负极是否接反,限流电阻是否串联,GND 是否共地;
- 引脚定义错误:确认代码中引脚(如 P1.0)与实际接线一致;
- 程序未下载成功:重新打开 STC-ISP,降低下载波特率(如 2400bps),下载时重新上电;
- 晶振问题:最小系统晶振未接或损坏,导致单片机无法运行,用万用表测晶振引脚是否有电压。
2. LED 常亮 / 常灭
- 延时时间过短 / 过长:调整延时函数的循环次数,或定时器计数阈值;
- 中断未开启:检查
EA=1和ET0=1是否配置; - 初值计算错误:晶振非 12MHz 时,需重新计算定时器初值(如 11.0592MHz 晶振,定时 10ms 初值 = 65536 - (10000×11.0592/12) ≈ 65536 - 9216 = 56320 → 0xD8F0)。
3. 闪烁频率不准
- 软件延时:晶振频率非 12MHz 时,延时误差大,建议换用定时器方案;
- 定时器:未重装初值,或晶振精度差(换用高精度晶振,如 11.0592MHz/12MHz)。
五、扩展玩法
- 多灯闪烁:定义多个引脚(如
P1^0、P1^1、P1^2),实现流水灯; - 按键控制:增加按键(接 P3.2),通过外部中断实现 "按一下亮,再按一下灭";
- 呼吸灯:通过定时器快速翻转引脚电平,调整高低电平占空比(PWM 模拟),实现 LED 渐亮渐灭。