关于FastLED库添加LED SM16705PD芯片过程

关于FastLED库添加LED SM16705PD芯片过程


注意:这只是本人随便做的记录,仅供参考
环境: vscode + PlatformIO
芯片:
测试: ws2812b
修改后的测试: SM16705PD
其他芯片添加可以参考一下!

一、导入FastLED库

1. 搜索FastLED库

在这里插入图片描述

2. 选择版本

  • 我选择的是目前最新版本 3.7.4
  • 选择后点击添加到项目即可
    在这里插入图片描述

3. 导入项目

  • 在项目文件里面就可以看见导入的库了
    在这里插入图片描述

二、写个 LED 例程

  • 随便写个可以运行LED灯带的项目(一般ws2812b最为经典,也最为常用)
#include "FastLED.h"  
  
// 定义LED的数量和连接的引脚  
#define NUM_LEDS 12  //12颗灯
#define DATA_PIN 12  //引脚
// 定义LED的类型。这里以常见的WS2812B为例  
CRGB leds[NUM_LEDS];  
void setup() {   
  // 初始化串口通讯  
  Serial.begin(115200);  
  // 初始化FastLED,设置引脚和数据速率  
  FastLED.addLeds<WS2812, DATA_PIN, RGB>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);  
  // 设置亮度,范围为0(关闭)到255(最亮)  
  FastLED.setBrightness(50);  
}  
void loop() {  
  // 遍历所有LED,并将它们逐个设置为红色  
  for(int i = 0; i < NUM_LEDS; i++) {  
    leds[i] = CRGB::Yellow;  
    // 发送数据到LED条,更新显示
    FastLED.show();  
    // 等待一小段时间后点亮下一个LED
    delay(500);  
  }  
  // 等待一小段时间后再次更新  
  delay(1000);  
  // 遍历所有LED,并将它们逐个设置为蓝色  
  for(int i = 0; i < NUM_LEDS; i++) {  
    leds[i] = CRGB::Green;  
    // 发送数据到LED条,更新显示
    FastLED.show();  
    // 等待一小段时间后点亮下一个LED
    delay(500);  
  }  
  // 等待一小段时间后再次更新  
  delay(1000);   
}
  • 复制文件到项目运行测试这个代码是否可用(可用就进行下一步)

三、定位修改文件位置

1. 需要在 FastLED.h 文件内添加芯片模板

(1) 找到 WS2812 这个变量 的位置
(2) 按 Ctrl + 右键 进入WS2812所在位置 FastLED.h 文件
(3)
在这里插入图片描述
(4)
在这里插入图片描述

2. 在 chipsets.h 文件添加一个模板

(1) 在这之前还需要去实现我们需要的 SM16705PD芯片的父类
(2) 所以先进入WS2812的父类
(3) 按 Ctrl + 右键 点击 父类 WS2812Controller800Khz 进入父类所在文件 chipsets.h
在这里插入图片描述

3. 在 clockless_rmt_esp32.h 文件修改(对类进行派生扩展)

(1) 按 Ctrl + 右键 进入 ClocklessController所在位置 clockless_rmt_esp32.h
(2) 准备对文件进行修改派生

4. 在 controller.h 添加 loadAndScale 和 getScale 的实例化对象

(1) 在文件里面有个叫 pixels.loadAndScale0() 的代码
(2) 按 Ctrl + 右键 进入找到其位置,总的有 3 个派生函数都需要添加(这里原本只有3个,被我改为了9个)
在这里插入图片描述

5. 在 pixeltypes.h 文件下 EOrder 枚举里面添加 颜色通道

(1) 在 main.cpp文件里面找到 RGB 这个变量, 按 Ctrl + 右键 进入枚举 在这里插入图片描述
(2) 添加枚举类型画圈部分都是(这里面 0 :红色 ,1:绿色,2:蓝色,3:白色,4:黄色)
在这里插入图片描述

6. 在 controller.h 里面修改 下面这几段代码

#define RGB_BYTE(RO,X) (((RO)>>(3*(2-(X)))) & 0x3)

/// @see RGB_BYTE(RO,X)
#define RGB_BYTE0(RO) ((RO>>6) & 0x3)
/// Gets the color channel for byte 1.
/// @see RGB_BYTE(RO,X)
#define RGB_BYTE1(RO) ((RO>>3) & 0x3)
/// Gets the color channel for byte 2.
/// @see RGB_BYTE(RO,X)
#define RGB_BYTE2(RO) ((RO) & 0x3)

四、修改文件

注意:文件修改顺序可能要变,不按寻找顺序来。

1. 首先在 EOrder 枚举里面添加 颜色通道(在RGB 后面添加即可)

// 添加五种颜色通道顺序
    RGBWY=001234, ///< Red,   Green, Blue,  White, Yellow (001234)
    RBGWY=002134, ///< Red,   Blue,  Green, White, Yellow (002134)
    GRBWY=010234, ///< Green, Red,   Blue,  White, Yellow (010234)
    GBRWY=012034, ///< Green, Blue,  Red,   White, Yellow (012034)
    BRGWY=020134, ///< Blue,  Red,   Green, White, Yellow (020134)
    BGRWY=021034, ///< Blue,  Green, Red,   White, Yellow (021034)
    WRGBY=301234, ///< White, Red,   Green, Blue,  Yellow (301234)
    WGRBY=310234, ///< White, Green, Red,   Blue,  Yellow (310234)
    WBRGY=320134, ///< White, Blue,  Red,   Green, Yellow (320134)
    YRGBW=401234, ///< Yellow, Red,  Green, Blue,  White  (401234)
    YGRBW=410234, ///< Yellow, Green, Red,  Blue,  White  (410234)
    YBRGW=420134  ///< Yellow, Blue, Red,   Green, White  (420134)

2. 修改 controller.h 里面 的 RGB_BYTE 计算值(不修改无法使用4和5通道,那么前面 EOrder 里面我们自己定义的值就没有用)

#define RO(X) RGB_BYTE(RGB_ORDER, X)

/// Gets the assigned color channel for a byte's position in the output,
/// using a passed RGB color order
/// @param RO the RGB color order
/// @param X the byte's position in the output (0-2)
/// @returns the color channel for that byte (0 = red, 1 = green, 2 = blue)
/// @see EOrder
// #define RGB_BYTE(RO,X) (((RO)>>(3*(2-(X)))) & 0x3) //原来的值
#define RGB_BYTE(RO,X) (((RO)>>(3*(4-(X)))) & 0x7)
// Gets the color channel for byte 0.
// /// @see RGB_BYTE(RO,X)
// #define RGB_BYTE0(RO) ((RO>>6) & 0x3) //原来的值
// /// Gets the color channel for byte 1.
// /// @see RGB_BYTE(RO,X)
// #define RGB_BYTE1(RO) ((RO>>3) & 0x3) //原来的值
// /// Gets the color channel for byte 2.
// /// @see RGB_BYTE(RO,X)
// #define RGB_BYTE2(RO) ((RO) & 0x3) //原来的值

/// 获取字节 0 的颜色通道。
/// @see RGB_BYTE(RO,X)
#define RGB_BYTE0(RO) ((RO>>12) & 0x7)
/// 获取字节 1 的颜色通道。
/// @see RGB_BYTE(RO,X)
#define RGB_BYTE1(RO) ((RO>>9) & 0x7)
/// 获取字节 2 的颜色通道。
/// @see RGB_BYTE(RO,X)
#define RGB_BYTE2(RO) ((RO>>6) & 0x7)
/// 获取字节 3 的颜色通道。
/// @see RGB_BYTE(RO,X)
#define RGB_BYTE3(RO) ((RO>>3) & 0x7)
/// 获取字节 4 的颜色通道。
/// @see RGB_BYTE(RO,X)
#define RGB_BYTE4(RO) ((RO) & 0x7)

3. 在 clockless_rmt_esp32.h 文件修改(对类进行派生扩展)

  • 直接写个基类,并派生出两个类 ClocklessController80Bit 和 ClocklessController
  • 值得注意的是 ClocklessController 就是本来库的类,只是我们对其稍微修改了下,让其成为其中一个派生类。
// 基类,包含虚函数
template <int DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 5>
class ClocklessControllerBase : public CPixelLEDController<RGB_ORDER>{}

// 处理80位数据的派生类
template <int DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 5>
class ClocklessController80Bit : public ClocklessControllerBase<DATA_PIN, T1, T2, T3, RGB_ORDER, XTRA0, FLIP, WAIT_TIME>{}

// 处理24位数据的派生类
template <int DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 5>
class ClocklessController : public ClocklessControllerBase<DATA_PIN, T1, T2, T3, RGB_ORDER, XTRA0, FLIP, WAIT_TIME>{}
#pragma once
#include "rmt.h"
FASTLED_NAMESPACE_BEGIN
#define FASTLED_HAS_CLOCKLESS 1
#define NUM_COLOR_CHANNELS 3

// 基类,包含虚函数
template <int DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 5>
class ClocklessControllerBase : public CPixelLEDController<RGB_ORDER>
{
protected:
    ESP32RMTController mRMTController;
    static_assert(FastPin<DATA_PIN>::validpin(), "Invalid pin specified");
public:
    ClocklessControllerBase()
        : mRMTController(DATA_PIN, T1, T2, T3, FASTLED_RMT_MAX_CHANNELS, FASTLED_RMT_BUILTIN_DRIVER)
    {}
    virtual void init() {}
    virtual uint16_t getMaxRefreshRate() const { return 400; }
    // 虚函数,派生类需要实现
    virtual void loadPixelData(PixelController<RGB_ORDER> & pixels) = 0;
    virtual void showPixels(PixelController<RGB_ORDER> & pixels) = 0;
};
// 处理80位数据的派生类
template <int DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 5>
class ClocklessController80Bit : public ClocklessControllerBase<DATA_PIN, T1, T2, T3, RGB_ORDER, XTRA0, FLIP, WAIT_TIME>
{
public:
    using ClocklessControllerBase<DATA_PIN, T1, T2, T3, RGB_ORDER, XTRA0, FLIP, WAIT_TIME>::ClocklessControllerBase;

    void loadPixelData(PixelController<RGB_ORDER> & pixels) override
    {
        int size_in_bytes = pixels.size() * 10; // 5个颜色通道,每个16位
        uint8_t * pData = this->mRMTController.getPixelBuffer(size_in_bytes);

        while (pixels.has(1)) {
            // *pData++ = pixels.loadAndScale0();
            // *pData++ = pixels.loadAndScale1();
            // *pData++ = pixels.loadAndScale2();
            // *pData++ = pixels.loadAndScale3();
            // *pData++ = pixels.loadAndScale4();
            // *pData++ = pixels.loadAndScale5();
            // *pData++ = pixels.loadAndScale6();
            // *pData++ = pixels.loadAndScale7();
            // *pData++ = pixels.loadAndScale8();
            // *pData++ = pixels.loadAndScale9();
            uint8_t r = pixels.loadAndScale0();
            uint8_t g = pixels.loadAndScale1();
            uint8_t b = pixels.loadAndScale2();
            uint8_t w = 0;
            uint8_t y = 0;

       
            // *pData++ = r >> 8;
            // *pData++ = r & 0xFF;
            // *pData++ = g >> 8;
            // *pData++ = g & 0xFF;
            // *pData++ = b >> 8;
            // *pData++ = b & 0xFF;
            // *pData++ = w >> 8;
            // *pData++ = w & 0xFF;
            // *pData++ = y >> 8;
            // *pData++ = y & 0xFF;
            // 将8位颜色数据扩展为16位
            *pData++ = r; // 高8位
            *pData++ = r; // 低8位
            *pData++ = g; // 高8位
            *pData++ = g; // 低8位
            *pData++ = b; // 高8位
            *pData++ = b; // 低8位
            *pData++ = w; // 高8位
            *pData++ = w; // 低8位
            *pData++ = y; // 高8位
            *pData++ = y; // 低8位

            pixels.advanceData();
            pixels.stepDithering();
        }
    }
    void showPixels(PixelController<RGB_ORDER> & pixels) override
    {
        this->loadPixelData(pixels);
        this->mRMTController.showPixels();
        // this->sendStandbyCommand(); // 发送待机指令
    }
    void sendStandbyCommand() {
        // 待机指令数据为 2'b01
        uint8_t standbyData = 0b01;
        sendData(standbyData);
    }
private:
    void sendData(uint8_t data) {
        uint8_t * pData = this->mRMTController.getPixelBuffer(1);
        *pData = data;
        this->mRMTController.showPixels();
    }
};
// 处理24位数据的派生类
template <int DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 5>
class ClocklessController : public ClocklessControllerBase<DATA_PIN, T1, T2, T3, RGB_ORDER, XTRA0, FLIP, WAIT_TIME>
{
public:
    using ClocklessControllerBase<DATA_PIN, T1, T2, T3, RGB_ORDER, XTRA0, FLIP, WAIT_TIME>::ClocklessControllerBase;

    void loadPixelData(PixelController<RGB_ORDER> & pixels) override
    {
        int size_in_bytes = pixels.size() * 3; // 3个颜色通道,每个8位
        uint8_t * pData = this->mRMTController.getPixelBuffer(size_in_bytes);

        while (pixels.has(1)) {
            *pData++ = pixels.loadAndScale0();
            *pData++ = pixels.loadAndScale1();
            *pData++ = pixels.loadAndScale2();
            pixels.advanceData();
        }
    }
    void showPixels(PixelController<RGB_ORDER> & pixels) override
    {
        this->loadPixelData(pixels);
        this->mRMTController.showPixels();
    }
};
FASTLED_NAMESPACE_END

4. 在 controller.h 添加 loadAndScale 和 getScale 的实例化对象

(1) 在文件里面有个叫 pixels.loadAndScale0() 的代码
(2) 按 Ctrl + 右键 进入找到其位置,总的有 3 个派生函数都需要添加(这里原本只有3个,被我改为了9个)

// Helper functions to get around gcc stupidities
        __attribute__((always_inline)) inline uint8_t loadAndScale0(int lane, uint8_t scale) { return loadAndScale<0>(*this, lane, scale); }  ///< non-template alias of loadAndScale<0>()
        __attribute__((always_inline)) inline uint8_t loadAndScale1(int lane, uint8_t scale) { return loadAndScale<1>(*this, lane, scale); }  ///< non-template alias of loadAndScale<1>()
        __attribute__((always_inline)) inline uint8_t loadAndScale2(int lane, uint8_t scale) { return loadAndScale<2>(*this, lane, scale); }  ///< non-template alias of loadAndScale<2>()
        __attribute__((always_inline)) inline uint8_t loadAndScale3(int lane, uint8_t scale) { return loadAndScale<3>(*this, lane, scale); }  ///< non-template alias of loadAndScale<3>()//自己添加的
        __attribute__((always_inline)) inline uint8_t loadAndScale4(int lane, uint8_t scale) { return loadAndScale<4>(*this, lane, scale); }  ///< non-template alias of loadAndScale<4>()//自己添加的
        __attribute__((always_inline)) inline uint8_t loadAndScale5(int lane, uint8_t scale) { return loadAndScale<5>(*this, lane, scale); }  ///< non-template alias of loadAndScale<4>()//自己添加的
        __attribute__((always_inline)) inline uint8_t loadAndScale6(int lane, uint8_t scale) { return loadAndScale<6>(*this, lane, scale); }  ///< non-template alias of loadAndScale<2>()
        __attribute__((always_inline)) inline uint8_t loadAndScale7(int lane, uint8_t scale) { return loadAndScale<7>(*this, lane, scale); }  ///< non-template alias of loadAndScale<3>()//自己添加的
        __attribute__((always_inline)) inline uint8_t loadAndScale8(int lane, uint8_t scale) { return loadAndScale<8>(*this, lane, scale); }  ///< non-template alias of loadAndScale<4>()//自己添加的
        __attribute__((always_inline)) inline uint8_t loadAndScale9(int lane, uint8_t scale) { return loadAndScale<9>(*this, lane, scale); }  ///< non-template alias of loadAndScale<4>()//自己添加的
        __attribute__((always_inline)) inline uint8_t advanceAndLoadAndScale0(int lane, uint8_t scale) { return advanceAndLoadAndScale<0>(*this, lane, scale); }  ///< non-template alias of advanceAndLoadAndScale<0>()
        __attribute__((always_inline)) inline uint8_t stepAdvanceAndLoadAndScale0(int lane, uint8_t scale) { stepDithering(); return advanceAndLoadAndScale<0>(*this, lane, scale); }  ///< stepDithering() and advanceAndLoadAndScale0()

        __attribute__((always_inline)) inline uint8_t loadAndScale0(int lane) { return loadAndScale<0>(*this, lane); }  ///< @copydoc loadAndScale0(int, uint8_t)
        __attribute__((always_inline)) inline uint8_t loadAndScale1(int lane) { return loadAndScale<1>(*this, lane); }  ///< @copydoc loadAndScale1(int, uint8_t)
        __attribute__((always_inline)) inline uint8_t loadAndScale2(int lane) { return loadAndScale<2>(*this, lane); }  ///< @copydoc loadAndScale2(int, uint8_t)
        __attribute__((always_inline)) inline uint8_t loadAndScale3(int lane) { return loadAndScale<3>(*this, lane); }  ///< @copydoc loadAndScale1(int, uint8_t)//自己添加的
        __attribute__((always_inline)) inline uint8_t loadAndScale4(int lane) { return loadAndScale<4>(*this, lane); }  ///< @copydoc loadAndScale2(int, uint8_t)//自己添加的
        __attribute__((always_inline)) inline uint8_t loadAndScale5(int lane) { return loadAndScale<5>(*this, lane); }  ///< @copydoc loadAndScale2(int, uint8_t)//自己添加的
        __attribute__((always_inline)) inline uint8_t loadAndScale6(int lane) { return loadAndScale<6>(*this, lane); }  ///< @copydoc loadAndScale2(int, uint8_t)
        __attribute__((always_inline)) inline uint8_t loadAndScale7(int lane) { return loadAndScale<7>(*this, lane); }  ///< @copydoc loadAndScale1(int, uint8_t)//自己添加的
        __attribute__((always_inline)) inline uint8_t loadAndScale8(int lane) { return loadAndScale<8>(*this, lane); }  ///< @copydoc loadAndScale2(int, uint8_t)//自己添加的
        __attribute__((always_inline)) inline uint8_t loadAndScale9(int lane) { return loadAndScale<9>(*this, lane); }  ///< @copydoc loadAndScale2(int, uint8_t)//自己添加的
        __attribute__((always_inline)) inline uint8_t advanceAndLoadAndScale0(int lane) { return advanceAndLoadAndScale<0>(*this, lane); }  ///< @copydoc advanceAndLoadAndScale0(int, uint8_t)
        __attribute__((always_inline)) inline uint8_t stepAdvanceAndLoadAndScale0(int lane) { stepDithering(); return advanceAndLoadAndScale<0>(*this, lane); }  ///< @copydoc stepAdvanceAndLoadAndScale0(int, uint8_t)

        __attribute__((always_inline)) inline uint8_t loadAndScale0() { return loadAndScale<0>(*this); }  ///< @copydoc loadAndScale0(int, uint8_t)
        __attribute__((always_inline)) inline uint8_t loadAndScale1() { return loadAndScale<1>(*this); }  ///< @copydoc loadAndScale1(int, uint8_t)
        __attribute__((always_inline)) inline uint8_t loadAndScale2() { return loadAndScale<2>(*this); }  ///< @copydoc loadAndScale2(int, uint8_t)
        __attribute__((always_inline)) inline uint8_t loadAndScale3() { return loadAndScale<3>(*this); }  ///< @copydoc loadAndScale1(int, uint8_t)//自己添加的
        __attribute__((always_inline)) inline uint8_t loadAndScale4() { return loadAndScale<4>(*this); }  ///< @copydoc loadAndScale2(int, uint8_t)//自己添加的
        __attribute__((always_inline)) inline uint8_t loadAndScale5() { return loadAndScale<5>(*this); }  ///< @copydoc loadAndScale2(int, uint8_t)//自己添加的
        __attribute__((always_inline)) inline uint8_t loadAndScale6() { return loadAndScale<6>(*this); }  ///< @copydoc loadAndScale2(int, uint8_t)
        __attribute__((always_inline)) inline uint8_t loadAndScale7() { return loadAndScale<7>(*this); }  ///< @copydoc loadAndScale1(int, uint8_t)//自己添加的
        __attribute__((always_inline)) inline uint8_t loadAndScale8() { return loadAndScale<8>(*this); }  ///< @copydoc loadAndScale2(int, uint8_t)//自己添加的
        __attribute__((always_inline)) inline uint8_t loadAndScale9() { return loadAndScale<9>(*this); }  ///< @copydoc loadAndScale2(int, uint8_t)//自己添加的
        __attribute__((always_inline)) inline uint8_t advanceAndLoadAndScale0() { return advanceAndLoadAndScale<0>(*this); }  ///< @copydoc advanceAndLoadAndScale0(int, uint8_t)
        __attribute__((always_inline)) inline uint8_t stepAdvanceAndLoadAndScale0() { stepDithering(); return advanceAndLoadAndScale<0>(*this); }  ///< @copydoc stepAdvanceAndLoadAndScale0(int, uint8_t)

        __attribute__((always_inline)) inline uint8_t getScale0() { return getscale<0>(*this); }  ///< non-template alias of getscale<0>()
        __attribute__((always_inline)) inline uint8_t getScale1() { return getscale<1>(*this); }  ///< non-template alias of getscale<1>()
        __attribute__((always_inline)) inline uint8_t getScale2() { return getscale<2>(*this); }  ///< non-template alias of getscale<2>()
        __attribute__((always_inline)) inline uint8_t getScale3() { return getscale<3>(*this); }  ///< non-template alias of getscale<1>()//自己添加的
        __attribute__((always_inline)) inline uint8_t getScale4() { return getscale<4>(*this); }  ///< non-template alias of getscale<2>()//自己添加的
        __attribute__((always_inline)) inline uint8_t getScale5() { return getscale<5>(*this); }  ///< non-template alias of getscale<2>()//自己添加的
        __attribute__((always_inline)) inline uint8_t getScale6() { return getscale<6>(*this); }  ///< non-template alias of getscale<2>()
        __attribute__((always_inline)) inline uint8_t getScale7() { return getscale<7>(*this); }  ///< non-template alias of getscale<1>()//自己添加的
        __attribute__((always_inline)) inline uint8_t getScale8() { return getscale<8>(*this); }  ///< non-template alias of getscale<2>()//自己添加的
        __attribute__((always_inline)) inline uint8_t getScale9() { return getscale<9>(*this); }  ///< non-template alias of getscale<2>()//自己添加的
};

5. 在 chipsets.h 文件添加一个模板

  • 模板添加就参照下面这个来
  • 值得注意的是它的参数
    • DATA_PIN //这个是引脚
    • C_NS(300) //表示 300 纳秒的时间常数,用于控制信号的时序。(0 码,高电平时间 和 1 码,低电平时间)
    • C_NS(900) // 0 码,低电平时间 和 1 码,高电平时间
    • C_NS(300) // Reset 码,低电平时间
    • RGB_ORDER //RGB通道选择
//这个是自带的
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
class SM16703Controller : public ClocklessController<DATA_PIN, C_NS(300), C_NS(600), C_NS(300), RGB_ORDER> {};
//下面这个是自己添加的
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
class SM16705Controller : public ClocklessController80Bit<DATA_PIN, C_NS(300), C_NS(900), C_NS(300), RGB_ORDER> {};

SM16705时序图:
在这里插入图片描述
SW2812时序图(作为参考):
在这里插入图片描述

6. 在 FastLED.h 文件内添加芯片模板

  • 有了这个才可以在 FastLED.addLeds() 这里面调用它,否则无法使用

/// @copydetails SM16703Controller //自己定义添加的
template<uint8_t DATA_PIN, EOrder RGB_ORDER> 
class SM16705 : public SM16705Controller<DATA_PIN, RGB_ORDER> {};

  • 调用
// 初始化FastLED,设置引脚和数据速率  
  FastLED.addLeds<SM16705, DATA_PIN, RGBWY>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);  
  // 设置亮度,范围为0(关闭)到255(最亮)  
  FastLED.setBrightness(50);

五、测试LED

下面给出个测试代码:下面的代码效果会按顺序点亮LED灯,并切换颜色。

#include "FastLED.h"  
// 定义LED的数量和连接的引脚  
#define NUM_LEDS 12  
#define DATA_PIN 12  
  
// 定义LED的类型。这里以常见的WS2812B为例  
CRGB leds[NUM_LEDS];  
void setup() {   
  // 初始化串口通讯  
  Serial.begin(115200);  
  // 初始化FastLED,设置引脚和数据速率  
  FastLED.addLeds<SM16705, DATA_PIN, RGBWY>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);  
  // 设置亮度,范围为0(关闭)到255(最亮)  
  FastLED.setBrightness(50);  
}  
void loop() {  
  // 遍历所有LED,并将它们逐个设置为红色  
  for(int i = 0; i < NUM_LEDS; i++) {  
    leds[i] = CRGB::YellowGreen;  
    // 发送数据到LED条,更新显示
    FastLED.show();  
    // 等待一小段时间后点亮下一个LED
    delay(500);  
  }  
  // 等待一小段时间后再次更新  
  delay(1000);  
  
  // 遍历所有LED,并将它们逐个设置为蓝色  
  for(int i = 0; i < NUM_LEDS; i++) {  
    leds[i] = CRGB::Green;  
    // 发送数据到LED条,更新显示
    FastLED.show();  
    // 等待一小段时间后点亮下一个LED
    delay(500);  
  }  
  // 等待一小段时间后再次更新  
  delay(1000);   
}

六、添加芯片小结问题

1. 为什么会要在添加 ClocklessControllerBase 添加派生类

  • 因为 FastLED库只支持 24bit 的颜色设置,一般 ws2812 芯片 只需要 3 个字节的数据来表示颜色 分别为 R \ G \ B 三种每一种占一个字节,一个字节就是 8bit 数据,3个字节就是 24bit 数据
  • SM16705PD 支持 5 种颜色(或5个通道),每种颜色需要 16 个bit表示(2个字节),因此总共有 80bit 的数据,因此才需要派生出一个类来专门处理 80bit 的数据
  • 下面是 WS2812与SM16705PD对比图:
    SM16705PD数据格式图:
    数据格式图
    在这里插入图片描述
    SM16705PD数据模式图:
    在这里插入图片描述
    WS2812数据时序图:
    在这里插入图片描述
    在这里插入图片描述

2. pixels.loadAndScale0() 的作用:

观察代码 :

uint8_t r = pixels.loadAndScale0();
uint8_t g = pixels.loadAndScale1();
uint8_t b = pixels.loadAndScale2();
  • 这里面每个代码的返回值就是一个 字节的颜色数据,因此这里会有3个字节的数据返回出来
  • 而我们添加 loadAndScale4() 和 loadAndScale5() 的作用就是让数据在返回两个通道的值,会分别给 W 和 Y ,就是白色和黄色,这样我们才能凑齐 5 个通道的值
  • 但是 因为 loadAndScale()本身就只返回一个字节的数据,而我们的 SM16705需要2和字节的数据,因此我们才需要下面这样做(这样就可以凑齐80bit的数据了):
// 将8位颜色数据扩展为16位
            *pData++ = r; // 高8位
            *pData++ = r; // 低8位
            *pData++ = g; // 高8位
            *pData++ = g; // 低8位
            *pData++ = b; // 高8位
            *pData++ = b; // 低8位
            *pData++ = w; // 高8位
            *pData++ = w; // 低8位
            *pData++ = y; // 高8位
            *pData++ = y; // 低8位

3. 模板解释:

//父类
template <int DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 5>
class ClocklessController80Bit : public ClocklessControllerBase<DATA_PIN, T1, T2, T3, RGB_ORDER, XTRA0, FLIP, WAIT_TIME>
//派生类
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
class SM16705Controller : public ClocklessController80Bit<DATA_PIN, C_NS(300), C_NS(900), C_NS(300), RGB_ORDER> {};

参数解释:
ClocklessController80Bit 类是一个模板类,继承自 ClocklessControllerBase 类。该类用于控制无时钟信号的 LED 灯带,通常用于 ESP32 平台。
模板参数:
DATA_PIN:数据引脚,用于控制 LED 灯带。
T1:第一个时间常数,单位为纳秒。(0 码,高电平时间;1 码,低电平时间)
T2:第二个时间常数,单位为纳秒。(0 码,低电平时间;1 码,高电平时间)
T3:第三个时间常数,单位为纳秒。(Reset 码,低电平时间)
RGB_ORDER:颜色顺序,默认为 RGB。
XTRA0:额外参数,默认为 0。
FLIP:布尔值,指示是否翻转信号,默认为 false。
WAIT_TIME:等待时间,单位为微秒,默认为 5。

4. 如果不想修改库,也可以使用以下代码:

#include "Arduino.h"
#include "esp32-hal.h"

// 根据不同的 ESP32 目标板定义内置 RGB LED 引脚
#define BUILTIN_RGBLED_PIN   12   // ESP32 没有内置 RGB LED

// 定义 LED 数量和总位数
#define NR_OF_LEDS   12  // LED 数量
#define NR_OF_ALL_BITS 80*NR_OF_LEDS  // 每个 LED 80 bits

// 定义 RMT 数据数组
rmt_data_t led_data[NR_OF_ALL_BITS + 2];  // 额外的 2 bits 用于待机指令

// 定义 RMT 发送对象指针
rmt_obj_t* rmt_send = NULL;

void setup() 
{
    Serial.begin(115200);  // 初始化串口通信,波特率为 115200
    
    // 初始化 RMT 发送对象
    if ((rmt_send = rmtInit(BUILTIN_RGBLED_PIN, RMT_TX_MODE, RMT_MEM_64)) == NULL)
    {
        Serial.println("init sender failed\n");  // 如果初始化失败,打印错误信息
    }

    // 设置 RMT 时钟周期
    float realTick = rmtSetTick(rmt_send, 100);  // 设置 RMT 时钟周期为 100ns
    Serial.printf("real tick set to: %fns\n", realTick);  // 打印实际设置的时钟周期
}

// 定义 RGB 颜色值
uint16_t color[] =   { 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF };  // 仅黄色通道有值,其他通道为 0
int led_index = 0;  // 当前点亮的 LED 索引

void loop() 
{
    // 初始化数据,仅点亮一个 LED
    int led, col, bit;
    int i = 0;
    for (led = 0; led < NR_OF_LEDS; led++) {
        for (col = 0; col < 5; col++) {
            for (bit = 0; bit < 16; bit++) {
                if ((color[col] & (1 << (15 - bit))) && (led == led_index)) {
                    // 设置 RMT 数据项表示逻辑 1
                    led_data[i].level0 = 1;  // 第一个阶段为高电平
                    led_data[i].duration0 = 9;  // 第一个阶段持续 900ns
                    led_data[i].level1 = 0;  // 第二个阶段为低电平
                    led_data[i].duration1 = 3;  // 第二个阶段持续 300ns
                } else {
                    // 设置 RMT 数据项表示逻辑 0
                    led_data[i].level0 = 1;  // 第一个阶段为高电平
                    led_data[i].duration0 = 3;  // 第一个阶段持续 300ns
                    led_data[i].level1 = 0;  // 第二个阶段为低电平
                    led_data[i].duration1 = 9;  // 第二个阶段持续 900ns
                }
                i++;  // 增加 RMT 数据数组的索引
            }
        }
    }

    // 添加待机指令 2'b01
    // led_data[i].level0 = 1;  // 第一个阶段为高电平
    // led_data[i].duration0 = 3;  // 第一个阶段持续 300ns
    // led_data[i].level1 = 0;  // 第二个阶段为低电平
    // led_data[i].duration1 = 9;  // 第二个阶段持续 900ns
    // i++;
    // led_data[i].level0 = 1;  // 第一个阶段为高电平
    // led_data[i].duration0 = 9;  // 第一个阶段持续 900ns
    // led_data[i].level1 = 0;  // 第二个阶段为低电平
    // led_data[i].duration1 = 3;  // 第二个阶段持续 300ns
    // i++;

    // 使 LED 在面板上移动
    if ((++led_index) >= NR_OF_LEDS) {
        led_index = 0;  // 如果超过 LED 数量,则重置为 0
    }

    // 发送数据
    rmtWrite(rmt_send, led_data, NR_OF_ALL_BITS + 2);  // 使用 RMT 发送 LED 数据

    // 进入待机模式后,进行 RESET
    delay(100);  // 延迟 100 毫秒
    rmtWrite(rmt_send, NULL, 0);  // 发送空数据以触发 RESET
    delay(200);  // 延迟 200 微秒以确保 RESET 完成
}

5. 修改定位顺序:

WS2812 定位:WS2812 -> WS2812Controller800Khz(父类) -> ClocklessController(父类)-> loadAndScale0()
LED通道定位顺序: RGB -> EOrder
增加通道上限: controller.h -> RGB_BYTE(RO,X)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值