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個字節表示

? }

}

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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/82350.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/82350.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/82350.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

互聯網大廠Java求職面試:Spring Cloud微服務架構設計中的挑戰與解決方案

互聯網大廠Java求職面試&#xff1a;Spring Cloud微服務架構設計中的挑戰與解決方案 面試場景設定 鄭薪苦是一位擁有豐富實戰經驗的Java開發者&#xff0c;他正在參加一場由某知名互聯網大廠的技術總監主持的面試。這場面試將圍繞Spring Cloud微服務架構展開&#xff0c;涵蓋…

品鑒JS的魅力之防抖與節流【JS】

前言 小水一波&#xff0c;函數的防抖與節流。 文章目錄 前言介紹實現方式防抖節流 介紹 防抖與節流的優化邏輯&#xff0c;在我們的日常開發中&#xff0c;有著一定的地位。 防抖和節流是兩種常用的性能優化技術&#xff0c;用于限制某個函數在一定時間內被觸發的次數,減少不…

# 使用 Hugging Face Transformers 和 PyTorch 實現信息抽取

使用 Hugging Face Transformers 和 PyTorch 實現信息抽取 在自然語言處理&#xff08;NLP&#xff09;領域&#xff0c;信息抽取是一種常見的任務&#xff0c;其目標是從文本中提取特定類型的結構化信息。本文將介紹如何使用 Hugging Face Transformers 和 PyTorch 實現基于大…

Firecrawl MCP Server 深度使用指南

無論是市場分析師洞察行業動態、研究者收集學術資料&#xff0c;還是開發者為智能應用采集數據&#xff0c;都對網絡數據采集工具提出了極高的要求。Firecrawl MCP Server 應運而生&#xff0c;它宛如一把犀利的 “數字手術刀”&#xff0c;能夠精準地剖析網頁&#xff0c;為用…

OceanBase數據庫全面指南(基礎入門篇)

文章目錄 一、OceanBase 簡介與安裝配置指南1.1 OceanBase 核心特點1.2 架構解析1.3 安裝部署實戰1.3.1 硬件要求1.3.2 安裝步驟詳解1.3.3 配置驗證二、OceanBase 基礎 SQL 語法入門2.1 數據查詢(SELECT)2.1.1 基礎查詢語法2.1.2 實際案例演示2.2 數據操作(INSERT/UPDATE/DE…

幾種環境下的Postgres數據庫安裝

1. Postgres 數據庫介紹 PostgreSQL&#xff08;又稱 Postgres&#xff09;是一種強大、開源的關系型數據庫管理系統&#xff08;RDBMS&#xff09;&#xff0c;它具備高度的可靠性、穩定性和可擴展性&#xff0c;主要特點如下&#xff1a; 開源&#xff1a;PostgreSQL 是基于開…

函數[x]和{x}在數論中的應用

函數[x]和{x}在數論中的應用 函數[x]和{x}的定義與基本性質&#xff08;定義1&#xff0c;命題1&#xff09;定義1例1命題1 函數[x]和{x}的應用&#xff08;定理1&#xff0c;推論1-推論3&#xff09;例2定理1注解5推論1例3例4推論2推論3命題2 函數[x]和{x}的定義與基本性質&am…

Python爬蟲(32)Python爬蟲高階:動態頁面處理與Scrapy+Selenium+BeautifulSoup分布式架構深度解析實戰

目錄 引言一、動態頁面爬取的技術背景1.1 動態頁面的核心特征1.2 傳統爬蟲的局限性 二、技術選型與架構設計2.1 核心組件分析2.2 架構設計思路1. 分層處理2. 數據流 三、代碼實現與關鍵技術3.1 Selenium與Scrapy的中間件集成3.2 BeautifulSoup與Scrapy Item的整合3.3 分布式爬取…

FreeSWITCH rtcp-mux 測試

rtcp 跟 rtp 占用同一個端口&#xff0c;這就是 rtcp 復用 Fs 呼出是這樣的&#xff1a; originate [rtcp_muxtrue][rtcp_audio_interval_msec5000]user/1001 &echo 需要同時指定 rtcp_audio_interval_msec&#xff0c;否則 rtcp_mux 不能生效 Fs 呼入不需要配置&#xf…

day019-特殊符號、正則表達式與三劍客

文章目錄 1. 磁盤空間不足-排查流程2. 李導推薦書籍2.1 大話存儲2.2 性能之巔 3. 特殊符號3.1 引號系列&#xff08;面試題&#xff09;3.2 重定向符號3.2.1 cat與重定向3.2.2 tr命令&#xff1a;替換字符3.2.3 xargs&#xff1a;參數轉換3.2.4 標準全量追加重定向 4. 正則表達…

Vue3 watch 使用與注意事項

watch 的第一個參數可以是不同形式的“數據源”&#xff1a;它可以是一個 ref (包括計算屬性)、一個響應式對象、一個 getter 函數、或多個數據源組成的數組&#xff1a; 1&#xff1a;reactive監聽對象 <template><div><h1>情況二&#xff1a;watchEffect…

醫學寫作供應商管理全流程優化

1. 供應商篩選與評估 1.1 資質審核 1.1.1 行業認證核查 核查供應商的行業認證,如AMWA醫學寫作認證、EMWA會員資格、ISO 9001等,確保其專業資質。 1.1.2 團隊背景評估 評估團隊成員專業背景,包括醫學/藥學學位、臨床試驗經驗、發表記錄,保障專業能力。 1.1.3 國際規范熟悉…

固態硬盤顆粒類型、選型與應用場景深度解析

一、固態硬盤顆粒類型的技術演進與特性 固態硬盤&#xff08;SSD&#xff09;的性能核心在于存儲單元結構的設計&#xff0c;這種設計直接決定了數據的存儲密度、讀寫速度、耐久度及成本效益。當前主流的閃存顆粒類型呈現從單層到多層架構的梯度演進&#xff0c;其技術特征與應…

CAPL自動化-診斷Demo工程

文章目錄 前言一、診斷控制面板二、診斷定義三、發送診斷通過類.方法的方式req.SetParameterdiagSetParameter四、SendRequestAndWaitForResponse前言 本文將介紹CANoe的診斷自動化測試,工程可以從CANoe的 Sample Configruration 界面打開,也可以參考下面的路徑中打開(以實…

嵌入式預處理鏈接腳本lds和map文件

在嵌入式開發中&#xff0c;.lds.S 文件是一個 預處理后的鏈接腳本&#xff08;Linker Script&#xff09;&#xff0c;它結合了 C 預處理器&#xff08;Preprocessor&#xff09; 的功能和鏈接腳本的語法。它的核心作用仍然是 定義內存布局和鏈接規則&#xff0c;但通過預處理…

PT5F2307觸摸A/D型8-Bit MCU

1. 產品概述 ● PT5F2307是一款51內核的觸控A/D型8位MCU&#xff0c;內置16K*8bit FLASH、內部256*8bit SRAM、外部512*8bit SRAM、觸控檢測、12位高精度ADC、RTC、PWM等功能&#xff0c;抗干擾能力強&#xff0c;適用于滑條遙控器、智能門鎖、消費類電子產品等電子應用領域。 …

RabbitMQ——消息確認

一、消息確認機制 生產者發送的消息&#xff0c;可能有以下兩種情況&#xff1a; 1> 消息消費成功 2> 消息消費失敗 為了保證消息可靠的到達消費者&#xff08;&#xff01;&#xff01;&#xff01;注意&#xff1a;消息確認機制和前面的工作模式中的publisher confi…

C++異步(1)

什么是異步? 異步就是多個線程是同時執行的&#xff0c;與之相對的就是線程同步&#xff0c;二者都應用在并發的場景上。 異步的特點 異步執行的任務無需等待其他任務完成&#xff0c;其本身是通過非阻塞的方式執行的&#xff0c;不依賴前驅任務&#xff0c;通常用于IO密集…

向量數據庫Milvus03-高級功能與性能調優

Milvus高級功能與性能調優 目錄 高級特性詳解性能調優技巧生產環境部署最佳實踐總結與展望 1. 高級特性詳解 1.1 多索引兼容 Milvus 支持多種索引類型&#xff08;如 HNSW、IVF_PQ、IVF_FLAT&#xff09;的混合使用&#xff0c;以適應不同場景的需求。 HNSW&#xff08;Hier…

5月24日day35打卡

模型可視化與推理 知識點回顧&#xff1a; 三種不同的模型可視化方法&#xff1a;推薦torchinfo打印summary權重分布可視化進度條功能&#xff1a;手動和自動寫法&#xff0c;讓打印結果更加美觀推理的寫法&#xff1a;評估模式 作業&#xff1a;調整模型定義時的超參數&#x…