ESP32学习笔记:WS2812B驱动

WS2812B是一款贴片RGB灯。由于采用了单总线通讯,所以需要特别关注下它的通讯时序。

调试细节:

本来以为会是一个比较简单的调试,结果还是花了很长时间才调试完成。

首先是关于ESP32的纳秒级延时确定,当时按照空指令始终调试不出来。之前在STM32平台上的nop()函数也不知道怎么用。

后来发掘出了一个比较简单的办法。就是一个个试,然后在main函数中按照1S的频率打印调试信息来倒推ns级别的延时是否可靠。

注意:在ESP32不能使用空语句加;来进行空指令延时,需要使用操作语句。

复制代码
unsigned long ns_delay_value = 0;

void delay_100_ns(int data)
{
    unsigned char i;

    ns_delay_value = 0;

    for(i = 0; i < data; i++)
    {
        ns_delay_value++;
    }
}

void delay_1_us()
{
    delay_100_ns(10);
}

void delay_1_ms()
{
    long i;
    for(i = 0; i < 1000; i++)
    {
        delay_1_us();
    }
}

void delay_1_s()
{
    long i;
    for(i = 0; i < 1000; i++)
    {
        delay_1_ms();
    }
}

然后在main函数中按照1S的频率打印调试信息:

复制代码
while(1){

        printf("ws2812B demo system run ...\n");
//        vTaskDelay(1000 / portTICK_PERIOD_MS);
        delay_1_s();
    }

基本确定了ns级别延时后,就可以按照时序来写ws2812的驱动函数啦。

复制代码
*WS2812B Drive*/
#define WS2812B_GPIO               8
#define WS2812B_GPIO_ACTIVE_LEVEL  1
#define ws2812b_pin_set()          gpio_set_level(WS2812B_GPIO, 1)
#define ws2812b_pin_rst()          gpio_set_level(WS2812B_GPIO, 0)

void ws2812b_writebyte(unsigned char data)
{
    unsigned char i;

    for(i = 0; i < 8; i++)
    {
        if(data & 0X80)
        {
            ws2812b_pin_set();
            delay_100_ns(3);
            ws2812b_pin_rst();
            delay_100_ns(3);
        }else
        {
            ws2812b_pin_set();
            delay_100_ns(1);
            ws2812b_pin_rst();
            delay_100_ns(3);
        }
        data <<= 1;
    }
}

void ws2812b_write_rgb(unsigned char red_value, unsigned char green_value, unsigned char blue_value)
{
    ws2812b_writebyte(red_value);
    ws2812b_writebyte(green_value);
    ws2812b_writebyte(blue_value);
}

后来发现依然无法驱动,到了晚上才发现自己犯了一个低级错误。ESP32的IO口没有进行初始化配置!

复制代码
void ws2812b_gpio_init(void)
{
    gpio_config_t gpio_conf;

    gpio_conf.intr_type = GPIO_INTR_DISABLE;
    gpio_conf.mode = GPIO_MODE_OUTPUT;

    gpio_conf.pin_bit_mask = (1ULL << WS2812B_GPIO);

    if (WS2812B_GPIO_ACTIVE_LEVEL) {
        gpio_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
        gpio_conf.pull_up_en = GPIO_PULLUP_DISABLE;
    } else {
        gpio_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
        gpio_conf.pull_up_en = GPIO_PULLUP_ENABLE;
    }

    gpio_config(&gpio_conf);
}

配置完IO口就可以进行WS2812B驱动啦。不过还是出现了一些小bug,比如初始化第一次点灯,绿色灯珠总是会不受控制地自动点亮!后来发现在IO初始化函数前预先执行一次点亮指令就可以消除这个bug!Nice!

复制代码
void app_main(void)
{

    ws2812b_write_rgb(0, 255, 0);
    ws2812b_gpio_init();

    delay_1_s();
    ws2812b_write_rgb(20, 20, 20);

    while(1){

        printf("ws2812B demo system run ...\n");
//        vTaskDelay(1000 / portTICK_PERIOD_MS);
        delay_1_s();
    }
}

至此,ESP32对于WS2812B的驱动函数就调试完成啦。

对于这个说起来简单但是异常曲折的小demo项目积累了如下经验:

1.ESP32的IO也是需要进行初始化配置的。

2.MCU的单指令确实能够进行粗略的ns级延时,为后续调试一些芯片时序提供了新的方法。

3.ESP32的GPIO8需要使用一个10K电阻上拉3.3V,否则无法进行程序下载。

2023-05-04 细节补充

1.在后续demo项目完善该驱动时,发现会出现初始化后,在别处点灯时,依然会出现亮出绿灯现象。

后来增加了灯珠的复位函数:

复制代码
void ws2812b_write_reset(void)
{
    unsigned int i = 0;

    ws2812b_pin_rst();

    for(i = 0; i < 300; i++)
    {
        delay_1_us();
    }
   
}

然后初始化变更为:

复制代码
ws2812b_write_rgb(0, 255, 0);
ws2812b_gpio_init();
ws2812b_write_reset();
ws2812b_write_rgb(20, 20, 20);

如果需要在别的函数位置电灯,择执行以下函数即可,亲测有效。

复制代码
ws2812b_write_rgb(0, 0, 0);
ws2812b_write_reset();
ws2812b_write_rgb(0, 0, 20);
相关推荐
学长毕设5 小时前
基于SpringBoot的青少年编程学习平台系统-附源码
spring boot·学习·青少年编程
小小de风呀9 小时前
de风——【从零开始学习Linux】(九):进程基础 —— 从冯诺依曼体系到 fork 创建进程
linux·学习
李某学编程9 小时前
基于ARM的微机原理学习笔记(一)
arm开发·笔记·学习
Song_RsHt10 小时前
Redis 与微服务,什么场景下无可替代
java·redis·后端·学习·微服务
sbjdhjd10 小时前
AI产业周度动态:从“更强模型”走向“可执行、可治理、可计价”的系统竞争 (2026年10月19日—10月25日)
人工智能·笔记·ai·开源·gemini·信息差·claude code
ss27311 小时前
AI时代首先数据库-PostgreSQL实战笔记 27 PostgreSQL数据写入与读取流程解析
数据库·笔记·postgresql
深圳老胡12 小时前
压力检测空吸功能硬件方案全解析:主流压力传感器品牌与实现路径
笔记·单片机·代码规范
程序猿追12 小时前
返回 null 不一定入队成功:鸿蒙 KMP上的并发优先队列观察笔记
笔记·华为·harmonyos·kmp
~kiss~13 小时前
PRO-LONG: Programmatic Memory Enables Long-Horizon Reasoning 程序式记忆赋能长程推理
学习
程序猿编码13 小时前
不依赖 vLLM/llama.cpp:一套面向学习的 DeepSeek-R1 CUDA 推理实现
c++·学习·语言模型·llama·vllm·大模型推理