目录
[1.1 什么是GPIO?](#1.1 什么是GPIO?)
[1.2 GPIO输入类型](#1.2 GPIO输入类型)
[1.3 GPIO输出类型](#1.3 GPIO输出类型)
[1.4 示例:检测P3_2是否为低电平](#1.4 示例:检测P3_2是否为低电平)
[2.1 中断的概念](#2.1 中断的概念)
[2.2 中断源](#2.2 中断源)
[2.3 中断优先级与嵌套](#2.3 中断优先级与嵌套)
[2.4 中断向量表](#2.4 中断向量表)
[2.5 中断处理流程](#2.5 中断处理流程)
[2.6 示例:外部中断0初始化和使用](#2.6 示例:外部中断0初始化和使用)
[3.1 定时器的作用](#3.1 定时器的作用)
[3.2 模式选择:](#3.2 模式选择:)
[3.3 定时器0的初始化和使用:](#3.3 定时器0的初始化和使用:)
1.首先将定时器TMOD寄存器的低四位置为0(高四位是定时器1):
[4.1 PWM简介](#4.1 PWM简介)
[4.2 应用:无源蜂鸣器发声](#4.2 应用:无源蜂鸣器发声)
[4.3 示例:输出200Hz方波,占空比50%](#4.3 示例:输出200Hz方波,占空比50%)
一、GPIO
1.1 什么是GPIO?
GPIO(General Purpose Input Output)即通用输入输出引脚,是单片机与外部世界交互的桥梁。
-
输入模式:检测引脚电平变化(高/低电平)
-
输出模式:控制引脚输出高/低电平
1.2 GPIO输入类型
| 类型 | 说明 |
|---|---|
| 悬空输入 | 电平不确定,容易受干扰 |
| 上拉输入 | 内部接上拉电阻,默认高电平 |
| 下拉输入 | 内部接下拉电阻,默认低电平 |
| 模拟输入 | 用于ADC采集模拟信号 |
1.3 GPIO输出类型
| 类型 | 说明 |
|---|---|
| 推挽输出 | 可输出强高电平和强低电平 |
| 开漏输出 | 只能输出低电平,高电平需外接上拉电阻 |
1.4 示例:检测P3_2是否为低电平
if ((P3 & (1 << 2)) == 0) {
// P3_2 为低电平
}
二、中断系统
2.1 中断的概念
中断是指CPU正在执行任务时,收到更紧急的任务请求,暂停当前任务,转而去处理紧急任务,处理完后再返回原任务继续执行。
2.2 中断源
51单片机共有5个中断源:
-
外部中断0(INT0)
-
外部中断1(INT1)
-
定时器0
-
定时器1
-
串口
2.3 中断优先级与嵌套
-
CPU会根据中断优先级决定先处理哪个中断
-
51单片机支持最多两层中断嵌套(arm不能嵌套)
2.4 中断向量表
本质上是一个数组,数组中存放的是中断服务函数的入口地址
中断向量:中断向量表中各中断服务函数的标号

2.5 中断处理流程
中断源发起请求
检查中断是否开启、是否被屏蔽
比较优先级
保护现场(保存当前寄存器)
执行中断服务函数
恢复现场,继续执行原任务
2.6 示例:外部中断0初始化和使用
1.查手册看外部中断默认是什么电平触发:

可以得知外部中断0是低电平触发,所以先把外部中断的引脚拉高,查看开发板原理图,找到INT0对应的引脚即P3.2
2.打开中断总开关:

寄存器IE的第八位和第1位置为1
3.选择外部中断0类型

有低电平触发和下降沿触发:
选择下降沿触发,只需要检测一下,而不是一直检测(低电平触发的话只要是低电平就会一直触发中断)
4.初始化代码示例:
//初始化
void int0_init(void)
{
//外部中断引脚拉高
P3 |= (1<<2);
//打开CPU中断总开关
IE |= (1<<7);
//打开外部中断开关
IE |= (1<<0);
//选择外部中断0类型
TCON |= (1<<0);
}
5.外部中断0的使用:
外部中断对应按键K3

初始化按键:
void key_init(void)
{
P3 |= (0x0F <<0);//按键初始化0000 1111
}
按下按键即触发中断,然后写一个中断函数
注意 interrupt 0一定要写在函数旁边(中断向量表,这个会把我写的函数对应到系统指定的中断0函数中去)
void int0_handler(void) interrupt 0 //向量0
{
g_n++ ;
}
三、定时器
3.1 定时器的作用
定时器能够产生一个精准的定时 ,对时序要求严格(高电平和低电平的时间必须是
精准的),常用于延时、PWM生成、计数等场景。
这里简要介绍一下时序图:
3.2 模式选择:

8位自动重装定时器:实际参与计数的只有TL0,当溢出后会将TH0的值再重新装回到TL0
这里选择的定时器模式是16位自增型计数器,从初值开始计数,溢出时触发中断。
-
计数范围:0 ~ 65535
-
计数频率 = 晶振频率 / 12(STC8952RC的晶振频率过大,所以用了12分频器)
-
计数一次时间 = 1 / 计数频率
示例:1ms定时器:
晶振频率:11.0592MHz(STC8952RC)
工作频率:11.0592MHz / 12 = 0.9216MHz
计数一次时间:1 / 0.9216MHz ≈ 1.085μs
1ms所需计数次数:1000μs / 1.085μs ≈ 922
所以初值设置为:65535 - 922 = 64613
3.3 定时器0的初始化和使用:
1.首先将定时器TMOD寄存器的低四位置为0(高四位是定时器1):
// 1. 将TMOD寄存器低4位清零
TMOD &= ~(0x0F << 0);
2.开始设置定时器工作模式:16位定时器
// 2. 设置定时器工作模式:16位定时器
TMOD |= (1 << 0);
3.设置计算出的定时器0初值
// 3. 设置定时器初值 64613
TH0 = g_i >> 8;
TL0 = g_i;
//TH0是存低四位的数据,TL0是存高四位的数据
4.开启三个开关
开启定时器计数
CPU响应所有中断(总开关)
允许定时器0产生中断(子开关)
// 4. 开启定时器计数
TCON |= (1 << 4);
// 5. CPU响应所有中断(总开关)
IE |= (1 << 7);
// 6. 允许定时器0产生中断(子开关)
IE |= (1 << 1);
5.示例定时器0初始化和使用:
// 定时器0初始化函数
void timer0_init(void)
{
// 1. 将TMOD寄存器低4位清零
TMOD &= ~(0x0F << 0);
// 2. 设置定时器工作模式:16位定时器
TMOD |= (1 << 0);
// 3. 设置定时器初值 64613
TH0 = g_i >> 8;
TL0 = g_i;
// 4. 开启定时器计数
TCON |= (1 << 4);
// 5. CPU响应所有中断(总开关)
IE |= (1 << 7);
// 6. 允许定时器0产生中断(子开关)
IE |= (1 << 1);
}
当计数到溢出后触发中断,随后执行中断函数:
// 外部中断0服务函数
void timer0_handler(void) interrupt 1
{
TH0 = g_i >> 8; //一定要复位初值,不然定时器触发一次中断后,不会再次触发
TL0 = g_i;
P2 ^= (1<<5);
}
注意:一定要复位初值,不然定时器触发一次中断后,不会再次触发
四、PWM与蜂鸣器
4.1 PWM简介
PWM(脉冲宽度调制) 脉冲宽度调制,能够产生一个方波,能够让引脚电平周期性发生变化
-
周期:一个方波所经历的时间(从上升沿/下降沿到下一个上升沿/下降沿 )
-
占空比:高电平在一个周期内所占的比例
4.2 应用:无源蜂鸣器发声
无源蜂鸣器需要外部提供震荡信号才能发声。通过PWM可以控制其音调和音量。
| 特性 | 有源蜂鸣器 | 无源蜂鸣器 |
|---|---|---|
| 内部结构 | 内置振荡源(多谐振荡器) | 没有振荡源,只有线圈和磁铁 |
| 驱动方式 | 通电即响(直流电压) | 需要PWM方波驱动(交流信号) |
| 频率控制 | 固定频率(不可变) | 可通过PWM频率改变音调 |
| 声音特点 | 单一频率,声音单调 | 可发出不同音调,甚至音乐 |
| PDF中描述 | "通电后会持续发出固定频率声音" | "通电后不会发出声音,需要给定一个震荡" |
4.3 示例:输出200Hz方波,占空比50%
周期 = 1 / 200Hz = 0.005s
半个周期 = 0.0025s(到半个周期时定时器0中断触发后翻转电平)
计数次数 = 0.0025s / 1.085μs ≈ 2304(1.085us数值如何得出看上面定时器1ms实现)
初值 = 65535 - 2304 = 63231

在定时器中断中函数中翻转蜂鸣器引脚电平,即可输出200hz方波:
// 定时器0服务函数
void timer0_handler(void) interrupt 1
{
TH0 = g_i >> 8; //填蜂鸣器的频率所算出来的初值
TL0 = g_i;
P2 ^= (1<<5);
}
五、总结
通过本文,我们系统梳理了51单片机的几个核心模块:
-
GPIO:输入输出基础
-
中断:提升系统响应能力
-
定时器:精准控制时间
-
PWM:实现波形输出与控制
这些知识点是嵌入式开发的入门必修课,理解它们之后,你将能更轻松地阅读芯片手册、编写底层驱动,甚至开发完整的嵌入式系统。

