关于RGB 调光抖动的问题

2019-12-15 12:04发布

大神,请教一个关于rgb的调光的问题:
我在调节亮度的时候,得到一个PWM 的调光曲线,R,G,B 的取值范围为(0~255)
然后通过如下的公式
                        u16Red = (uint16)((uint32)u8CurrRed * (uint32)au16DimmerCurve[u8CurrLevel]/(uint32)255);
                        u16Green = (uint16)((uint32)u8CurrGreen * (uint32)au16DimmerCurve[u8CurrLevel]/(uint32)255);
                        u16Blue = (uint16)((uint32)u8CurrBlue * (uint32)au16DimmerCurve[u8CurrLevel]/(uint32)255);
得到r,g,b的值,然后输出PWM,但是调 {MOD}的时候还好,调节亮度的时候会有点抖动,请问有没有什么好的建议?
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
15条回答
smallwood
2019-12-17 12:30
本帖最后由 smallwood 于 2018-11-12 12:39 编辑

调光要用对数/指数, 这是大家都知道的, 因为人眼看光度的变化是非线性的, 所以要把pwm值先变成曲线再写进pwm timer, 这样调出来的光人眼看起来才是线性的.

想要PWM调光细腻平滑不抖动, 有两个决定因素:1). pwm timer的分辨率要够大, 2). 扫描频率要够高.

第一点pwm timer分辨率: 决定了pwm的duty cycle波形变化够不够细腻. 用8bit(256级)pwm timer是不够的,要用16bit(65536计),有32bit就更好. 不过16bit timer做出来的调光效果已经可以非常平滑, 无论是0.1秒内快速调光,还是1小时/10小时内很慢调光, 光度/颜 {MOD}的过渡肉眼都可以没法看出任何抖动.
第二点扫描频率: 就是每一次扫描变更一次pwm timer的值. 每秒扫描60次或以上肉眼已经看不出闪动(所谓频闪), 当然扫描频率越高越好, 例如几百Hz到几KHz, 扫描频率够高的话, 就没有所谓的用手机摄像头拍照会看到频闪.

一般的stm8和stm32都有16bit pwm timer, 用一个pwm timer就可以做到.

给你程序设计的思路:

1. 设timer的period为:65535, 如果是stm8s用16MHz, 在每次timer中断里刷新pwm timer内容, 刷新频率就是: 16000000/65536=244.14Hz, 已经超过最低60次每秒的扫描频率所以很足够了. 如果是stm32f0用48MHz, 刷新频率就是: 48000000/65536=732.42Hz 更好.

2. 在timer的中断里, 用指数算式(不要用查表)算出每一次的pwm值,写进pwm timer. 例如:

-----------------------------------
#include "stm32f0xx.h"
#include <math.h>
...

static float brightness = 0;
void TIM3_IRQHandler(void)
{
    double pwm_value;

    brightness = brightness + 0.1; //+0.1是每次增加0.1级调光, 这只是任意的, 你可以根据要求自己算每次要加/减多少.
    pwm_value = pow(brightness ^ 2.2); //pow()函数, 2.2是一个阈值,不同阈值会影响曲线特性,你可以改为2, 1.x, 2.x 看看那个更好更符合你的调光要求.

    if(pwm_value > 65535)
        pwm_value = 65535;
    else if(pwm_value < 1)
        pwm_value =0;

    TIM3->CCR1 = (uint32_t)pwm_value;
}

-----------------------------------

解释一下: 上面不是完整的程序,只是为了解释程序的思路而已. 大概意思是从完全不亮调到全亮(在2秒多内). brightness 是一个线性值,你可以设0-154.6344, 这样就可以得到最暗/最亮的pwm_value值: 0-65535.022 (65535.022=pow(154.6344^2.2)) 你可以在timer中断里每次把brightness 加0.1: brightness = brightness + 0.1;
你也可以不在timer中断里, 而在一个loop里设pwm timer的值.

一周热门 更多>