1
#include <SPI.h>
// ESP32-C系列的SPI引脚
#define MOSI_PIN 7 // ESP32-C3/C6的SPI MOSI引脚
#define NUM_LEDS 30 // LED灯带实际LED数量 - 确保与实际数量匹配!
#define SPI_CLOCK 10000000 // SPI时钟频率
// 颜色结构体
struct CRGB {
uint8_t r;
uint8_t g;
uint8_t b;
};
// 定义常用颜色
namespace Colors {
const CRGB Black = {0, 0, 0};
const CRGB White = {255, 255, 255};
const CRGB Red = {255, 0, 0};
const CRGB Green = {0, 255, 0};
const CRGB Blue = {0, 0, 255};
}
CRGB leds[NUM_LEDS];
uint8_t brightness = 20; // 亮度 (0-255)
// SK6812协议需要精确的时序
// T0H: 0码高电平时间 ~0.3us
// T0L: 0码低电平时间 ~0.9us
// T1H: 1码高电平时间 ~0.6us
// T1L: 1码低电平时间 ~0.6us
// RES: 重置时间 >80us
// 根据SPI时钟调整字节模式
// 每个位需要至少3个字节来正确表示时序
#define BYTES_PER_BIT 3
#define BYTES_PER_LED (3 * 8 * BYTES_PER_BIT) // 3颜色 * 8位/颜色 * 字节/位
uint8_t spiBuffer[NUM_LEDS * BYTES_PER_LED + 100]; // 添加一些额外的缓冲空间
// 在ESP32上初始化SPI
SPIClass * vspi = NULL;
void setup() {
// 初始化串口调试
Serial.begin(115200);
Serial.println("ESP32-C SPI SK6812控制初始化开始");
// 初始化SPI
vspi = new SPIClass(SPI);
vspi->begin(MOSI_PIN);
// 设置SPI属性
vspi->beginTransaction(SPISettings(SPI_CLOCK, MSBFIRST, SPI_MODE0));
// 测试模式 - 打印灯带配置
Serial.print("控制 ");
Serial.print(NUM_LEDS);
Serial.println(" 个LED");
// 初始化LED为关闭状态
clearAll();
delay(500);
// 测试所有LED - 确认连接
testAllLeds();
}
void loop() {
// 从头到尾逐个点亮
sequentialLightUp();
// 从尾到头逐个熄灭
sequentialLightDown();
}
// 测试所有LED - 确认连接和灯带长度
void testAllLeds() {
// 全部设为红色
for(int i = 0; i < NUM_LEDS; i++) {
leds[i] = Colors::Red;
}
show();
delay(500);
// 全部设为绿色
for(int i = 0; i < NUM_LEDS; i++) {
leds[i] = Colors::Green;
}
show();
delay(500);
// 全部设为蓝色
for(int i = 0; i < NUM_LEDS; i++) {
leds[i] = Colors::Blue;
}
show();
delay(500);
// 全部熄灭
clearAll();
delay(500);
}
// 将HSV颜色转换为RGB
CRGB hsv2rgb(uint8_t h, uint8_t s, uint8_t v) {
CRGB rgb;
// 实现HSV到RGB的转换
uint8_t region, remainder, p, q, t;
if (s == 0) {
rgb.r = v;
rgb.g = v;
rgb.b = v;
return rgb;
}
region = h / 43;
remainder = (h - (region * 43)) * 6;
p = (v * (255 - s)) >> 8;
q = (v * (255 - ((s * remainder) >> 8))) >> 8;
t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8;
switch (region) {
case 0:
rgb.r = v; rgb.g = t; rgb.b = p;
break;
case 1:
rgb.r = q; rgb.g = v; rgb.b = p;
break;
case 2:
rgb.r = p; rgb.g = v; rgb.b = t;
break;
case 3:
rgb.r = p; rgb.g = q; rgb.b = v;
break;
case 4:
rgb.r = t; rgb.g = p; rgb.b = v;
break;
default:
rgb.r = v; rgb.g = p; rgb.b = q;
break;
}
return rgb;
}
void sequentialLightUp() {
// 清除所有LED
clearAll();
// 从第一个LED开始逐个点亮
for(int i = 0; i < NUM_LEDS; i++) {
// 选择不同的颜色效果
leds[i] = hsv2rgb(i * 10, 255, 255); // 渐变色相
// 更新灯带显示
show();
delay(50); // 控制点亮速度
}
}
void sequentialLightDown() {
// 从最后一个LED开始逐个熄灭
for(int i = NUM_LEDS - 1; i >= 0; i--) {
leds[i] = Colors::Black; // 熄灭
// 更新灯带显示
show();
delay(50); // 控制熄灭速度
}
}
// 清除所有LED
void clearAll() {
for(int i = 0; i < NUM_LEDS; i++) {
leds[i] = Colors::Black;
}
show();
}
// 重新优化的代码,确保正确的位时序
void show() {
// 准备SPI数据缓冲区
memset(spiBuffer, 0, sizeof(spiBuffer)); // 先清空缓冲区
prepareSPIBuffer();
// 发送数据前输出调试信息
Serial.println("发送LED数据...");
// 通过SPI发送数据
//vspi->transferBytes(spiBuffer, nullptr, NUM_LEDS * BYTES_PER_LED);
vspi->transferBytes(spiBuffer, nullptr, NUM_LEDS * 3 * 8);
// vspi->transferBytes(spiBuffer, nullptr, NUM_LEDS);
// 添加重置时间
delayMicroseconds(300); // >280μs的LED重置时间
}
// 更精确的SPI缓冲区准备
void prepareSPIBuffer() {
int bufferPos = 0;
// 处理每个LED的数据
for(int i = 0; i < NUM_LEDS; i++) {
// 应用亮度
uint8_t r = (leds[i].r * brightness) / 255;
uint8_t g = (leds[i].g * brightness) / 255;
uint8_t b = (leds[i].b * brightness) / 255;
// SK6812使用GRB顺序
// 转换每个颜色分量为SPI数据
convertByte(bufferPos, g); // 绿色
bufferPos += 8 * BYTES_PER_BIT;
convertByte(bufferPos, r); // 红色
bufferPos += 8 * BYTES_PER_BIT;
convertByte(bufferPos, b); // 蓝色
bufferPos += 8 * BYTES_PER_BIT;
}
}
// 优化的位编码 - 使用更少的字节
void convertByte(int offset, uint8_t byte) {
for(int i = 0; i < 8; i++) { // 每个字节8位
// 获取最高位
bool bit = byte & 0x80;
byte <<= 1;
// 根据SK6812的协议,为SPI准备数据
// 调整以下值以匹配您的SPI时钟和SK6812的时序需求
if(bit) {
// 1码 (T1H ~ 0.6us, T1L ~ 0.6us)
spiBuffer[offset + 0] = 0xF8; // 11111000
spiBuffer[offset + 1] = 0x00; // 00000000
spiBuffer[offset + 2] = 0x00; // 00000000
} else {
// 0码 (T0H ~ 0.3us, T0L ~ 0.9us)
spiBuffer[offset + 0] = 0xC0; // 11000000
spiBuffer[offset + 1] = 0x00; // 00000000
spiBuffer[offset + 2] = 0x00; // 00000000
}
offset += BYTES_PER_BIT; // 每位使用BYTES_PER_BIT个字节表示
}
}
2
#include <FastLED.h>
#define LED_PIN 6 // 数据引脚
#define NUM_LEDS 30 // LED数量
#define LED_TYPE SK6812 // LED类型
#define COLOR_ORDER GRB // 颜色顺序
CRGB leds[NUM_LEDS];
void setup() {
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS);
FastLED.setBrightness(50); // 设置亮度
}
void loop() {
// 从头到尾逐个点亮
sequentialLightUp();
// 从尾到头逐个熄灭
sequentialLightDown();
}
void sequentialLightUp() {
// 清除所有LED
FastLED.clear();
// 从第一个LED开始逐个点亮
for(int i = 0; i < NUM_LEDS; i++) {
// 选择不同的颜色效果
leds[i] = CHSV(i * 10, 255, 255); // 渐变色相
FastLED.show();
delay(50); // 控制点亮速度
}
}
void sequentialLightDown() {
// 从最后一个LED开始逐个熄灭
for(int i = NUM_LEDS - 1; i >= 0; i--) {
leds[i] = CRGB::Black; // 熄灭
FastLED.show();
delay(50); // 控制熄灭速度
}
}
// 可选:添加更多炫酷效果
void rainbowEffect() {
static uint8_t hue = 0;
for(int i = 0; i < NUM_LEDS; i++) {
leds[i] = CHSV(hue + (i * 10), 255, 255);
}
EVERY_N_MILLISECONDS(100) {
hue++;
}
FastLED.show();
}