#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_log.h"
#include "driver/ledc.h"
#define MAX_NODE_NUM 6
#define MINUTES_IN_A_DAY 1440 // 一天的总分钟数
// GPIO映射
#define LEDC_GPIO_R 5 // 对应io5
#define LEDC_GPIO_G 6 // 对应io6
#define LEDC_GPIO_B 7 // 对应io7
#define LEDC_GPIO_W 4 // 对应io4
// 通道定义
#define LEDC_CHANNEL_R LEDC_CHANNEL_0
#define LEDC_CHANNEL_G LEDC_CHANNEL_1
#define LEDC_CHANNEL_B LEDC_CHANNEL_2
#define LEDC_CHANNEL_W LEDC_CHANNEL_3
#define LEDC_TIMER LEDC_TIMER_0
#define LEDC_MODE LEDC_LOW_SPEED_MODE
#define LEDC_DUTY_RES LEDC_TIMER_8_BIT // 8位分辨率,范围0-255
#define LEDC_FREQUENCY 5000 // 5kHz的PWM频率
typedef struct {
int minute_of_day; // 时间点,以分钟计
uint8_t rgbw[4]; // RGBW值
} TimeNode;
TimeNode timeNodes[MAX_NODE_NUM];
// 初始化时间点
void init_time_nodes() {
// 示例,初始化12个时间点和对应的RGBW值
timeNodes[0].minute_of_day = 5; // 08:00
timeNodes[0].rgbw[0] = 0; // R
timeNodes[0].rgbw[1] = 0; // G
timeNodes[0].rgbw[2] = 0; // B
timeNodes[0].rgbw[3] = 0; // W
timeNodes[1].minute_of_day = 10; // 12:00
timeNodes[1].rgbw[0] = 254;
timeNodes[1].rgbw[1] = 254;
timeNodes[1].rgbw[2] = 254;
timeNodes[1].rgbw[3] = 254;
timeNodes[2].minute_of_day = 20; // 12:00
timeNodes[2].rgbw[0] = 50;
timeNodes[2].rgbw[1] = 100;
timeNodes[2].rgbw[2] = 50;
timeNodes[2].rgbw[3] = 100;
timeNodes[3].minute_of_day = 30; // 12:00
timeNodes[3].rgbw[0] = 0;
timeNodes[3].rgbw[1] = 254;
timeNodes[3].rgbw[2] = 0;
timeNodes[3].rgbw[3] = 254;
timeNodes[4].minute_of_day = 40; // 12:00
timeNodes[4].rgbw[0] = 100;
timeNodes[4].rgbw[1] = 100;
timeNodes[4].rgbw[2] = 200;
timeNodes[4].rgbw[3] = 100;
timeNodes[5].minute_of_day = 50; // 12:00
timeNodes[5].rgbw[0] = 0;
timeNodes[5].rgbw[1] = 0;
timeNodes[5].rgbw[2] = 0;
timeNodes[5].rgbw[3] = 0;
// 继续初始化其他时间点...
}
// 软件模拟当前时间从00:00开始的分钟数
int simulated_minutes = 0;
// 线性插值计算RGBW值
void interpolate_rgbw(uint8_t *rgbw_start, uint8_t *rgbw_end, float t, uint8_t *rgbw_out) {
for (int i = 0; i < 4; i++) {
rgbw_out[i] = (uint8_t)(rgbw_start[i] + t * (rgbw_end[i] - rgbw_start[i]));
}
}
// 根据当前时间找到相邻的时间点
void find_adjacent_nodes(int current_minute, int *start_idx, int *end_idx, float *t) {
for (int i = 0; i < MAX_NODE_NUM - 1; i++) {
int start_minute = timeNodes[i].minute_of_day;
int end_minute = timeNodes[i + 1].minute_of_day;
if (current_minute >= start_minute && current_minute <= end_minute) {
*start_idx = i;
*end_idx = i + 1;
// 计算t,表示当前时间相对于两个时间点的比例
*t = (float)(current_minute - start_minute) / (float)(end_minute - start_minute);
return;
}
}
// 如果当前时间超过最后一个时间点,保持最后一个状态
*start_idx = MAX_NODE_NUM - 1;
*end_idx = MAX_NODE_NUM - 1;
*t = 0.0f; // t = 0表示保持最后一个状态
}
// 初始化LEDC模块
void init_ledc() {
// 配置LEDC定时器
ledc_timer_config_t ledc_timer = {
.speed_mode = LEDC_MODE,
.timer_num = LEDC_TIMER,
.duty_resolution = LEDC_DUTY_RES,
.freq_hz = LEDC_FREQUENCY,
.clk_cfg = LEDC_AUTO_CLK
};
ledc_timer_config(&ledc_timer);
// 配置LEDC通道
ledc_channel_config_t ledc_channel[4] = {
{
.speed_mode = LEDC_MODE,
.channel = LEDC_CHANNEL_R,
.timer_sel = LEDC_TIMER,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = LEDC_GPIO_R,
.duty = 0, // 初始占空比为0
.hpoint = 0
},
{
.speed_mode = LEDC_MODE,
.channel = LEDC_CHANNEL_G,
.timer_sel = LEDC_TIMER,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = LEDC_GPIO_G,
.duty = 0,
.hpoint = 0
},
{
.speed_mode = LEDC_MODE,
.channel = LEDC_CHANNEL_B,
.timer_sel = LEDC_TIMER,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = LEDC_GPIO_B,
.duty = 0,
.hpoint = 0
},
{
.speed_mode = LEDC_MODE,
.channel = LEDC_CHANNEL_W,
.timer_sel = LEDC_TIMER,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = LEDC_GPIO_W,
.duty = 0,
.hpoint = 0
}
};
// 初始化每个通道
for (int i = 0; i < 4; i++) {
ledc_channel_config(&ledc_channel[i]);
}
// 启动LEDC淡入淡出功能
ledc_fade_func_install(0);
}
// 设置RGBW灯的亮度值
void set_rgbw(uint8_t *rgbw) {
// 设置R通道占空比
ledc_set_duty(LEDC_MODE, LEDC_CHANNEL_R, rgbw[0]);
ledc_update_duty(LEDC_MODE, LEDC_CHANNEL_R);
// 设置G通道占空比
ledc_set_duty(LEDC_MODE, LEDC_CHANNEL_G, rgbw[1]);
ledc_update_duty(LEDC_MODE, LEDC_CHANNEL_G);
// 设置B通道占空比
ledc_set_duty(LEDC_MODE, LEDC_CHANNEL_B, rgbw[2]);
ledc_update_duty(LEDC_MODE, LEDC_CHANNEL_B);
// 设置W通道占空比
ledc_set_duty(LEDC_MODE, LEDC_CHANNEL_W, rgbw[3]);
ledc_update_duty(LEDC_MODE, LEDC_CHANNEL_W);
}
void app_main(void) {
init_time_nodes(); // 初始化时间点
init_ledc(); // 初始化LEDC模块
uint8_t rgbw_out[4]; // 保存输出的RGBW值
while (true) {
// 模拟时间流逝,每次循环增加1分钟
simulated_minutes = (simulated_minutes + 1) % MINUTES_IN_A_DAY; // 每分钟递增
int start_idx, end_idx;
float t;
find_adjacent_nodes(simulated_minutes, &start_idx, &end_idx, &t); // 找到相邻时间点
// 计算渐变的RGBW值
interpolate_rgbw(timeNodes[start_idx].rgbw, timeNodes[end_idx].rgbw, t, rgbw_out);
// 设置RGBW输出
set_rgbw(rgbw_out);
vTaskDelay(pdMS_TO_TICKS(1000)); // 模拟每分钟更新一次
}
}