0x00 背景
这篇文章大部分内容是我参考一篇国外极客写的文章,然后加上我的理解以及其他文献资料的补充来帮助读者理解。在这里不得不佩服人家的分享精神以及理论结合实际的能力,因为他的文章确实帮助我解决了在线性调LED亮度中遇到的问题。
0x01 文章里出现的英文单词解释
lightness = LED 亮度
luminance = LED 的照度(单位:流明),即单位面积上通过的光量
0x02 用PWM控制LED亮度遇到的问题
其实用PWM控制LED的亮度并不是你想的那么简单。下图描绘出PWM是一种通过调整占空比的方式工作的方波:
通过调整PWM高电平的占空比,我们可以控制LED的亮度(lightness)。大部分单片机都带PWM外设,或者你用软件模拟一个PWM也行。
然而当我们用下面的代码线性控制PWM输出时,LED的亮度(lightness)在我们人眼视觉的上看却不是线性的变化:
可以看到,从暗到亮,线性效果并不是那么好,在前一段亮度增加的非常快,后期大部分时间都是在全亮的状态,如下图:
这背后的原因就是人眼对光的感知并不是线性的,而是呈log函数形式,那么解决问题的方法就来了!
0x03 如何让PWM占空比和亮度(lightness)呈线性
为了解决问题,我们必须让PWM的输出符合人眼的视觉感知曲线。下面的CIE 1931 lightness 公式即描绘了我们人眼是如何感知光的亮度:
将公式转换一下得到:
公式中,L是亮度(lightness),Y是流明(luminance)分析一下上面的公式,L就是我们人眼感知的亮度,Y就是光线的照度流明,那么怎么将L、Y以及PWM联系起来呢?通过查阅相关文献,我知道了luminance和PWM是呈正比的关系,其实也很好解释,PWM为高电平时LED导通,导通后就有光通过,而luminance表征的正是光通过的量。参考文献见下图:
然后根据上面的公式,我们只需要将L作为输入,线性的给L赋值,就可以得到对应的Y(同PWM)。
0x04 在单片机中实现上述理论推导
如果在单片机中实现上面的公式会很慢,应为涉及到除法及开立方运算。所以需要我们生成一个保存运算结果的表格供单片机查询即可。下面的Python 脚本程序即提供了自动生成L->PWM表格的功能。Python 脚本如何使用请自行学习。
在电脑上执行上面的Python脚本代码后,会在本地生成一个.h头文件,里面包含一个Lightness 和 PWM关系的一维数组表格。
脚本中 INPUT_SIZE = 255 表示将LED的亮度(lightness)等分成256阶,即256灰阶度,OUTPUT_SIZE = 255 表示你用的是一个8-bit 的PWM。下面举个栗子:
比如你的单片机用的是10-bit PWM外设,而LED的亮度你希望等分成32阶,那么你需要将INPUT_SIZE设置成31,OUTPUT_SIZE 设置成1023。最后运行脚本你会生成一个包含32个元素的一维数组,元素值域在0~1023,形如:
const unsigned char cie[32] = {0, 4, 7, ... , 940, 1023};
将生成数组应用到单片机程序中,用如下代码测试:
最后,可以看到LED的亮度在我们人眼的观察下,最终呈现线性的变化!
网友评论