ESP32学习】驱动ws2812

说明

本片文章不做详细介绍,博主本身学习程度不高,没有系统学过FreeRtos操作系统,因此本文逻辑可能会有点混乱,而且不会进行原理的分析。本文主要是站在一个小白的角度,一步步从完全不了解FreeRtos到初步能在Rtos里面运行和修改例层。

先介绍WS2812b

ws2812b是一种能显示RGB三原色组合成的颜色显示灯,封装为5050,有四个引脚,分别是VCC、VSS、DIN、DOUT。引脚介绍如图(1)
图(1)WS2812引脚描述

电源供电范围规格书上描述为3.5-5.3V,但是实测3.3V也能驱动,逻辑电平为-0.5V-VDD-0.5V;这里DIN是通信接口的输入,RGB的数据就是从这里输入,而WS2812b具有级联功能,主要是通过DOUT实现,DIN输入的数据会被第一级WS2812截取24位,后面的数据会通过DOUT传输给下一个WS2812B,从而实现级联。如图(2)
在这里插入图片描述
上面是WS2812b的硬件接口,相对比较简单,只有一个数据口,逻辑也相对简单易懂,但是在时序方面则是相对比较严格。WS2812传输因为只有一跟数据线,所以只能传输0或1,因此在时序控制方面需要区分开1和0的时序。根据规格书,时序要求为图(3)
在这里插入图片描述
在这里插入图片描述
因此软件上可以通过IO口,输出高低电平来模拟时序。按照标准控制时序,传输一个位时间为1.25us,一个WS2812需要24位,即30us,假设100个WS2812组成矩阵,则一帧的时间为3ms,即可以实现333HZ的刷新率,对于30HZ刷新率最大可以控制1000个WS2812,即33*33.

RTOS理解学习

博主是第一次学习RTOS,并不懂RTOS的内部各种原理,所以一开始学习十分痛苦,RTOS函数与程序函数傻傻分不清,一些接口传递参数也分辨不清(特别是对于带有结构体、指针的接口,基本上看到就懵了,此处主要是C基础不扎实,因为都是爱好自学的,学得并不系统)
先说结论,通过看了一轮百度、博文的介绍后,一堆专业名词,到头来还是没看懂RTOS,最后看到一篇博文介绍API接口,想着先看看接口函数,再对RTOS理解。结果看了几遍RTOS的API接口函数之后,再对比源码,发现好像我并不需要了解RTOS的底层原理,我最主要能弄懂各个API接口以及各个接口的传递参数,其实就可以修改源码了。
**所以,如果不是为了学习底层,仅仅是为了使用以及修改代码的话,可以从API接口开始学习,会有奇效!!!**而在学习之处也不需要把所有API接口都搞懂,关于任务创建删除、消息列队、任务调度这几个先搞懂,就可以满足大部分需求了。

ESP32驱动WS2812代码

先贴源码

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "sdkconfig.h"
#include "nvs_flash.h"
#include "esp_task_wdt.h"
#include "time.h"
#include "unistd.h"

#define BLINK_GPIO 2			//定义一个IO,用于WS2812通信
#define BLINK1_GPIO 0			//定义一个IO,用于呼吸灯
#define ws2812b_din_pin_set() gpio_set_level(BLINK_GPIO, 1)	//WS2812宏定义,输出高电平
#define ws2812b_din_pin_rst() gpio_set_level(BLINK_GPIO, 0); 	//WS2812宏定义,输出低电平

TaskHandle_t start_task_handler;				//创建test_task任务句柄
void delay_ns(int data)                //假设是100ns,实际上时间不确定
{
    int i;
    for(i=0;i<(data*20);i++);  
}

void ws2812b_rst(void)
{
    ws2812b_din_pin_set();
    //esp_rom_delay_us(300);
    delay_ns(500);           //50us
    ws2812b_din_pin_rst();
}


void ws2812b_writebyte_byt(unsigned char dat)
{
    unsigned char i;
    for(i=0;i<8;i++)
    {
        if(dat & 0x80)
        {
            ws2812b_din_pin_set();
            //esp_rom_delay_us(780);
            usleep(1);
            ws2812b_din_pin_rst();   
            delay_ns(5);   
        }
        else
        {
            ws2812b_din_pin_set();
            delay_ns(3);					//延时***ns
            ws2812b_din_pin_rst(); 
            usleep(1);						//延时1us
        }
        dat <<= 1;
    }
}

void ws2812b_write_rgb_byte(unsigned char r_data, unsigned char g_data, unsigned char b_data)
{
    ws2812b_writebyte_byt(r_data);
    ws2812b_writebyte_byt(g_data);
    ws2812b_writebyte_byt(b_data);
}

void LED_Task(void *pvParameters)
{
    char i=0;
    while(1)
    {
        i=~i;
        gpio_set_level(BLINK_GPIO, i);
        delay();
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

void ws2812_task(void *pvParameters)
{
    char i;
    unsigned char kj;
    unsigned char kk;
    unsigned char kl;
    while(1)
    {
         for(i=0;i<255;i++)
        {
            kj=random();
            kk=random();
            kl=random();
            ws2812b_write_rgb_byte(kj,kk,kl);
            ws2812b_rst();
            printf("j=%d\r\n",kj);
            vTaskDelay(1000 / portTICK_PERIOD_MS);
        }
    }
}

void delay_s(void *pvParameters)
{
    int i;
    while(1)
    {
        for(i=0;i<5000000;i++);
    }
}

void start_task(void* pvParameters)
{
    xTaskCreate(&ws2812_task,"ws2812_task",8192,NULL,4,NULL);
    vTaskDelete(start_task_handler);
}


void app_main()
{
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK( ret );

    gpio_pad_select_gpio(BLINK_GPIO);
    gpio_pad_select_gpio(BLINK1_GPIO);
    gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT);
    gpio_set_direction(BLINK1_GPIO, GPIO_MODE_OUTPUT);
    
    xTaskCreate(&start_task,"start_task",2048,NULL,5,start_task_handler);
    esp_task_wdt_deinit();
}

上诉源码可以实现外接一个WS2812,通过Random函数随机产生RGB的组合颜色,其中控制WS2812的代码为

void ws2812b_writebyte_byt(unsigned char dat)
{
    unsigned char i;
    for(i=0;i<8;i++)
    {
        if(dat & 0x80)
        {
            ws2812b_din_pin_set();
            //esp_rom_delay_us(780);
            usleep(1);
            ws2812b_din_pin_rst();   
            delay_ns(5);   
        }
        else
        {
            ws2812b_din_pin_set();
            delay_ns(3);					//延时***ns
            ws2812b_din_pin_rst(); 
            usleep(1);						//延时1us
        }
        dat <<= 1;
    }
}

实话说,这个delay_ns是博主通过实验估算的延时,单位为100ns,实际上似乎不是,因为没有仪器,所以测试不出实际的延时,然后配合usleep函数,延时1us,从而可以满足WS2812的时序要求,这份代码实际上是试出来的,因此1不具备指导性,只能作为参考。

  • 9
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值