19. Chapter LVGL WS2812

In this chapter, we learn to control the onboard WS2812 RGB LED with the touch screen.

19.1. Project 19.1 LVGL WS2812

In the code, we use four sliders to control the LED, three of which control the LED’s red, green and blue colors, and one controls the brightness.

19.1.1. Component List

ESP32-S3 WROOM x1

Chapter02_00

USB cable x1

Chapter02_01

2.8-inch Screen

Chapter07_00

ESP32-S3 WROOM Shield x1

Chapter01_01

19.1.2. Circuit

Connect Freenove ESP32-S3 to the computer using the USB cable.

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

../../../_images/Chapter10_00.png

19.1.3. Sketch

../../../_images/Chapter19_00.png

Here is an illustration of the example:

../../../_images/Chapter19_01.png

By sliding the slider of different colors, the ESP32S3’s onboard LED will change color accordingly, and the values of color data are shown at the top of the screen.

The following is the program code:

19.1.3.1. Sketch_19_Lvgl_WS2812.ino

 1#include <lvgl.h>
 2#include "Arduino.h"
 3#include "display.h"
 4#include "ws2812_ui.h"
 5Display screen;
 6void setup() {
 7  Serial.begin(115200);
 8
 9  /*** Init screen ***/
10  screen.init();
11
12  /***  Print lvgl version ***/
13  String LVGL_Arduino = "Hello Arduino! ";
14  LVGL_Arduino += String('V') + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();
15  Serial.println(LVGL_Arduino);
16  Serial.println("I am LVGL_Arduino");
17  Serial.println("Setup done");
18
19  /*** The custom code ***/
20  setup_scr_ws2812(&guider_ws2812_ui);
21  lv_scr_load(guider_ws2812_ui.ws2812);
22}
23
24void loop() {
25  screen.routine();
26  delay(5);
27}

19.1.3.2. ws2812_ui.h

The declaration file about the the LED’s interface and driver is as below:

 1#ifndef __WS2812_UI_H
 2#define __WS2812_UI_H
 3
 4#include "lvgl.h"
 5#include "Arduino.h"
 6
 7#define LEDS_COUNT 1
 8#define LEDS_PIN 48
 9#define CHANNEL 0
10
11typedef struct lvgl_ws2812
12{
13	lv_obj_t *ws2812;
14  lv_obj_t *ws2812_home;
15
16  lv_obj_t *ws2812_slider_red;
17  lv_obj_t *ws2812_slider_green;
18  lv_obj_t *ws2812_slider_blue;
19  lv_obj_t *ws2812_slider_brightness;
20
21  lv_obj_t *ws2812_lable_red;
22  lv_obj_t *ws2812_lable_green;
23  lv_obj_t *ws2812_lable_blue;
24  lv_obj_t *ws2812_lable_brightness;
25
26  lv_obj_t *ws2812_text_red;
27  lv_obj_t *ws2812_text_green;
28  lv_obj_t *ws2812_text_blue;
29  lv_obj_t *ws2812_text_brightness;
30
31}lvgl_ws2812_ui;
32
33extern lvgl_ws2812_ui guider_ws2812_ui;    //ws2812 ui structure 
34
35bool ws2812_init(void);
36void ws2812_set_color(int num, int red, int green, int blue, int brightness);
37
38void setup_scr_ws2812(lvgl_ws2812_ui *ui); //Parameter configuration function on the ws2812 screen
39
40#endif

Here is the complete code:

19.1.3.3. ws2812_ui.cpp

  1//#include "main_ui.h"
  2#include "lvgl.h"
  3#include "ws2812_ui.h"
  4#include "lv_img.h"
  5#include "Freenove_WS2812_Lib_for_ESP32.h"
  6
  7lvgl_ws2812_ui guider_ws2812_ui;
  8Freenove_ESP32_WS2812 strip = Freenove_ESP32_WS2812(LEDS_COUNT, LEDS_PIN, CHANNEL, TYPE_GRB);
  9
 10bool ws2812_init(void) {
 11  strip.begin();
 12  strip.setBrightness(1);
 13  return 1;
 14}
 15
 16void ws2812_set_color(int num, int red, int green, int blue, int brightness) {
 17  red = constrain(red, 0, 255);
 18  green = constrain(green, 0, 255);
 19  blue = constrain(blue, 0, 255);
 20  brightness = constrain(brightness, 0, 255);
 21  strip.setBrightness(brightness);
 22  strip.setLedColorData(num, red, green, blue);
 23  strip.show();
 24}
 25
 26static void ws2812_imgbtn_home_event_handler(lv_event_t *e) {
 27  lv_event_code_t code = lv_event_get_code(e);
 28  switch (code) {
 29    case LV_EVENT_CLICKED:
 30      {
 31        Serial.println("Clicked the logo button.");
 32      }
 33      break;
 34    case LV_EVENT_RELEASED:
 35      {
 36        /*
 37        if (!lv_obj_is_valid(guider_main_ui.main))
 38          setup_scr_main(&guider_main_ui);
 39        lv_scr_load(guider_main_ui.main);
 40        lv_obj_del(guider_music_ui.music);
 41        */
 42      }
 43      break;
 44    default:
 45      break;
 46  }
 47}
 48
 49static void slider_event_cb(lv_event_t *e) {
 50  LV_UNUSED(e);
 51  int color_red = lv_slider_get_value(guider_ws2812_ui.ws2812_slider_red);
 52  int color_green = lv_slider_get_value(guider_ws2812_ui.ws2812_slider_green);
 53  int color_blue = lv_slider_get_value(guider_ws2812_ui.ws2812_slider_blue);
 54  int color_brightness = lv_slider_get_value(guider_ws2812_ui.ws2812_slider_brightness);
 55
 56  lv_label_set_text_fmt(guider_ws2812_ui.ws2812_text_red, "%d", color_red);
 57  lv_label_set_text_fmt(guider_ws2812_ui.ws2812_text_green, "%d", color_green);
 58  lv_label_set_text_fmt(guider_ws2812_ui.ws2812_text_blue, "%d", color_blue);
 59  lv_label_set_text_fmt(guider_ws2812_ui.ws2812_text_brightness, "%d", color_brightness);
 60
 61  ws2812_set_color(0, color_red, color_green, color_blue, color_brightness);
 62}
 63
 64void create_lable(lvgl_ws2812_ui *ui, lv_obj_t **lable1, lv_obj_t **lable2) {
 65  *lable1 = lv_label_create(ui->ws2812);
 66  lv_obj_set_style_text_align(*lable1, LV_TEXT_ALIGN_LEFT, 0);
 67  lv_obj_set_size(*lable1, 85, 20);
 68
 69  *lable2 = lv_label_create(ui->ws2812);
 70  lv_obj_set_style_text_align(*lable2, LV_TEXT_ALIGN_CENTER, 0);
 71  lv_obj_set_size(*lable2, 45, 20);
 72}
 73
 74static lv_obj_t *create_slider(lvgl_ws2812_ui *ui, lv_color_t color) {
 75  lv_obj_t *slider = lv_slider_create(ui->ws2812);
 76  lv_slider_set_range(slider, 0, 255);
 77  lv_obj_set_size(slider, 200, 10);
 78  lv_obj_set_style_bg_color(slider, color, LV_PART_KNOB);
 79  lv_obj_set_style_bg_color(slider, color, LV_PART_INDICATOR);
 80  lv_obj_add_event_cb(slider, slider_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
 81  return slider;
 82}
 83
 84//Parameter configuration function on the ws2812 screen
 85void setup_scr_ws2812(lvgl_ws2812_ui *ui) {
 86  ws2812_init();
 87
 88  //Write codes picture
 89  ui->ws2812 = lv_obj_create(NULL);
 90  static lv_style_t bg_style;
 91  lv_style_init(&bg_style);
 92  lv_style_set_bg_color(&bg_style, lv_color_hex(0xffffff));
 93  lv_obj_add_style(ui->ws2812, &bg_style, LV_PART_MAIN);
 94
 95  lv_img_home_init();
 96  //Write codes picture_home
 97  ui->ws2812_home = lv_imgbtn_create(ui->ws2812);
 98  lv_obj_remove_style_all(ui->ws2812_home);
 99  lv_obj_set_pos(ui->ws2812_home, 150, 10);
100  lv_obj_set_size(ui->ws2812_home, 80, 80);
101  lv_img_set_src(ui->ws2812_home, &img_home);
102  static lv_style_t style_pr;              //Apply for a style
103  lv_style_init(&style_pr);                //Initialize it
104  lv_style_set_translate_y(&style_pr, 5);  //Style: Every time you trigger, move down 5 pixels
105  lv_obj_add_style(ui->ws2812_home, &style_pr, LV_STATE_PRESSED);
106
107  create_lable(ui, &ui->ws2812_lable_red, &ui->ws2812_text_red);
108  lv_obj_set_pos(ui->ws2812_lable_red, 10, 10);
109  lv_obj_set_pos(ui->ws2812_text_red, 95, 10);
110  lv_label_set_text(ui->ws2812_lable_red, "red");
111  lv_label_set_text(ui->ws2812_text_red, "255");
112  static lv_style_t style_color_red;
113  lv_style_init(&style_color_red);
114  lv_style_set_border_width(&style_color_red, 2);
115  lv_style_set_border_color(&style_color_red, lv_palette_main(LV_PALETTE_RED));
116  lv_style_set_text_color(&style_color_red, lv_palette_main(LV_PALETTE_RED));
117  lv_obj_add_style(ui->ws2812_lable_red, &style_color_red, LV_PART_MAIN);
118  lv_obj_add_style(ui->ws2812_text_red, &style_color_red, LV_PART_MAIN);
119
120  create_lable(ui, &ui->ws2812_lable_green, &ui->ws2812_text_green);
121  lv_obj_set_pos(ui->ws2812_lable_green, 10, 30);
122  lv_obj_set_pos(ui->ws2812_text_green, 95, 30);
123  lv_label_set_text(ui->ws2812_lable_green, "green");
124  lv_label_set_text(ui->ws2812_text_green, "255");
125  static lv_style_t style_color_green;
126  lv_style_init(&style_color_green);
127  lv_style_set_border_width(&style_color_green, 2);
128  lv_style_set_border_color(&style_color_green, lv_palette_main(LV_PALETTE_GREEN));
129  lv_style_set_text_color(&style_color_green, lv_palette_main(LV_PALETTE_GREEN));
130  lv_obj_add_style(ui->ws2812_lable_green, &style_color_green, LV_PART_MAIN);
131  lv_obj_add_style(ui->ws2812_text_green, &style_color_green, LV_PART_MAIN);
132
133  create_lable(ui, &ui->ws2812_lable_blue, &ui->ws2812_text_blue);
134  lv_obj_set_pos(ui->ws2812_lable_blue, 10, 50);
135  lv_obj_set_pos(ui->ws2812_text_blue, 95, 50);
136  lv_label_set_text(ui->ws2812_lable_blue, "blue");
137  lv_label_set_text(ui->ws2812_text_blue, "255");
138  static lv_style_t style_color_blue;
139  lv_style_init(&style_color_blue);
140  lv_style_set_border_width(&style_color_blue, 2);
141  lv_style_set_border_color(&style_color_blue, lv_palette_main(LV_PALETTE_BLUE));
142  lv_style_set_text_color(&style_color_blue, lv_palette_main(LV_PALETTE_BLUE));
143  lv_obj_add_style(ui->ws2812_lable_blue, &style_color_blue, LV_PART_MAIN);
144  lv_obj_add_style(ui->ws2812_text_blue, &style_color_blue, LV_PART_MAIN);
145
146  create_lable(ui, &ui->ws2812_lable_brightness, &ui->ws2812_text_brightness);
147  lv_obj_set_pos(ui->ws2812_lable_brightness, 10, 70);
148  lv_obj_set_pos(ui->ws2812_text_brightness, 95, 70);
149  lv_label_set_text(ui->ws2812_lable_brightness, "brightness");
150  lv_label_set_text(ui->ws2812_text_brightness, "255");
151  static lv_style_t style_color_brightness;
152  lv_style_init(&style_color_brightness);
153  lv_style_set_border_width(&style_color_brightness, 1);
154  lv_style_set_border_color(&style_color_brightness, lv_palette_darken(LV_PALETTE_GREY, 2));
155  lv_style_set_text_color(&style_color_brightness, lv_palette_darken(LV_PALETTE_GREY, 2));
156  lv_obj_add_style(ui->ws2812_lable_brightness, &style_color_brightness, LV_PART_MAIN);
157  lv_obj_add_style(ui->ws2812_text_brightness, &style_color_brightness, LV_PART_MAIN);
158
159  ui->ws2812_slider_red = create_slider(ui, lv_palette_main(LV_PALETTE_RED));
160  ui->ws2812_slider_green = create_slider(ui, lv_palette_main(LV_PALETTE_GREEN));
161  ui->ws2812_slider_blue = create_slider(ui, lv_palette_main(LV_PALETTE_BLUE));
162  ui->ws2812_slider_brightness = create_slider(ui, lv_palette_main(LV_PALETTE_GREY));
163
164  lv_slider_set_value(ui->ws2812_slider_red, LV_OPA_10, LV_ANIM_OFF);
165  lv_slider_set_value(ui->ws2812_slider_green, LV_OPA_10, LV_ANIM_OFF);
166  lv_slider_set_value(ui->ws2812_slider_blue, LV_OPA_10, LV_ANIM_OFF);
167  lv_slider_set_value(ui->ws2812_slider_brightness, LV_OPA_10, LV_ANIM_OFF);
168
169  lv_obj_align(ui->ws2812_slider_red, LV_ALIGN_LEFT_MID, 20, -20);
170  lv_obj_align_to(ui->ws2812_slider_green, ui->ws2812_slider_red, LV_ALIGN_OUT_BOTTOM_MID, 0, 40);
171  lv_obj_align_to(ui->ws2812_slider_blue, ui->ws2812_slider_green, LV_ALIGN_OUT_BOTTOM_MID, 0, 40);
172  lv_obj_align_to(ui->ws2812_slider_brightness, ui->ws2812_slider_blue, LV_ALIGN_OUT_BOTTOM_MID, 0, 40);
173
174  lv_event_send(ui->ws2812_slider_brightness, LV_EVENT_VALUE_CHANGED, NULL);
175  lv_obj_add_event_cb(ui->ws2812_home, ws2812_imgbtn_home_event_handler, LV_EVENT_VALUE_CHANGED, NULL);
176}

Call the WS2812 library file.

1#include "Freenove_WS2812_Lib_for_ESP32.h"

Apply for a WS2812 interface object and configure its parameters.

1Freenove_ESP32_WS2812 strip = Freenove_ESP32_WS2812(LEDS_COUNT, LEDS_PIN, CHANNEL, TYPE_GRB);

Initialize the WS2812 LED and set its brightness to 1.

1bool ws2812_init(void) {
2  strip.begin();
3  strip.setBrightness(1);
4  return 1;
5}

WS2812 color setting function, through which the color of the specified WS2812 LED can be set. Parameter num refers to the index number of the specified LED, and the remaining four parameters correspond to the red, green, blue and brightness values respectivey.

1void ws2812_set_color(int num, int red, int green, int blue, int brightness) {
2  red = constrain(red, 0, 255);
3  green = constrain(green, 0, 255);
4  blue = constrain(blue, 0, 255);
5  brightness = constrain(brightness, 0, 255);
6  strip.setBrightness(brightness);
7  strip.setLedColorData(num, red, green, blue);
8  strip.show();
9}

Label creation function, which is used to create labels in batches, and the created objects are returned through formal parameters.

1void create_lable(lvgl_ws2812_ui *ui, lv_obj_t **lable1, lv_obj_t **lable2) {
2  *lable1 = lv_label_create(ui->ws2812);
3  lv_obj_set_style_text_align(*lable1, LV_TEXT_ALIGN_LEFT, 0);
4  lv_obj_set_size(*lable1, 85, 20);
5
6  *lable2 = lv_label_create(ui->ws2812);
7  lv_obj_set_style_text_align(*lable2, LV_TEXT_ALIGN_CENTER, 0);
8  lv_obj_set_size(*lable2, 45, 20);
9}

Use the label creation function to create two labels and assign values to the actual parameters corresponding to the two formal parameters of the function, and set the position and content of the labels.

1create_lable(ui, &ui->ws2812_lable_red, &ui->ws2812_text_red);
2lv_obj_set_pos(ui->ws2812_lable_red, 10, 10);
3lv_obj_set_pos(ui->ws2812_text_red, 95, 10);
4lv_label_set_text(ui->ws2812_lable_red, "red");
5lv_label_set_text(ui->ws2812_text_red, "255");

The slider creation function specifies the color of the slider through the formal parameter, and returns the created slider through the return value. Each slider has a range of 0-255. The created sliders are associated with the slider_event_cb function.

1static lv_obj_t *create_slider(lvgl_ws2812_ui *ui, lv_color_t color) {
2  lv_obj_t *slider = lv_slider_create(ui->ws2812);
3  lv_slider_set_range(slider, 0, 255);
4  lv_obj_set_size(slider, 200, 10);
5  lv_obj_set_style_bg_color(slider, color, LV_PART_KNOB);
6  lv_obj_set_style_bg_color(slider, color, LV_PART_INDICATOR);
7  lv_obj_add_event_cb(slider, slider_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
8  return slider;
9}

Call the slider creation function to create four sliders of different colors and assign them to the corresponding slider objects.

1ui->ws2812_slider_red = create_slider(ui, lv_palette_main(LV_PALETTE_RED));
2ui->ws2812_slider_green = create_slider(ui, lv_palette_main(LV_PALETTE_GREEN));
3ui->ws2812_slider_blue = create_slider(ui, lv_palette_main(LV_PALETTE_BLUE));
4ui->ws2812_slider_brightness = create_slider(ui, lv_palette_main(LV_PALETTE_GREY));

Sets the initial value of the slider. LV_OPA_10 means 10%, and the range of the slider is 0-255. Therefore, the value of LV_OPA_10 is 25.

1lv_slider_set_value(ui->ws2812_slider_red, LV_OPA_10, LV_ANIM_OFF);
2lv_slider_set_value(ui->ws2812_slider_green, LV_OPA_10, LV_ANIM_OFF);
3lv_slider_set_value(ui->ws2812_slider_blue, LV_OPA_10, LV_ANIM_OFF);
4lv_slider_set_value(ui->ws2812_slider_brightness, LV_OPA_10, LV_ANIM_OFF);

Trigger a slider event and set the callback function of the home button in the interface.

1lv_event_send(ui->ws2812_slider_brightness, LV_EVENT_VALUE_CHANGED, NULL);
2lv_obj_add_event_cb(ui->ws2812_home, ws2812_imgbtn_home_event_handler, LV_EVENT_VALUE_CHANGED, NULL);

Slider event callback function. Every time this function is triggered, get the values of the four sliders and display them in the value area in the upper left corner, and set the corresponding color and brightness of the onboard WS2812 LED.

 1static void slider_event_cb(lv_event_t *e) {
 2  LV_UNUSED(e);
 3  int color_red = lv_slider_get_value(guider_ws2812_ui.ws2812_slider_red);
 4  int color_green = lv_slider_get_value(guider_ws2812_ui.ws2812_slider_green);
 5  int color_blue = lv_slider_get_value(guider_ws2812_ui.ws2812_slider_blue);
 6  int color_brightness = lv_slider_get_value(guider_ws2812_ui.ws2812_slider_brightness);
 7
 8  lv_label_set_text_fmt(guider_ws2812_ui.ws2812_text_red, "%d", color_red);
 9  lv_label_set_text_fmt(guider_ws2812_ui.ws2812_text_green, "%d", color_green);
10  lv_label_set_text_fmt(guider_ws2812_ui.ws2812_text_blue, "%d", color_blue);
11  lv_label_set_text_fmt(guider_ws2812_ui.ws2812_text_brightness, "%d", color_brightness);
12
13  ws2812_set_color(0, color_red, color_green, color_blue, color_brightness);
14}