Files
gpio_led/main/led_strip_example_main.c
2026-06-24 16:37:26 +08:00

118 lines
4.1 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <string.h>
#include <math.h>
#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));
}
}