/* * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ #include #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_log.h" #include "driver/rmt_tx.h" #include "led_strip_encoder.h" #define RMT_LED_STRIP_RESOLUTION_HZ 10000000 // 10MHz resolution #define RMT_LED_STRIP_GPIO_NUM 10 // GPIO10 #define EXAMPLE_LED_NUMBERS 22 // 22个LED #define REFRESH_MS 20 // 刷新间隔,20ms = 50fps #define BREATH_CYCLE_MS 3000 // 呼吸周期(淡入+淡出) #define CHASE_SPEED_DEG 5 // 每次色环偏移角度 static const char *TAG = "rainbow_breath"; static uint8_t led_strip_pixels[EXAMPLE_LED_NUMBERS * 3]; /** * @brief HSV转RGB */ void led_strip_hsv2rgb(uint32_t h, uint32_t s, uint32_t v, uint32_t *r, uint32_t *g, uint32_t *b) { h %= 360; uint32_t rgb_max = v * 255 / 100; uint32_t rgb_min = rgb_max * (100 - s) / 100; uint32_t i = h / 60; uint32_t diff = h % 60; uint32_t rgb_adj = (rgb_max - rgb_min) * diff / 60; switch (i) { case 0: *r = rgb_max; *g = rgb_min + rgb_adj; *b = rgb_min; break; case 1: *r = rgb_max - rgb_adj; *g = rgb_max; *b = rgb_min; break; case 2: *r = rgb_min; *g = rgb_max; *b = rgb_min + rgb_adj; break; case 3: *r = rgb_min; *g = rgb_max - rgb_adj; *b = rgb_max; break; case 4: *r = rgb_min + rgb_adj; *g = rgb_min; *b = rgb_max; break; default: *r = rgb_max; *g = rgb_min; *b = rgb_max - rgb_adj; break; } } void app_main(void) { ESP_LOGI(TAG, "Create RMT TX channel on GPIO%d", RMT_LED_STRIP_GPIO_NUM); rmt_channel_handle_t led_chan = NULL; rmt_tx_channel_config_t tx_chan_config = { .clk_src = RMT_CLK_SRC_DEFAULT, .gpio_num = RMT_LED_STRIP_GPIO_NUM, .mem_block_symbols = 64, .resolution_hz = RMT_LED_STRIP_RESOLUTION_HZ, .trans_queue_depth = 4, }; ESP_ERROR_CHECK(rmt_new_tx_channel(&tx_chan_config, &led_chan)); ESP_LOGI(TAG, "Install led strip encoder"); rmt_encoder_handle_t led_encoder = NULL; led_strip_encoder_config_t encoder_config = { .resolution = RMT_LED_STRIP_RESOLUTION_HZ, }; ESP_ERROR_CHECK(rmt_new_led_strip_encoder(&encoder_config, &led_encoder)); ESP_LOGI(TAG, "Enable RMT TX channel"); ESP_ERROR_CHECK(rmt_enable(led_chan)); ESP_LOGI(TAG, "Start Rainbow Breath Chase, LED count: %d", EXAMPLE_LED_NUMBERS); rmt_transmit_config_t tx_config = { .loop_count = 0, }; uint16_t hue_offset = 0; // 彩虹色环偏移(跑马灯) int breath_tick = 0; // 呼吸时间计数器 while (1) { // 计算当前呼吸亮度系数:0.0 ~ 1.0 float breath_phase = (2.0f * 3.1415926f * breath_tick * REFRESH_MS) / BREATH_CYCLE_MS; float breath_brightness = (sinf(breath_phase) + 1.0f) / 2.0f; // 0.0 ~ 1.0 // 为每个LED计算颜色:彩虹分布 + 呼吸亮度 for (int i = 0; i < EXAMPLE_LED_NUMBERS; i++) { // 每个LED在色环上均匀分布,加上偏移实现流动 uint16_t hue = ((i * 360 / EXAMPLE_LED_NUMBERS) + hue_offset) % 360; uint32_t r, g, b; // 先计算全亮彩虹色 led_strip_hsv2rgb(hue, 100, 100, &r, &g, &b); // 叠加呼吸亮度 r = (uint32_t)(r * breath_brightness); g = (uint32_t)(g * breath_brightness); b = (uint32_t)(b * breath_brightness); // GRB顺序写入 led_strip_pixels[i * 3 + 0] = (uint8_t)g; led_strip_pixels[i * 3 + 1] = (uint8_t)b; led_strip_pixels[i * 3 + 2] = (uint8_t)r; } // 发送数据到灯带 ESP_ERROR_CHECK(rmt_transmit(led_chan, led_encoder, led_strip_pixels, sizeof(led_strip_pixels), &tx_config)); ESP_ERROR_CHECK(rmt_tx_wait_all_done(led_chan, portMAX_DELAY)); // 更新跑马灯偏移 hue_offset = (hue_offset + CHASE_SPEED_DEG) % 360; // 更新呼吸计数器 breath_tick++; vTaskDelay(pdMS_TO_TICKS(REFRESH_MS)); } }