详解51单片机定时器PWM原理及应用

目录

前言

一、PWM的介绍

二、在定时器中配置PWM

三、代码

 总结


前言


        PWM普遍应用于惯性系统,我们知道单片机几乎只能输出“1”和“0”两种状态,即开和关,想要输出模拟量是不太容易实现的,那么怎样才能使单片机输出平滑的线性信号呢?没接触过PWM的小伙伴可能第一时间想到的就是高中时学过的滑动电位器,利用欧姆定律调整阻值而改变电流,但这种方法精度低,效率低,功耗高,故障率也高,于是聪明的人们发明出了PWM,它是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在从测量、通信到功率控制与变换的许多领域中,如呼吸灯,电机控速、开关电源等。

一、PWM的介绍


        PWM(Pulse Width Modulation)即脉冲宽度调制,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量。

        何为脉冲宽度调制?比如说,我们线输出1ms的高电平,再输出1ms的低电平以此快速进行输出,那么这段电信号并没有以全程高电平的状态输出,也没有以全程低电平的状态输出,而是以稳定的中间电平状态输出。再比方说周期的时间是10ms,脉宽时间是8ms 那么低电平时间就是2ms 总的占空比 8/(8+2)= 80%,就会以80%总电流的强度输出。根据这个就可以控制电机的速度或LED灯的亮度。

         值得一提的是,这种调制方法只适用于惯性系统,例如电机的转动,当从高电平跳变到低电平时,电机不会马上停止转动,而是靠着惯性继续旋转,LED灯则是根据人眼的视觉暂留效果,当它熄灭的一瞬间会留有余晖,连当频率很快的时候,LED灯的亮暗过度就会看上去很自然。

二、在定时器中配置PWM


        高级的MCU都有配备相应的PWM功能的,可见PWM这一技术的应用还是偏多的,而8051系列单片机没有配备这一功能,我们需要采用定时器中断的方法来生成。用定时器输出一段连续变化的方波,由于方波的占空比不同输出的电流也不相同,这样就可以模拟出稳定变化的电信号。

        它的具体原理如下:

         如上图所示,蓝线就是计数器的计数值,由于计数器可以实现自动重装载,当计数值自增或自减到某一大小,就会回到初始值反复这一过程,类似于沙漏的原理,当然自动重装值是可以自行去设定的。我们再设置一个比较值,即图中的红线,当计数值小于比较直就为低电平,当计数值自增到大于比较值就为高电平,一直自增到重装值清零,反复这一过程。前面计数值<比较值的时间为低电平,后面计数值>比较值的时间为高电平,这样一段方波信号就形成了。我们可以通过调节比较值的大小来调节方波的占空比,调节重装值的大小来调节频率。

   

三、代码


        这是一种用延时函数的方法,实现LED的亮暗变换:

#include <REGX52.H>
sbit LED=P2^0;

void Delay(unsigned int t)
{
	while(t--);
}

void main()
{
	unsigned char Time,i;
	while(1)
	{
		for(Time=0;Time<100;Time++)		//改变亮灭时间,由暗到亮
		{
			for(i=0;i<20;i++)			//计次延时
			{
				LED=0;					//LED亮
				Delay(Time);			//延时Time
				LED=1;					//LED灭
				Delay(100-Time);		//延时100-Time
			}
		}
		for(Time=100;Time>0;Time--)		//改变亮灭时间,由亮到暗
		{
			for(i=0;i<20;i++)			//计次延时
			{
				LED=0;					//LED亮
				Delay(Time);			//延时Time
				LED=1;					//LED灭
				Delay(100-Time);		//延时100-Time
			}
		}
	}
}

        通过控制点亮与熄灭的延时长短来控制亮度。

        下面是用定时器来实现电机速度调节:

#include <REGX52.H>
#include "Delay.h"
#include "Key.h"
#include "Nixie.h"
#include "Timer0.h"

sbit Motor=P1^0;

unsigned char Counter,Compare;	        //计数值和比较值,用于输出PWM
unsigned char KeyNum,Speed;

void main()
{
	Timer0_Init();                      //初始化定时器
	while(1)
	{
		KeyNum=Key();
		if(KeyNum==1)
		{
			Speed++;
			Speed%=4;
			if(Speed==0){Compare=0;}	//设置比较值,改变PWM占空比
			if(Speed==1){Compare=50;}
			if(Speed==2){Compare=75;}
			if(Speed==3){Compare=100;}
		}
		Nixie(1,Speed);
	}
}

void Timer0_Routine() interrupt 1
{
	TL0 = 0x9C;		                    //设置定时初值
	TH0 = 0xFF;		                    //设置定时初值
	Counter++;
	Counter%=100;	                    //计数值变化范围限制在0~99
	if(Counter<Compare)	                //计数值小于比较值
	{
		Motor=1;		                //输出1
	}    
	else				                //计数值大于比较值
	{
		Motor=0;		                //输出0
	}
}
#include <REGX52.H>
#include "Delay.h"

unsigned char Key()
{
	unsigned char KeyNumber=0;
	
	if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=1;}
	if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=2;}
	if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=3;}
	if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=4;}
	
	return KeyNumber;
}
#include <REGX52.H>
#include "Delay.h"

//数码管段码表
unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};


void Nixie(unsigned char Location,Number)
{
	switch(Location)		//位码输出
	{
		case 1:P2_4=1;P2_3=1;P2_2=1;break;
		case 2:P2_4=1;P2_3=1;P2_2=0;break;
		case 3:P2_4=1;P2_3=0;P2_2=1;break;
		case 4:P2_4=1;P2_3=0;P2_2=0;break;
		case 5:P2_4=0;P2_3=1;P2_2=1;break;
		case 6:P2_4=0;P2_3=1;P2_2=0;break;
		case 7:P2_4=0;P2_3=0;P2_2=1;break;
		case 8:P2_4=0;P2_3=0;P2_2=0;break;
	}
	P0=NixieTable[Number];	//段码输出
	Delay(1);				//显示一段时间
	P0=0x00;				//段码清0,消影
}
void Delay(unsigned int xms)     
{
	unsigned char i, j;
	while(xms--)
	{
		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
	}
}

        

51单片机PWM

       

 
总结


        注意:由于PWM信号强度弱,所以一般不直接接在负载上,而是通过驱动电路控制负载。

物联沃分享整理
物联沃-IOTWORD物联网 » 详解51单片机定时器PWM原理及应用

发表评论