基本功能:利用PWM脉宽信号实现独立按键S7对L1指示灯亮度变化的控制。PWM脉宽信号的频率为100Hz。L1指示灯有4种亮度模式,分别是完全熄灭、10%的亮度50%的亮度和90%的亮度。
按下S7按键,循环切换L1指示灯的四种亮度模式。
以上是我们需要使用的模块
我们先来了解什么是PWM
脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制。
pwm的频率:
是指1秒钟内信号从高电平到低电平再回到高电平的次数(一个周期);
也就是说一秒钟PWM有多少个周期
单位: Hz
表示方式: 50Hz 100Hz
pwm的周期:
T=1/f
周期=1/频率
50Hz = 20ms 一个周期
如果频率为50Hz ,也就是说一个周期是20ms 那么一秒钟就有 50次PWM周期
占空比:
是一个脉冲周期内,高电平的时间与整个周期时间的比例
单位: % (0%-100%)
表示方式:20%
周期: 一个脉冲信号的时间 1s内测周期次数等于频率
脉宽时间: 高电平时间
上图中 脉宽时间占总周期时间的比例,就是占空比
比方说周期的时间是10ms,脉宽时间是8ms 那么低电平时间就是2ms 总的占空比 8/(8+2)= 80%
这就是占空比为80%的脉冲信号
PWM原理
以单片机为例,我们知道,单片机的IO口输出的是数字信号,IO口只能输出高电平和低电平
假设高电平为5V 低电平则为0V 那么我们要输出不同的模拟电压,就要用到PWM,通过改变IO口输出的方波的占空比从而获得使用数字信号模拟成的模拟电压信号
我们知道,电压是以一种连接1或断开0的重复脉冲序列被夹到模拟负载上去的(例如LED灯,直流电机等),连接即是直流供电输出,断开即是直流供电断开。通过对连接和断开时间的控制,理论上来讲,可以输出任意不大于最大电压值(即0~5V之间任意大小)的模拟电压
比方说 占空比为50% 那就是高电平时间一半,低电平时间一半,在一定的频率下,就可以得到模拟的2.5V输出电压 那么75%的占空比 得到的电压就是3.75V
pwm的调节作用来源于对“占周期”的宽度控制,“占周期”变宽,输出的能量就会提高,通过阻容变换电路所得到的平均电压值也会上升,“占周期”变窄,输出的电压信号的电压平均值就会降低,通过阻容变换电路所得到的平均电压值也会下降
也就是,在一定的频率下,通过不同的占空比 即可得到不同的输出模拟电压
pwm就是通过这种原理实现D/A转换的。
总结:
PWM就是在合适的信号频率下,通过一个周期里改变占空比的方式来改变输出的有效电压
那我们在CT107D单片机平台上怎么实现呢,我们来分析分析
首先我们需要使用到定时器来控制PWM的频率,我们以100Hz为例,那么一个周期就为1s/100=10ms,由于我们需要将占空比设置为可控制的状态,即0-100%,那么我们就需要将一个周期10ms/100=100us,那么我们就能得到定时器定时的时间。
#include "reg52.h"
sbit L1 = P0^0;
sbit S7 = P3^0;
void SelectHC573()
{
P2 = (P2 & 0x1f) | 0x80;
}
//============定时相关的函数================
unsigned char count = 0;
unsigned char pwm_duty = 0;
void InitTimer0()
{
TMOD = 0x01;
TH0 = (65535 - 100) / 256;
TL0 = (65535 - 100) % 256;
ET0 = 1;
EA = 1;
}
void ServiceTimer0() interrupt 1
{
TH0 = (65535 - 100) / 256;
TL0 = (65535 - 100) % 256;
count++;
if(count == pwm_duty)
{
L1 = 1;
}
else if(count == 100)
{
L1 = 0;
count = 0;
}
}
//==========================================
//============按键相关的函数================
void Delay(unsigned int t)
{
while(t--);
}
unsigned char stat = 0;
void ScanKeys()
{
if(S7 == 0)
{
Delay(100);
if(S7 == 0)
{
switch(stat)
{
case 0:
L1 = 0;
TR0 = 1;
pwm_duty = 10;
stat = 1;
break;
case 1:
pwm_duty = 50;
stat = 2;
break;
case 2:
pwm_duty = 90;
stat = 3;
break;
case 3:
L1 = 1;
TR0 = 0;
stat = 0;
break;
}
while(S7 == 0);
}
}
}
//============================================
void main()
{
SelectHC573();
L1 = 1;
InitTimer0();
while(1)
{
ScanKeys();
}
}
我们来理解一下这个代码,InitTimer0()是定时器初始化函数,我们很容易理解,重点是
count++;
if(count == pwm_duty)
{
L1 = 1;
}
else if(count == 100)
{
L1 = 0;
count = 0;
}
我们以LED1为例,因为在CT107D平台上,LED在低电平点亮,高电平熄灭,所以在PWM中,低电平相当于高电平,高电平相当于低电平,默认状态下L1=1,当我们按下按钮,L1=0,PWM_duty=10,即在0-10为低电平,10-100为高电平,相当于10%占空比。所以在PWM中,需要灵活运用,分清高电平有效还是低电平有效,在进行pwm占空比的调节。