LVGL Examples
This example shows some of the LVGL widgets usage.
Checkout the LVGL documentation for more information.
Note
If you haven’t download the code:
Download examples from github termod-s3
Unzip the downloaded termod-s3-main.zip
Or just clone the repository
git clone https://github.com/TAMCTec/termod-s3.git
Note
If you don’t have lvgl installed, check this out: Install LVGL Library (Optional).
Open termod-s3/examples/lv_example/lv_example.ino
with Arduino IDE.
Remember to select ESP32S3 Dev Module
and port, then click upload.
#include "lv_helper.h"
lv_obj_t* arc;
lv_obj_t* slider;
lv_obj_t* arcValueLabel;
// Arc
void lv_example_arc_1(void) {
arc = lv_arc_create(lv_scr_act());
lv_obj_set_size(arc, 100, 100);
lv_arc_set_rotation(arc, 135);
lv_arc_set_bg_angles(arc, 0, 270);
lv_arc_set_value(arc, 0);
lv_arc_set_range(arc, 0, 100);
lv_obj_align(arc, LV_ALIGN_TOP_MID, 0, 10);
arcValueLabel = lv_label_create(arc);
lv_label_set_text(arcValueLabel, String(0).c_str());
lv_obj_center(arcValueLabel);
lv_obj_add_event_cb(arc, arcValueChanged, LV_EVENT_VALUE_CHANGED, NULL);
}
static void arcValueChanged(lv_event_t* e){
lv_obj_t* obj = lv_event_get_target(e);
int value = (int)lv_arc_get_value(obj);
lv_label_set_text(arcValueLabel, String(value).c_str());
lv_bar_set_value(slider, value, LV_ANIM_OFF);
}
// Slider
void lv_example_slider_1(void) {
slider = lv_slider_create(lv_scr_act());
lv_obj_align(slider, LV_ALIGN_TOP_MID, 0, 130);
lv_obj_add_event_cb(slider, sliderValueChanged, LV_EVENT_VALUE_CHANGED, NULL);
}
static void sliderValueChanged(lv_event_t* e){
lv_obj_t* obj = lv_event_get_target(e);
int value = (int)lv_slider_get_value(obj);
lv_label_set_text(arcValueLabel, String(value).c_str());
lv_arc_set_value(arc, value);
}
// Button and toggle
void lv_example_btn_1(void){
lv_obj_t * label;
lv_obj_t * btn1 = lv_btn_create(lv_scr_act());
lv_obj_add_event_cb(btn1, event_handler, LV_EVENT_ALL, NULL);
lv_obj_align(btn1, LV_ALIGN_TOP_MID, 80, 170);
label = lv_label_create(btn1);
lv_label_set_text(label, "Button");
lv_obj_center(label);
lv_obj_t * btn2 = lv_btn_create(lv_scr_act());
lv_obj_add_event_cb(btn2, event_handler, LV_EVENT_ALL, NULL);
lv_obj_align(btn2, LV_ALIGN_TOP_MID, -80, 170);
lv_obj_add_flag(btn2, LV_OBJ_FLAG_CHECKABLE);
lv_obj_set_height(btn2, LV_SIZE_CONTENT);
label = lv_label_create(btn2);
lv_label_set_text(label, "Toggle");
lv_obj_center(label);
}
static void event_handler(lv_event_t* e){
lv_event_code_t code = lv_event_get_code(e);
if(code == LV_EVENT_CLICKED) {
Serial.println("Clicked");
}
else if(code == LV_EVENT_VALUE_CHANGED) {
Serial.println("Toggled");
}
}
void lv_example_checkbox_1(void) {
lv_obj_t * checkboxs = lv_obj_create(lv_scr_act());
lv_obj_set_flex_flow(checkboxs, LV_FLEX_FLOW_COLUMN);
lv_obj_set_flex_align(checkboxs, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER);
lv_obj_align(checkboxs, LV_ALIGN_TOP_MID, 0, 220);
lv_obj_set_size(checkboxs, 200, 160);
lv_obj_t * cb;
cb = lv_checkbox_create(checkboxs);
lv_checkbox_set_text(cb, "Apple");
lv_obj_add_event_cb(cb, checkbox_event_handler, LV_EVENT_ALL, NULL);
cb = lv_checkbox_create(checkboxs);
lv_checkbox_set_text(cb, "Banana");
lv_obj_add_state(cb, LV_STATE_CHECKED);
lv_obj_add_event_cb(cb, checkbox_event_handler, LV_EVENT_ALL, NULL);
cb = lv_checkbox_create(checkboxs);
lv_checkbox_set_text(cb, "Lemon");
lv_obj_add_event_cb(cb, checkbox_event_handler, LV_EVENT_ALL, NULL);
cb = lv_checkbox_create(checkboxs);
lv_checkbox_set_text(cb, "Melon\nand a new line");
lv_obj_add_event_cb(cb, checkbox_event_handler, LV_EVENT_ALL, NULL);
lv_obj_update_layout(cb);
}
static void checkbox_event_handler(lv_event_t* e) {
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t * obj = lv_event_get_target(e);
if(code == LV_EVENT_VALUE_CHANGED) {
const char * txt = lv_checkbox_get_text(obj);
const char * state = lv_obj_get_state(obj) & LV_STATE_CHECKED ? "Checked" : "Unchecked";
Serial.printf("%s: %s\n", txt, state);
Serial.flush();
}
}
// Dropdown
void lv_example_dropdown_1(void) {
lv_obj_t * dd = lv_dropdown_create(lv_scr_act());
lv_dropdown_set_options(dd, "Apple\n"
"Banana\n"
"Orange\n"
"Cherry\n"
"Grape\n"
"Raspberry\n"
"Melon\n"
"Orange\n"
"Lemon\n"
"Nuts");
lv_obj_align(dd, LV_ALIGN_TOP_MID, 0, 400);
lv_obj_add_event_cb(dd, dropdown_event_handler, LV_EVENT_ALL, NULL);
}
static void dropdown_event_handler(lv_event_t* e) {
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t * obj = lv_event_get_target(e);
if(code == LV_EVENT_VALUE_CHANGED) {
char buf[32];
lv_dropdown_get_selected_str(obj, buf, sizeof(buf));
Serial.printf("Option: %s\n", buf);
Serial.flush();
}
}
// Roller
void lv_example_roller_1(void) {
lv_obj_t *roller1 = lv_roller_create(lv_scr_act());
lv_roller_set_options(
roller1,
"January\n"
"February\n"
"March\n"
"April\n"
"May\n"
"June\n"
"July\n"
"August\n"
"September\n"
"October\n"
"November\n"
"December",
LV_ROLLER_MODE_INFINITE
);
lv_roller_set_visible_row_count(roller1, 4);
lv_obj_align(roller1, LV_ALIGN_TOP_MID, 0, 460);
lv_obj_add_event_cb(roller1, roller_event_handler, LV_EVENT_ALL, NULL);
}
static void roller_event_handler(lv_event_t* e) {
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t * obj = lv_event_get_target(e);
if(code == LV_EVENT_VALUE_CHANGED) {
char buf[32];
lv_roller_get_selected_str(obj, buf, sizeof(buf));
Serial.printf("Selected month: %s\n", buf);
Serial.flush();
}
}
// Switches
void lv_example_switch_1(void) {
lv_obj_t * li;
lv_obj_t * sw;
lv_obj_t * label;
li = lv_obj_create(lv_scr_act());
lv_obj_clear_flag(li, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_set_size(li, 310, 50);
lv_obj_align(li, LV_ALIGN_TOP_MID, 0, 610);
sw = lv_switch_create(li);
lv_obj_align(sw, LV_ALIGN_RIGHT_MID, -10, 0);
lv_obj_add_event_cb(sw, switch_event_handler, LV_EVENT_ALL, NULL);
label = lv_label_create(li);
lv_label_set_text(label, "Switch 1");
lv_obj_align(label, LV_ALIGN_LEFT_MID, 10, 0);
li = lv_obj_create(lv_scr_act());
lv_obj_clear_flag(li, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_set_size(li, 310, 50);
lv_obj_align(li, LV_ALIGN_TOP_MID, 0, 670);
sw = lv_switch_create(li);
lv_obj_add_state(sw, LV_STATE_CHECKED);
lv_obj_align(sw, LV_ALIGN_RIGHT_MID, -10, 0);
lv_obj_add_event_cb(sw, switch_event_handler, LV_EVENT_ALL, NULL);
label = lv_label_create(li);
lv_label_set_text(label, "Switch 2");
lv_obj_align(label, LV_ALIGN_LEFT_MID, 10, 0);
}
static void switch_event_handler(lv_event_t* e) {
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t * obj = lv_event_get_target(e);
if(code == LV_EVENT_VALUE_CHANGED) {
Serial.printf("State: %s\n", lv_obj_has_state(obj, LV_STATE_CHECKED) ? "On" : "Off");
Serial.flush();
}
}
// Calender
void lv_example_calendar_1(void) {
lv_obj_t* calendar = lv_calendar_create(lv_scr_act());
lv_obj_set_size(calendar, 300, 200);
lv_obj_align(calendar, LV_ALIGN_TOP_MID, 0, 730);
lv_obj_add_event_cb(calendar, calendar_event_handler, LV_EVENT_ALL, NULL);
lv_calendar_set_today_date(calendar, 2022, 8, 9);
lv_calendar_set_showed_date(calendar, 2022, 8);
/*Highlight a few days*/
static lv_calendar_date_t highlighted_days[3]; /*Only its pointer will be saved so should be static*/
highlighted_days[0].year = 2022;
highlighted_days[0].month = 8;
highlighted_days[0].day = 7;
highlighted_days[1].year = 2022;
highlighted_days[1].month = 2;
highlighted_days[1].day = 11;
highlighted_days[2].year = 2022;
highlighted_days[2].month = 2;
highlighted_days[2].day = 22;
lv_calendar_set_highlighted_dates(calendar, highlighted_days, 3);
lv_calendar_header_dropdown_create(calendar);
// lv_calendar_header_arrow_create(calendar);
// lv_calendar_set_showed_date(calendar, 2021, 10);
}
static void calendar_event_handler(lv_event_t* e) {
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t * obj = lv_event_get_current_target(e);
if(code == LV_EVENT_VALUE_CHANGED) {
lv_calendar_date_t date;
if(lv_calendar_get_pressed_date(obj, &date)) {
Serial.printf("Clicked date: %02d.%02d.%d\n", date.day, date.month, date.year);
Serial.flush();
}
}
}
void lv_example_chart_1(void) {
/*Create a chart*/
lv_obj_t * chart;
chart = lv_chart_create(lv_scr_act());
lv_obj_set_size(chart, 200, 150);
lv_obj_align(chart, LV_ALIGN_TOP_MID, 0, 940);
lv_chart_set_type(chart, LV_CHART_TYPE_LINE); /*Show lines and points too*/
/*Add two data series*/
lv_chart_series_t * ser1 = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_RED), LV_CHART_AXIS_PRIMARY_Y);
lv_chart_series_t * ser2 = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_GREEN), LV_CHART_AXIS_SECONDARY_Y);
/*Set the next points on 'ser1'*/
lv_chart_set_next_value(chart, ser1, 10);
lv_chart_set_next_value(chart, ser1, 10);
lv_chart_set_next_value(chart, ser1, 10);
lv_chart_set_next_value(chart, ser1, 10);
lv_chart_set_next_value(chart, ser1, 10);
lv_chart_set_next_value(chart, ser1, 10);
lv_chart_set_next_value(chart, ser1, 10);
lv_chart_set_next_value(chart, ser1, 30);
lv_chart_set_next_value(chart, ser1, 70);
lv_chart_set_next_value(chart, ser1, 90);
/*Directly set points on 'ser2'*/
ser2->y_points[0] = 90;
ser2->y_points[1] = 70;
ser2->y_points[2] = 65;
ser2->y_points[3] = 65;
ser2->y_points[4] = 65;
ser2->y_points[5] = 65;
ser2->y_points[6] = 65;
ser2->y_points[7] = 65;
ser2->y_points[8] = 65;
ser2->y_points[9] = 65;
lv_chart_refresh(chart); /*Required after direct set*/
}
void setup() {
Serial.begin(115200);
lh_init(DISPLAY_LANDSCAPE);
Serial.println("LVGL Example: Ready");
lv_example_arc_1();
lv_example_slider_1();
lv_example_btn_1();
lv_example_checkbox_1();
lv_example_dropdown_1();
lv_example_roller_1();
lv_example_switch_1();
lv_example_calendar_1();
lv_example_chart_1();
}
void loop() {
lv_timer_handler();
}
#include "lv_helper.h"
TFT_eSPI lh_tft = TFT_eSPI();
TAMC_FT62X6 lh_tp = TAMC_FT62X6();
static lv_disp_draw_buf_t lh_draw_buf;
static lv_color_t lh_buf[ DISPLAY_WIDTH * 10 ];
static lv_disp_drv_t lh_disp_drv;
static lv_indev_drv_t lh_indev_drv;
uint16_t width, height;
void lh_init(int rotation){
Wire.begin();
lh_tp.begin();
lv_init();
lh_tft.begin();
if (rotation == 1 || rotation == 3){
width = DISPLAY_HEIGHT;
height = DISPLAY_WIDTH;
} else {
width = DISPLAY_WIDTH;
height = DISPLAY_HEIGHT;
}
lh_tft.setRotation(rotation);
lh_tp.setRotation(rotation);
lv_disp_draw_buf_init( &lh_draw_buf, lh_buf, NULL, DISPLAY_WIDTH * 10 );
/*Initialize the display*/
lv_disp_drv_init( &lh_disp_drv );
/*Change the following line to your display resolution*/
lh_disp_drv.hor_res = width;
lh_disp_drv.ver_res = height;
lh_disp_drv.flush_cb = lh_disp_flush;
lh_disp_drv.draw_buf = &lh_draw_buf;
lv_disp_drv_register( &lh_disp_drv );
/*Initialize the (dummy) input device driver*/
lv_indev_drv_init( &lh_indev_drv );
lh_indev_drv.type = LV_INDEV_TYPE_POINTER;
lh_indev_drv.read_cb = lh_touchpad_read;
lv_indev_drv_register( &lh_indev_drv );
}
/* Display flushing */
void lh_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) {
uint32_t w = (area->x2 - area->x1 + 1);
uint32_t h = (area->y2 - area->y1 + 1);
lh_tft.startWrite();
lh_tft.setAddrWindow( area->x1, area->y1, w, h );
lh_tft.pushColors( ( uint16_t * )&color_p->full, w * h, true );
lh_tft.endWrite();
lv_disp_flush_ready(disp);
}
/*Read the touchpad*/
void lh_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data) {
lh_tp.read();
if (!lh_tp.isTouched) {
data->state = LV_INDEV_STATE_RELEASED;
}
else{
data->state = LV_INDEV_STATE_PRESSED;
/*Set the coordinates*/
data->point.x = lh_tp.points[0].x;
data->point.y = lh_tp.points[0].y;
}
}
#ifndef LV_HELPER_H
#define LV_HELPER_H
#include <lvgl.h>
#include "TAMC_FT62X6.h"
#include "Wire.h"
#include <TFT_eSPI.h>
#define DISPLAY_PORTRAIT 2
#define DISPLAY_LANDSCAPE 3
#define DISPLAY_PORTRAIT_FLIP 0
#define DISPLAY_LANDSCAPE_FLIP 1
#define DISPLAY_WIDTH 240
#define DISPLAY_HEIGHT 320
/* Display flushing */
void lh_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p);
/*Read the touchpad*/
void lh_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data);
void lh_init(int rotation);
#endif // LV_HELPER_H