首页 > 其他分享 >零知开源——使用 GPIO 模拟时序驱动 WS2812B LED 灯带

零知开源——使用 GPIO 模拟时序驱动 WS2812B LED 灯带

时间:2024-12-07 14:31:59浏览次数:5  
标签:LED 零知 int 灯带 void uint8 灯珠 ++ WS2812B

利用零知增强版的GPIO 模拟时序

       在本教程中,我们将探讨如何使用 零知增强版的 GPIO 接口来模拟 WS2812B LED 灯带的信号传输时序,从而实现对单色或多彩 LED 灯带的控制。这种技术允许我们避开专用驱动库,直接与硬件进行交互,理解并掌握 WS2812B 的通信机制。

一、工具原料

电脑、Windows系统

零知增强版开发板

Micro-usb线

WS2812RGB灯

       WS2812B 是一款内含控制器芯片的全彩 LED 灯珠,每个灯珠可以独立显示红、绿、蓝三色。它通过单一数据线接收命令,实现高精度颜色控制。

二、硬件连接

零知增强版

WS2812B

5V

VCC

GND

GND

51

Din

1、硬件连接示意图

2、实际效果

三、传输时序和颜色控制

1、信号传输时序

WS2812B 的数据传输遵循特定的时间序列:

  • 高电平持续时间决定比特值:T1H 和 T0H 分别代表比特 1 和比特 0 的高电平持续时间。
  • 低电平持续时间:T1L 和 T0L。

注:T1H 为 800ns,T1L 为 450ns 表示 1 比特。

  T0H 为 400ns,T0L 为 850ns 表示 0 比特。

2、颜色控制

控制全局亮度和遵循WS2812B发送的时序:

  • 通过brightness参数调节RGB灯的全局亮度
  • WS2812B协议发送时序为G -> R -> B

四、代码驱动

1、相关定义和初始化

// WS2812B相关定义
#define WS2812B_PIN 51      // WS2812B数据引脚
#define NUM_LEDS 8          // 灯珠数量
#define MAX_BRIGHTNESS 0.5  // 全局亮度调节(范围:0.0 - 1.0)

// WS2812B控制协议时间(根据各自的时序进行修改该定义)
#define T1H 800
#define T1L 450
#define T0H 400
#define T0L 850

// 初始化WS2812B引脚
void setupWS2812B() {
    pinMode(WS2812B_PIN, OUTPUT);
    digitalWrite(WS2812B_PIN, LOW);
}

// 更精确的纳秒延时函数(这里只是示例,实际可能需要更复杂的实现)
// 假设使用了支持纳秒级延时的定时器库
// 这里暂时使用简单的微秒级延时近似
void delayNanoseconds(unsigned long ns) {
    delayMicroseconds(ns / 1000);
}

2、控制颜色和发送相关数据

// 发送一个比特
void WS2812B_SendBit(bool bitVal) {
    if (bitVal) {
        // 发送逻辑1
        digitalWrite(WS2812B_PIN, HIGH);
        delayNanoseconds(T1H);
        digitalWrite(WS2812B_PIN, LOW);
        delayNanoseconds(T1L);
    } else {
        // 发送逻辑0
        digitalWrite(WS2812B_PIN, HIGH);
        delayNanoseconds(T0H);
        digitalWrite(WS2812B_PIN, LOW);
        delayNanoseconds(T0L);
    }
}

// 发送一个字节
void WS2812B_SendByte(uint8_t byte) {
    for (int i = 7; i >= 0; i--) {
        WS2812B_SendBit(byte & (1 << i));
    }
}

// 发送RGB颜色数据(带亮度调节)
void WS2812B_SendColor(uint8_t red, uint8_t green, uint8_t blue, float brightness) {
    // 应用全局亮度调节
    red = (uint8_t)(red * brightness * MAX_BRIGHTNESS);
    green = (uint8_t)(green * brightness * MAX_BRIGHTNESS);
    blue = (uint8_t)(blue * brightness * MAX_BRIGHTNESS);

    // WS2812B协议发送顺序:G -> R -> B
    WS2812B_SendByte(green);
    WS2812B_SendByte(red);
    WS2812B_SendByte(blue);
}

3、实现流水灯、呼吸灯等功能

// 效果:彩虹追逐
void rainbowChaseEffect(uint8_t wait) {
    for (int offset = 0; offset < 255; offset++) {
        for (int i = 0; i < NUM_LEDS; i++) {
            int hue = (i * 255 / NUM_LEDS + offset) % 255;
            uint8_t r = 0, g = 0, b = 0;
            if (hue < 85) {
                r = 255 - hue * 3;
                g = hue * 3;
                b = 0;
            } else if (hue < 170) {
                hue -= 85;
                r = 0;
                g = 255 - hue * 3;
                b = hue * 3;
            } else {
                hue -= 170;
                r = hue * 3;
                g = 0;
                b = 255 - hue * 3;
            }
            WS2812B_SendColor(r, g, b, MAX_BRIGHTNESS);
        }
        delay(wait);
    }
}

// 呼吸灯效果
void breathAndFlow(uint8_t red, uint8_t green, uint8_t blue, uint8_t steps, uint16_t period, uint8_t wait, uint8_t iterations) {
    int ledStep[NUM_LEDS]; // 为每个 LED 创建一个步骤计数器
    for (int i = 0; i < NUM_LEDS; i++) {
        ledStep[i] = 0; // 初始化每个LED的步进
    }

    uint8_t cycleCounter = 0; // 添加循环计数器

    while (cycleCounter < iterations) { // 有限循环,迭代指定次数
        for (int i = 0; i < NUM_LEDS; i++) {
            // 计算当前 LED 的亮度比例
            float brightness = (sin(ledStep[i] * (M_PI / (steps))) + 1) / 2;
            WS2812B_SendColor(red, green, blue, brightness); // 使用计算出的亮度

            // 更新 LED 的步骤计数器,模拟呼吸效果
            ledStep[i] = (ledStep[i] + 1) % (steps * 2); // 确保计数器在达到两倍步骤后重置

            // 计算每个步骤的时间间隔
            delayMicroseconds(period / steps);
        }
       
        // 在一轮呼吸之后关闭所有灯
        clearAllLeds();

        // 增加循环计数器
        cycleCounter++;

        // 根据需要添加延迟,虽然这不是必须的
        delay(wait);
    }
}

// 增加一个状态变量来记录是否有颜色覆盖
bool isCovered = false;

// 流水灯
void ShampEffect(uint8_t red, uint8_t green, uint8_t blue, uint8_t trailDecay, uint8_t wait) {
    // 特殊处理第一个灯
    WS2812B_SendColor(red, green, blue, MAX_BRIGHTNESS);
    // 从第二个灯开始的索引为1
    for (int i = 0; i < NUM_LEDS; i++) {
        for (int j = 0; j <= NUM_LEDS; j++) {
            if (i - j == 0) {
                if (!isCovered) {
                    // 如果没有被覆盖,设置为绿色
                    WS2812B_SendColor(0, 0, 0, MAX_BRIGHTNESS);
                } else {
                    WS2812B_SendColor(red, green, blue, MAX_BRIGHTNESS);
                }
            } else {
                WS2812B_SendColor(0, 0, 0, MAX_BRIGHTNESS * trailDecay / 255.0);
            }
        }
        if (i == NUM_LEDS - 1) {
            // 当到达最后一个灯时,标记为已覆盖
            isCovered = true;
        }
        delay(wait);
    }
}

4、控制灯的状态

// 设置特定位置灯珠颜色
void setLedColor(uint8_t pos, uint8_t red, uint8_t green, uint8_t blue, float brightness) {
    if (pos < NUM_LEDS) {
        // 只发送前面灯珠的关闭信号,直到要设置颜色的灯珠位置
        for (int i = 0; i < pos; i++) {
            WS2812B_SendColor(0, 0, 0, 0);
        }
        // 设置目标灯珠颜色
        WS2812B_SendColor(red, green, blue, brightness);
        // 发送后面灯珠的关闭信号,从目标灯珠的下一个位置开始
        for (int i = pos + 1; i < NUM_LEDS; i++) {
            WS2812B_SendColor(0, 0, 0, 0);
        }
    }
}

// 设置所有灯珠颜色
void setAllLeds(uint8_t red, uint8_t green, uint8_t blue, float brightness) {
    clearAllLeds();// 先清除所有灯珠,确保没有杂色
    for (int i = 0; i < NUM_LEDS; i++) {
        WS2812B_SendColor(red, green, blue, brightness);
    }
}

// 清除所有灯珠
void clearAllLeds() {
    for (int i = 0; i < NUM_LEDS * 3; i++) {
        WS2812B_SendByte(0);
    }
}

5、主循环

// 初始化
void setup() {
    setupWS2812B();
    clearAllLeds();  // 确保灯带初始状态关闭
}

// 主循环
void loop() {
    uint8_t Count = 0;
    //clearAllLeds();
    // 设置第六个灯珠为蓝色
    //setLedColor(5, 0, 0, 255, MAX_BRIGHTNESS);
    //delay(500);
    while(Count < 10)
    {
      ShampEffect(0, 0, random(255), 256, 200);
      Count ++;
    }
   
    //rainbowChaseEffect(1000);
    breathAndFlow(0,255,0,5,50,100,100);
}

五、成果展示

将上诉代码验证后上传到零知板,可以看到以下流水灯、呼吸灯等测试结果。

<iframe allowfullscreen="true" data-mediaembed="csdn" frameborder="0" id="9ShjWh8B-1733301167309" src="https://live.csdn.net/v/embed/437153"></iframe>

使用 GPIO 模拟时序驱动 WS2812B LED 灯带

标签:LED,零知,int,灯带,void,uint8,灯珠,++,WS2812B
From: https://blog.csdn.net/lingzhilab/article/details/144241703

相关文章

  • 【51编程经验笔记】第三节:累计主循环次数使LED灯闪烁
    第三节:累计主循环次数使LED灯闪烁。开场白:上一节鸿哥提到delay()延时函数消耗的时间太长了,其它任务根本没有机会执行,我们该怎么改善?本节教大家利用累计主循环次数的方法来解决这个问题。这一节要教会大家两个知识点:第一点:利用累计主循环次数的方法实现时间延时第二点:switch核心语......
  • 【51编程经验笔记】第二节:鸿哥的三区一线理论 & delay()延时实现LED灯的闪烁
    第二节:delay()延时实现LED灯的闪烁。开场白:  上一节鸿哥列出了初学者七大误区,到底什么才是初学者关注的核心?那就是裸机奔跑的程序结构。一个好的程序结构,本身就是一个微型的多任务操作系统。鸿哥教给大家的就是如何编写这个简单的操作系统。在main函数循环中用switch语句实现......
  • 新手必看!小小白也能用Rust点亮LED,入门嵌入式开发(上)
    讲动人的故事,写懂人的代码"你作为编程新手,为什么要学Rust?"我在微信里问小小白。我是一名有着30多年IT从业经验的老程序员,正在创作一本Rust编程入门书,致力于降低Rust那传说中陡峭的学习曲线。小小白是我最近在社交网络上认识的朋友,他对学习Rust充满热情。作为一名......
  • 基于51单片机和16X16LED点阵屏(MAX7219驱动)的自制独立按键控制的小游戏《贪吃蛇》
    目录系列文章目录前言一、效果展示二、原理分析三、各模块代码1、定时器02、自制独立按键(8位)3、16X16LED点阵屏(MAX7219驱动)四、主函数总结系列文章目录前言《贪吃蛇》,一款经典的、怀旧的小游戏,单片机入门必写程序。基于51单片机和8X8LED点阵屏(板载74HC595驱动)的......
  • VAS1260Q奇力LED驱动芯片DCDC降压恒流可替代Diodes8860
    VAS1260Q是一款专为车规级LED照明设计的连续模式电感降压驱动器,能够高效地驱动单个或多个串联LED。它集成了高端输出电流检测电路,并通过外部电阻设置标称平均输出电流,具有高可靠性和宽广的应用场景。核心技术参数    1.    输入电压范围:5V至60V,适应多种电源......
  • STM32:(入门)实现LED2灯循环闪烁
    思路:认识开发板的引脚——进行参数配置——运行代码——烧入开发板一、认识开发板的引脚(认识开发板)(STM32有2个LED灯的引脚分别是LED1-PA3,LED2-PB8【反面】) 依据题目,LED2灯---PB8二、进行参数配置(打开STM32CubeMx软件(新建项目)----选择版本【例题使用STM32F151C8】-......
  • Acknowledgements of Socket.IO
     https://socket.io/docs/v4/emitting-events/#Acknowledgements AcknowledgementsEventsaregreat,butinsomecasesyoumaywantamoreclassicrequest-responseAPI.InSocket.IO,thisfeatureisnamedacknowledgements.Youcanaddacallbackasthelas......
  • 点亮一个LED指示灯
    初心从事嵌入式开发已经是第七个年头了,想想还从来没有网上发布过一点东西。可能也是由于工作环境没有方便的互联网的原因,更大的原因是我这个人比较懒;但是和公司新人的技术分享,我可从来没有吝啬过,公司内部的共享资料库我的提交量也是第一。找个平台记录一下,至少证明我也在这......
  • socket() failed (24: Too many open files)
     这个错误因为超出了ulimitnofile当前bash的这样修改:[root@A06~]#ulimit-n200[root@A06~]#ulimit-n2000000[root@A06~]#ulimit-n2000000 systemd启动的程序这样修改[root@A06~]#cat/usr/lib/systemd/system/nginx.service|grep-C1-inofile[Ser......
  • 26 基于STM32的智能门禁系统(指纹、蓝牙、刷卡、OLED、电机)
    目录一、主要功能二、硬件资源三、程序编程四、实现现象一、主要功能基于STM32单片机,六个按键,分别代表指纹、蓝牙、刷卡的正确进门与错误进门;比如第一个按键按下,表示指纹正确,OLED显示指纹正确,开门,第二个按键按下的话,则指纹错误,OLED显示指纹错误,请重试,第二个按键连......