51单片机学习笔记15-PWM脉冲编码调制

目录

[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(低电平,电机停止/减速)
	}
}
相关推荐
麦托团子1 天前
51单片机学习笔记10-点阵屏
51单片机
恶魔泡泡糖2 天前
51单片机外部中断
c语言·单片机·嵌入式硬件·51单片机
项目題供诗2 天前
51单片机入门(五)
单片机·嵌入式硬件·51单片机
A-code2 天前
嵌入式UI刷新:观察者模式实战
stm32·单片机·mcu·物联网·51单片机
项目題供诗3 天前
51单片机入门(四)
单片机·嵌入式硬件·51单片机
项目題供诗3 天前
51单片机入门(三)
单片机·嵌入式硬件·51单片机
电子工程师成长日记-C513 天前
51单片机16路抢答器
单片机·嵌入式硬件·51单片机
项目題供诗3 天前
51单片机入门(二)
单片机·嵌入式硬件·51单片机
恶魔泡泡糖3 天前
51单片机步进电机
单片机·嵌入式硬件·51单片机