WS2812 RGB LED
The WS2812E is a smart externally-controlled LED light source that integrates a control circuit and a light-emitting circuit. Its shape is the same as a 5050 LED bead, and each element is one pixel. The pixel internally contains a smart digital interface data latch, signal reshaping and amplification drive circuit, as well as a high-precision internal oscillator and a programmable constant-current control section, which effectively ensures highly consistent pixel light color.
Module Source
Purchase link: https://item.taobao.com/item.htm?spm=a1z10.3-c-s.w4002-24706531953.16.223a6a4bKqBE02&id=558408103026 Materials download link: https://pan.baidu.com/s/1OkCpw8ooDyuw947V0b89Rw Extraction code: AB12
Specifications
Operating voltage: 3.7-5.3V Operating current: 16 mA Control method: Single-wire bus Number of pins: 4 Pin (2.54mm pitch header)
View Materials
The WS2812 data protocol uses a single-wire return-to-zero code communication method, supports a serial cascade interface, and can complete data reception and decoding through a single signal line. Each LED is a pixel, and the three primary colors of each pixel can achieve 256-level brightness display, completing 16,777,216 colors of full-true color display.
After power-on reset, the DIN terminal receives data transmitted from the controller. The first 24 bits of data sent are extracted by the first pixel and sent to the data latch inside the pixel. The remaining data is reshaped and amplified by the internal reshaping circuit and then forwarded through the DO port to the next cascaded pixel. With each pixel the signal passes through, it is reduced by 24 bits. The pixel uses an automatic reshaping and forwarding technology, so that the number of cascaded pixels is not limited by signal transmission — it is only limited by signal transmission speed requirements.
Control Method
Because a single-wire bus is used, one line completes the 24-bit color data of a single LED, and what data is sent is determined by the length of the high and low level times. The 24-bit data structure is shown in the figure below.
Where G represents green of the three colors, R represents red, and B represents blue. For example, if you want to display only red, send 0X00FF00.
Control Timing
Sending 24-bit color data, it is determined whether the sent data is 0 or 1 by the length of the high and low level times.
To send one bit of data 0, the bus must be pulled high for the T0H time and then pulled low for the T0L time before the WS2812 will automatically recognize the data as 0.
To send one bit of data 1, the bus must be pulled high for the T1H time and then pulled low for the T1L time before the WS2812 will automatically recognize the data as 1.
Regarding high and low level times, 1us can be implemented through the official example, but how do we accurately calculate 220ns~420ns?
Here, we sample through a logic analyzer.
Implementation code:
/******************************************************************
* Function Name: Ws2812b_WriteByte
* Function Description: Write one byte of data to the WS2812
* Function Parameters: byte the byte data to write
* Function Return: None
* Author: LC
* Notes: 1-code timing = high 580ns~1us then low 220ns~420ns
* 0-code timing = high 220ns~380ns then low 580ns~1us
******************************************************************/
void Ws2812b_WriteByte(unsigned char byte)
{
int i = 0, j = 0;
for(i = 0; i < 8; i++ )
{
if( byte & (0x80 >> i) )// Current bit is 1
{
RGB_PIN_H();
delay_1us(1);//0.75us
RGB_PIN_L();
for(j = 0; j < 8; j++ );//0.25us
}
else// Current bit is 0
{
RGB_PIN_H();
for(j = 0; j < 8; j++ );//0.25us
RGB_PIN_L();
delay_1us(1);//0.833us
}
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Porting Process
Pin Selection
Port to Project
Our goal is to port the example to the ESP32-S3 dev board. Complete driver code has been provided for you. Follow the steps below to complete the porting.
For detailed instructions on creating folders and new .c and .h files, refer to section 1.4.2 in the [DHT11 Temperature and Humidity Sensor] chapter; we will not repeat it here.
Just note that here we change the file names bsp_dht11.c and bsp_dht11.h to bsp_ws2812.c and bsp_ws2812.h, and the folder name to WS2812.
Write Code
In the file bsp_ws2812.c, write the following code.
/*
* LCSC-Openkits (LCKFB) software and hardware materials and related expansion board software and hardware materials are all open source on the official website.
* Dev board official website: www.lckfb.com
* Technical support resides on the forum; any technical questions are welcome for exchange and learning at any time.
* LCKFB Forum: club.szlcsc.com
* Follow our Bilibili account: [LCSC-Openkits (LCKFB)] to keep up with our latest updates!
* We do not make money by selling boards; we take cultivating engineers as our mission.
* Change Logs:
* Date Author Notes
* 2024-01-15 LCKFB-lp first version
*/
#include "bsp_ws2812.h"
#include "stdio.h"
#include "math.h"
unsigned char LedsArray[WS2812_MAX * 3]; // Define the color data storage array
unsigned int ledsCount = WS2812_NUMBERS; // Define the default actual number of RGB LEDs
unsigned int nbLedsBytes = WS2812_NUMBERS*3; // Define the actual number of RGB LED color data
static void delay_ms(unsigned int ms)
{
vTaskDelay(ms / portTICK_PERIOD_MS);
}
static void delay_us(unsigned int us)
{
ets_delay_us(us);
}
static void delay_1ms(unsigned int ms)
{
vTaskDelay(ms / portTICK_PERIOD_MS);
}
static void delay_1us(unsigned int us)
{
ets_delay_us(us);
}
/******************************************************************
* Function Name: WS2812_GPIO_Init
* Function Description: Initialize the WS2812 pin
* Function Parameters: None
* Function Return: None
* Author: LC
* Notes: None
******************************************************************/
void WS2812_GPIO_Init(void)
{
gpio_config_t lll_config = {
.pin_bit_mask = (1ULL<<GPIO_DIN), // Configure pin
.mode =GPIO_MODE_OUTPUT, // Output mode
.pull_up_en = GPIO_PULLUP_DISABLE, // Disable pull-up
.pull_down_en = GPIO_PULLDOWN_DISABLE, // Disable pull-down
.intr_type = GPIO_INTR_DISABLE // Disable pin interrupt
};
gpio_config(&lll_config);
}
/******************************************************************
* Function Name: rgb_SetColor
* Function Description: Set the RGB LED color
* Function Parameters: LedId which LED to control color color data
* Function Return: None
* Author: LC
* Notes: Here I swap green and red so that it matches our everyday red-green-blue order
******************************************************************/
void rgb_SetColor(unsigned char LedId, unsigned long color)
{
if( LedId > ledsCount )
{
return; // to avoid overflow
}
LedsArray[LedId * 3] = (color>>8)&0xff;
LedsArray[LedId * 3 + 1] = (color>>16)&0xff;
LedsArray[LedId * 3 + 2] = (color>>0)&0xff;
}
/******************************************************************
* Function Name: rgb_SetRGB
* Function Description: Set the RGB LED color (primary color setting)
* Function Parameters: LedId which LED to control red red data green green data blue blue data
* Function Return: None
* Author: LC
* Notes: None
******************************************************************/
void rgb_SetRGB(unsigned char LedId, unsigned long red, unsigned long green, unsigned long blue)
{
unsigned long Color=red<<16|green<<8|blue;
rgb_SetColor(LedId,Color);
}
/******************************************************************
* Function Name: rgb_SendArray
* Function Description: Send RGB LED data
* Function Parameters: None
* Function Return: None
* Author: LC
* Notes: None
******************************************************************/
void rgb_SendArray(void)
{
unsigned int i;
// Send data
for(i=0; i<nbLedsBytes; i++)
Ws2812b_WriteByte(LedsArray[i]);
}
/******************************************************************
* Function Name: RGB_LED_Reset
* Function Description: Reset ws2812
* Function Parameters: None
* Function Return: None
* Author: LC
* Notes: Low level for more than 280us
******************************************************************/
void RGB_LED_Reset(void)
{
RGB_PIN_L();
delay_1us(281);
}
/******************************************************************
* Function Name: Ws2812b_WriteByte
* Function Description: Write one byte of data to the WS2812
* Function Parameters: byte the byte data to write
* Function Return: None
* Author: LC
* Notes: 1-code timing = high 580ns~1us then low 220ns~420ns
* 0-code timing = high 220ns~380ns then low 580ns~1us
******************************************************************/
void Ws2812b_WriteByte(unsigned char byte)
{
int i = 0, j = 0;
for(i = 0; i < 8; i++ )
{
if( byte & (0x80 >> i) )// Current bit is 1
{
RGB_PIN_H();
delay_1us(1);//0.75us
RGB_PIN_L();
for(j = 0; j < 8; j++ );//0.25us
}
else// Current bit is 0
{
RGB_PIN_H();
for(j = 0; j < 8; j++ );//0.25us
RGB_PIN_L();
delay_1us(1);//0.833us
}
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
In the file bsp_ws2812.h, write the following code.
/*
* LCSC-Openkits (LCKFB) software and hardware materials and related expansion board software and hardware materials are all open source on the official website.
* Dev board official website: www.lckfb.com
* Technical support resides on the forum; any technical questions are welcome for exchange and learning at any time.
* LCKFB Forum: club.szlcsc.com
* Follow our Bilibili account: [LCSC-Openkits (LCKFB)] to keep up with our latest updates!
* We do not make money by selling boards; we take cultivating engineers as our mission.
* Change Logs:
* Date Author Notes
* 2024-01-15 LCKFB-lp first version
*/
#ifndef _BSP_WS2812_H_
#define _BSP_WS2812_H_
#include <stdio.h>
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/uart.h"
#include "driver/gpio.h"
#include "driver/i2c.h"
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "freertos/queue.h"
#include <inttypes.h>
#include "sdkconfig.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "rom/ets_sys.h"
#include "esp_system.h"
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "driver/spi_common.h"
#include "hal/gpio_types.h"
#include "string.h"
#define GPIO_DIN 1
// User parameter area
//#define WS2812_FREQUENCY
#define RGB_PIN_L() gpio_set_level(GPIO_DIN, 0) // Control RGB LED pin (must be configured as push-pull output)
#define RGB_PIN_H() gpio_set_level(GPIO_DIN, 1) // Control RGB LED pin (must be configured as push-pull output)
#define WS2812_MAX 4 // Maximum number of RGB LEDs
#define WS2812_NUMBERS 4 // Number of RGB LEDs
#define RED 0xff0000 // Red
#define GREEN 0x00ff00 // Green
#define BLUE 0x0000ff // Blue
#define BLACK 0x000000 // Off
#define WHITE 0xffffff // White
//8.3 -8 0.000000083
//4.16 -9 0.00000000416
void Ws2812b_WriteByte(unsigned char byte);// Send one byte of data (@12.000MHz, theoretically 83ns per machine cycle, measured about 76ns)
void setLedCount(unsigned char count);// Set the number of RGB LEDs, range 0-25.
unsigned char getLedCount();// Query function for the number of RGB LEDs
void rgb_SetColor(unsigned char LedId, unsigned long color);// Set RGB LED color
void rgb_SetRGB(unsigned char LedId, unsigned long red, unsigned long green, unsigned long blue);// Set RGB LED color
void rgb_SendArray();// Send RGB LED data
void WS2812_GPIO_Init(void);
void RGB_LED_Write1(void);
void RGB_LED_Reset(void);
#endif2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
Porting Verification
In the main function of your project, write the following code.
/*
* LCSC-Openkits (LCKFB) software and hardware materials and related expansion board software and hardware materials are all open source on the official website.
* Dev board official website: www.lckfb.com
* Technical support resides on the forum; any technical questions are welcome for exchange and learning at any time.
* LCKFB Forum: club.szlcsc.com
* Follow our Bilibili account: [LCSC-Openkits (LCKFB)] to keep up with our latest updates!
* We do not make money by selling boards; we take cultivating engineers as our mission.
* Change Logs:
* Date Author Notes
* 2024-01-15 LCKFB-lp first version
*/
#include <stdio.h>
#include "bsp_ws2812.h"
#include "string.h"
#include "esp_private/esp_task_wdt.h"
#include "esp_private/esp_task_wdt_impl.h"
unsigned int buff[]={RED,GREEN,BLUE,WHITE};
int app_main(void)
{
int i = 0;
esp_task_wdt_deinit();
WS2812_GPIO_Init();
printf("WS2812 Start......\r\n");
while(1)
{
for( i = 0; i < 4; i++ )
{
rgb_SetColor(i,buff[i]);
rgb_SendArray();
vTaskDelay(500 / portTICK_PERIOD_MS);
}
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Power-on effect:
Driver code:
File Download
📌 Materials Download Center (Click to Jump)
📌 In the Materials Download Center -> Module Porting Materials Download, inside the compressed package of this chapter.