当前位置: 首页 > news >正文

esp32cmini SK6812 2个方式

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个字节表示

  }

}


#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();
}

相关文章:

  • JavaScript APIs学习day2--DOM!!
  • Open CASCADE学习|刚体沿曲线运动实现方法
  • 前端学习(5)—— JavaScript(WebAPI)
  • 文件上传功能uploadify.js报updateSettings is not a function
  • EasyRTC嵌入式音视频通信SDK一对一音视频通信,打造远程办公/医疗/教育等场景解决方案
  • 【RabbitMQ】记录 InvalidDefinitionException: Java 8 date/time type
  • 超低延迟音视频直播技术的未来发展与创新
  • 数据库健康监测器(BHM)实战:如何通过 HTML 报告识别潜在问题
  • 深入理解万维网:URL、HTTP与HTML
  • 第16天-使用Python Pillow库常见图像处理场景
  • 如何使用Antv X6使用拖拽布局?
  • anaconda创建环境出错HTTPS
  • 每日Prompt:实物与手绘涂鸦创意广告
  • 【HTML-4】HTML段落标签:构建内容结构的基础
  • MySQL备份恢复:数据安全的终极指南
  • RPC 协议详解、案例分析与应用场景
  • 将VMware上的虚拟机和当前电脑上的Wifi网卡处在同一个局域网下,实现同一个局域网下实现共享
  • Neo4j实现向量检索
  • 【专题】机器学习期末复习资料
  • 【机器学习】支持向量机(SVM)
  • 长沙市做网站的网站/app推广引流
  • 做情趣用品网站需要哪些资质/企业专业搜索引擎优化
  • 三亚市住房和城乡建设局/怀化网站seo
  • 云南企业网站/北京百度推广代理
  • 哪个做砍价活动的网站好/aso关键词优化计划
  • 日照网站优化/微信营销技巧