0
点赞
收藏
分享

微信扫一扫

Proteus仿真C51利用双定时器输出占空比可变的PWM(一)

一、引言

实际应用当中,我们不仅常用到一定占空比的PWM信号,而且更希望得到占空比可以受控变化的PWM信号,以便控制汽车伺服电机的转速,或者控制汽车氛围灯的亮暗变化,基于软件的延时固然可以实现改变占空比,但基于硬件定时器来控制一个周期内的占空比,固定周期内的占空比控制更准确,更可靠,甚至改变信号的周期也很方便,程序也简单清晰明了,可读性也比较强。

二、PWM信号简述

1、PWM信号

PWM(PulseWidthModulation),脉冲宽度调制是一种模拟控制方式,根据相应载荷的变化来调制晶体管基极或MOS管栅极的偏置,来实现晶体管或MOS管导通时间的改变,从而实现开关稳压电源输出的改变。这种方式能使电源的输出电压在工作条件变化时保持恒定,是利用微处理器的数字信号对模拟电路进行控制的一种非常有效的技术。广泛应用在从测量、通信到功率控制与变换的许多领域中。

2、PWM信号占空比

PWM信号占空比是指在一个脉冲周期内,高电平的时间与整个周期时间的比例。

单位: % (0%-100%)

三、Proteus仿真实例目标

利用AT89C51的Timer0和Timer1,分别控制PWM信号周期内的高电平定时和低电平定时,来控制输出占空比受控的PWM信号,从而来控制LED灯的亮暗变化,通过占空比的变化,可以清楚看到LED由暗到亮再由亮到暗反复的变化过程,PWM信号周期为10ms。

四、Proteus实例原理图

 

五、Proteus 仿真结果

1、周期测量

实测周期为10.04ms,误差取决于整除和取余。

2、动态仿真记录

从下面示波器仿真的动态记录可以看出,PWM信号的占空比是不断受控变化的。

 

六、已调试程序

/* Main.c file generated by Baoyufei
 * UART AT89C51 Frequency 12MHz 
 * PWM drives Atmosphere lamp of Automobile 
 * Created:   Saturday April 24, 2022
 * Processor: AT89C51
 * Compiler:  Keil μVision5
 * Version:   v1.0
 */

#include <reg52.h>

#define up 1
#define down 0 
 
// 类型重定义,便于移植
typedef unsigned char uchar;
typedef unsigned int uint; 

uchar i, Count = 10; //保持已设定某占空比PWM信号的计数
uchar cnt_H = 1;     //PWM周期10ms(100Hz),cnt_H为高电平初值
uchar cnt_L = 99;    //PWM周期10ms(100Hz),cnt_l为低电平初值

uchar half = up;

sbit pulse = P3^4;

/* main 主函数*/
void main()
{
   pulse = 1;    //PWM起始输出高电平
   TMOD  = 0x11; //Timer0 方式一16位,用作高电平定时;Timer1方式一16位定时,用作低电平定时;
   ET0   = 0;    //关闭定时中断   
   ET1   = 0;    //关闭定时中断 
   TF0   = 0;    //清零溢出
   TF1   = 0;    //清零溢出 
   
   while(1)
   {
     for(i = 0; i < Count; i++)
     {
	 TH0   = (uint)(65536-cnt_H*100)/256; //设定Timer0
	 TL0   = (uint)(65536-cnt_H*100)%256; //设定Timer0
	 TR0   = 1;   //启动Timer0
	 while(!TF0); //等待溢出置位
	 TR0   = 0;   //停止Timer0		 
	 pulse = ~pulse; //PWM输出电平翻转
	 TF0   = 0;   //清零溢出  
	 TH1   = (uint)(65536-cnt_L*100)/256; //设定Timer1
	 TL1   = (uint)(65536-cnt_L*100)%256; //设定Timer1
	 TR1   = 1; //启动Timer1
	 while(!TF1); //等待溢出置位
	 TR1   = 0;   //停止Timer1		 
         TF1   = 0;   //清零溢出 
	 pulse = ~pulse; //PWM输出电平翻转
      }
      //达到Count计数上限后,调整Timer0和Timer1的初值,以调整占空比
      if(i == Count)
      {
	 if(half == up) //如果占空比处于加宽的过程中
	    {
	    switch(cnt_H) //根据上次的占空比递加,cnt_H+cnt_L=100即保证周期不变,case分得越细,占空比变化越平滑。
	       {
	          case   1: cnt_H =  3; cnt_L =  97; break; 
	          case   3: cnt_H =  5; cnt_L =  95; break; 		  
	          case   5: cnt_H = 10; cnt_L =  90; break; 
	          case  10: cnt_H = 15; cnt_L =  85; break; 
	          case  15: cnt_H = 20; cnt_L =  80; break; 
	          case  20: cnt_H = 25; cnt_L =  75; break; 
	          case  25: cnt_H = 30; cnt_L =  70; break; 
	          case  30: cnt_H = 35; cnt_L =  65; break; 
	          case  35: cnt_H = 40; cnt_L =  60; break; 
	          case  40: cnt_H = 45; cnt_L =  55; break; 
	          case  45: cnt_H = 50; cnt_L =  50; break; 		  
		      case  50: cnt_H = 60; cnt_L =  40; break;
		      case  60: cnt_H = 70; cnt_L =  30; break;
		      case  70: cnt_H = 85; cnt_L =  15; break;
		      //由宽变窄的转折点
	    	  case  85: cnt_H = 99; cnt_L =   1; half = down;break;	  
	    	  default: break;
	       } 
	    }
	 if(half == down) //如果占空比处于变窄的过程中
	    {
	       switch(cnt_H) //根据上次的占空比递减,cnt_H+cnt_L=100即保证周期不变,case分得越细,占空比变化越平滑。
	       {
    		  case  99:  cnt_H =  85; cnt_L =  15; break;  
	    	  case  85:  cnt_H =  70; cnt_L =  30; break; 
	    	  case  70:  cnt_H =  60; cnt_L =  40; break;  
	    	  case  60:  cnt_H =  50; cnt_L =  50; break;  
	    	  case  50:  cnt_H =  45; cnt_L =  55; break;    
	    	  case  45:  cnt_H =  40; cnt_L =  60; break;  
	    	  case  40:  cnt_H =  35; cnt_L =  75; break;  		 
	    	  case  35:  cnt_H =  30; cnt_L =  70; break;
	    	  case  30:  cnt_H =  25; cnt_L =  75; break;  
	    	  case  25:  cnt_H =  20; cnt_L =  80; break;  
	    	  case  20:  cnt_H =  15; cnt_L =  85; break; 
	    	  case  15:  cnt_H =  10; cnt_L =  90; break; 
	    	  case  10:  cnt_H =   5; cnt_L =  95; break;  
	    	  case   5:  cnt_H =   3; cnt_L =  97; break; 
	    	  //由窄变宽的转折点
	    	  case   3:  cnt_H =   1; cnt_L =  99; half = up; break; 		
	    	  default:   break;    
	       }
	    }
	  i = 0; //设定好占空比参数cnt_H和cnt_L之后,清零i,启动新一轮的占空比信号输出
	 }       
     }   
}

七、总结

从所附的代码可以看出,程序简单,定时器控制可靠准确,值得推荐。该PWM信号控制汽车氛围灯的亮暗将另起文章介绍。

举报

相关推荐

0 条评论