PWM在单片机中的运用是十分广泛的,它的基本原理很简单,但往往运用于不同场合上含义也不完全相同,这儿我先把基本概念和基本原理给咱们介绍一下,后边遇到用的时分最少知道是个什么东西。
PWM是Pulse Width ModulaTIon的缩写,它的中文姓名是脉冲宽度调制,一种说法是它运用微处理器的数字输出来对模仿电路进行操控的一种有用的技能,其实便是运用数字信号到达一个模仿信号的作用。这是个什么概念呢?咱们一步步来介绍。
这是一个周期是10ms,即频率是 100Hz的波形,可是每个周期内,凹凸电平脉冲宽度各不相同,这便是PWM的实质。在这儿咱们要记住一个概念,叫做“占空比”。占空比是指高电平的时刻占整个周期的份额。比方榜首部分波形的占空比是 40%,第二部分波形占空比是 60%,第三部分波形占空比是 80%,这便是 PWM 的解说。
那为何它能对模仿电路进行操控呢?咱们想一想,咱们数字电路里,只要 0 和 1 两种状况,比方咱们第 2 章学会的点亮 LED 小灯那个程序,当咱们写一个 LED = 0;小灯就会长亮,当咱们写一个 LED = 1;小灯就会灭掉。当咱们让小灯亮和灭距离运转的时分,小灯是闪耀。
假设咱们把这个距离不断的减小,减小到咱们的肉眼分辩不出来,也便是 100Hz 以上的频率,这个时分小灯表现出来的现象便是既坚持亮的状况,但亮度又没有 LED = 0;时的亮度高。那咱们不断改动时刻参数,让 LED = 0;的时刻大于或许小于 LED = 1;的时刻,会发现亮度都不相同,这便是模仿电路的感觉了,不再是朴实的 0 和 1,还有亮度不断改动。咱们会发现,假设咱们用 100Hz 的信号,假设高电平平息小灯,低电平点亮小灯的话,榜首部分波形平息 4ms,点亮 6ms,亮度最高,第二部分平息 6ms,点亮 4ms,亮度次之,第三部分平息 8ms,点亮 2ms,亮度最低。那么用程序验证一下咱们的理论,咱们用守时器T0 守时改动 P0.0 的输出来完成 PWM,与纯守时不同的是,这儿咱们每周期内都要重载两次守时器初值,即用两个不同的初值来操控凹凸电平的不同持续时刻。为了使亮度的改动愈加显着,程序中运用的占空比距离更大。
#include
sbitPWMOUT= P0^0;
sbitADDR0= P1^0;
sbitADDR1= P1^1;
sbitADDR2= P1^2;
sbitADDR3= P1^3;
sbitENLED= P1^4;
unsignedchar HighRH=0;//高电平重载值的高字节
unsignedchar HighRL=0;//高电平重载值的低字节
unsignedchar LowRH=0;//低电平重载值的高字节
unsignedchar LowRL=0;//低电平重载值的低字节
voidConfigPWM(unsignedint fr,unsignedchar dc);
voidClosePWM();
voidmain(){
unsignedint i;
EA=1;//开总中止
ENLED=0;//使能独立 LED
ADDR3=1;
ADDR2=1;
ADDR1=1;
ADDR0=0;
while(1){
ConfigPWM(100,10);//频率 100Hz,占空比 10%
for(i=0; i《40000; i++);
ClosePWM();
ConfigPWM(100,40);//频率 100Hz,占空比 40%
for(i=0; i《40000; i++);
ClosePWM();
ConfigPWM(100,90);//频率 100Hz,占空比 90%
for(i=0; i《40000; i++);
ClosePWM();//封闭 PWM,相当于占空比 100%
for(i=0; i《40000; i++);
}
}
/* 装备并发动 PWM,fr-频率,dc-占空比 */
voidConfigPWM(unsignedint fr,unsignedchar dc){
unsignedint high, low;
unsignedlong tmp;
tmp=(11059200/12)/ fr;//核算一个周期所需的计数值
high=(tmp*dc)/100;//核算高电平所需的计数值
low= tmp- high;//核算低电平所需的计数值
high=65536- high+12;//核算高电平的重载值并补偿中止延时
low=65536- low+12;//核算低电平的重载值并补偿中止延时
HighRH=(unsignedchar)(high》》8);//高电平重载值拆分为凹凸字节
HighRL=(unsignedchar)high;
LowRH=(unsignedchar)(low》》8);//低电平重载值拆分为凹凸字节
LowRL=(unsignedchar)low;
TMOD&=0xF0;//清零 T0 的操控位
TMOD|=0x01;//装备 T0 为形式 1
TH0= HighRH;//加载 T0 重载值
TL0= HighRL;
ET0=1;//使能 T0 中止
TR0=1;//发动 T0
PWMOUT=1;//输出高电平
}
/* 封闭 PWM */
voidClosePWM(){
TR0=0;//中止守时器
ET0=0;//制止中止
PWMOUT=1;//输出高电平
}
/* T0 中止服务函数,发生 PWM 输出 */
voidInterruptTImer0() interrupt1{
if(PWMOUT==1){//当时输出为高电平时,装载低电平值并输出低电平
TH0= LowRH;
TL0= LowRL;
PWMOUT=0;
}else{//当时输出为低电平时,装载高电平值并输出高电平
TH0= HighRH;
TL0= HighRL;
PWMOUT=1;
}
}
需求提示咱们的是,由于规范 51 单片机中没有专门的 PWM 模块,所以咱们用守时器加中止的方法来发生 PWM,而现在有许多的单片机都会集成硬件的 PWM 模块,这种情况下需求咱们做的就仅仅是核算一下周期计数值和占空比计数值然后装备到相关的 SFR 中即可,既使程序得到了简化又保证了 PWM 的输出质量(由于消除了中止延时的影响)。
咱们编译下载程序后,会发现小灯从最亮到灭总共 4 个亮度等级。假设咱们让亮度等级更多,而且让亮度等级接连起来,会发生一个小灯突变的作用,与呼吸有点相似,所以咱们习惯上称之为呼吸灯,程序代码如下,这个程序用了 2 个守时器 2 个中止,这是咱们榜首次这样用,咱们能够学习一下。咱们来试试这个程序,试完了咱们必定要能自己把程序写出来,牢记。
#include
sbitPWMOUT= P0^0;
sbitADDR0= P1^0;
sbitADDR1= P1^1;
sbitADDR2= P1^2;
sbitADDR3= P1^3;
sbitENLED= P1^4;
unsignedlong PeriodCnt=0;//PWM 周期计数值
unsignedchar HighRH=0;//高电平重载值的高字节
unsignedchar HighRL=0;//高电平重载值的低字节
unsignedchar LowRH=0;//低电平重载值的高字节
unsignedchar LowRL=0;//低电平重载值的低字节
unsignedchar T1RH=0;//T1 重载值的高字节
unsignedchar T1RL=0;//T1 重载值的低字节
voidConfigTImer1(unsignedint ms);
voidConfigPWM(unsignedint fr,unsignedchar dc);
voidmain(){
EA=1;//开总中止
ENLED=0;//使能独立 LED
ADDR3=1;
ADDR2=1;
ADDR1=1;
ADDR0=0;
ConfigPWM(100,10);//装备并发动 PWM
ConfigTImer1(50);//用 T1 守时调整占空比
while(1);
}
/* 装备并发动 T1,ms-守时时刻 */
voidConfigTimer1(unsignedint ms){
unsignedlong tmp;//暂时变量
tmp=11059200/12;//守时器计数频率
tmp=(tmp* ms)/1000;//核算所需的计数值
tmp=65536- tmp;//核算守时器重载值
tmp= tmp+12;//补偿中止呼应延时形成的差错
T1RH=(unsignedchar)(tmp》》8);//守时器重载值拆分为凹凸字节
T1RL=(unsignedchar)tmp;
TMOD&=0x0F;//清零 T1 的操控位
TMOD|=0x10;//装备 T1 为形式 1
TH1= T1RH;//加载 T1 重载值
TL1= T1RL;
ET1=1;//使能 T1 中止
TR1=1;//发动 T1
}
/* 装备并发动 PWM,fr-频率,dc-占空比 */
voidConfigPWM(unsignedint fr,unsignedchar dc){
unsignedint high, low;
PeriodCnt=(11059200/12)/ fr;//核算一个周期所需的计数值
high=(PeriodCnt*dc)/100;//核算高电平所需的计数值
low= PeriodCnt- high;//核算低电平所需的计数值
high=65536- high+12;//核算高电平的守时器重载值并补偿中止延时
low=65536- low+12;//核算低电平的守时器重载值并补偿中止延时
HighRH=(unsignedchar)(high》》8);//高电平重载值拆分为凹凸字节
HighRL=(unsignedchar)high;
LowRH=(unsignedchar)(low》》8);//低电平重载值拆分为凹凸字节
LowRL=(unsignedchar)low;
TMOD&=0xF0;//清零 T0 的操控位
TMOD|=0x01;//装备 T0 为形式 1
TH0= HighRH;//加载 T0 重载值
TL0= HighRL;
ET0=1;//使能 T0 中止
TR0=1;//发动 T0
PWMOUT=1;//输出高电平
}
/* 占空比调整函数,频率不变只调整占空比 */
voidAdjustDutyCycle(unsignedchar dc){
unsignedint high, low;
high=(PeriodCnt*dc)/100;//核算高电平所需的计数值
low= PeriodCnt- high;//核算低电平所需的计数值
high = 65536 – high + 12
来历;21ic