【51单片机学习笔记】 最小系统、GPIO、数码管、按键、LED、外部中断、 定时器中断
📖今日学习:51单片机最小系统、GPIO口使用、LED点亮、数码管显示、按键检测;外部中断、定时器/计数器中断。
🔍文章大纲
- 51单片机最小系统
- GPIO口基础概念
- LED灯驱动(输出)
- 数码管显示(静态、动态扫描)
- 按键输入检测(查询方式)
- 中断系统基础概念
- 外部中断
- 定时器/计数器中断
- ✨学习重点汇总
- ⚠️易错点&踩坑记录
- 📝今日学习小结
---

1. 51单片机最小系统
最小系统是单片机能够正常运行的最少硬件电路,4部分组成:
- 单片机主控芯片(如STC89C52)
- 电源电路:给单片机供电,一般5V直流供电
- 晶振电路 :提供系统时钟,常见11.0592MHz、12MHz。
- 12MHz:机器周期 = 1us,方便延时计算
- 11.0592MHz:串口波特率可以精准匹配,串口项目首选
- 复位电路:上电复位,让单片机程序从0地址从头开始执行。
机器周期:51单片机12个时钟周期 = 1个机器周期。
晶振12MHz,时钟周期1/12us,机器周期恰好1us。
2. GPIO口基础概念
51单片机标准有4组IO口:P0、P1、P2、P3,每组8位(P0.0~P0.7)。
| IO口 | 特点 |
|---|---|
| P0 | 开漏输出,无上拉电阻;做输出必须外接上拉电阻;可地址/数据复用 |
| P1 | 准双向口,内部带上拉电阻,普通IO,无复用功能 |
| P2 | 准双向口,带上拉;外部存储器高8位地址复用 |
| P3 | 准双向口,带上拉;引脚复用功能(外部中断、定时器、串口) |
准双向口:作为输入之前,必须先向端口写
1,释放引脚,才能正确读取外部电平。P0口特殊:内部没有上拉,输出低电平有效,输出高电平是高阻态。
寄存器操作示例:
// P1口全部置0
P1 = 0x00;
// P1.0单独置1
P1_0 = 1;
3. LED灯点亮(GPIO输出)
LED二极管:阳极接高电平,阴极接低电平才会点亮 。
两种硬件接法:
- 共阴极:阴极接GND,IO输出高电平,灯亮。
- 共阳极:阳极接VCC,IO输出低电平,灯亮。
必须串联限流电阻(220Ω左右),防止电流过大烧毁LED和IO引脚。
示例代码(P1.0控制LED,低电平点亮)
#include <reg52.h>
sbit led = P1^0;
void main(void)
{
while(1)
{
led = 0; //点亮
}
}
简单延时函数,实现LED闪烁
void delay_ms(unsigned int t)
{
unsigned int i,j;
for(i=t;i>0;i--)
for(j=110;j>0;j--);
}
4. 数码管显示
数码管由a~g七个段 + dp小数点组成。
- 共阳数码管 :公共端接VCC;段脚输出低电平点亮段。
- 共阴数码管 :公共端接GND;段脚输出高电平点亮段。
静态数码管
每个数码管段脚独立;只要赋值段码,数字持续显示。
优点:程序简单,无闪烁;缺点:占用IO多,数码管数量多时不适合。
段码表:
共阴:
0~9:0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F
动态扫描数码管
多位数码管,段选共用一套IO,位选控制哪一个数码管点亮 。
流程:
- 送当前要显示数字的段码;
- 打开对应位选,点亮这一位;
- 短暂延时;
- 关闭位选(消影);
- 循环切换下一位;
利用人眼视觉暂留,高速循环扫描,人眼看到多位同时显示。
⚠️消影很关键:不关闭位选直接切换段码,会出现重影乱码。
动态扫描简单逻辑伪代码:
while(1)
{
送第一位段码;
开第一位位选;
delay();
关闭所有位选; //消影
送第二位段码;
开第二位位选;
delay();
关闭所有位选;
}
5. 按键输入检测(查询方式)
按键原理:按下引脚电平翻转;松开恢复。
机械按键存在机械抖动:按下/松开瞬间电平抖动5‑10ms,直接读取会误判多次。
解决抖动两种方案:
- 软件延时消抖:检测到电平变化,延时10ms再读一次电平确认。
- 硬件消抖:外接电容。
51准双向口做输入:读取按键前,IO口先写1。
查询方式按键示例:
sbit key = P3^2;
void key_scan(void)
{
if(key == 0) //按键按下低电平
{
delay_ms(10); //软件消抖
if(key == 0)
{
//按键处理业务
}
while(key == 0); //等待松开
delay_ms(10);
}
}
查询方式缺点:CPU一直循环扫描按键,占用CPU资源。可以使用外部中断实现按键检测。
6. 51中断系统基础
中断:CPU正在执行主程序,收到外部事件信号,暂停主程序,跳转去执行中断服务函数;执行完毕回到断点继续运行主程序。
51单片机5个中断源:
| 中断源 | 中断号 | 说明 |
|---|---|---|
| 外部中断0 | 0 | INT0(P3.2) |
| 定时器0中断 | 1 | T0 |
| 外部中断1 | 2 | INT1(P3.3) |
| 定时器1中断 | 3 | T1 |
| 串口中断 | 4 | UART |
关键寄存器:
IE:中断允许寄存器,总中断EA,各个中断使能位。EA:总中断开关,必须置1,所有中断才能生效。
IP:中断优先级寄存器,高优先级可以打断低优先级中断。- 外部中断:
TCON寄存器,设置触发方式(下降沿触发 / 低电平触发)。 - 定时器:
TMOD定时器模式寄存器;THx TLx定时器初值寄存器。
中断服务函数格式:
void 中断服务函数名(void) interrupt 中断号
{
//中断处理代码
}
⚠️中断服务函数不要写延时、复杂业务;尽量简短快速执行完。
7. 外部中断
外部中断0:P3.2(INT0);外部中断1:P3.3(INT1)
两种触发方式:
- 低电平触发:引脚持续低电平,会不断反复触发中断;适合外部电平信号。
- 下降沿触发(边沿触发):引脚从高电平跳变到低电平一瞬间触发一次,按键推荐使用。
配置步骤:
- 设置IT0/IT1选择触发方式;
- EX0 / EX1打开对应外部中断;
- EA=1开启总中断;
- 编写interrupt对应中断号的中断服务函数。
示例:外部中断0,下降沿触发按键
#include <reg52.h>
sbit led = P1^0;
void int0_init(void)
{
IT0 = 1; //下降沿触发
EX0 = 1; //开启外部中断0
EA = 1; //打开总中断
}
//外部中断0服务函数,中断号0
void int0_isr(void) interrupt 0
{
led = ~led; //按键触发翻转LED状态
}
void main(void)
{
int0_init();
while(1)
{
//主循环可以做别的事情
}
}
边沿触发:只会跳变瞬间进一次中断;低电平触发,如果引脚一直低电平,会反复进入中断。
8. 定时器/计数器中断
定时器本质:对机器周期计数;计数值溢出,触发定时器中断。
- 定时器模式:对单片机内部机器周期计数,用来定时。
- 计数器模式:对外部T0(P3.4)、T1(P3.5)引脚外部脉冲计数。
TMOD寄存器:设置T0、T1工作模式;模式1最常用:16位定时器,TH高8位,TL低8位,最大计数65536。
12M晶振机器周期1us;模式1,最多定时65536us = 65.536ms。
定时时间 = (65536‑初值) * 机器周期。
定时器配置步骤:
- TMOD设置工作模式;
- 给TH0、TL0装载计数初值;
- ET0打开定时器0中断;
- TR0启动定时器;
- EA=1开启总中断;
- 写定时器中断服务函数,中断里面重新给TH0 TL0赋初值!模式1不会自动重装。
示例:12M晶振,定时器0模式1定时50ms中断
void timer0_init(void)
{
TMOD |= 0x01; //T0模式1,16位定时器
//50ms 初值 65536‑50000 = 15536
TH0 = 15536 / 256;
TL0 = 15536 % 256;
ET0 = 1; //开启T0中断
TR0 = 1; //启动定时器0
EA = 1; //总中断打开
}
//定时器0中断服务函数,中断号1
void timer0_isr(void) interrupt 1
{
//模式1,必须手动重装初值!!
TH0 = 15536 / 256;
TL0 = 15536 % 256;
//定时到,业务处理
}
✨学习重点
- 最小系统四大部分:电源、晶振、复位、单片机;分清12M与11.0592M晶振用途,机器周期概念。
- 4组GPIO:P0开漏无上拉;P1/P2/P3准双向口;准双向口做输入要先写1;P3口具备引脚复用功能。
- LED:分清共阳、共阴极接法,必须串联限流电阻。
- 数码管:分清共阴/共阳段码;动态扫描原理,消影操作必不可少,防止重影;视觉暂留实现多位同时显示。
- 按键:机械抖动,软件延时消抖原理;查询扫描按键优缺点。
- 中断核心概念:打断主程序,执行中断服务函数;
EA总中断开关,不打开所有中断无效。 - 外部中断:低电平触发 vs 下降沿(边沿触发);按键优先边沿触发。
- 定时器中断:模式1为16位,不会自动重装初值,中断服务函数内手动重新赋值THx TLx;定时时间计算公式。
- 中断服务函数规则:
interrupt + 中断号;函数不能有参数、返回值;中断内部尽量简短,禁止大量延时。
⚠️易错点&踩坑记录
- ❌准双向IO做输入,忘记先写
1,读按键一直电平错误。 - ❌P0口输出忘记加上拉电阻,输出高电平是高阻态,LED/外设工作异常。
- ❌LED省略限流电阻,直接接IO,烧坏LED或者单片机IO引脚。
- ❌数码管动态扫描没有消影,切换段码时出现重影、乱码。
- ❌按键不做消抖,按下一次多次触发,逻辑错乱。
- ❌外部中断使用低电平触发,按键按住不放,不断重复进中断;按键场景优先下降沿触发。
- ❌中断忘记打开总中断
EA=1,中断完全不响应。 - ❌定时器模式1,中断服务函数忘记手动重装TH0 TL0初值,只进一次中断,之后不再触发。
- ❌定时器初值计算错误,定时时间和预期完全不符。
- ❌中断服务函数里面写长延时、复杂业务逻辑;中断要快进快出,耗时逻辑放到主循环。
- ❌中断服务函数写错中断号,跑到错误的中断处理,程序跑飞。
- ❌混淆共阳、共阴数码管段码,写反,数码显示乱数字。
📝今日学习小结
今天学习51单片机基础硬件与软件编程:掌握最小系统组成;理解4组GPIO口电气特性;完成LED点亮闪烁;数码管静态、动态扫描显示;按键查询检测。
学习51中断系统,掌握外部中断实现按键触发;定时器中断完成定时功能。