背景

最近做的项目中,有要求要实现LED灯光强弱变化控制的,之前有了解过呼吸灯的概念,也知道通过PWM来控制,但也只是停留在概念上面,以前也没有真正去做过这方面的,所以就在网上再搜罗了一番,感觉还是有些云里雾里的,最后只好自己静下心来,从原理上弄懂先。

原理

了解到要想改变LED亮度改变LED的电流,就需要,一则改变限流电阻,二则改变供电电压值
前者一般电阻都是选定,无法再做实时更改,就算可以实时(如数字电位器)在此也是大材小用。
后者则是一个良好的选择,电压怎么变,如下:

呼吸灯效果 Android_单片机

  • 该图展示了方波(PWM)与其电压有效值或者平均值的关系。
  • t/T的值可以改变输出的电压有效值或者平均值,t则是高电平时间T则是方波(PWM)的周期值
    我们只要固定方波周期值,固定高电平时间,即固定了占空比,也就固定了输出电压值。

实践

  • 例程代码:
//灯亮度控制
void Light_LuxAssign(unsigned char Lux_Strenth)//亮度配置(实设置高电平时长)
{
	static unsigned char breath_rt;         //呼吸计时器
	static const unsigned char breath_Ta=20;这里就先固定一下周期值(周期值不能超过22ms.否则会有闪烁现象,视觉暂留)
	static unsigned char breath_Ton; //高电平时间
	breath_Ton=Lux_Strenth;//注意Lux_Strenth不能超过周期值breath_Ta
	if(breath_Ta<breath_rt)//计时器累加到一个周期
	{
		breath_rt=0; //计时器归零	
	}		
	else 
	{
		breath_rt++;//计时器继续累加
	}
	(breath_Ton>breath_rt)?(LED7_O(1)):(LED7_O(0));//灯亮灭时间控制
}

这段函数功能是实现输入一个固定的高电平时间值(即固定占空比),然后LED就实现了LED的亮度控制。

呼吸灯效果 Android_呼吸灯效果 Android_02

  • 按此思路,然后就来呼吸灯的实现步骤:
  • 实现呼吸灯的效果,即运行过程中,就需要实现占空比(高电平时长)如同呼吸一样消长。因为如上言,改变占空比,即改变LED两端的电压有效值,也就改变了驱动LED的有效电流值,从而实现LED暗亮的渐变效果。即动态占空比的实现
  • 实现代码如下:
void Breath_Light(unsigned char breath_speed,unsigned char breath_Ta)// 呼吸速率(us)|呼吸时间(us)
{
	#define BREATH_TASK_TIME 200 //时基200us

	static unsigned char breath_dir;//呼吸方向(呼气/吸气)
	static unsigned char breath_rt;//呼吸计时器
	static unsigned char breath_speed_cnt;//呼吸速率累加器
	static unsigned char breath_Ton;//高电平时间
	
	if(!breath_dir)
	{
		if(breath_Ta<breath_rt)//计时器累加到一个周期
		{
			breath_rt=0; //计时器归零
			if(0==breath_speed_cnt++%breath_speed)	
			{
				breath_speed_cnt=0;
		   	breath_Ton++;//占空比加大
			}				
		}		
		else  //
		{
			breath_rt++;//计时器继续累加
		}
		if(breath_Ton>=breath_Ta)
		{		
			breath_dir=1;
			breath_Ton=breath_Ta;
		}	
		(breath_Ton>breath_rt)?(LED7_O(1)):(LED7_O(0));	//Ton导通时间区	
	}
	else
	{
		if(breath_Ta<breath_rt)//计时器累加到一个周期
		{
			breath_rt=0; //计时器归零
			if(0==breath_speed_cnt++%breath_speed)	
			{
				breath_speed_cnt=0;
				breath_Ton--;//占空比减小
			}		
		}		
		else  //
		{
			breath_rt++;//计时器继续累加
		}
		if(0>=breath_Ton)
		{		
			breath_dir=0;
			breath_Ton=0;
		}
		(breath_Ton>breath_rt)?(LED7_O(1)):(LED7_O(0));		
	}
}
  • 上面函数是在定时器(定时时基为200us)中运行的.
  • 定时器中断如下:
void TIM1_ISR() interrupt 3 
{
//	Breath_Light(5,100);//呼吸灯
	Light_LuxAssign(20);//暗弱控制
}