WS2812是单线通信,0码和1码都是由高低电平组成,只不过高低电平占用时间有区别
发送第一个24位数据时,第一个WS2812会记录并且锁存起来,再发第二个的24位的时候,就会把数据直接传输给第二个WS2812并记录,再发第三个24位数据,第前两个因为已经记录了数据,因此都会将数据流转到下一个,最后也就是第三个会收到数据。如此类推,直到我们发送一个RESET信号,本次传输才结束
添加控制灯的组件库
led_strip
https://components.espressif.com/components/espressif/led_strip/versions/2.5.5
控制台输入
bash
idf.py add-dependency "espressif/led_strip^3.0.0"
然后编译会生成组件目录
RMT
使用 ESP RMT 库进行驱动
官方关于RMT的介绍:RMT(红外遥控器)是一个红外发送/接收控制器, 其特殊设计支持生成各类信号。红外遥控发射器从内置的 RAM(随机存取存储器)区中读取连续的脉冲码, 并对输出信号进行载波调制。尽管RMT外设主要用于远程红外应用,由于其灵活的数据格式,RMT同样可支持其它协议。WS2812是集成了驱动电路和单线控制的数字RGB LED,其协议数据格式兼容于RMT外设。
驱动WS2812要求的时序很高,我们用IO口模拟控制比较困难,用SPI或者I2C时序也对不上,因此红外是最优选择
RMT初始化
c
// 使用默认参数填入rmt_config_t结构体
rmt_config_t config = RMT_DEFAULT_CONFIG_TX(CONFIG_EXAMPLE_RMT_TX_GPIO, RMT_TX_CHANNEL);
// 将时钟设置为40MHz
config.clk_div = 2;
// 调用两个函数完成初始化
ESP_ERROR_CHECK(rmt_config(&config));
ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));
WS2812初始化
c
// install ws2812 driver 安装ws2812驱动
led_strip_config_t strip_config = LED_STRIP_DEFAULT_CONFIG(CONFIG_EXAMPLE_STRIP_LED_NUMBER, (led_strip_dev_t)config.channel);
led_strip_t *strip = led_strip_new_rmt_ws2812(&strip_config);
if (!strip) {
ESP_LOGE(TAG, "install WS2812 driver failed");
}
// Clear LED strip (turn off all LEDs)关闭所有ws2812
ESP_ERROR_CHECK(strip->clear(strip, 100));
示例代码:
ws2812.c
点击展开代码
c
#include "ws2812.h"
#include <stdlib.h>
#include "driver/gpio.h"
#include "driver/rmt.h"
#include "esp_mac.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "led_strip.h"
static led_strip_t *strip = NULL;
/********************************************************************************
* @brief: ws2812 初始化
* @return {*}
********************************************************************************/
void ws2812_init() {
rmt_config_t config = RMT_DEFAULT_CONFIG_TX(GPIO_LED_PIN, RMT_TX_CHANNEL);
config.clk_div = 2; // 时钟分频,设置为2可以提高时序精度
ESP_ERROR_CHECK(rmt_config(&config));
ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));
// 使用 LED Strip 库
led_strip_config_t strip_config =
LED_STRIP_DEFAULT_CONFIG(LED_NUM, (led_strip_dev_t)config.channel);
strip = led_strip_new_rmt_ws2812(&strip_config);
if (!strip) {
printf("Failed to install WS2812 driver\n");
}
// 清空 LED
ESP_ERROR_CHECK(strip->clear(strip, 100));
vTaskDelay(pdMS_TO_TICKS(100));
// 设置固定颜色
set_static_color(255, 0, 0);
vTaskDelay(pdMS_TO_TICKS(100));
// // 呼吸灯效果(蓝色)
// xTaskCreate(breathing_effect, "breathing_effect", 2048,
// (void *){0, 0, 255, 20}, 5, NULL);
// // 彩虹渐变效果
// xTaskCreate(rainbow_effect, "rainbow_effect", 2048, (void *)20, 5, NULL);
// 跑马灯效果
// xTaskCreate(chasing_effect, "chasing_effect", 2048, NULL, 5, NULL);
}
/********************************************************************************
* @brief: 固定颜色
* @param {uint8_t} red
* @param {uint8_t} green
* @param {uint8_t} blue
* @return {*}
********************************************************************************/
void set_static_color(uint8_t red, uint8_t green, uint8_t blue) {
for (int i = 0; i < LED_NUM; i++) {
strip->set_pixel(strip, i, red, green, blue);
}
strip->refresh(strip, 100);
}
/********************************************************************************
* @brief: 彩虹渐变
* @param {uint8_t} wait_ms
* @return {*}
********************************************************************************/
void rainbow_effect(uint8_t wait_ms) {
uint8_t hue = 0;
while (1) {
for (int i = 0; i < LED_NUM; i++) {
uint8_t red = 0, green = 0, blue = 0;
hsv2rgb(hue + i * 10, 255, 50, &red, &green, &blue); // HSV 转 RGB
strip->set_pixel(strip, i, red, green, blue);
}
strip->refresh(strip, 100);
hue += 5; // 控制颜色变化速度
vTaskDelay(pdMS_TO_TICKS(wait_ms));
}
}
/********************************************************************************
* @brief: 呼吸灯效果
* @param {uint8_t} red
* @param {uint8_t} green
* @param {uint8_t} blue
* @param {uint8_t} wait_ms
* @return {*}
********************************************************************************/
void breathing_effect(uint8_t red, uint8_t green, uint8_t blue,
uint8_t wait_ms) {
while (1) {
for (int brightness = 0; brightness < 256; brightness += 5) {
for (int i = 0; i < LED_NUM; i++) {
strip->set_pixel(strip, i, (red * brightness) / 255,
(green * brightness) / 255, (blue * brightness) / 255);
}
strip->refresh(strip, 100);
vTaskDelay(pdMS_TO_TICKS(wait_ms));
}
for (int brightness = 255; brightness >= 0; brightness -= 5) {
for (int i = 0; i < LED_NUM; i++) {
strip->set_pixel(strip, i, (red * brightness) / 255,
(green * brightness) / 255, (blue * brightness) / 255);
}
strip->refresh(strip, 100);
vTaskDelay(pdMS_TO_TICKS(wait_ms));
}
}
}
/********************************************************************************
* @brief: 跑马灯效果
* @param {uint8_t} red
* @param {uint8_t} green
* @param {uint8_t} blue
* @param {uint8_t} wait_ms
* @return {*}
********************************************************************************/
void chasing_effect() {
int led_pos = 0; // 跑马灯的当前位置
while (true) {
// 清除所有 LED
strip->clear(strip, 50);
vTaskDelay(pdMS_TO_TICKS(1000)); // 延时 100 毫秒
// 设置跑马灯效果
strip->set_pixel(strip, led_pos, 255, 0, 0); // 设置当前 LED 为红色
strip->refresh(strip, 100); // 刷新 LED 状态
// 更新跑马灯位置
led_pos = (led_pos + 1) % LED_NUM;
// vTaskDelay(pdMS_TO_TICKS(100)); // 延时 100 毫秒
}
}
/********************************************************************************
* @brief: HSV 转 RGB 函数
* @param {uint8_t} hue
* @param {uint8_t} sat
* @param {uint8_t} val
* @param {uint8_t} *r
* @param {uint8_t} *g
* @param {uint8_t} *b
* @return {*}
********************************************************************************/
void hsv2rgb(uint8_t hue, uint8_t sat, uint8_t val, uint8_t *r, uint8_t *g,
uint8_t *b) {
uint8_t region, remainder, p, q, t;
if (sat == 0) {
*r = val;
*g = val;
*b = val;
return;
}
region = hue / 43;
remainder = (hue - (region * 43)) * 6;
p = (val * (255 - sat)) >> 8;
q = (val * (255 - ((sat * remainder) >> 8))) >> 8;
t = (val * (255 - ((sat * (255 - remainder)) >> 8))) >> 8;
switch (region) {
case 0:
*r = val;
*g = t;
*b = p;
break;
case 1:
*r = q;
*g = val;
*b = p;
break;
case 2:
*r = p;
*g = val;
*b = t;
break;
case 3:
*r = p;
*g = q;
*b = val;
break;
case 4:
*r = t;
*g = p;
*b = val;
break;
default:
*r = val;
*g = p;
*b = q;
break;
}
}
ws2812.h
点击展开代码
c
#ifndef WS2812_H
#define WS2812_H
#include <stdio.h>
// RMT 发送通道
#define RMT_TX_CHANNEL RMT_CHANNEL_0
// LED 数据端口
#define GPIO_LED_PIN 41
// LED 数量
#define LED_NUM 2
void ws2812_init();
void set_static_color(uint8_t red, uint8_t green, uint8_t blue);
void rainbow_effect(uint8_t wait_ms);
void breathing_effect(uint8_t red, uint8_t green, uint8_t blue,
uint8_t wait_ms);
void chasing_effect();
void hsv2rgb(uint8_t hue, uint8_t sat, uint8_t val, uint8_t *r, uint8_t *g,
uint8_t *b);
#endif