蓝桥杯单片机比赛学习:8、PWM的基本原理之呼吸灯

经过7节的学习,我们已经掌握了基本的硬件的使用规则,从本节开始我们开始学习一些模块的使用PWM、PCF8591、AT24C02、DS18B20、DS1302、555频率测量、光敏电阻测量、超声波测距等。本节先将PWM的基本原理,本节通过调节呼吸灯进一步理解PWM。如果之前的led、按键、数码管、中断等有不懂的请去我的主页看一下之前的文章,或许可以帮助你。(1条消息) Do My Best的博客_CSDN博客-蓝桥杯单片机比赛学习领域博主

pwm的概念 

PWM脉冲宽度调制,就是英文 “Pulse Width Modulation” 的缩写,根据相应载荷的变化来调制晶体管基极或MOS管栅极的偏置,来实现晶体管或MOS管导通时间的改变,从而实现开关稳压电源输出的改变。这种方式能使电源的输出电压在工作条件变化时保持恒定,是利用微处理器的数字信号对模拟电路进行控制的一种非常有效的技术。

pwm的频率(Hz)

就是1s中有几个脉冲(周期),如1s内有50个脉冲,则pwm的频率就是50Hz。

什么是脉冲?

脉冲就是从低电平到高电平再回到低电平,这样就是1个脉冲信号。

例:如下图,如果1s中产生3个脉冲(也就是3个周期),那么此pwm的频率就为3Hz。

7abaa86e5fac492b8cfbde6f777a6014.png

 

PWM的周期 (S)

pwm的周期(T = 1 / f),也就是频率的倒数。

例:pwm频率(f)为50Hz,周期(T)就为20ms

1s中有50个周期(脉冲),每个周期为20ms

 

PWM的占空比

pwm的占空比就是 在一个周期内,高电平时间占整个周期时间的比例。

 例:一个pwm的周期为20ms,高电平的时间为15ms,则此pwm的占空比为15/20 = 75%

2a7282d474094889b188b2e4e6f902fc.png

 

PWM的基本原理 

在我们使用单片机的时候一般都会使用到PWM进行小车调速、灯光亮度调节等,一般的,都是通过IO口输出高低电平调节占空比。例如,假设单片机输出的高电平为5V,低电平为0V,我们要想得到0~5V之间的任意电压就要使用PWM,通过改变IO口的占空比从而实现DA转化(数字量转化为模拟量)

我们知道,单片机可以输出5V和0V的电压,那么怎么输出0~5V之间的任意电压呢?我们现在就得使用pwm改变占空比 进而 输出0~5V之间的任意电压。

例:如下图,占空比依次为50% 25% 75%,他们的输出电压为:

占空比为50%:Vout = 5V*50%=2.5V

占空比为25%:Vout = 5V*25%=1.25V

占空比为75%:Vout = 5V*75%=3.75V

f883d11a11de4227931b45c8fc6c41df.png

综上,PWM的 这种原理就是通过DA转换来实现的,最重要的是我们要知道输出电压是通过改变占空比来实现的。

PWM调节呼吸灯

在这里我们需要知道这样的小知识,LED灯的亮度是由电压来决定的,给的电压大LED亮度强,给的电压小LED亮度弱

从百度上我们可以搜到,人眼对于83Hz的频率以上的刷新率基本不感到闪烁?

3153dda00eda4ee79efd0e36c6ab82a2.png

 用定时器模拟pwm,具体参数如何设置?如下图,请认真看,重点!重点!!重点!!!

d74333bd42354f3193903a9cc3d6b8c2.png

 步骤:

1、我们用定时器模拟一个pwm周期,我们选择频率为200Hz,周期为5ms(T=1/200s)的周期信号,每隔50us进一次中断,程序如下

void Timer0Init(void)		//50微秒@12.000MHz
{
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0xCE;		//设置定时初值
	TH0 = 0xFF;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时

	EA=1;
	ET0=1;
}

//每50us进入一次中断,flag++,当flag=100时,就相当于过了5ms
//也就是相当于我们这里设置了一个pwm周期为5ms,频率为200Hz(f = 1/T)
void Timer0Service(void)  interrupt 1
{
	flag++;								
	if(flag==100)
		flag=0;
}

 

2、并通过以下程序来设置脉冲宽度(也就是高电平的时间)

void key_scan(void)
{  
  if(s4==0)
  {
    delay_ms(10);
    if(s4==0)
    {
			set_flag+=10;        //通过按键设置脉宽时间,每按一次脉宽时间增大,周期不变,输出电压高,LED变亮
			if(set_flag>100)    //周期为5ms(我们自行设计分为100份),占空比不能超过100
					set_flag=0;
			
			while(s4==0)
			{
				led_pwm();
			}
    } 
  } 
}

3、通过步骤2设置的脉冲时间,进而算出占空比,占空比实现的程序如下

void led_pwm(void)
{
	if(flag<=set_flag)    //set_flag为脉冲宽度(高电平时间)
		led_stat=0x00;
	else
		led_stat=0xff;
		
	
	slect_138_573(4,led_stat);
}

 通过以上步骤既可以实现pwm控制呼吸灯,完整代码如下:

#include "stc15f2k60s2.h"
#include "intrins.h"

unsigned char flag=0,set_flag=0,led_stat=0xff;

//***********独立按键****************
sbit s7 = P3^0;
sbit s6 = P3^1;
sbit s5 = P3^2;
sbit s4 = P3^3;
//***********************************

void Delay1ms()		//@12.000MHz
{
	unsigned char i, j;

	i = 12;
	j = 169;
	do
	{
		while (--j);
	} while (--i);
}

void delay_ms(int x)
{
	while(x--)
	{
		Delay1ms();
	}
}


/* 选择通道并且输入数据 */
void slect_138_573(unsigned char channel, unsigned char dat)
{
	P0 = 0x00;
	P0 = dat;										/* 这里用P0而不用其他端口是因为我们操作LED、数码管、继电器、蜂鸣器都是对P0进行操作 */
	switch(channel)							/* 选择通道 */
	{
		case 4:										/* 使Y4输出低电平0,也就是操作LED */
			P2 = (P2 & 0x1f) | 0x80;/* (P2 & 0x1f)就是将前3位清0,再操作前3位。将0x80转为2进制1000 0000,这里只看前3位100就是Y4 */
		break;
		case 5:										/* 使Y5输出低电平0,也就是操作继电器和蜂鸣器 */
			P2 = (P2 & 0x1f) | 0xa0;
		break;
		case 6:										/* 使Y6输出低电平0,也就是操作8个数码管 */
			P2 = (P2 & 0x1f) | 0xc0;
		break;
		case 7:										/* 使Y7输出低电平0,也就是操作8个数码管中的1个数码管显示值 */
			P2 = (P2 & 0x1f) | 0xe0;
		break;
		case 0:										/* 关闭所有通道 */
			P2 = (P2 & 0x1f) | 0x00;
		break;
	}
	P2 = (P2 & 0x1f) | 0x00;		/* 使用后,关闭所有通道 */
	
}

void led_pwm(void)
{
	if(flag<=set_flag)
		led_stat=0x00;
	else
		led_stat=0xff;
		
	
	slect_138_573(4,led_stat);
}

void key_scan(void)
{  
  if(s4==0)
  {
    delay_ms(10);
    if(s4==0)
    {
			set_flag+=10;
			if(set_flag>100)
					set_flag=0;
			
			while(s4==0)
			{
				led_pwm();
			}
    } 
  } 
}



void Timer0Init(void)		//50微秒@12.000MHz
{
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0xCE;		//设置定时初值
	TH0 = 0xFF;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时

	EA=1;
	ET0=1;
}

//每50us进入一次中断,flag++,当flag=100时,就相当于过了5ms
//也就是相当于我们这里设置了一个pwm周期为5ms,频率为200Hz(f = 1/T)
void Timer0Service(void)  interrupt 1
{
	flag++;								
	if(flag==100)
		flag=0;
}


void System_init(void)
{
	slect_138_573(4,0xff);
	slect_138_573(5,0x00);
	Timer0Init();
}

void main(void)
{
	System_init();
	while(1)
	{
		key_scan();
		led_pwm();
	}
}

 总结:LED灯的亮度就是通过调节占空比来实现,通过调节占空比调节输出电压,进而调节LED灯的亮度。

 

 

  • 20
    点赞
  • 91
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Do My Best

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值