├── .gitignore
├── image.jpg
├── 59333df79fe9b88a5f6df7c52084de0.jpg
├── idf_component.yml
├── CMakeLists.txt
├── LICENSE
├── Kconfig.projbuild
├── include
├── led_strip.h
└── ws2812_control.h
├── README.md
├── README_EN.md
├── led_strip_rmt_ws2812.c
└── ws2812_control.cpp
/.gitignore:
--------------------------------------------------------------------------------
1 | dist/
--------------------------------------------------------------------------------
/image.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NingZiXi/ws2812_control/HEAD/image.jpg
--------------------------------------------------------------------------------
/59333df79fe9b88a5f6df7c52084de0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NingZiXi/ws2812_control/HEAD/59333df79fe9b88a5f6df7c52084de0.jpg
--------------------------------------------------------------------------------
/idf_component.yml:
--------------------------------------------------------------------------------
1 | version: 1.4.1
2 | license: "MIT"
3 | description: ws2812_control
4 | url: https://github.com/NingZiXi/ws2812_control
5 | files:
6 | exclude:
7 | - .git
8 | dependencies:
9 | idf:
10 | version: ">=4.4.7"
11 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | idf_component_register(SRCS "ws2812_control.cpp"
2 | "led_strip_rmt_ws2812.c"
3 | INCLUDE_DIRS "include"
4 | REQUIRES driver esp_timer
5 | )
6 |
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 宁子希
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/Kconfig.projbuild:
--------------------------------------------------------------------------------
1 | menu "ws2812 config"
2 |
3 | choice WS2812_MODE
4 | prompt "ws2812 mode (Strip mode, Matrix mode)"
5 | default WS2812_MODE_STRIP
6 | help
7 | Select the mode of the matrix.
8 |
9 | config WS2812_MODE_STRIP
10 | bool "Strip mode"
11 | help
12 | Select strip mode (single WS2812 strip).
13 |
14 | config WS2812_MODE_MATRIX
15 | bool "Matrix mode"
16 | help
17 | Select WS2812 mode (matrix of WS2812 LEDs).
18 | endchoice
19 |
20 | config WS2812_TX_GPIO
21 | int "GPIO number for ws2812 TX"
22 | default 33
23 | help
24 | GPIO number for the number TX signal.
25 |
26 | if WS2812_MODE_STRIP
27 | config WS2812_STRIP_LED_NUMBER
28 | int "Number of LEDs in the strip"
29 | default 12
30 | help
31 | Number of LEDs in the WS2812 LED strip.
32 | endif
33 |
34 | if WS2812_MODE_MATRIX
35 | config WS2812_MATRIX_WIDTH
36 | int "Matrix width (number of LEDs per row)"
37 | default 8
38 | help
39 | Number of LEDs in each row of the matrix.
40 |
41 | config WS2812_MATRIX_HEIGHT
42 | int "Matrix height (number of LEDs per column)"
43 | default 8
44 | help
45 | Number of LEDs in each column of the matrix.
46 |
47 | choice WS2812_MATRIX_START_CORNER
48 | prompt "Matrix start corner"
49 | default WS2812_MATRIX_START_TOP_RIGHT
50 | help
51 | Select the starting corner of the LED matrix.
52 |
53 | config WS2812_MATRIX_START_TOP_LEFT
54 | bool "Top left"
55 |
56 | config WS2812_MATRIX_START_TOP_RIGHT
57 | bool "Top right"
58 |
59 | config WS2812_MATRIX_START_BOTTOM_LEFT
60 | bool "Bottom left"
61 |
62 | config WS2812_MATRIX_START_BOTTOM_RIGHT
63 | bool "Bottom right"
64 | endchoice
65 |
66 | choice "Matrix Layout Orientation"
67 | prompt "Matrix Layout Orientation"
68 | default WS2812_MATRIX_LAYOUT_HORIZONTAL
69 | help
70 | Choose whether the matrix is row-major or column-major.
71 |
72 | config WS2812_MATRIX_LAYOUT_HORIZONTAL
73 | bool "Row-Major (Horizontal)"
74 |
75 | config WS2812_MATRIX_LAYOUT_VERTICAL
76 | bool "Column-Major (Vertical)"
77 | endchoice
78 |
79 | choice "Matrix Scan Order"
80 | prompt "Matrix Scan Order"
81 | default WS2812_MATRIX_SCAN_ZIGZAG
82 | help
83 | Choose the scanning order of the matrix lines.
84 |
85 | config WS2812_MATRIX_SCAN_PROGRESSIVE
86 | bool "Progressive"
87 |
88 | config WS2812_MATRIX_SCAN_ZIGZAG
89 | bool "Zigzag"
90 | endchoice
91 | endif
92 |
93 | endmenu
94 |
--------------------------------------------------------------------------------
/include/led_strip.h:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Espressif Systems (Shanghai) PTE LTD
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | #pragma once
15 |
16 | #ifdef __cplusplus
17 | extern "C" {
18 | #endif
19 |
20 | #include "esp_err.h"
21 |
22 | /**
23 | * @brief LED Strip Type
24 | *
25 | */
26 | typedef struct led_strip_s led_strip_t;
27 |
28 | /**
29 | * @brief LED Strip Device Type
30 | *
31 | */
32 | typedef void *led_strip_dev_t;
33 |
34 | /**
35 | * @brief Declare of LED Strip Type
36 | *
37 | */
38 | struct led_strip_s {
39 | /**
40 | * @brief Set RGB for a specific pixel
41 | *
42 | * @param strip: LED strip
43 | * @param index: index of pixel to set
44 | * @param red: red part of color
45 | * @param green: green part of color
46 | * @param blue: blue part of color
47 | *
48 | * @return
49 | * - ESP_OK: Set RGB for a specific pixel successfully
50 | * - ESP_ERR_INVALID_ARG: Set RGB for a specific pixel failed because of invalid parameters
51 | * - ESP_FAIL: Set RGB for a specific pixel failed because other error occurred
52 | */
53 | esp_err_t (*set_pixel)(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue);
54 |
55 | /**
56 | * @brief Refresh memory colors to LEDs
57 | *
58 | * @param strip: LED strip
59 | * @param timeout_ms: timeout value for refreshing task
60 | *
61 | * @return
62 | * - ESP_OK: Refresh successfully
63 | * - ESP_ERR_TIMEOUT: Refresh failed because of timeout
64 | * - ESP_FAIL: Refresh failed because some other error occurred
65 | *
66 | * @note:
67 | * After updating the LED colors in the memory, a following invocation of this API is needed to flush colors to strip.
68 | */
69 | esp_err_t (*refresh)(led_strip_t *strip, uint32_t timeout_ms);
70 |
71 | /**
72 | * @brief Clear LED strip (turn off all LEDs)
73 | *
74 | * @param strip: LED strip
75 | * @param timeout_ms: timeout value for clearing task
76 | *
77 | * @return
78 | * - ESP_OK: Clear LEDs successfully
79 | * - ESP_ERR_TIMEOUT: Clear LEDs failed because of timeout
80 | * - ESP_FAIL: Clear LEDs failed because some other error occurred
81 | */
82 | esp_err_t (*clear)(led_strip_t *strip, uint32_t timeout_ms);
83 |
84 | /**
85 | * @brief Free LED strip resources
86 | *
87 | * @param strip: LED strip
88 | *
89 | * @return
90 | * - ESP_OK: Free resources successfully
91 | * - ESP_FAIL: Free resources failed because error occurred
92 | */
93 | esp_err_t (*del)(led_strip_t *strip);
94 | };
95 |
96 | /**
97 | * @brief LED Strip Configuration Type
98 | *
99 | */
100 | typedef struct {
101 | uint32_t max_leds; /*!< Maximum LEDs in a single strip */
102 | led_strip_dev_t dev; /*!< LED strip device (e.g. RMT channel, PWM channel, etc) */
103 | } led_strip_config_t;
104 |
105 | /**
106 | * @brief Default configuration for LED strip
107 | *
108 | */
109 | #define LED_STRIP_DEFAULT_CONFIG(number, dev_hdl) \
110 | { \
111 | .max_leds = number, \
112 | .dev = dev_hdl, \
113 | }
114 |
115 | /**
116 | * @brief Install a new ws2812 driver (based on RMT peripheral)
117 | *
118 | * @param config: LED strip configuration
119 | * @return
120 | * LED strip instance or NULL
121 | */
122 | led_strip_t *led_strip_new_rmt_ws2812(const led_strip_config_t *config);
123 |
124 | /**
125 | * @brief Init the RMT peripheral and LED strip configuration.
126 | *
127 | * @param[in] channel: RMT peripheral channel number.
128 | * @param[in] gpio: GPIO number for the RMT data output.
129 | * @param[in] led_num: number of addressable LEDs.
130 | * @return
131 | * LED strip instance or NULL
132 | */
133 | led_strip_t * led_strip_init(uint8_t channel, uint8_t gpio, uint16_t led_num);
134 |
135 | /**
136 | * @brief Denit the RMT peripheral.
137 | *
138 | * @param[in] strip: LED strip
139 | * @return
140 | * - ESP_OK
141 | * - ESP_FAIL
142 | */
143 | esp_err_t led_strip_denit(led_strip_t *strip);
144 |
145 | #ifdef __cplusplus
146 | }
147 | #endif
148 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
🏳️🌈 ESP32 WS2812 Control
3 |
4 |
5 | ws2812_control是一个专为ESP32设计的WS2812 LED控制组件
6 | 支持多种LED效果和矩阵/条形两种工作模式
7 | 提供丰富的API接口和可配置参数
8 |
9 |
10 |
11 | English
12 | · 简体中文
13 | · 更新日志
14 | · 反馈问题
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | ---
39 |
40 | ## 概述
41 |
42 | 本项目提供了一个用于控制 WS2812 LED 灯条的库,适用于 ESP32系列微控制器。该库包含了多种效果,如呼吸、渐变、闪烁和彩虹效果,以及基本的开关功能。设计时考虑了模块化和易集成性,方便在其他项目中使用。
43 |
44 | ## 功能特性
45 | - **支持WS2812矩阵屏**:除了普通WS2812驱动外还适用于创建多种排列和大小的 LED 矩阵。
46 | - **HSV 到 RGB 转换**:提供了一个辅助函数,用于将 HSV 颜色空间转换为 RGB 颜色空间。
47 | - **多种 LED 效果**:支持常亮、关闭、呼吸、渐入、慢闪、快闪和彩虹效果。
48 | - **单个 LED 控制**:可以单独设置某个 LED 的颜色。
49 | - **颜色宏定义**:预定义了多种常用颜色,如白色、绿色、红色、蓝色等。
50 | - **模块化设计**:代码结构清晰,易于扩展和维护。
51 |
52 | ## 配置WS2812参数
53 |
54 | 在menuconfig中配置WS2812参数,进入menuconfig找到ws2812 config菜单,此配置菜单用于设置 WS2812 LED 的信号引脚和工作模式,工作模式包括条形模式(Strip mode)和矩阵模式(Matrix mode)。根据所选的模式,您还可以配置相关参数,在条形模式(Strip mode)下只需要配置 LED 的数量即可,而在矩阵模式(Matrix mode)下,您还需要配置以下参数:
55 |
56 | 1. **矩阵宽高**:设置矩阵中每行每列的 LED 数量。
57 | 2. **矩阵布局类型**:指定矩阵的布局类型和方向,以便灵活支持不同的安装方式。
58 |
59 | 配置完成后,保存并退出 `menuconfig`,即可按照设定的模式和参数控制 WS2812 LED,下面先以条形模式举例介绍的使用方法。
60 |
61 | ## 条形模式(Strip mode)使用方法
62 | ### 1. 创建 WS2812 控制句柄
63 |
64 | 首先,需要创建一个 WS2812 控制句柄,用于后续的 LED 控制操作。
65 |
66 | ```c
67 | ws2812_strip_t* WS2812=ws2812_create();
68 | ```
69 |
70 | ### 2. 设置 LED 效果
71 |
72 | 可以通过调用 `ws2812_set` 函数来设置 LED 的效果。例如,设置所有 LED 为常亮状态,颜色为红色:
73 |
74 | ```c
75 | //方式1
76 | ws2812_set(WS2812, COLOR_RED, LED_EFFECT_ON);
77 | //方式2
78 | led_set_on(WS2812,COLOR_RED);
79 | //也可使用COLOR_RGB(255,0,0)来设置红色或自定义颜色
80 | led_set_on(WS2812,COLOR_RGB(255,0,0));
81 | ```
82 |
83 | ### 3. 常用功能
84 |
85 | - **设置单个 LED 颜色**:
86 |
87 | ```c
88 | led_set_pixel(WS2812, 0, COLOR_GREEN); // 设置第0个LED为绿色
89 | ```
90 |
91 | - **关闭所有 LED**:
92 |
93 | ```c
94 | led_set_off(WS2812);
95 | ```
96 |
97 | - **呼吸效果**:
98 |
99 | ```c
100 | //方式1
101 | ws2812_set(WS2812, COLOR_BLUE, LED_EFFECT_BREATH);
102 | //方式2
103 | led_set_breath(WS2812, COLOR_RGB(255, 0, 0), 10); // 红色呼吸
104 | ```
105 |
106 | - **彩虹效果**:
107 |
108 | ```c
109 | //方式1
110 | ws2812_set(WS2812, COLOR_BLUE, LED_EFFECT_RAINBOW);
111 | //方式2
112 | led_set_rainbow(WS2812, 20); // 20ms间隔的彩虹效果
113 | ```
114 |
115 | - **颜色渐变效果**:
116 |
117 | ```c
118 | led_set_color_gradient(WS2812, COLOR_RED, COLOR_BLUE, 1000); // 从红色渐变到蓝色,持续1000ms
119 | ```
120 |
121 |
122 | #### `ws2812_set()`第三个参数 模式可设置以下效果
123 | >
124 | LED_EFFECT_ON // 使LED灯常亮效果
125 | LED_EFFECT_BREATH, // 使LED灯呼吸效果
126 | LED_EFFECT_FADE_IN, // 使LED灯淡入效果
127 | LED_EFFECT_BLINK_SLOW, // 使LED灯慢闪烁效果
128 | LED_EFFECT_BLINK_FAST, // 使LED灯快闪烁效果
129 | LED_EFFECT_RAINBOW // 使LED灯彩虹效果
130 |
131 | 需注意`ws2812_set()`的配置应用于所有灯珠
132 |
133 | 更多API请参考 [ws2812_control.h](include\ws2812_control.h) 文件
134 |
135 | ### 示例代码
136 |
137 | 以下是此库的示例代码,
138 |
139 | ```c
140 | #include
141 | #include
142 |
143 | void app_main(void){
144 |
145 | // 创建一个WS2812灯带
146 | ws2812_strip_t* WS2812=ws2812_create();
147 |
148 | //点亮灯带 颜色(255,0,0)
149 | led_set_on(WS2812,COLOR_RGB(255,0,0));
150 | }
151 | ```
152 |
153 | ## 矩阵模式(Matrix mode)使用方法
154 |
155 | 矩阵模式(Matrix mode)的使用方法与条形模式(Strip mode)类似
156 |
157 | ```c
158 | //创建ws2812矩阵控制句柄
159 | ws2812_matrix_t* WS2812 = ws2812_matrix_create();
160 |
161 | //设置第2行第2列的LED为红色
162 | led_matrix_set_pixel(WS2812,2,2,COLOR_RGB(255,0,0));
163 |
164 | //更新矩阵显示
165 | led_matrix_show(WS2812);
166 | ```
167 |
168 | ### 示例代码
169 |
170 |
171 |
172 | ```c
173 | #include
174 | #include
175 |
176 | void app_main(void){
177 |
178 | //创建ws2812矩阵控制句柄
179 | ws2812_matrix_t* WS2812 = ws2812_matrix_create();
180 |
181 | //设置LED为红色
182 | led_matrix_set_pixel(WS2812,0,0,COLOR_RGB(255,0,0));
183 | led_matrix_set_pixel(WS2812,1,1,COLOR_RGB(255,0,0));
184 | led_matrix_set_pixel(WS2812,2,2,COLOR_RGB(255,0,0));
185 | led_matrix_set_pixel(WS2812,3,3,COLOR_RGB(255,0,0));
186 |
187 | //更新矩阵显示
188 | led_matrix_show(WS2812);
189 | }
190 | ```
191 | 
192 | ## 依赖项
193 |
194 | - ESP-IDF >= 4.4.7 (最新IDF 5.3.1 经过测试可用)
195 | - led_strip 灯条驱动库
196 |
197 | ## 许可证
198 |
199 | 本项目采用 MIT 许可证。更多信息请参阅 [LICENSE](LICENSE) 文件。
200 |
201 | ## 贡献
202 |
203 | 欢迎任何形式的贡献,包括但不限于代码改进、文档更新、问题反馈等。请通过 GitHub 提交 Pull Request 或 Issue。
204 |
205 | ## 作者
206 |
207 | - 宁子希 (1589326497@qq.com)
208 |
209 | ## 版本历史
210 |
211 | - 1.0.0 (2024-08-31)
212 | - 初始版本发布
213 | - 1.1.0 (2024-10-31)
214 | - 增加跑马灯效果(led_set_marquee)
215 | - 1.2.0 (2024-11-26)
216 | - 增加矩阵模式
217 | - 1.3.0 (2025-4-27)
218 | - 改进彩虹效果实现
219 | - 动画led效果改由定时器实现
220 | - 1.4.0 (2025-9-5)
221 | - 增加颜色渐变效果(led_set_color_gradient)
222 | ## 🤝 贡献
223 | 本项目采用 MIT 许可证,详情请参阅 [LICENSE](LICENSE) 文件。
224 |
225 |
226 | 感谢您使用 ESP32 WS2812 Control!🌈
227 | 如果觉得项目对您有帮助,请给个 ⭐ Star 支持一下!
228 |
229 |
--------------------------------------------------------------------------------
/include/ws2812_control.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file ws2812_control.h
3 | * @author 宁子希 (1589326497@qq.com)
4 | * @brief WS2812灯条和矩阵屏幕控制 依赖led_strip库
5 | * @version 1.3.0
6 | * @date 2024-08-31
7 | *
8 | * @copyright Copyright (c) 2024
9 | *
10 | */
11 | #ifndef WS2812_CONTROL_H
12 | #define WS2812_CONTROL_H
13 |
14 | #include
15 | #include "led_strip.h"
16 | #include "freertos/FreeRTOS.h"
17 | #include "freertos/task.h"
18 | #include "freertos/queue.h"
19 | #include "sdkconfig.h"
20 |
21 | #ifdef __cplusplus
22 | extern "C" {
23 | #endif
24 |
25 | typedef led_strip_t ws2812_strip_t;
26 |
27 | // 定义颜色宏
28 | #define COLOR_RGB(r, g, b) ((led_color_t){(r), (g), (b)}) //自定义RGB颜色
29 | #define COLOR_WHITE (led_color_t){255, 255, 255} // 白色
30 | #define COLOR_GREEN (led_color_t){0, 255, 0} // 绿色
31 | #define COLOR_RED (led_color_t){255, 0, 0} // 红色
32 | #define COLOR_BLUE (led_color_t){0, 0, 255} // 蓝色
33 | #define COLOR_YELLOW (led_color_t){255, 255, 0} // 黄色
34 | #define COLOR_CYAN (led_color_t){0, 255, 255} // 青色
35 | #define COLOR_MAGENTA (led_color_t){255, 0, 255} // 洋红色
36 | #define COLOR_BLACK (led_color_t){0, 0, 0} // 黑色
37 | #define COLOR_ORANGE (led_color_t){255, 165, 0} // 橙色
38 | #define COLOR_PURPLE (led_color_t){128, 0, 128} // 紫色
39 | #define COLOR_PINK (led_color_t){255, 192, 203} // 粉色
40 | #define COLOR_GRAY (led_color_t){128, 128, 128} // 灰色
41 | #define COLOR_BROWN (led_color_t){165, 42, 42} // 棕色
42 | #define COLOR_LIME (led_color_t){0, 255, 0} // 酸橙绿
43 | #define COLOR_TEAL (led_color_t){0, 128, 128} // 蓝绿色
44 | #define COLOR_NAVY (led_color_t){0, 0, 128} // 海军蓝
45 | #define COLOR_FUCHSIA (led_color_t){255, 0, 255} // 紫红色
46 | #define COLOR_MAROON (led_color_t){128, 0, 0} // 栗色
47 | #define COLOR_OLIVE (led_color_t){128, 128, 0} // 橄榄绿
48 |
49 | // led_color_t 结构体表示 LED 灯的颜色
50 | typedef struct {
51 | uint32_t red;
52 | uint32_t green;
53 | uint32_t blue;
54 | } led_color_t;
55 |
56 | //ws2812 灯带模式结构体定义
57 | #ifdef CONFIG_WS2812_MODE_STRIP
58 |
59 | // led_effect_t 枚举类型表示 LED 灯的效果类型
60 | typedef enum {
61 | // 关闭LED灯效果
62 | LED_EFFECT_OFF,
63 | // 使LED灯常亮效果
64 | LED_EFFECT_ON,
65 | // 使LED灯呼吸效果
66 | LED_EFFECT_BREATH,
67 | // 使LED灯淡入效果
68 | LED_EFFECT_FADE_IN,
69 | // 使LED灯慢闪烁效果
70 | LED_EFFECT_BLINK_SLOW,
71 | // 使LED灯快闪烁效果
72 | LED_EFFECT_BLINK_FAST,
73 | // 使LED灯彩虹效果
74 | LED_EFFECT_RAINBOW
75 | } led_effect_t;
76 |
77 | //ws2812 矩阵屏幕模式结构体定义
78 | #elif defined(CONFIG_WS2812_MODE_MATRIX)
79 |
80 | /**
81 | * @brief 矩阵屏幕类型,用于定义矩阵屏幕的布局和扫描方式
82 | *
83 | */
84 | #define MATRIX_START_TOP_LEFT 0x00 // 左上角
85 | #define MATRIX_START_TOP_RIGHT 0x01 // 右上角
86 | #define MATRIX_START_BOTTOM_LEFT 0x02 // 左下角
87 | #define MATRIX_START_BOTTOM_RIGHT 0x03 // 右下角
88 | #define MATRIX_START_CORNER 0x03 // 起始角落掩码
89 |
90 | #define MATRIX_LAYOUT_HORIZONTAL 0x00 // 行优先布局
91 | #define MATRIX_LAYOUT_VERTICAL 0x04 // 列优先布局
92 | #define MATRIX_LAYOUT_AXIS 0x04 // 布局轴掩码
93 |
94 | #define MATRIX_SCAN_PROGRESSIVE 0x00 // 连续扫描(每行的像素顺序相同)
95 | #define MATRIX_SCAN_ZIGZAG 0x08 // 之字形扫描 (每行的像素顺序在行之间反转)
96 | #define MATRIX_SCAN_SEQUENCE 0x08 // 扫描顺序掩码
97 |
98 |
99 |
100 | //WS2812Matrix结构体子类
101 | typedef struct {
102 | uint8_t matrixWidth;
103 | uint8_t matrixHeight;
104 | uint8_t pin;
105 | uint8_t matrixType;
106 | } ws2812_matrix_config;
107 |
108 | //ws2812_matrix_t 结构体表示 WS2812 灯条矩阵
109 | typedef struct {
110 | ws2812_strip_t *strip;
111 | ws2812_matrix_config config;
112 | } ws2812_matrix_t;
113 |
114 |
115 | #endif
116 |
117 |
118 | //ws2812 灯带模式函数声明
119 | #ifdef CONFIG_WS2812_MODE_STRIP
120 |
121 | /**
122 | * @brief 创建WS2812控制句柄
123 | *
124 | * @return ws2812_strip_t* - WS2812控制句柄
125 | */
126 | ws2812_strip_t* ws2812_create();
127 |
128 | /**
129 | * @brief 设置单个LED的颜色
130 | *
131 | * @param strip - WS2812控制句柄
132 | * @param index - LED的索引
133 | * @param color - LED的颜色
134 | */
135 | void led_set_pixel(ws2812_strip_t *strip, int index, led_color_t color);
136 |
137 | /**
138 | * @brief 使所有LED常亮
139 | *
140 | * @param strip - WS2812控制句柄
141 | * @param color - LED的颜色
142 | */
143 | void led_set_on(ws2812_strip_t *strip, led_color_t color);
144 |
145 | /**
146 | * @brief 关闭所有LED
147 | *
148 | * @param strip - WS2812控制句柄
149 | */
150 | void led_set_off(ws2812_strip_t *strip);
151 |
152 | /**
153 | * @brief 使所有LED呼吸效果
154 | *
155 | * @param strip - WS2812控制句柄
156 | * @param color - LED的颜色
157 | * @param interval_ms - 呼吸时间间隔
158 | */
159 | void led_set_breath(ws2812_strip_t *strip, led_color_t color, uint32_t interval_ms);
160 |
161 | /**
162 | * @brief 使所有LED缓缓亮起
163 | *
164 | * @param strip - WS2812控制句柄
165 | * @param color - LED的颜色
166 | */
167 | void led_set_fade_in(ws2812_strip_t *strip, led_color_t color);
168 |
169 | /**
170 | * @brief 使所有LED闪烁
171 | *
172 | * @param strip - WS2812控制句柄
173 | * @param color - LED的颜色
174 | * @param interval_ms - 闪烁时间间隔
175 | */
176 | void led_set_blink(ws2812_strip_t *strip, led_color_t color, uint32_t interval_ms);
177 |
178 | /**
179 | * @brief 使所有LED彩虹效果
180 | *
181 | * @param strip - WS2812控制句柄
182 | * @param interval_ms - 彩虹时间间隔
183 | */
184 | void led_set_rainbow(ws2812_strip_t *strip, uint32_t interval_ms);
185 |
186 | /**
187 | * @brief 自选LED效果
188 | *
189 | * @param strip - WS2812控制句柄
190 | * @param color - LED的颜色
191 | * @param effect - LED的效果类型
192 | */
193 | void ws2812_set(ws2812_strip_t *strip, led_color_t color, led_effect_t effect);
194 |
195 | /**
196 | * @brief LED跑马灯效果
197 | *
198 | * @param strip - WS2812控制句柄
199 | * @param index_start - 开始的LED索引
200 | * @param index_end - 结束的LED索引
201 | * @param color - LED的颜色
202 | * @param delay_ms - 延迟时间
203 | */
204 | void led_set_marquee(ws2812_strip_t *strip, int index_start, int index_end, led_color_t color, int delay_ms);
205 |
206 | /**
207 | * @brief 更新LED显示
208 | *
209 | * @param strip - WS2812控制句柄
210 | */
211 | void update_led_display(ws2812_strip_t *strip);
212 |
213 | /**
214 | * @brief 使所有LED从一个颜色渐变到另一个颜色
215 | *
216 | * @param strip - WS2812控制句柄
217 | * @param start_color - 起始颜色
218 | * @param end_color - 结束颜色
219 | * @param duration_ms - 渐变持续时间(毫秒)
220 | */
221 | void led_set_color_gradient(ws2812_strip_t *strip, led_color_t start_color, led_color_t end_color, uint32_t duration_ms);
222 |
223 |
224 | //ws2812 矩阵屏幕模式函数声明
225 | #elif defined(CONFIG_WS2812_MODE_MATRIX)
226 | /**
227 | * @brief 创建WS2812矩阵控制句柄
228 | *
229 | * @return ws2812_matrix_t*
230 | */
231 | ws2812_matrix_t* ws2812_matrix_create();
232 |
233 | /**
234 | * @brief 设置单个LED的颜色
235 | *
236 | * @param matrix - WS2812控制句柄
237 | * @param x - led灯珠x坐标
238 | * @param y - led灯珠y坐标
239 | * @param color - LED的颜色
240 | */
241 | void led_matrix_set_pixel(ws2812_matrix_t *matrix, int x, int y, led_color_t color);
242 |
243 | /**
244 | * @brief 更新LED显示
245 | *
246 | * @param matrix
247 | */
248 | void led_matrix_show(ws2812_matrix_t *matrix);
249 |
250 | /**
251 | * @brief 清空LED显示
252 | *
253 | * @param matrix
254 | */
255 | void led_matrix_clear(ws2812_matrix_t *matrix);
256 |
257 | #endif
258 |
259 | #ifdef __cplusplus
260 | }
261 | #endif
262 |
263 | #endif // WS2812_CONTROL_H
264 |
--------------------------------------------------------------------------------
/README_EN.md:
--------------------------------------------------------------------------------
1 | 
2 | 🏳️🌈 ESP32 WS2812 Control
3 |
4 |
5 | ws2812_control is a WS2812 LED control component designed for ESP32
6 | Supports multiple LED effects and two working modes: matrix and strip
7 | Provides rich API interfaces and configurable parameters
8 |
9 |
10 |
11 | English
12 | · 简体中文
13 | · Changelog
14 | · Report Issues
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | ---
39 |
40 | ## Overview
41 |
42 | This project provides a library for controlling WS2812 LED strips, compatible with ESP32 series microcontrollers. The library includes various effects such as breathing, fading, blinking, and rainbow effects, as well as basic on/off functionality. Designed with modularity and easy integration in mind, it can be conveniently used in other projects.
43 |
44 | ## Features
45 | - **Supports WS2812 Matrix**: In addition to regular WS2812 drivers, it also supports creating LED matrices of various arrangements and sizes.
46 | - **HSV to RGB Conversion**: Provides a helper function for converting HSV color space to RGB color space.
47 | - **Multiple LED Effects**: Supports always-on, off, breathing, fade-in, slow blink, fast blink, and rainbow effects.
48 | - **Individual LED Control**: Can set the color of individual LEDs.
49 | - **Color Macros**: Predefined common colors such as white, green, red, blue, etc.
50 | - **Modular Design**: Clear code structure, easy to extend and maintain.
51 |
52 | ## Configuration
53 |
54 | Configure WS2812 parameters in menuconfig. Navigate to the ws2812 config menu to set the signal pin and working mode (Strip mode or Matrix mode). Depending on the selected mode, you may need to configure additional parameters:
55 |
56 | 1. **Matrix Dimensions**: Set the number of LEDs per row and column in the matrix.
57 | 2. **Matrix Layout Type**: Specify the matrix layout type and direction to support different installation methods.
58 |
59 | After configuration, save and exit `menuconfig` to control WS2812 LEDs according to the set mode and parameters. Below is an example using Strip mode.
60 |
61 | ## Strip Mode Usage
62 | ### 1. Create WS2812 Handle
63 |
64 | First, create a WS2812 control handle for subsequent LED operations.
65 |
66 | ```c
67 | ws2812_strip_t* WS2812=ws2812_create();
68 | ```
69 |
70 | ### 2. Set LED Effects
71 |
72 | Use the `ws2812_set` function to set LED effects. For example, set all LEDs to always-on with red color:
73 |
74 | ```c
75 | // Method 1
76 | ws2812_set(WS2812, COLOR_RED, LED_EFFECT_ON);
77 | // Method 2
78 | led_set_on(WS2812,COLOR_RED);
79 | // Or use COLOR_RGB(255,0,0) to set red or custom colors
80 | led_set_on(WS2812,COLOR_RGB(255,0,0));
81 | ```
82 |
83 | ### 3. Common Functions
84 |
85 | - **Set Individual LED Color**:
86 |
87 | ```c
88 | led_set_pixel(WS2812, 0, COLOR_GREEN); // Set LED 0 to green
89 | ```
90 |
91 | - **Turn Off All LEDs**:
92 |
93 | ```c
94 | led_set_off(WS2812);
95 | ```
96 |
97 | - **Breathing Effect**:
98 |
99 | ```c
100 | // Method 1
101 | ws2812_set(WS2812, COLOR_BLUE, LED_EFFECT_BREATH);
102 | // Method 2
103 | led_set_breath(WS2812, COLOR_RGB(255, 0, 0), 10); // Red breathing
104 | ```
105 |
106 | - **Rainbow Effect**:
107 |
108 | ```c
109 | // Method 1
110 | ws2812_set(WS2812, COLOR_BLUE, LED_EFFECT_RAINBOW);
111 | // Method 2
112 | led_set_rainbow(WS2812, 20); // Rainbow effect with 20ms interval
113 | ```
114 |
115 | #### Available Effects for `ws2812_set()`
116 | >
117 | LED_EFFECT_ON // Always-on effect
118 | LED_EFFECT_BREATH, // Breathing effect
119 | LED_EFFECT_FADE_IN, // Fade-in effect
120 | LED_EFFECT_BLINK_SLOW, // Slow blink effect
121 | LED_EFFECT_BLINK_FAST, // Fast blink effect
122 | LED_EFFECT_RAINBOW // Rainbow effect
123 |
124 | Note: `ws2812_set()` applies to all LEDs.
125 |
126 | - **Color Gradient Effect**:
127 |
128 | ```c
129 | led_set_color_gradient(WS2812, COLOR_RED, COLOR_BLUE, 1000); // Gradient from red to blue over 1000ms
130 | ```
131 |
132 | For more APIs, please refer to [ws2812_control.h](include\ws2812_control.h).
133 |
134 | ### Example Code
135 |
136 | ```c
137 | #include
138 | #include
139 |
140 | void app_main(void){
141 | // Create a WS2812 strip
142 | ws2812_strip_t* WS2812=ws2812_create();
143 |
144 | // Turn on strip with color (255,0,0)
145 | led_set_on(WS2812,COLOR_RGB(255,0,0));
146 | }
147 | ```
148 |
149 | ## Matrix Mode Usage
150 |
151 | Matrix mode usage is similar to Strip mode.
152 |
153 | ```c
154 | // Create WS2812 matrix handle
155 | ws2812_matrix_t* WS2812 = ws2812_matrix_create();
156 |
157 | // Set LED at row 2, column 2 to red
158 | led_matrix_set_pixel(WS2812,2,2,COLOR_RGB(255,0,0));
159 |
160 | // Update matrix display
161 | led_matrix_show(WS2812);
162 | ```
163 |
164 | ### Example Code
165 |
166 | ```c
167 | #include
168 | #include
169 |
170 | void app_main(void){
171 | // Create WS2812 matrix handle
172 | ws2812_matrix_t* WS2812 = ws2812_matrix_create();
173 |
174 | // Set LEDs to red
175 | led_matrix_set_pixel(WS2812,0,0,COLOR_RGB(255,0,0));
176 | led_matrix_set_pixel(WS2812,1,1,COLOR_RGB(255,0,0));
177 | led_matrix_set_pixel(WS2812,2,2,COLOR_RGB(255,0,0));
178 | led_matrix_set_pixel(WS2812,3,3,COLOR_RGB(255,0,0));
179 |
180 | // Update matrix display
181 | led_matrix_show(WS2812);
182 | }
183 | ```
184 | 
185 |
186 | ## Dependencies
187 | - ESP-IDF >= 4.4.7 (Tested with latest IDF 5.3.1)
188 | - led_strip driver library
189 |
190 | ## License
191 | This project is licensed under the MIT License. See [LICENSE](LICENSE) for details.
192 |
193 | ## Contributing
194 | Contributions of any kind are welcome, including but not limited to code improvements, documentation updates, and issue reports. Please submit Pull Requests or Issues via GitHub.
195 |
196 | ## Author
197 | - Ning ZiXi (1589326497@qq.com)
198 |
199 | ## Version History
200 | - 1.0.0 (2024-08-31)
201 | - Initial release
202 | - 1.1.0 (2024-10-31)
203 | - Added marquee effect (led_set_marquee)
204 | - 1.2.0 (2024-11-26)
205 | - Added matrix mode
206 | - 1.3.0 (2025-4-27)
207 | - Improved rainbow effect implementation
208 | - Animation effects now use timer
209 | - 1.4.0 (2025-4-28)
210 | - Added color gradient effect (led_set_color_gradient)
211 |
212 | ## 🤝 Contributing
213 | This project is licensed under the MIT License. See [LICENSE](LICENSE) for details.
214 |
215 |
216 | Thank you for using ESP32 WS2812 Control! 🌈
217 | If you find this project helpful, please give it a ⭐ Star!
218 |
219 |
--------------------------------------------------------------------------------
/led_strip_rmt_ws2812.c:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Espressif Systems (Shanghai) PTE LTD
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | #include
15 | #include
16 | #include
17 | #include "esp_log.h"
18 | #include "esp_attr.h"
19 | #include "led_strip.h"
20 | #include "driver/rmt.h"
21 |
22 | #define RMT_TX_CHANNEL RMT_CHANNEL_0
23 |
24 | static const char *TAG = "ws2812";
25 | #define STRIP_CHECK(a, str, goto_tag, ret_value, ...) \
26 | do \
27 | { \
28 | if (!(a)) \
29 | { \
30 | ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
31 | ret = ret_value; \
32 | goto goto_tag; \
33 | } \
34 | } while (0)
35 |
36 | #define WS2812_T0H_NS (350)
37 | #define WS2812_T0L_NS (1000)
38 | #define WS2812_T1H_NS (1000)
39 | #define WS2812_T1L_NS (350)
40 | #define WS2812_RESET_US (280)
41 |
42 | static uint32_t ws2812_t0h_ticks = 0;
43 | static uint32_t ws2812_t1h_ticks = 0;
44 | static uint32_t ws2812_t0l_ticks = 0;
45 | static uint32_t ws2812_t1l_ticks = 0;
46 |
47 | typedef struct {
48 | led_strip_t parent;
49 | rmt_channel_t rmt_channel;
50 | uint32_t strip_len;
51 | uint8_t buffer[0];
52 | } ws2812_t;
53 |
54 | /**
55 | * @brief Conver RGB data to RMT format.
56 | *
57 | * @note For WS2812, R,G,B each contains 256 different choices (i.e. uint8_t)
58 | *
59 | * @param[in] src: source data, to converted to RMT format
60 | * @param[in] dest: place where to store the convert result
61 | * @param[in] src_size: size of source data
62 | * @param[in] wanted_num: number of RMT items that want to get
63 | * @param[out] translated_size: number of source data that got converted
64 | * @param[out] item_num: number of RMT items which are converted from source data
65 | */
66 | static void IRAM_ATTR ws2812_rmt_adapter(const void *src, rmt_item32_t *dest, size_t src_size,
67 | size_t wanted_num, size_t *translated_size, size_t *item_num)
68 | {
69 | if (src == NULL || dest == NULL) {
70 | *translated_size = 0;
71 | *item_num = 0;
72 | return;
73 | }
74 | const rmt_item32_t bit0 = {{{ ws2812_t0h_ticks, 1, ws2812_t0l_ticks, 0 }}}; //Logical 0
75 | const rmt_item32_t bit1 = {{{ ws2812_t1h_ticks, 1, ws2812_t1l_ticks, 0 }}}; //Logical 1
76 | size_t size = 0;
77 | size_t num = 0;
78 | uint8_t *psrc = (uint8_t *)src;
79 | rmt_item32_t *pdest = dest;
80 | while (size < src_size && num < wanted_num) {
81 | for (int i = 0; i < 8; i++) {
82 | // MSB first
83 | if (*psrc & (1 << (7 - i))) {
84 | pdest->val = bit1.val;
85 | } else {
86 | pdest->val = bit0.val;
87 | }
88 | num++;
89 | pdest++;
90 | }
91 | size++;
92 | psrc++;
93 | }
94 | *translated_size = size;
95 | *item_num = num;
96 | }
97 |
98 | static esp_err_t ws2812_set_pixel(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue)
99 | {
100 | esp_err_t ret = ESP_OK;
101 | ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent);
102 | STRIP_CHECK(index < ws2812->strip_len, "index out of the maximum number of leds", err, ESP_ERR_INVALID_ARG);
103 | uint32_t start = index * 3;
104 | // In thr order of GRB
105 | ws2812->buffer[start + 0] = green & 0xFF;
106 | ws2812->buffer[start + 1] = red & 0xFF;
107 | ws2812->buffer[start + 2] = blue & 0xFF;
108 | return ESP_OK;
109 | err:
110 | return ret;
111 | }
112 |
113 | static esp_err_t ws2812_refresh(led_strip_t *strip, uint32_t timeout_ms)
114 | {
115 | esp_err_t ret = ESP_OK;
116 | ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent);
117 | STRIP_CHECK(rmt_write_sample(ws2812->rmt_channel, ws2812->buffer, ws2812->strip_len * 3, true) == ESP_OK,
118 | "transmit RMT samples failed", err, ESP_FAIL);
119 | return rmt_wait_tx_done(ws2812->rmt_channel, pdMS_TO_TICKS(timeout_ms));
120 | err:
121 | return ret;
122 | }
123 |
124 | static esp_err_t ws2812_clear(led_strip_t *strip, uint32_t timeout_ms)
125 | {
126 | ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent);
127 | // Write zero to turn off all leds
128 | memset(ws2812->buffer, 0, ws2812->strip_len * 3);
129 | return ws2812_refresh(strip, timeout_ms);
130 | }
131 |
132 | static esp_err_t ws2812_del(led_strip_t *strip)
133 | {
134 | ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent);
135 | free(ws2812);
136 | return ESP_OK;
137 | }
138 |
139 | led_strip_t *led_strip_new_rmt_ws2812(const led_strip_config_t *config)
140 | {
141 | led_strip_t *ret = NULL;
142 | STRIP_CHECK(config, "configuration can't be null", err, NULL);
143 |
144 | // 24 bits per led
145 | uint32_t ws2812_size = sizeof(ws2812_t) + config->max_leds * 3;
146 | ws2812_t *ws2812 = calloc(1, ws2812_size);
147 | STRIP_CHECK(ws2812, "request memory for ws2812 failed", err, NULL);
148 |
149 | uint32_t counter_clk_hz = 0;
150 | STRIP_CHECK(rmt_get_counter_clock((rmt_channel_t)config->dev, &counter_clk_hz) == ESP_OK,
151 | "get rmt counter clock failed", err, NULL);
152 | // ns -> ticks
153 | float ratio = (float)counter_clk_hz / 1e9;
154 | ws2812_t0h_ticks = (uint32_t)(ratio * WS2812_T0H_NS);
155 | ws2812_t0l_ticks = (uint32_t)(ratio * WS2812_T0L_NS);
156 | ws2812_t1h_ticks = (uint32_t)(ratio * WS2812_T1H_NS);
157 | ws2812_t1l_ticks = (uint32_t)(ratio * WS2812_T1L_NS);
158 |
159 | // set ws2812 to rmt adapter
160 | rmt_translator_init((rmt_channel_t)config->dev, ws2812_rmt_adapter);
161 |
162 | ws2812->rmt_channel = (rmt_channel_t)config->dev;
163 | ws2812->strip_len = config->max_leds;
164 |
165 | ws2812->parent.set_pixel = ws2812_set_pixel;
166 | ws2812->parent.refresh = ws2812_refresh;
167 | ws2812->parent.clear = ws2812_clear;
168 | ws2812->parent.del = ws2812_del;
169 |
170 | return &ws2812->parent;
171 | err:
172 | return ret;
173 | }
174 |
175 | led_strip_t * led_strip_init(uint8_t channel, uint8_t gpio, uint16_t led_num)
176 | {
177 | static led_strip_t *pStrip;
178 |
179 | rmt_config_t config = RMT_DEFAULT_CONFIG_TX(gpio, channel);
180 | // set counter clock to 40MHz
181 | config.clk_div = 2;
182 |
183 | ESP_ERROR_CHECK(rmt_config(&config));
184 | ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));
185 |
186 | // install ws2812 driver
187 | led_strip_config_t strip_config = LED_STRIP_DEFAULT_CONFIG(led_num, (led_strip_dev_t)config.channel);
188 |
189 | pStrip = led_strip_new_rmt_ws2812(&strip_config);
190 |
191 | if ( !pStrip ) {
192 | ESP_LOGE(TAG, "install WS2812 driver failed");
193 | return NULL;
194 | }
195 |
196 | // Clear LED strip (turn off all LEDs)
197 | ESP_ERROR_CHECK(pStrip->clear(pStrip, 100));
198 |
199 | return pStrip;
200 | }
201 |
202 | esp_err_t led_strip_denit(led_strip_t *strip)
203 | {
204 | ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent);
205 | ESP_ERROR_CHECK(rmt_driver_uninstall(ws2812->rmt_channel));
206 | return strip->del(strip);
207 | }
208 |
--------------------------------------------------------------------------------
/ws2812_control.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file ws2812_control.c
3 | * @author 宁子希 (1589326497@qq.com)
4 | * @brief WS2812灯条和矩阵屏幕控制 依赖led_strip库
5 | * @version 1.3.0
6 | * @date 2024-08-31
7 | *
8 | * @copyright Copyright (c) 2024
9 | *
10 | */
11 | #include "sdkconfig.h"
12 | #include "freertos/FreeRTOS.h"
13 | #include "freertos/task.h"
14 | #include "esp_log.h"
15 | #include "driver/rmt.h"
16 | #include "led_strip.h"
17 | #include "ws2812_control.h"
18 | #include "esp_timer.h"
19 |
20 | static const char *TAG = "WS2812_control";
21 |
22 | #define RMT_TX_CHANNEL RMT_CHANNEL_0
23 | #define EXAMPLE_CHASE_SPEED_MS (240)
24 |
25 | // 定时器回调函数指针类型
26 | typedef void (*led_effect_func_t)(ws2812_strip_t*, led_color_t);
27 |
28 | // 定时器状态结构体
29 | typedef struct {
30 | ws2812_strip_t* strip;
31 | led_color_t color;
32 | led_effect_func_t effect_func;
33 | int counter;
34 | bool active;
35 | } timer_effect_state_t;
36 |
37 | // 全局定时器状态和句柄
38 | static timer_effect_state_t timer_state;
39 | static esp_timer_handle_t led_timer;
40 |
41 | /**
42 | *@brief 简单的辅助函数,将 HSV 颜色空间转换为 RGB 颜色空间
43 | *
44 | *@param h 色相值,范围为[0,360]
45 | *@param s 饱和度值,范围为[0,100]
46 | *@param v 亮度值,范围为[0,100]
47 | *@param r 指向存储红色值的指针
48 | *@param g 指向存储绿色值的指针
49 | *@param b 指向存储蓝色值的指针
50 | *
51 | */
52 | void led_strip_hsv2rgb(uint32_t h, uint32_t s, uint32_t v, uint32_t *r, uint32_t *g, uint32_t *b)
53 | {
54 | h %= 360; // h -> [0,360]
55 | uint32_t rgb_max = v * 2.55f;
56 | uint32_t rgb_min = rgb_max * (100 - s) / 100.0f;
57 |
58 | uint32_t i = h / 60;
59 | uint32_t diff = h % 60;
60 |
61 | // RGB adjustment amount by hue
62 | uint32_t rgb_adj = (rgb_max - rgb_min) * diff / 60;
63 |
64 | switch (i) {
65 | case 0:
66 | *r = rgb_max;
67 | *g = rgb_min + rgb_adj;
68 | *b = rgb_min;
69 | break;
70 | case 1:
71 | *r = rgb_max - rgb_adj;
72 | *g = rgb_max;
73 | *b = rgb_min;
74 | break;
75 | case 2:
76 | *r = rgb_min;
77 | *g = rgb_max;
78 | *b = rgb_min + rgb_adj;
79 | break;
80 | case 3:
81 | *r = rgb_min;
82 | *g = rgb_max - rgb_adj;
83 | *b = rgb_max;
84 | break;
85 | case 4:
86 | *r = rgb_min + rgb_adj;
87 | *g = rgb_min;
88 | *b = rgb_max;
89 | break;
90 | default:
91 | *r = rgb_max;
92 | *g = rgb_min;
93 | *b = rgb_max - rgb_adj;
94 | break;
95 | }
96 | }
97 |
98 | /**
99 | *@brief 简单的辅助函数,将 RGB 颜色空间转换为 HSV 颜色空间
100 | *
101 | *@param r 红色值,范围为[0,255]
102 | *@param g 绿色值,范围为[0,255]
103 | *@param b 蓝色值,范围为[0,255]
104 | *@param h 指向存储色相值的指针
105 | *@param s 指向存储饱和度值的指针
106 | *@param v 指向存储亮度值的指针
107 | *
108 | */
109 | void led_strip_rgb2hsv(uint32_t r, uint32_t g, uint32_t b, uint32_t *h, uint32_t *s, uint32_t *v)
110 | {
111 | uint32_t rgb_max = (r > g && r > b) ? r : (g > b ? g : b);
112 | uint32_t rgb_min = (r < g && r < b) ? r : (g < b ? g : b);
113 | uint32_t delta = rgb_max - rgb_min;
114 |
115 | // 计算亮度值
116 | *v = rgb_max / 2.55f;
117 |
118 | // 如果最大值为0,则饱和度和色相都为0
119 | if (rgb_max == 0) {
120 | *s = 0;
121 | *h = 0;
122 | return;
123 | }
124 |
125 | // 计算饱和度
126 | *s = (delta * 100) / rgb_max;
127 |
128 | // 如果delta为0,则色相为0
129 | if (delta == 0) {
130 | *h = 0;
131 | return;
132 | }
133 |
134 | // 计算色相
135 | if (rgb_max == r) {
136 | *h = (60 * ((int32_t)(g - b) / (int32_t)delta) + 360) % 360;
137 | } else if (rgb_max == g) {
138 | *h = (60 * ((int32_t)(b - r) / (int32_t)delta) + 120) % 360;
139 | } else {
140 | *h = (60 * ((int32_t)(r - g) / (int32_t)delta) + 240) % 360;
141 | }
142 | }
143 |
144 | // 定时器回调函数
145 | static void led_timer_callback(void* arg){
146 | if (timer_state.active && timer_state.effect_func) {
147 | timer_state.effect_func(timer_state.strip, timer_state.color);
148 | timer_state.counter++;
149 | }
150 | }
151 |
152 | //ws2812 灯带模式
153 | #ifdef CONFIG_WS2812_MODE_STRIP
154 |
155 | // 创建WS2812控制句柄
156 | ws2812_strip_t* ws2812_create() {
157 | // 初始化WS2812控制任务
158 | rmt_config_t config = RMT_DEFAULT_CONFIG_TX((gpio_num_t)CONFIG_WS2812_TX_GPIO, RMT_TX_CHANNEL);
159 | config.clk_div = 2;
160 |
161 | ESP_ERROR_CHECK(rmt_config(&config));
162 | ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));
163 |
164 | led_strip_config_t strip_config = LED_STRIP_DEFAULT_CONFIG(CONFIG_WS2812_STRIP_LED_NUMBER, (led_strip_dev_t)config.channel);
165 | ws2812_strip_t *strip = led_strip_new_rmt_ws2812(&strip_config);
166 |
167 | if (!strip) {
168 | ESP_LOGE(TAG, "install WS2812 driver failed");
169 | }
170 |
171 | ESP_ERROR_CHECK(strip->clear(strip, 100));
172 |
173 | // 初始化定时器
174 | esp_timer_create_args_t timer_args = {
175 | .callback = &led_timer_callback,
176 | .arg = NULL,
177 | .dispatch_method = ESP_TIMER_TASK,
178 | .name = "led_timer"
179 | };
180 | ESP_ERROR_CHECK(esp_timer_create(&timer_args, &led_timer));
181 |
182 | return strip;
183 | }
184 |
185 | // 设置 LED 颜色(单个)
186 | void led_set_pixel(ws2812_strip_t *strip,int index, led_color_t color) {
187 | if (timer_state.active) {
188 | esp_timer_stop(led_timer);
189 | }
190 | if (index >= 0 && index < CONFIG_WS2812_STRIP_LED_NUMBER) {
191 | ESP_ERROR_CHECK(strip->set_pixel(strip, index,color.red, color.green, color.blue));
192 | }
193 | ESP_ERROR_CHECK(strip->refresh(strip, 100));
194 | }
195 |
196 | // LED 全部常亮
197 | void led_set_on(ws2812_strip_t *strip, led_color_t color) {
198 | if (timer_state.active) {
199 | esp_timer_stop(led_timer);
200 | }
201 | for (int i = 0; i < CONFIG_WS2812_STRIP_LED_NUMBER; i++) {
202 | ESP_ERROR_CHECK(strip->set_pixel(strip, i, color.red, color.green, color.blue));
203 | }
204 | ESP_ERROR_CHECK(strip->refresh(strip, 100));
205 | }
206 |
207 | // LED 关闭
208 | void led_set_off(ws2812_strip_t *strip) {
209 | if (timer_state.active) {
210 | esp_timer_stop(led_timer);
211 | }
212 | for (int i = 0; i < CONFIG_WS2812_STRIP_LED_NUMBER; i++) {
213 | ESP_ERROR_CHECK(strip->set_pixel(strip, i, 0, 0, 0)); // 设置为黑色
214 | }
215 | ESP_ERROR_CHECK(strip->refresh(strip, 100));
216 | }
217 |
218 | // LED 呼吸效果
219 | void led_set_breath(ws2812_strip_t *strip, led_color_t color, uint32_t interval_ms) {
220 | if (timer_state.active) {
221 | esp_timer_stop(led_timer);
222 | }
223 |
224 | // 设置定时器状态
225 | timer_state.strip = strip;
226 | timer_state.color = color;
227 | timer_state.active = true;
228 | timer_state.counter = 0;
229 |
230 | timer_state.effect_func = [](ws2812_strip_t* strip, led_color_t color) {
231 | static int brightness = 0;
232 | static bool increasing = true;
233 |
234 | // 更新亮度
235 | if (increasing) {
236 | brightness++;
237 | if (brightness >= 255) increasing = false;
238 | } else {
239 | brightness--;
240 | if (brightness <= 0) increasing = true;
241 | }
242 |
243 | // 设置LED亮度
244 | for (int j = 0; j < CONFIG_WS2812_STRIP_LED_NUMBER; j++) {
245 | ESP_ERROR_CHECK(strip->set_pixel(
246 | strip, j,
247 | (color.red * brightness) / 255,
248 | (color.green * brightness) / 255,
249 | (color.blue * brightness) / 255
250 | ));
251 | }
252 | strip->refresh(strip, 100);
253 | };
254 |
255 | // 启动定时器,使用传入的时间间隔
256 | ESP_ERROR_CHECK(esp_timer_start_periodic(led_timer, interval_ms * 1000)); // 转换为微秒
257 | }
258 |
259 | // LED 缓缓亮起
260 | void led_set_fade_in(ws2812_strip_t *strip, led_color_t color) {
261 | if (timer_state.active) {
262 | esp_timer_stop(led_timer);
263 | }
264 | for (int i = 0; i < 256; i++) {
265 | for (int j = 0; j < CONFIG_WS2812_STRIP_LED_NUMBER; j++) {
266 | ESP_ERROR_CHECK(strip->set_pixel(strip, j, (color.red * i) / 255, (color.green * i) / 255, (color.blue * i) / 255));
267 | }
268 | ESP_ERROR_CHECK(strip->refresh(strip, 100));
269 | vTaskDelay(pdMS_TO_TICKS(20)); // 调整渐变速度
270 | }
271 | }
272 |
273 | // 闪烁效果
274 | void led_set_blink(ws2812_strip_t *strip, led_color_t color, uint32_t interval_ms) {
275 | if (timer_state.active) {
276 | esp_timer_stop(led_timer);
277 | }
278 |
279 | // 设置定时器状态
280 | timer_state.strip = strip;
281 | timer_state.color = color;
282 | timer_state.active = true;
283 | timer_state.counter = 0;
284 |
285 | timer_state.effect_func = [](ws2812_strip_t* strip, led_color_t color) {
286 | static bool is_on = false;
287 |
288 | if (is_on) {
289 | for (int i = 0; i < CONFIG_WS2812_STRIP_LED_NUMBER; i++) {
290 | ESP_ERROR_CHECK(strip->set_pixel(strip, i, 0, 0, 0)); // 设置为黑色
291 | }
292 | ESP_ERROR_CHECK(strip->refresh(strip, 100));
293 | } else {
294 | for (int i = 0; i < CONFIG_WS2812_STRIP_LED_NUMBER; i++) {
295 | ESP_ERROR_CHECK(strip->set_pixel(strip, i, color.red, color.green, color.blue));
296 | }
297 | ESP_ERROR_CHECK(strip->refresh(strip, 100));
298 | }
299 | is_on = !is_on;
300 | };
301 |
302 | // 启动定时器,使用传入的时间间隔
303 | ESP_ERROR_CHECK(esp_timer_start_periodic(led_timer, interval_ms * 1000)); // 转换为微秒
304 | }
305 |
306 | // 彩虹效果
307 | void led_set_rainbow(ws2812_strip_t *strip, uint32_t interval_ms) {
308 | if (timer_state.active) {
309 | esp_timer_stop(led_timer);
310 | }
311 |
312 | // 设置定时器状态
313 | timer_state.strip = strip;
314 | timer_state.active = true;
315 | timer_state.counter = 0;
316 |
317 | timer_state.effect_func = [](ws2812_strip_t* strip, led_color_t color) {
318 | static uint16_t hue = 0;
319 | uint32_t red, green, blue;
320 |
321 | for (int i = 0; i < CONFIG_WS2812_STRIP_LED_NUMBER; i++) {
322 | uint16_t led_hue = hue + (i * 360 / CONFIG_WS2812_STRIP_LED_NUMBER);
323 | led_hue %= 360; // 确保色相值在0-359范围内
324 | led_strip_hsv2rgb(led_hue, 100, 100, &red, &green, &blue);
325 | ESP_ERROR_CHECK(strip->set_pixel(strip, i, red, green, blue));
326 | }
327 | ESP_ERROR_CHECK(strip->refresh(strip, 100));
328 | hue = (hue + 1) % 360;
329 | };
330 |
331 | // 启动定时器
332 | ESP_ERROR_CHECK(esp_timer_start_periodic(led_timer, interval_ms * 1000));
333 | }
334 |
335 | void ws2812_set(ws2812_strip_t *strip, led_color_t color, led_effect_t effect){
336 | // 根据不同的效果值执行相应的 LED 控制操作
337 | switch (effect) {
338 | case LED_EFFECT_ON:
339 | //设置灯条状态为开启,并设置颜色
340 | led_set_on(strip, color);
341 | break;
342 | case LED_EFFECT_OFF:
343 | //关闭灯条
344 | led_set_off(strip);
345 | break;
346 | case LED_EFFECT_BREATH:
347 | // 设置呼吸效果
348 | led_set_breath(strip, color ,10);
349 | break;
350 | case LED_EFFECT_FADE_IN:
351 | //设置渐入效果
352 | led_set_fade_in(strip, color);
353 | break;
354 | case LED_EFFECT_BLINK_SLOW:
355 | //设置缓慢闪烁效果
356 | led_set_blink(strip, color,500);
357 | break;
358 | case LED_EFFECT_BLINK_FAST:
359 | // 快速闪烁效果
360 | led_set_blink(strip, color,100);
361 | break;
362 | case LED_EFFECT_RAINBOW:
363 | // 彩虹效果
364 | led_set_rainbow(strip, 20);
365 | break;
366 | }
367 | }
368 |
369 | // 设置 LED 跑马灯(从 index_start 到 index_end)
370 | void led_set_marquee(ws2812_strip_t *strip, int index_start, int index_end, led_color_t color, int delay_ms) {
371 | if (timer_state.active) {
372 | esp_timer_stop(led_timer);
373 | }
374 | if (index_start < 0 || index_end < 0 || index_start >= CONFIG_WS2812_STRIP_LED_NUMBER || index_end >= CONFIG_WS2812_STRIP_LED_NUMBER ) {
375 | ESP_LOGE(TAG, "无效的 LED 索引");
376 | return; // 参数检查
377 | }
378 |
379 | // 逐个亮起 LED
380 | if (index_start < index_end) {
381 | // 从 index_start 到 index_end
382 | for (int i = index_start; i <= index_end; i++) {
383 | ESP_ERROR_CHECK(strip->set_pixel(strip, i, color.red, color.green, color.blue));
384 | ESP_ERROR_CHECK(strip->refresh(strip, delay_ms)); // 刷新显示
385 |
386 | // 延迟以控制亮起速度
387 | vTaskDelay(pdMS_TO_TICKS(delay_ms));
388 | }
389 | } else {
390 | // 从 index_start 到 index_end
391 | for (int i = index_start; i >= index_end; i--) {
392 | ESP_ERROR_CHECK(strip->set_pixel(strip, i, color.red, color.green, color.blue));
393 | ESP_ERROR_CHECK(strip->refresh(strip, delay_ms)); // 刷新显示
394 |
395 | // 延迟以控制亮起速度
396 | vTaskDelay(pdMS_TO_TICKS(delay_ms));
397 | }
398 | }
399 |
400 | // 确保最终的 LED 关闭
401 | led_set_off(strip);
402 | }
403 |
404 | // 全局变量用于存储渐变效果的状态
405 | static uint32_t gradient_start_h, gradient_start_s, gradient_start_v;
406 | static uint32_t gradient_end_h, gradient_end_s, gradient_end_v;
407 | static uint32_t gradient_steps;
408 | static uint32_t gradient_current_step = 0;
409 |
410 | // 渐变效果的定时器回调函数
411 | void gradient_effect_func(ws2812_strip_t* strip, led_color_t color) {
412 | if (gradient_current_step <= gradient_steps) {
413 | // 计算当前步骤的HSV值
414 | uint32_t current_h, current_s, current_v;
415 |
416 | // 处理色相的最短路径插值
417 | int32_t hue_diff = (int32_t)gradient_end_h - (int32_t)gradient_start_h;
418 | if (hue_diff > 180) {
419 | hue_diff -= 360;
420 | } else if (hue_diff < -180) {
421 | hue_diff += 360;
422 | }
423 |
424 | current_h = (gradient_start_h + (hue_diff * (int32_t)gradient_current_step) / (int32_t)gradient_steps) % 360;
425 | current_s = gradient_start_s + ((int32_t)((gradient_end_s - gradient_start_s) * gradient_current_step) / (int32_t)gradient_steps);
426 | current_v = gradient_start_v + ((int32_t)((gradient_end_v - gradient_start_v) * gradient_current_step) / (int32_t)gradient_steps);
427 |
428 | // 将HSV转换为RGB
429 | uint32_t red, green, blue;
430 | led_strip_hsv2rgb(current_h, current_s, current_v, &red, &green, &blue);
431 |
432 | // 设置所有LED的颜色
433 | for (int i = 0; i < CONFIG_WS2812_STRIP_LED_NUMBER; i++) {
434 | ESP_ERROR_CHECK(strip->set_pixel(strip, i, red, green, blue));
435 | }
436 | ESP_ERROR_CHECK(strip->refresh(strip, 100));
437 |
438 | gradient_current_step++;
439 |
440 | // 如果达到最后一步,停止定时器
441 | if (gradient_current_step > gradient_steps) {
442 | gradient_current_step = 0; // 重置步骤计数器
443 | esp_timer_stop(led_timer);
444 | }
445 | }
446 | }
447 |
448 | // 从一个颜色渐变到另一个颜色
449 | void led_set_color_gradient(ws2812_strip_t *strip, led_color_t start_color, led_color_t end_color, uint32_t duration_ms) {
450 | if (timer_state.active) {
451 | esp_timer_stop(led_timer);
452 | }
453 |
454 | // 将RGB颜色转换为HSV
455 | led_strip_rgb2hsv(start_color.red, start_color.green, start_color.blue, &gradient_start_h, &gradient_start_s, &gradient_start_v);
456 | led_strip_rgb2hsv(end_color.red, end_color.green, end_color.blue, &gradient_end_h, &gradient_end_s, &gradient_end_v);
457 |
458 | const uint32_t step_interval_ms = 20; // 50Hz刷新率
459 |
460 | gradient_steps = duration_ms / step_interval_ms;
461 |
462 | if (gradient_steps == 0) {
463 | gradient_steps = 1;
464 | }
465 |
466 | // 重置当前步骤计数器
467 | gradient_current_step = 0;
468 |
469 | // 设置定时器状态
470 | timer_state.strip = strip;
471 | timer_state.color = start_color;
472 | timer_state.effect_func = gradient_effect_func;
473 | timer_state.active = true;
474 |
475 | uint32_t interval_us = step_interval_ms * 1000;
476 | ESP_ERROR_CHECK(esp_timer_start_periodic(led_timer, interval_us));
477 | }
478 |
479 | // 更新LED显示
480 | void update_led_display(ws2812_strip_t *strip) {
481 | strip->refresh(strip, 100);
482 | }
483 |
484 |
485 |
486 | #elif defined(CONFIG_WS2812_MODE_MATRIX)
487 |
488 | ws2812_matrix_t* ws2812_matrix_create() {
489 | ws2812_matrix_t *matrix = (ws2812_matrix_t *)malloc(sizeof(ws2812_matrix_t));
490 | if (!matrix) {
491 | ESP_LOGE(TAG, "Failed to allocate memory for ws2812_matrix_t");
492 | return NULL;
493 | }
494 |
495 | matrix->config.matrixWidth = CONFIG_WS2812_MATRIX_WIDTH;
496 | matrix->config.matrixHeight = CONFIG_WS2812_MATRIX_HEIGHT;
497 | matrix->config.pin = CONFIG_WS2812_TX_GPIO;
498 |
499 | // 设置起始角落
500 | #if defined(CONFIG_WS2812_MATRIX_START_TOP_LEFT)
501 | matrix->config.matrixType = MATRIX_START_TOP_LEFT;
502 | #elif defined(CONFIG_WS2812_MATRIX_START_TOP_RIGHT)
503 | matrix->config.matrixType = MATRIX_START_TOP_RIGHT;
504 | #elif defined(CONFIG_WS2812_MATRIX_START_BOTTOM_LEFT)
505 | matrix->config.matrixType = MATRIX_START_BOTTOM_LEFT;
506 | #elif defined(CONFIG_WS2812_MATRIX_START_BOTTOM_RIGHT)
507 | matrix->config.matrixType = MATRIX_START_BOTTOM_RIGHT;
508 | #endif
509 |
510 | // 设置布局方向
511 | #if defined(CONFIG_WS2812_MATRIX_LAYOUT_HORIZONTAL)
512 | matrix->config.matrixType |= MATRIX_LAYOUT_HORIZONTAL;
513 | #elif defined(CONFIG_WS2812_MATRIX_LAYOUT_VERTICAL)
514 | matrix->config.matrixType |= MATRIX_LAYOUT_VERTICAL;
515 | #endif
516 |
517 | // 设置扫描顺序
518 | #if defined(CONFIG_WS2812_MATRIX_SCAN_PROGRESSIVE)
519 | matrix->config.matrixType |= MATRIX_SCAN_PROGRESSIVE;
520 | #elif defined(CONFIG_WS2812_MATRIX_SCAN_ZIGZAG)
521 | matrix->config.matrixType |= MATRIX_SCAN_ZIGZAG;
522 | #endif
523 |
524 | // 初始化RMT配置
525 | rmt_config_t config = RMT_DEFAULT_CONFIG_TX((gpio_num_t)CONFIG_WS2812_TX_GPIO, RMT_TX_CHANNEL);
526 | config.clk_div = 2;
527 |
528 | ESP_ERROR_CHECK(rmt_config(&config));
529 | ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));
530 |
531 | // 初始化LED条配置
532 | led_strip_config_t strip_config = LED_STRIP_DEFAULT_CONFIG(
533 | CONFIG_WS2812_MATRIX_WIDTH * CONFIG_WS2812_MATRIX_HEIGHT,
534 | (led_strip_dev_t)config.channel
535 | );
536 | matrix->strip = led_strip_new_rmt_ws2812(&strip_config);
537 |
538 | if (!matrix->strip) {
539 | ESP_LOGE(TAG, "Failed to create WS2812 strip");
540 | free(matrix);
541 | return NULL;
542 | }
543 |
544 | ESP_ERROR_CHECK(matrix->strip->clear(matrix->strip, 100));
545 | return matrix;
546 | }
547 |
548 |
549 | void led_matrix_set_pixel(ws2812_matrix_t *matrix, int x, int y, led_color_t color) {
550 | if (!matrix || !matrix->strip) {
551 | ESP_LOGE(TAG, "Matrix or strip handle is NULL");
552 | return;
553 | }
554 |
555 | // 检查坐标是否在矩阵范围内
556 | if (x < 0 || x >= matrix->config.matrixWidth || y < 0 || y >= matrix->config.matrixHeight) {
557 | ESP_LOGE(TAG, "Coordinates out of bounds");
558 | return;
559 | }
560 |
561 | int index;
562 |
563 | // 判断布局是行优先还是列优先
564 | if (matrix->config.matrixType & MATRIX_LAYOUT_VERTICAL) {
565 | // 列优先布局
566 | if (matrix->config.matrixType & MATRIX_SCAN_ZIGZAG) {
567 | // 之字形扫描
568 | index = (y % 2 == 0) ? (y * matrix->config.matrixWidth + x)
569 | : (y * matrix->config.matrixWidth + (matrix->config.matrixWidth - 1 - x));
570 | } else {
571 | // 连续扫描
572 | index = y * matrix->config.matrixWidth + x;
573 | }
574 | } else {
575 | // 行优先布局
576 | if (matrix->config.matrixType & MATRIX_SCAN_ZIGZAG) {
577 | // 之字形扫描
578 | index = (x % 2 == 0) ? (x * matrix->config.matrixHeight + y)
579 | : (x * matrix->config.matrixHeight + (matrix->config.matrixHeight - 1 - y));
580 | } else {
581 | // 连续扫描
582 | index = x * matrix->config.matrixHeight + y;
583 | }
584 | }
585 |
586 | // 调整索引以处理起始角
587 | switch (matrix->config.matrixType & MATRIX_START_CORNER) {
588 | case MATRIX_START_TOP_RIGHT:
589 | index = (matrix->config.matrixWidth * matrix->config.matrixHeight - 1) - index;
590 | break;
591 | case MATRIX_START_BOTTOM_LEFT:
592 | index = (matrix->config.matrixHeight - 1 - y) * matrix->config.matrixWidth + x;
593 | break;
594 | case MATRIX_START_BOTTOM_RIGHT:
595 | index = (matrix->config.matrixWidth * matrix->config.matrixHeight - 1) - index;
596 | break;
597 | case MATRIX_START_TOP_LEFT:
598 | default:
599 | // 无需调整
600 | break;
601 | }
602 |
603 | // 设置指定 LED 的颜色
604 | matrix->strip->set_pixel(matrix->strip, index, color.red, color.green, color.blue);
605 | }
606 |
607 | // 刷新显示以更新 LED
608 | void led_matrix_show(ws2812_matrix_t *matrix) {
609 | if (matrix == NULL || matrix->strip == NULL) {
610 | ESP_LOGE(TAG, "Matrix or strip handle is NULL");
611 | return;
612 | }
613 | matrix->strip->refresh(matrix->strip, 100);
614 | }
615 |
616 | void led_matrix_clear(ws2812_matrix_t *matrix){
617 |
618 | if (matrix == NULL || matrix->strip == NULL) {
619 | ESP_LOGE(TAG, "Matrix or strip handle is NULL");
620 | return;
621 | }
622 | matrix->strip->clear(matrix->strip,100); // 清空所有 LED
623 | }
624 |
625 | #endif
626 |
--------------------------------------------------------------------------------