目录
[15.1 PWM简介](#15.1 PWM简介)
[15.2 项目示例1:呼吸灯](#15.2 项目示例1:呼吸灯)
[✅main.c 主函数:](#✅main.c 主函数:)
[15.3 项目示例1:直流电机调速](#15.3 项目示例1:直流电机调速)
[✅main.c 主函数:](#✅main.c 主函数:)
15.1 PWM简介


15.2 项目示例1:呼吸灯
✅项目功能:
51 单片机通过软件模拟 PWM(脉冲宽度调制)实现 LED 呼吸灯效果
✅项目架构:

✅main.c 主函数:
cpp
#include <REGX52.H> // 51单片机寄存器定义头文件,提供IO口、寄存器等底层硬件定义
sbit LED=P2^0; // 定义LED控制引脚:P2口第0位(可根据硬件接线修改)
/**
* @brief 简单延时函数(软件延时)
* @param t 延时计数参数,t越大,延时时间越长(依赖晶振频率,仅作粗略延时)
* @retval 无
* @note 该延时无精准时序,仅用于控制LED亮灭的相对时长
*/
void Delay(unsigned int t)
{
while(t--); // 空循环延时:t递减至0时结束,实现简单的时间延迟
}
void main()
{
unsigned char Time,i; // 定义变量:Time=LED亮的时长(控制占空比);i=内层循环计次变量(稳定占空比)
while(1) // 死循环:持续实现呼吸灯效果
{
// 第一阶段:LED由暗到亮(占空比从0%增加到100%)
for(Time=0;Time<100;Time++) // Time从0到99递增,亮的时长逐渐增加,灭的时长逐渐减少
{
for(i=0;i<20;i++) // 内层循环计次(20次):让当前占空比的亮灭状态保持一段时间,避免闪烁过快
{
LED=0; // LED亮(P2^0输出低电平,需硬件上LED负极接该引脚、正极接电阻到VCC)
Delay(Time); // 亮的延时:时长=Time(随Time增大,亮的时间越长)
LED=1; // LED灭(P2^0输出高电平)
Delay(100-Time); // 灭的延时:时长=100-Time(随Time增大,灭的时间越短)
}
}
// 第二阶段:LED由亮到暗(占空比从100%减少到0%)
for(Time=100;Time>0;Time--) // Time从100到1递减,亮的时长逐渐减少,灭的时长逐渐增加
{
for(i=0;i<20;i++) // 内层循环计次:稳定当前占空比的亮灭状态
{
LED=0; // LED亮
Delay(Time); // 亮的延时:时长=Time(随Time减小,亮的时间越短)
LED=1; // LED灭
Delay(100-Time); // 灭的延时:时长=100-Time(随Time减小,灭的时间越长)
}
}
}
}
15.3 项目示例1:直流电机调速
✅项目功能:
51 单片机通过定时器 0 模拟 PWM(脉冲宽度调制)实现直流电机转速档位控制
✅项目架构:

✅main.c 主函数:
cpp
#include <REGX52.H> // 51单片机寄存器定义头文件,提供IO口、中断、定时器等底层硬件定义
#include "Delay.h" // 延时函数头文件(按键驱动可能依赖该文件实现消抖延时)
#include "Key.h" // 按键驱动头文件,包含Key()函数(读取按键编号)
#include "Nixie.h" // 数码管驱动头文件,包含Nixie()函数(数码管显示数字)
#include "Timer0.h" // 定时器0驱动头文件,包含Timer0_Init()函数(初始化定时器0)
sbit Motor=P1^0; // 定义电机控制引脚:P1口第0位(需外接电机驱动模块,如L298N)
// PWM核心变量:
// Counter:定时器中断计数值(用于累计中断次数,构成PWM周期)
// Compare:PWM比较值(用于控制占空比,Counter<Compare时输出高电平,否则低电平)
unsigned char Counter,Compare;
// 功能变量:
// KeyNum:存储读取到的按键编号(0=无按键,1=按键1按下)
// Speed:电机转速档位(0~3档,对应不同占空比)
unsigned char KeyNum,Speed;
void main()
{
Timer0_Init(); // 初始化定时器0(配置为100us中断一次,为PWM提供时间基准)
while(1) // 死循环:持续检测按键、更新档位、显示档位
{
KeyNum=Key(); // 读取按键值(非阻塞式,依赖定时器扫描或软件消抖)
if(KeyNum==1) // 检测到按键1按下
{
Speed++; // 档位自增(0→1→2→3→0循环)
Speed%=4; // 取模4,限制档位范围在0~3
// 根据档位设置PWM比较值,改变占空比(PWM周期=100个中断=10ms)
if(Speed==0){Compare=0;} // 0档:占空比0%(电机停转)
if(Speed==1){Compare=50;} // 1档:占空比50%(电机中速)
if(Speed==2){Compare=75;} // 2档:占空比75%(电机高速)
if(Speed==3){Compare=100;} // 3档:占空比100%(电机全速)
}
Nixie(1,Speed); // 数码管第1位显示当前转速档位(0/1/2/3)
}
}
/**
* @brief 定时器0中断服务函数(PWM信号生成核心)
* @note 定时器0配置为100us中断一次,100次中断构成10ms的PWM周期;
* 通过对比计数值Counter和比较值Compare,控制Motor引脚的高低电平,生成不同占空比的PWM。
*/
void Timer0_Routine() interrupt 1
{
TL0 = 0x9C; // 重置定时器0初值(11.0592MHz晶振,定时100us)
TH0 = 0xFF; // 同上,确保每次中断间隔精准100us
Counter++; // 中断计数值自增(累计中断次数)
Counter%=100; // 限制计数值范围在0~99(构成10ms的PWM周期:100×100us=10ms)
if(Counter<Compare) // 计数值 < 比较值 → 输出高电平
{
Motor=1; // Motor引脚输出1(高电平,控制电机运转,需配合驱动模块)
}
else // 计数值 ≥ 比较值 → 输出低电平
{
Motor=0; // Motor引脚输出0(低电平,电机停止/减速)
}
}