一、概述
玩过单片机的基本都做过用LED灯实现呼吸灯的功能,但是只要认真观察,会发现LED的亮度变化在低占空比的时候,变化很明显,而在高占空比的时候反而变化很小,导致呼吸灯表现呼吸不均匀的现象呢?带着这个问题,我将为大家介绍如何使用PWM控制,来实现LED亮度的线性变化。
二、原理分析
首先,我们知道LED驱动是恒流的,而PWM调节的是恒流时间与断流时间的比值,所以占空比和光通量的输出应该是线性的。虽然,光通量是可以随时间线性变化,但是人眼对光的感受却不是线性的。一般表现形式为,在弱光情况下,很小的光通量能让人眼感觉光变化很大,在强光情况下,很大的光通量变化,人眼的感觉也不大。
图一表示实际的占空比与光通量的线性关系;图二表示人眼的感光变化;图三图四同理;
三、代码实现
从上图可以知道,要想实现人眼感光的线性变化,那么将实际光通量控制为非线性变化,即控制PWM非线性变化。我的思路是设计一个PWM表来存储适当的PWM控制值,通过顺序输入这个表的值来实现控制。如下代码:
static const uint16_t s_cusLEDPWM[57] = {
0,0,0,0,0,
1,1,1,1,2,2,2,3,4,5,
6,7,8,10,12,15,18,22,26,31,
38,46,55,66,79,95,114,137,164,197,
237,284,341,410,492,590,708,850,1020,1224,
1469,1763,2116,2539,3047,3657,4388,5266,6319,7583,
9100,10000
};
__task void AppTask10Ms(void)
{
static uint8_t s_ucPWMDir = 0,s_ucPWMNbr = 0,s_ucLEDPWMCount = 0;
static uint16_t s_usTIM1CH1PWM = 0;
while(1)
{
if(++s_ucLEDPWMCount >= 5)
{
s_ucLEDPWMCount = 0;
if(s_ucPWMDir == 0)
{
if(s_ucPWMNbr < 56)
{
s_usTIM1CH1PWM = s_cusLEDPWM[s_ucPWMNbr++];
}
else
{
s_ucPWMDir = 1;
}
}
else
{
if(s_ucPWMNbr > 0) s_usTIM1CH1PWM = s_cusLEDPWM[s_ucPWMNbr--];
else
{
s_ucPWMDir = 0;
}
}
g_tTimPWMOpr.SetTIMOutPWM(GPIOA,GPIO_Pin_8,TIM1,1,10000,(10000 - s_usTIM1CH1PWM));
g_tTimPWMOpr.SetTIMOutPWM(GPIOA,GPIO_Pin_11,TIM1,4,10000,(10000 - s_usTIM1CH1PWM));
}
os_dly_wait(10);
}
}
问:这个表怎么设置的?
答:使用Execl表格辅助计算,计算公式为:第K个数据=第K-1个数据*调光系数;
四、总结
通过上述的方式,即可实现简单的LED线性调光;