一、冷暖光的PWM关系;
我们在买灯具时候,一般看我们的灯支持怎么样的调节,比如只是单色,冷暖色,还是RGB七彩控制的。
一般地,家庭也就单色和冷暖光为多,而 RGB 是那些舞台音乐场景为多。所以,智能家居的灯具涉及,以单色和冷暖光为多,以 冷暖光为例,那些灯具的色温是怎么定义的? PWM 又是如何输出这样的效果呢? 这里,我一一为大家阐述:
2.1、色温的定义
任何一种属性都有单位,比如温度有摄氏度,而色温的单位是 卡尔文 ,简称 K,下面一图说明了:
色温数值越大,看到的效果越冷白;
误解:色温越大,就越暖光;
而我们常买的灯具又是如何产生这样的效果呢? 聪明的开发者,采用冷白灯珠和暖光灯具各自产生的亮度不一样,就有了以上的效果!下面是我平时开发中常用的2钟灯珠类型,3.3v即可点亮;
2.2、PWM与指定的色温亮度的计算
PWM平滑调光已经在目前最新的 master 分支实现了,例子位置在:
这里带带大家简单入门这个例子:
- LEDC功能来源 ESP32 之鉴,
ledc_timer_config_t
的配置分辨率尤其重要,例子是采用13位的LEDC_TIMER_13_BIT
,又可以参照结构体设置其他分辨率; - 配置 GPIO 引脚的方法,参考官方例子;
- 然后,我们最关心的是设置占空比方法的对应方法入参,
ledc_set_fade_with_time(模式,通道,周期,渐变时间);
而设置周期的入参范围:[ 0 , 2的分辨率位数次方],以13位分辨率举个例子,就是 2的13次方,即 2^13=8192。所以,设置是13位分辨率的话,入参范围为:【0,8192】。 - 还有重要一步,开始设置,类似
pwm_start()
;采用ledc_fade_start(模式,通道 是否阻塞);
,后面的阻塞和非阻塞可能有些不懂,就是等待这个方法函数执行完毕再下一个方法,而如果是非阻塞,直接返回执行下一个函数;
而目前 2020.4.30 我本人今天在跑这个例子时候,发现一个bug,现已提交上去,具体的issue链接在这: issues/883,对于这个bug我也是无脑解决,具体的解决方法在上述的链接里面;
以上就是的带领大家简单入门 LEDC 的例子,下面步入正题;
既然有2个灯珠同时在亮,各自的亮度不同来调节色温亮度,那么我们好奇的是如何通过 pwm 产生这样的关系呢?
很多人也许会这样说:色温大小就是暖色灯珠的亮度明暗,而亮度大小就是冷白灯珠的亮度明暗,这样的说话是错误的!
对于 PWM 和 色温亮度的计算的公式,博主接触到很多公式,这里本人总结的为例,如下:
- color_temperature :用户预想的灯具色温数值,范围[2700,6500] ,这范围是参 阿里飞燕平台的;
- brightness :用户预想的灯具的亮度数值,范围[0,100]
- 下面的 8192 的是从上面 13位定时器
- 计算过程如下,得到的
cold_tmp
是PWM
冷灯珠的占空比,warm_tmp
是PWM
冷灯珠的占空比:
int part = (APK_MAX_COLORTEMP - APK_MIN_COLORTEMP) / 100;
int temp = APK_MAX_COLORTEMP - color_temperature;
int tempWW = ((temp) / part);
uint8_t outCW = (brightness - (brightness * tempWW / 100));
uint8_t outWW = (brightness * tempWW / 100);
int outBrightnessChannle = 8192 * outCW / 100;
int outColortempChannle = 8192 * outWW / 100;
看了上面的计算步骤,是否很简单?我们可以假想一下:
- 效果1 中性光 :
入参color_temperature
= 4096 ,brightness
= 100 ;
代入公式后得到:outColortempChannle
=4096 ,outBrightnessChannle
=50 ; - 效果2 最冷光 :
入参color_temperature
= 8192 ,brightness
= 100 ;
代入公式后得到:outColortempChannle
=8192 ,outBrightnessChannle
=0; - 效果3 最暖光 :
入参color_temperature
= 0,brightness
= 100 ;
代入公式后得到:outColortempChannle
=0,outBrightnessChannle
=8192 ;
效果 | 预想的各路PWM输出 | 以上公式算出来的PWM输出 | 对比结果 |
中性光 | 2路一样亮度的输出 |
| 符合 |
最冷光效果 | 冷灯珠100亮度,暖灯珠0亮度 |
| 反了 |
最暖光效果 | 冷灯珠 0亮度,暖灯珠100亮度 |
| 反了 |
以上步骤,为啥结论是反了?因为上上图可以看到:色温数值越大表示越冷效果,意味着色温越大,其暖灯珠的PWM高电平占空比越小! 那么我们如何纠正这个错误呢?
这不用我来说吧?把入参的 color_temperature
修改为即可:
color_temperature = 6500 - color_temperature + 2700
二、相关API接口
- 先看看我们的头文件,思路非常清晰,就是可开发性非常高。
- 根据自己的需求,修改 GPIO 引脚配置;
/*************** 用户可修改 start **********************/
#define LEDC_FADE_TIME (2000) //渐变时间
#define APK_MAX_COLORTEMP 6500 //用户定义最大的色温数值
#define APK_MID_COLORTEMP 4800 //用户定义中间的色温数值
#define APK_MIN_COLORTEMP 2700 //用户定义最小的色温数值
#define APK_MAX_COLOR 255 //用户定义最大的RGB数值
//pwm gpio口配置
#define CHANNLE_PWM_TOTAL 5 //五路
#define PWM_CW_OUT_IO_NUM 14 //冷灯珠
#define PWM_WW_OUT_IO_NUM 13 //暖灯珠
#define PWM_RED_OUT_IO_NUM 12 //红色灯珠
#define PWM_GREEN_OUT_IO_NUM 15 //绿色灯珠
#define PWM_BLUE_OUT_IO_NUM 5 //蓝色灯珠
//是否带有记忆功能
#define IS_SAVE_PARAMS true
/*************** 用户可修改 end**********************/
typedef struct User_dev_status_t
{
int Power;
int Mode;
int Brightness;
int Colortemp;
int Red;
int Green;
int Blue;
} User_dev_status_t;
/**
* @brief 设置
*/
esp_err_t pwm_init_data(); //gpio初始化
esp_err_t light_driver_set_color_temperature(uint8_t color_temperature);
esp_err_t light_driver_set_brightness(uint8_t brightness);
esp_err_t light_driver_set_colorTemperature(int colorTemperature);
esp_err_t light_driver_set_ctb(const int brightness, const int color_temperature); //设置色温亮度
esp_err_t light_driver_set_rgb(const uint8_t red, const uint8_t green, const uint8_t blue);
esp_err_t light_driver_set_switch(bool status); //设置开关
esp_err_t light_driver_set_mode(uint8_t mode); //设置模式
esp_err_t light_driver_set_cycle(uint8_t nums); // 设置呼吸效果
esp_err_t light_driver_set_ctb_from_last(); //恢复上次的状态
三、其他
- 一般地,不能同时调节 RGB 和 冷暖灯珠的;
- 具体的使用参考demo吧,也欢迎大家留言:
https://github.com/xuhongv/StudyInEsp8266/tree/master/47_ESP8266_Rtos3.0_Brightness_Colortemp