Movatterモバイル変換


[0]ホーム

URL:


Skip to content
HOMEESP32ESP8266ESP32-CAMRASPBERRY PIMICROPYTHONRPi PICOARDUINOREVIEWS

ESP32 CYD with LVGL: Display Temperature on Line Chart (BME280)

In this guide, you’ll learn how to display temperature from the BME280 sensor on an ESP32 Cheap Yellow Display (CYD) using LVGL (Light Versatile Graphics Library). You’ll learn how to draw a line chart to display data from a sensor. The ESP32 will be programmed using Arduino IDE.

ESP32 CYD with LVGL: Display Temperature on Line Chart (BME280)

New to the ESP32 Cheap Yellow Display? Start here:Getting Started with ESP32 Cheap Yellow Display Board – CYD (ESP32-2432S028R).

Project Overview

In this project, we’ll draw a line chart with the temperature from the BME280 sensor on the ESP32 CYD screen. Here’s the main features:

  • The chart displays a maximum of 20 data points;
  • When a new point is added to the screen, the oldest data point is deleted;
  • The vertical axis range will adjust automatically depending on the current values plotted on the chart;
  • You can touch next to the data points to check the precise value of a point—it will draw a label with its value next to it.
ESP32 CYD Project Overview Line Chart BME280

Prerequisites

Before proceeding, make sure you follow the next prerequisites. You must follow all steps, otherwise, your project will not work.

1) Parts Required and Wiring the Circuit

For this project, you need the following parts:

We’ll use I2C communication protocol to get data from the BME280 sensor. On the ESP32 CYD board there is anextended IO socket that allows you to connect external peripherals. We’ll connect the sensor to the CN1 connector.

ESP32 CYD Cheap Yellow Display Board JST Connector Connecting BME280 Sensor

Your board should have come with a little JST connector to access those GPIOs.

We’ll connect SDA to GPIO 27, and SCL to GPIO 22.

ESP32 CYD Cheap Yellow Display Board JST Connector

If you’re not familiar with the BME280 sensor, we recommend that you read our getting started guide:ESP32 with BME280 Sensor using Arduino IDE (Pressure, Temperature, Humidity)

The CYD board should have a built-in LDR (light-dependent resistor) next to the screen and connected to GPIO 34.

ESP32 Cheap Yellow Display LDR (Light Dependent ResistorESP32-Cheap-Yellow-)

2) Install ESP32 Boards in Arduino IDE

Arduino IDE 2 Logo

We’ll program the ESP32 using Arduino IDE. Make sure you have the ESP32 boards installed. Follow the next tutorial:

3) Get familiar with the ESP32 Cheap Yellow Display

The ESP32-2432S028R development board has become known in the maker community as the “Cheap Yellow Display” or CYD for short. This development board, whose main chip is an ESP32-WROOM-32 module, comes with a 2.8-inch TFT touchscreen LCD, a microSD card interface, an RGB LED, and all the required circuitry to program and apply power to the board.

ESP32 Cheap Yellow Display CYD Board ESP32-2432S028R front

If this is your first time using the ESP32 Cheap Yellow Display, make sure to follow our getting started guide:

4) Install TFT and LVGL Libraries

LVGL (Light and Versatile Graphics Library) is a free and open-source graphics library that provides a wide range of easy-to-use graphical elements for your microcontroller projects that require a graphical user interface (GUI).

LVGL new logo

Follow the next tutorial to install and configure the required libraries to use LVGL for the ESP32 Cheap Yellow Display using Arduino IDE.

5) Install BME280 Libraries

For this project, we’ll use the Adafruit BME280 library to get data from the BME280. In the Arduino IDE, go toSketch>Include Library >Manage Libraries. Search for Adafruit BME280 Library on the search box and install the library. Also, install any dependencies that are currently not installed (usually the Adafruit Bus IO and the Adafruit Unified Sensor libraries).

Installing Adafruit BME280 Sensor Library Arduino IDE

Learn more about the CYD Pinout:ESP32 Cheap Yellow Display (CYD) Pinout (ESP32-2432S028R).

Displaying Temperature Line Chart on ESP32 CYD using LVGL – Arduino Code

The following code will create the chart with values from the BME280 sensor.

/*  Rui Santos & Sara Santos - Random Nerd Tutorials - https://RandomNerdTutorials.com/esp32-cyd-lvgl-line-chart/  |  https://RandomNerdTutorials.com/esp32-tft-lvgl-line-chart/    THIS EXAMPLE WAS TESTED WITH THE FOLLOWING HARDWARE:    1) ESP32-2432S028R 2.8 inch 240×320 also known as the Cheap Yellow Display (CYD): https://makeradvisor.com/tools/cyd-cheap-yellow-display-esp32-2432s028r/      SET UP INSTRUCTIONS: https://RandomNerdTutorials.com/cyd-lvgl/    2) REGULAR ESP32 Dev Board + 2.8 inch 240x320 TFT Display: https://makeradvisor.com/tools/2-8-inch-ili9341-tft-240x320/ and https://makeradvisor.com/tools/esp32-dev-board-wi-fi-bluetooth/      SET UP INSTRUCTIONS: https://RandomNerdTutorials.com/esp32-tft-lvgl/    Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.    The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.*//*  Install the "lvgl" library version 9.X by kisvegabor to interface with the TFT Display - https://lvgl.io/    *** IMPORTANT: lv_conf.h available on the internet will probably NOT work with the examples available at Random Nerd Tutorials ***    *** YOU MUST USE THE lv_conf.h FILE PROVIDED IN THE LINK BELOW IN ORDER TO USE THE EXAMPLES FROM RANDOM NERD TUTORIALS ***    FULL INSTRUCTIONS AVAILABLE ON HOW CONFIGURE THE LIBRARY: https://RandomNerdTutorials.com/cyd-lvgl/ or https://RandomNerdTutorials.com/esp32-tft-lvgl/   */#include <lvgl.h>/*  Install the "TFT_eSPI" library by Bodmer to interface with the TFT Display - https://github.com/Bodmer/TFT_eSPI    *** IMPORTANT: User_Setup.h available on the internet will probably NOT work with the examples available at Random Nerd Tutorials ***    *** YOU MUST USE THE User_Setup.h FILE PROVIDED IN THE LINK BELOW IN ORDER TO USE THE EXAMPLES FROM RANDOM NERD TUTORIALS ***    FULL INSTRUCTIONS AVAILABLE ON HOW CONFIGURE THE LIBRARY: https://RandomNerdTutorials.com/cyd-lvgl/ or https://RandomNerdTutorials.com/esp32-tft-lvgl/   */#include <TFT_eSPI.h>// Install the "XPT2046_Touchscreen" library by Paul Stoffregen to use the Touchscreen - https://github.com/PaulStoffregen/XPT2046_Touchscreen - Note: this library doesn't require further configuration#include <XPT2046_Touchscreen.h>// Install Adafruit Unified Sensor and Adafruit BME280 Library#include <Wire.h>#include <Adafruit_Sensor.h>#include <Adafruit_BME280.h>#define I2C_SDA 27#define I2C_SCL 22TwoWire I2CBME = TwoWire(0);Adafruit_BME280 bme;// SET VARIABLE TO 0 FOR TEMPERATURE IN FAHRENHEIT DEGREES#define TEMP_CELSIUS 1#define BME_NUM_READINGS 20float bme_last_readings[BME_NUM_READINGS] = {-20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0};float scale_min_temp;float scale_max_temp;// Touchscreen pins#define XPT2046_IRQ 36   // T_IRQ#define XPT2046_MOSI 32  // T_DIN#define XPT2046_MISO 39  // T_OUT#define XPT2046_CLK 25   // T_CLK#define XPT2046_CS 33    // T_CSSPIClass touchscreenSPI = SPIClass(VSPI);XPT2046_Touchscreen touchscreen(XPT2046_CS, XPT2046_IRQ);#define SCREEN_WIDTH 240#define SCREEN_HEIGHT 320// Touchscreen coordinates: (x, y) and pressure (z)int x, y, z;#define DRAW_BUF_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT / 10 * (LV_COLOR_DEPTH / 8))uint32_t draw_buf[DRAW_BUF_SIZE / 4];// Generally, you should use "unsigned long" for variables that hold timeunsigned long previousMillis = 0; // will store last time the chart was updated// Interval at which the chart will be updated (milliseconds) 10000 milliseconds = 10 secondsconst long interval = 10000;// If logging is enabled, it will inform the user about what is happening in the libraryvoid log_print(lv_log_level_t level, const char * buf) {  LV_UNUSED(level);  Serial.println(buf);  Serial.flush();}// Get the Touchscreen datavoid touchscreen_read(lv_indev_t * indev, lv_indev_data_t * data) {  // Checks if Touchscreen was touched, and prints X, Y and Pressure (Z)  if(touchscreen.tirqTouched() && touchscreen.touched()) {    // Get Touchscreen points    TS_Point p = touchscreen.getPoint();    // Advanced Touchscreen calibration, LEARN MORE » https://RandomNerdTutorials.com/touchscreen-calibration/    float alpha_x, beta_x, alpha_y, beta_y, delta_x, delta_y;    // REPLACE WITH YOUR OWN CALIBRATION VALUES » https://RandomNerdTutorials.com/touchscreen-calibration/    alpha_x = -0.000;    beta_x = 0.090;    delta_x = -33.771;    alpha_y = 0.066;    beta_y = 0.000;    delta_y = -14.632;    x = alpha_y * p.x + beta_y * p.y + delta_y;    // clamp x between 0 and SCREEN_WIDTH - 1    x = max(0, x);    x = min(SCREEN_WIDTH - 1, x);    y = alpha_x * p.x + beta_x * p.y + delta_x;    // clamp y between 0 and SCREEN_HEIGHT - 1    y = max(0, y);    y = min(SCREEN_HEIGHT - 1, y);    // Basic Touchscreen calibration points with map function to the correct width and height    //x = map(p.x, 200, 3700, 1, SCREEN_WIDTH);    //y = map(p.y, 240, 3800, 1, SCREEN_HEIGHT);    z = p.z;    data->state = LV_INDEV_STATE_PRESSED;    // Set the coordinates    data->point.x = x;    data->point.y = y;    // Print Touchscreen info about X, Y and Pressure (Z) on the Serial Monitor    Serial.print("X = ");    Serial.print(x);    Serial.print(" | Y = ");    Serial.print(y);    Serial.print(" | Pressure = ");    Serial.print(z);    Serial.println();  }  else {    data->state = LV_INDEV_STATE_RELEASED;  }}// Draw a label on that chart with the value of the pressed pointstatic void chart_draw_label_cb(lv_event_t * e) {  lv_event_code_t code = lv_event_get_code(e);  lv_obj_t * chart = (lv_obj_t*) lv_event_get_target(e);  if(code == LV_EVENT_VALUE_CHANGED) {    lv_obj_invalidate(chart);  }  if(code == LV_EVENT_REFR_EXT_DRAW_SIZE) {    int32_t * s = (int32_t*)lv_event_get_param(e);    *s = LV_MAX(*s, 20);  }  // Draw the label on the chart based on the pressed point  else if(code == LV_EVENT_DRAW_POST_END) {    int32_t id = lv_chart_get_pressed_point(chart);    if(id == LV_CHART_POINT_NONE) return;    LV_LOG_USER("Selected point %d", (int)id);    lv_chart_series_t * ser = lv_chart_get_series_next(chart, NULL);    while(ser) {      lv_point_t p;      lv_chart_get_point_pos_by_id(chart, ser, id, &p);      int32_t * y_array = lv_chart_get_y_array(chart, ser);      int32_t value = y_array[id];      char buf[16];      #if TEMP_CELSIUS        const char degree_symbol[] = "\u00B0C";      #else        const char degree_symbol[] = "\u00B0F";      #endif      // Preparing the label text for the selected data point      lv_snprintf(buf, sizeof(buf), LV_SYMBOL_DUMMY " %3.2f %s ", float(bme_last_readings[id]), degree_symbol);      // Draw the rectangular label that will display the temperature value      lv_draw_rect_dsc_t draw_rect_dsc;      lv_draw_rect_dsc_init(&draw_rect_dsc);      draw_rect_dsc.bg_color = lv_color_black();      draw_rect_dsc.bg_opa = LV_OPA_60;      draw_rect_dsc.radius = 2;      draw_rect_dsc.bg_image_src = buf;      draw_rect_dsc.bg_image_recolor = lv_color_white();      // Rectangular label size      lv_area_t a;      a.x1 = chart->coords.x1 + p.x - 35;      a.x2 = chart->coords.x1 + p.x + 35;      a.y1 = chart->coords.y1 + p.y - 30;      a.y2 = chart->coords.y1 + p.y - 10;      lv_layer_t * layer = lv_event_get_layer(e);      lv_draw_rect(layer, &draw_rect_dsc, &a);      ser = lv_chart_get_series_next(chart, ser);    }  }  else if(code == LV_EVENT_RELEASED) {    lv_obj_invalidate(chart);  }}// Draw chartvoid lv_draw_chart(void) {  // Clear screen  lv_obj_clean(lv_scr_act());  // Create a a text label aligned on top  lv_obj_t * label = lv_label_create(lv_screen_active());  lv_label_set_text(label, "BME280 Temperature Readings");  lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 10);  // Create a container to display the chart and scale  lv_obj_t * container_row = lv_obj_create(lv_screen_active());  lv_obj_set_size(container_row, SCREEN_HEIGHT-20,  SCREEN_WIDTH-40);  lv_obj_align(container_row, LV_ALIGN_BOTTOM_MID, 0, -10);  // Set the container in a flexbox row layout aligned center  lv_obj_set_flex_flow(container_row, LV_FLEX_FLOW_ROW);  lv_obj_set_flex_align(container_row, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);  // Create a chart  lv_obj_t * chart = lv_chart_create(container_row);  lv_obj_set_size(chart, SCREEN_HEIGHT-90, SCREEN_WIDTH-70);  lv_chart_set_point_count(chart, BME_NUM_READINGS);  lv_obj_add_event_cb(chart, chart_draw_label_cb, LV_EVENT_ALL, NULL);  lv_obj_refresh_ext_draw_size(chart);  // Add a data series  lv_chart_series_t * chart_series = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_GREEN), LV_CHART_AXIS_PRIMARY_Y);  for(int i = 0; i < BME_NUM_READINGS; i++) {    if(float(bme_last_readings[i]) != -20.0) { // Ignores default array values      // Set points in the chart and scale them with an *100 multiplier to remove the 2 floating-point numbers      chart_series->y_points[i] = float(bme_last_readings[i]) * 100;    }  }  // Set the chart range and also scale it with an *100 multiplier to remove the 2 floating-point numbers  lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, int(scale_min_temp-1)*100, int(scale_max_temp+1)*100);  lv_chart_refresh(chart); // Required to update the chart with the new values  // Create a scale (y axis for the temperature) aligned vertically on the right  lv_obj_t * scale = lv_scale_create(container_row);  lv_obj_set_size(scale, 15, SCREEN_WIDTH-90);  lv_scale_set_mode(scale, LV_SCALE_MODE_VERTICAL_RIGHT);  lv_scale_set_label_show(scale, true);  // Set the scale ticks count   lv_scale_set_total_tick_count(scale, int(scale_max_temp+2) - int(scale_min_temp-1));  if((int(scale_max_temp+2) - int(scale_min_temp-1)) < 10) {    lv_scale_set_major_tick_every(scale, 1); // set y axis to have 1 tick every 1 degree  }  else {    lv_scale_set_major_tick_every(scale, 10); // set y axis to have 1 tick every 10 degrees  }  // Set the scale style and range  lv_obj_set_style_length(scale, 5, LV_PART_ITEMS);  lv_obj_set_style_length(scale, 10, LV_PART_INDICATOR);  lv_scale_set_range(scale, int(scale_min_temp-1), int(scale_max_temp+1));}// Get the latest BME readingsvoid get_bme_readings(void) {  #if TEMP_CELSIUS    float bme_temp = bme.readTemperature();  #else    float bme_temp = 1.8 * bme.readTemperature() + 32;    #endif    // Reset scale range (chart y axis) variables  scale_min_temp = 120.0;  scale_max_temp = -20.0;  // Shift values to the left of the array and inserts the latest reading at the end  for (int i = 0; i < BME_NUM_READINGS; i++) {    if(i == (BME_NUM_READINGS-1) && float(bme_temp) < 120.0) {      bme_last_readings[i] = float(bme_temp);  // Inserts the new reading at the end    }    else {      bme_last_readings[i] = float(bme_last_readings[i + 1]);  // Shift values to the left of the array    }    // Get the min/max value in the array to set the scale range (chart y axis)    if((float(bme_last_readings[i]) < scale_min_temp) && (float(bme_last_readings[i]) != -20.0 )) {      scale_min_temp = bme_last_readings[i];    }    if((float(bme_last_readings[i]) > scale_max_temp) && (float(bme_last_readings[i]) != -20.0 )) {      scale_max_temp = bme_last_readings[i];    }  }  Serial.print("Min temp: ");  Serial.println(float(scale_min_temp));  Serial.print("Max temp: ");  Serial.println(float(scale_max_temp));  Serial.print("BME last reading: ");  Serial.println(float(bme_last_readings[BME_NUM_READINGS-1]));  lv_draw_chart();}void setup() {  String LVGL_Arduino = String("LVGL Library Version: ") + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();  Serial.begin(115200);  Serial.println(LVGL_Arduino);  I2CBME.begin(I2C_SDA, I2C_SCL, 100000);  bool status;  // Passing a &Wire2 to set custom I2C ports  status = bme.begin(0x76, &I2CBME);  if (!status) {    Serial.println("Could not find a valid BME280 sensor, check wiring!");    while (1);  }    // Start LVGL  lv_init();  // Register print function for debugging  lv_log_register_print_cb(log_print);  // Start the SPI for the touchscreen and init the touchscreen  touchscreenSPI.begin(XPT2046_CLK, XPT2046_MISO, XPT2046_MOSI, XPT2046_CS);  touchscreen.begin(touchscreenSPI);  // Set the Touchscreen rotation in landscape mode  // Note: in some displays, the touchscreen might be upside down, so you might need to set the rotation to 0: touchscreen.setRotation(0);  touchscreen.setRotation(2);  // Create a display object  lv_display_t * disp;  // Initialize the TFT display using the TFT_eSPI library  disp = lv_tft_espi_create(SCREEN_WIDTH, SCREEN_HEIGHT, draw_buf, sizeof(draw_buf));  lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_270);    // Initialize an LVGL input device object (Touchscreen)  lv_indev_t * indev = lv_indev_create();  lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);  // Set the callback function to read Touchscreen input  lv_indev_set_read_cb(indev, touchscreen_read);  get_bme_readings();}void loop() {  lv_task_handler();  // let the GUI do its work  lv_tick_inc(5);     // tell LVGL how much time has passed  delay(5);           // let this time pass    unsigned long currentMillis = millis();  if (currentMillis - previousMillis >= interval) {    // save the last time that chart was updated    previousMillis = currentMillis;    get_bme_readings();      }}

View raw code

How Does the Code Work?

Let’s take a look at how to get temperature from the BME280 sensor and add the current reading to the line chart. Alternatively, you can skip to theDemonstrationsection.

Including Libraries

In all your sketches, you need to include thelvgl.h and theTFT_eSPI.h libraries to display on the screen.

#include <lvgl.h>#include <TFT_eSPI.h>

You need to include the following libraries to interface with the BME280 sensor.

#include <Wire.h>#include <Adafruit_Sensor.h>#include <Adafruit_BME280.h>

BME280 I2C Pins

Set the I2C pins to use the BME280 sensor, create a new I2C bus instance to use those pins, and create anAdafruit_BME280 object calledbme to refer to the sensor.

#define I2C_SDA 27#define I2C_SCL 22TwoWire I2CBME = TwoWire(0);Adafruit_BME280 bme;

Celsius or Fahrenheit

Our code is prepared to display the temperature in Celsius or Fahrenheit degrees. To choose your desired unit, you can set the value of theTEMP_CELSIUS variable. It is set to1 by default to display the temperature in Celsius degrees.

#define TEMP_CELSIUS 1    

If you want to display in Fahrenheit degrees instead, set it to0.

#define TEMP_CELSIUS 0

Number of Readings and Scale Variables

The data to be displayed on the chart needs to be placed in an array. We’ll display a maximum of 20 readings. These are saved on thebme_last_readings array.

#define BME_NUM_READINGS 20float bme_last_readings[BME_NUM_READINGS] = {-20.0, -20.0, -20.0, -20.0, -20.0,-20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0,-20.0, -20.0, -20.0, -20.0};

We also create two global variablesscale_min_temp andscale_max_temp that will be used to adjust the scale range.

float scale_min_temp;float scale_max_temp;

Defining the Display Width and Height

You need to define your display width and height in all your sketches that use LVGL. If you’re using the recommended display, the size is 240×320.

#define SCREEN_WIDTH 241#define SCREEN_HEIGHT 320

Creating a Drawing Buffer

You need to create a buffer to draw on the display as follows:

#define DRAW_BUF_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT / 10 * (LV_COLOR_DEPTH / 8))uint32_t draw_buf[DRAW_BUF_SIZE / 4];

You should also include this in all LVGL examples.

Debugging Function

For debugging with the LVGL library, you should use thelog_print() function. It is defined below. Include it in all your sketches before thesetup().

// If logging is enabled, it will inform the user about what is happening in the libraryvoid log_print(lv_log_level_t level, const char * buf) {  LV_UNUSED(level);  Serial.println(buf);  Serial.flush();}

setup()

In thesetup(), include the following lines for debugging. These will print the version of LVGL that you’re using. You must be using version 9.

String LVGL_Arduino = String("LVGL Library Version: ") + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();Serial.begin(115200);Serial.println(LVGL_Arduino);

Initializing the BME280 sensor

In thesetup(), start by initializing the BME280 sensor.

I2CBME.begin(I2C_SDA, I2C_SCL, 100000);bool status;// Passing a &Wire2 to set custom I2C portsstatus = bme.begin(0x76, &I2CBME);if (!status) {  Serial.println("Could not find a valid BME280 sensor, check wiring!");  while (1);}

Initialize the LVGL Library

Initialize the LVGL Library by calling thelv_init() function in thesetup().

// Start LVGLlv_init();

Register Debugging Function

Register yourlog_print() function declared previously as a function associated with debugging LVGL.

// Register print function for debugginglv_log_register_print_cb(log_print);

Getting BME280 Readings

In thesetup(), we call theget_bme_readings() which will get new sensor readings and display them on the chart.

get_bme_readings();

This function is also called every 10 seconds (interval variable) in theloop() to add a new data point to the chart.

unsigned long currentMillis = millis();if (currentMillis - previousMillis >= interval) {  // save the last time that chart was updated  previousMillis = currentMillis;  get_bme_readings();}

In theget_bme_readings(), we start by getting a new temperature reading and save it on thebme_temp variable (in Celsius or Fahrenheit degrees).

#if TEMP_CELSIUS  float bme_temp = bme.readTemperature();#else  float bme_temp = 1.8 * bme.readTemperature() + 32;#endif

Every time we get a new data point, we’ll reset the scale range (y-axis).

// Reset scale range (chart y axis) variablesscale_min_temp = 120.0;scale_max_temp = -20.0;

We add the new temperature value at the end of the array and shift all data points to the left of the array.

// Shift values to the left of the array and inserts the latest reading at the endfor (int i = 0; i < BME_NUM_READINGS; i++) {  if(i == (BME_NUM_READINGS-1) && float(bme_temp) < 120.0) {    bme_last_readings[i] = float(bme_temp); //Inserts the new reading at the end  }  else {    bme_last_readings[i] = float(bme_last_readings[i+1]);    // Shift values to the left of the array  }

Thebme_last_readings array now contains the data to be displayed on the chart.

We’ll go through the array and get the maximum and the minimum temperature readings and save them on thescale_max_temp andscale_min_temp variables so that we can adjust the y-axis later.

// Get the min/max value in the array to set the scale range (chart y axis)if((float(bme_last_readings[i]) < scale_min_temp) && (float(bme_last_readings[i]) != -20.0 )) {  scale_min_temp = bme_last_readings[i];}if((float(bme_last_readings[i]) > scale_max_temp) && (float(bme_last_readings[i]) != -20.0 )) {  scale_max_temp = bme_last_readings[i];}

Now that we have our array ready and the maximum and minimum temperature values, we can start drawing the chart. We created a function calledlv_draw_chart() where we added all the instructions
to draw the chart.

lv_draw_chart();

Drawing the Chart

In thelv_draw_chart() we draw the chart and add all the other widgets to the screen.

We add a text label at the top with theBME280 Temperature Readings text.

// Create a a text label aligned on toplv_obj_t * label = lv_label_create(lv_screen_active());lv_label_set_text(label, "BME280 Temperature Readings");lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 10);

Next, we create a container (container_row) where we’ll add the chart and the corresponding scale (y-axis) and we set its alignment.

// Create a container to display the chart and scalelv_obj_t * container_row = lv_obj_create(lv_screen_active());lv_obj_set_size(container_row, SCREEN_HEIGHT-20, SCREEN_WIDTH-40);lv_obj_align(container_row, LV_ALIGN_BOTTOM_MID, 0, -10);// Set the container in a flexbox row layout aligned centerlv_obj_set_flex_flow(container_row, LV_FLEX_FLOW_ROW);lv_obj_set_flex_align(container_row, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);

We create an LVGL chart object using thelv_chart_create() function. We pass as argument where we want to place the chart. In this case, we want to place it inside thecontainer_row.

lv_obj_t * chart = lv_chart_create(container_row);

Set the chart size.

lv_obj_set_size(chart, SCREEN_HEIGHT-90, SCREEN_WIDTH-70);

Set the number of points you want to display simultaneously on the chart.

lv_chart_set_point_count(chart, BME_NUM_READINGS);

Add an event to the chart so that it displays the pressed point value—that will be handled inside thechart_draw_label_cb() callback function.

lv_obj_add_event_cb(chart, chart_draw_label_cb, LV_EVENT_ALL, NULL);

After creating the chart, we need to create a data series for the chart using thelv_chart_add_series(). Pass as argument the chart you’re referring to, the color of the series, and the Y axis.

lv_chart_series_t * chart_series = lv_chart_add_series(chart,lv_palette_main(LV_PALETTE_GREEN), LV_CHART_AXIS_PRIMARY_Y);

Afterward, we add all our points in the array to the chart series.

for(int i = 0; i < BME_NUM_READINGS; i++) {  if(float(bme_last_readings[i]) != -20.0) { // Ignores default array values    // Set points in the chart and scale them with an    // *100 multiplier to remove the 2 floating-point numbers   chart_series->y_points[i] = float(bme_last_readings[i]) * 100;  }}

Set the chart range taking into account thescale_max_temp andscale_min_temp values that we got previously.

// Set the chart range and also scale it with an// *100 multiplier to remove the 2 floating-point numberslv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, int(scale_min_temp-1)*100,int(scale_max_temp+1)*100);

Call thelv_chart_refresh() function to update all values on the chart.

lv_chart_refresh(chart); // Required to update the chart with the new values

Create a vertical scale for the chart using thelv_scale_create() function and place it inside thecontainer_row aligned vertically on the right.

// Create a scale (y axis for the temperature) aligned vertically on the rightlv_obj_t * scale = lv_scale_create(container_row);lv_obj_set_size(scale, 15, SCREEN_WIDTH-90);lv_scale_set_mode(scale, LV_SCALE_MODE_VERTICAL_RIGHT);lv_scale_set_label_show(scale, true);

Set the scale smaller divisions.

// Set the scale ticks countlv_scale_set_total_tick_count(scale,int(scale_max_temp+2)-int(scale_min_temp-1));if((int(scale_max_temp+2) - int(scale_min_temp-1)) < 10) {  lv_scale_set_major_tick_every(scale, 1); // set y axis to have 1 tick every 1 degree}else {  lv_scale_set_major_tick_every(scale, 10);//set y axis to have 1 tick every 10 degrees}

Set the scale style and range.

// Set the scale style and rangelv_obj_set_style_length(scale, 5, LV_PART_ITEMS);lv_obj_set_style_length(scale, 10, LV_PART_INDICATOR);lv_scale_set_range(scale, int(scale_min_temp-1), int(scale_max_temp+1));

Drawing the Chart

When you press the chart, it will display a label with the values for the pressed data point.

lv_obj_add_event_cb(chart, chart_draw_label_cb, LV_EVENT_ALL, NULL);

All of that is handled on thechart_draw_label_cb() function.

// Draw a label on that chart with the value of the pressed pointstatic void chart_draw_label_cb(lv_event_t * e) {  lv_event_code_t code = lv_event_get_code(e);  lv_obj_t * chart = (lv_obj_t*) lv_event_get_target(e);  if(code == LV_EVENT_VALUE_CHANGED) {    lv_obj_invalidate(chart);  }  if(code == LV_EVENT_REFR_EXT_DRAW_SIZE) {    int32_t * s = (int32_t*)lv_event_get_param(e);    *s = LV_MAX(*s, 20);  }  // Draw the label on the chart based on the pressed point  else if(code == LV_EVENT_DRAW_POST_END) {    int32_t id = lv_chart_get_pressed_point(chart);    if(id == LV_CHART_POINT_NONE) return;      LV_LOG_USER("Selected point %d", (int)id);      lv_chart_series_t * ser = lv_chart_get_series_next(chart, NULL);      while(ser) {        lv_point_t p;        lv_chart_get_point_pos_by_id(chart, ser, id, &p);        int32_t * y_array = lv_chart_get_y_array(chart, ser);        int32_t value = y_array[id];        char buf[16];        #if TEMP_CELSIUS          const char degree_symbol[] = "\u00B0C";        #else          const char degree_symbol[] = "\u00B0F";        #endif        // Preparing the label text for the selected data point        lv_snprintf(buf, sizeof(buf), LV_SYMBOL_DUMMY " %3.2f %s ", float(bme_last_readings[id]), degree_symbol);        // Draw the rectangular label that will display the temperature value        lv_draw_rect_dsc_t draw_rect_dsc;        lv_draw_rect_dsc_init(&draw_rect_dsc);        draw_rect_dsc.bg_color = lv_color_black();        draw_rect_dsc.bg_opa = LV_OPA_60;        draw_rect_dsc.radius = 2;        draw_rect_dsc.bg_image_src = buf;        draw_rect_dsc.bg_image_recolor = lv_color_white();        // Rectangular label size        lv_area_t a;        a.x1 = chart->coords.x1 + p.x - 35;        a.x2 = chart->coords.x1 + p.x + 35;        a.y1 = chart->coords.y1 + p.y - 30;        a.y2 = chart->coords.y1 + p.y - 10;        lv_layer_t * layer = lv_event_get_layer(e);        lv_draw_rect(layer, &draw_rect_dsc, &a);        ser = lv_chart_get_series_next(chart, ser);      }    }    else if(code == LV_EVENT_RELEASED) {      lv_obj_invalidate(chart);    }}

Demonstration

Upload the code to your board. Go toTools>Boardand selectESP32>ESP32 Dev Module. Then, select the right COM port inTools>Port. Finally, click the upload button.

Arduino IDE 2 Upload Button

After uploading the code, it will display the chart with one point. Wait 10 seconds to get a second point, 10 seconds more for the third point, and so on.

ESP32 CYD LVGL Display Temperature Line Chart BME280

Wait until you have the chart filled with the 20 data points. A new value is added every 10 seconds—the chart is automatically updated.

ESP32 CYD LVGL Display Temperature Line Chart BME280 Demonstration

You can press on a specific data point to check its precise value.

The serial monitor displays the latest temperature reading as well as the minimum and maximum values from the array.

ESP32 CYD BME280 line chart serial monitor temperature demonstration

Wrapping Up

In this tutorial, you learned to display sensor data on a line chart with the Cheap Yellow display screen using the LVGL library.

We hope you found this tutorial useful. We’re preparing more guides about this board, so stay tuned. If you would like to learn more about creating graphical user interfaces using the LVGL library with the ESP32, check out our latest eBook:

Other guides you might like reading:

To learn more about the ESP32, make sure to take a look at our resources:



SMART HOME with Raspberry Pi ESP32 and ESP8266 Node-RED InfluxDB eBook
Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »
Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »

Enjoyed this project? Stay updated by subscribing our newsletter!

18 thoughts on “ESP32 CYD with LVGL: Display Temperature on Line Chart (BME280)”

  1. Hell Rui,
    again a very good article!

    1WIRE SENSORS
    I remember that you did good work using 1wire-Sensors.
    I managed to use a SIM800L board, using you code to log temperatures and send them to a webserver and log the data there.

    1WIRE Sensors are the best for serious mesurements of one to many points.

    May be there is a chance for a project to log the temp values locally onto the sd-card and also send them to a webserver using GET or POST and display them locally on the CYD.

    Thanks!

    Reply
  2. Hello Sara and Rui. A few years ago you asked us if we had any nice design ideas.
    What do you think of a simple internet radio or mp3 player with the Yello screen?
    Greetings Bert

    Reply
    • Hi.
      We’ll have to take a look into that.
      We don’t have any audio tutorials at the moment.
      We’re not familiar with that topic, but that’s something new we need to take a look at.
      Regards,
      Sara

      Reply
  3. Thank you.

    Reply
  4. I love these articles as they are both well written and easy to digest. I have a suggestion for another article. One that uses EEZ Studio for UI development. EEZ Studio is free of charge and Open Source. I believe it will make developing User Interfaces much easier.

    Reply
    • I agree. EEZ Studio looks like the ideal way of creating displays. What isn’t clear is how to integrate with esp32 and how to send data between ESP32 and EEZ code.

      Reply
      • There is a channel on YT named lvgl_beginner. I used the instructions there to get EEZ Studio to work with the CYD. I am not at home at the moment or I would post a working example. The YT channel uses much of the information provided here and gives credit.

        Reply
  5. hola Sara, me gusta mucho la informacion que brindan en este espacio, verdaderamente es muy interesante. Hoy en dia tengo inquietud en aprender reconocimiento facial, tactil y de voz a traves de estas tecnologias (arduino, raspberry, etc), tendras algo de informacion al respecto???

    Reply
  6. Good evening.
    Is there a chance You will make a tutorial using the EP32-S3 480*272 dsplay with capacitive touch screen like the one of link below?
    It could be very interesting.
    Regards.
    Maurizio

    it.aliexpress.com/item/1005007713873296.html?spm=a2g0o.productlist.main.3.7c855047gAs59d&algo_pvid=3d89783c-8883-41f2-aa9a-a05372e84f8b&algo_exp_id=3d89783c-8883-41f2-aa9a-a05372e84f8b-2&pdp_ext_f=%7B%22order%22%3A%225%22%2C%22eval%22%3A%221%22%7D&pdp_npi=4%40dis%21EUR%2122.99%2122.99%21%21%21188.91%21188.91%21%40211b653717533896106655235e2691%2112000041944045365%21sea%21IT%215299029%21X&curPageLogUid=i6l7zWjSN8XB&utparam-url=scene%3Asearch%7Cquery_from%3A

    Reply
  7. Good job!

    But there are many ESP32 CYD boards with 2.2″ or 2.4″ capacitive touch displays available on the market. Is there any source code or some hints on how to get started with these PCBAs?

    Unfortunately, the code is not working 1:1 on these boards. At the moment I have no clue what the differences are and what I need to change. For example, my PCBA is equipped with:

    ESP-WROOM-32, printed GUITION and copper with: ESP32-2432S024

    Reply
  8. Great work!
    If we use BMP180 instead of BME280, what do we need to change in the code besides calling the libraries?

    Reply

Leave a CommentCancel reply

Learn ESP32

ESP32 Introduction

ESP32 Arduino IDE

ESP32 Arduino IDE 2.0

VS Code and PlatformIO

ESP32 Pinout

ESP32 Inputs Outputs

ESP32 PWM

ESP32 Analog Inputs

ESP32 Interrupts Timers

ESP32 Deep Sleep

Protocols

ESP32 Web Server

ESP32 LoRa

ESP32 BLE

ESP32 BLE Client-Server

ESP32 Bluetooth

ESP32 MQTT

ESP32 ESP-NOW

ESP32 Wi-Fi

ESP32 WebSocket

ESP32 ESP-MESH

ESP32 Email

ESP32 Text Messages

ESP32 HTTP GET POST

HTTP GET Web APIs

HTTP POST Web APIs

Server-Sent Events

Web Servers

Output Web Server

PWM Slider Web Server

PWM Multiple Sliders Web Server

Async Web Server

Relay Web Server

Servo Web Server

DHT Web Server

BME280 Web Server

BME680 Web Server

DS18B20 Web Server

LoRa Web Server

Plot/Chart Web Server

Chart Multiple Series Web Server

SPIFFS Web Server

Thermostat Web Server

Momentary Switch Web Server

Physical Button Web Server

Input Fields Web Server

Images Web Server

RGB LED Web Server

Timer/Pulse Web Server

HTTP Auth Web Server

MPU-6050 Web Server

MicroSD Card Web Server

Stepper Motor Web Server

Stepper Motor WebSocket

Gauges Web Server

DIY Cloud

ESP32 Weather Station

Control GPIOs

View Sensor Readings

ESP32 MySQL

ESP32 PHP Email

ESP32 SIM800L

Cloud Node-RED Dashboard

Cloud MQTT Broker

ESP32 Cloud MQTT

ESP-NOW

ESP-NOW Introduction

ESP-NOW Two-Way

ESP-NOW One-to-Many

ESP-NOW Many-to-One

ESP-NOW + Wi-Fi Web Server

Firebase

Firebase Realtime Database

Firebase Web App

Firebase Authentication

Firebase BME280

Firebase Web App Sensor Readings

Firebase ESP32 Data Logging

Modules

ESP32 Relay Module

ESP32 DC Motors

ESP32 Servo

ESP32 Stepper Motor

ESP32 MicroSD Card

ESP32 MicroSD Card Data Logging

ESP32 PIR

ESP32 HC-SR04

ESP32 I2C Multiplexer

Sensors

ESP32 DHT11/DHT22

ESP32 BME280

ESP32 BME680

ESP32 DS18B20

ESP32 Multiple DS18B20

ESP32 BMP180

ESP32 BMP388

MQTT DHT11/DHT22

MQTT BME280

MQTT BME680

MQTT DS18B20

ESP32 MPU-6050

Displays

ESP32 OLED

ESP32 LCD

OLED Temperature

ESP32 Features

ESP32 Hall Sensor

ESP32 Touch Sensor

ESP32 I2C

ESP32 Flash Memory

ESP32 Dual Core

Useful Guides

ESP32 Troubleshooting

ESP32 Access Point

ESP32 Fixed IP Address

ESP32 MAC Address

ESP32 Hostname

ESP32 OTA

ESP32 OTA Arduino

ESP32 OTA VS Code

ESP32 Solar Panels

ESP32 Alexa

ESP32 Install SPIFFS

ESP32 Time and Date

ESP32 Epoch Time

ESP32 Google Sheets

ESP32 Email Altert

ESP32 ThingSpeak

Weather Station Shield

ESP32 IoT Shield

ESP32 Weather Station PCB

ESP32 Wi-Fi Manager

VS Code and PlatformIO

VS Code SPIFFS

VS Code Workspaces

Save Data Preferences Library

Reconnect to Wi-Fi

Useful Wi-Fi Functions

Other Projects

Telegram Control Outputs

Telegram Sensor Readings

Telegram Detect Motion

Telegram Group

ESP32 Status PCB

ESP32 BMP388 Datalogger

ESP32 Web Serial

ESP32 Door Monitor

ESP32 Door Telegram

ESP32 NTP Timezones

ESP32 Boards

ESP32 Camera

ESP32 LoRa

ESP32 OLED

ESP32 SIM800L

Learn More

Learn ESP32

Learn ESP8266

Learn ESP32-CAM

Learn MicroPython

Learn Arduino

Build Web Servers eBook

Smart Home eBook

Firebase Web App eBook

ESP32 Premium Course

Affiliate Disclosure:Random Nerd Tutorials is a participant in affiliate advertising programs designed to provide a means for us to earn fees by linking to Amazon, eBay, AliExpress, and other sites. We might be compensated for referring traffic and business to these companies.



Learn ESP32 with Arduino IDE eBook » Complete guide to program the ESP32 with Arduino IDE!



SMART HOME with Raspberry Pi, ESP32, and ESP8266 » learn how to build a complete home automation system.



Learn Raspberry Pi Pico/Pico W with MicroPython​ » The complete getting started guide to get the most out of the the Raspberry Pi Pico/Pico W (RP2040) microcontroller board using MicroPython programming language.



🔥 Learn LVGL: Build GUIs for ESP32 Projects​ » Learn how to build Graphical User Interfaces (GUIs) for ESP32 Projects using LVGL (Light Versatile Graphics Library) with the Arduino IDE.

Download Our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.


[8]ページ先頭

©2009-2025 Movatter.jp