PWM控制LED亮度线性变化的单片机实现

一、概述

玩过单片机的基本都做过用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线性调光;

参考文章:LED亮度线性变化难搞?PWM占空比帮你忙

猜你喜欢

转载自blog.csdn.net/SammySum/article/details/95938143