How to display sensor data in a label

Description

I’m trying to display a sensor data in a display with LVGL

What MCU/Processor/Board and compiler are you using?

ESP32 NodeMCU and ILI9341 and Arduino IDE

What LVGL version are you using?

v.7

What do you want to achieve?

Update sensor data every 2 seconds and learn how to use the library

What have you tried so far?

Try to set the text in of a label in the loop() with the sensor data but doesn’t appear nothing in the tft

Code to reproduce

#include <lvgl.h>
#include <TFT_eSPI.h>
#include <Wire.h>
#include <string.h>.
#include "SparkFun_SCD30_Arduino_Library.h" //Click here to get the library: http://librarymanager/All#SparkFun_SCD30
SCD30 airSensor;



TFT_eSPI tft = TFT_eSPI(); /* TFT instance */
static lv_disp_buf_t disp_buf;
static lv_color_t buf[LV_HOR_RES_MAX * 10];

static lv_obj_t * bg_top;
static lv_obj_t * bg_middle1;
static lv_obj_t * bg_bottom;
static lv_obj_t * label_status;
static lv_obj_t * label_co2;
static lv_obj_t * label_temp;
static lv_obj_t * label_hum;


#if USE_LV_LOG != 0
/* Serial debugging */
void my_print(lv_log_level_t level, const char * file, uint32_t line, const char * dsc)
{

    Serial.printf("%s@%d->%s\r\n", file, line, dsc);
    Serial.flush();
}
#endif

/* Display flushing */
void my_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);

    tft.startWrite();
    tft.setAddrWindow(area->x1, area->y1, w, h);
    tft.pushColors(&color_p->full, w * h, true);
    tft.endWrite();

    lv_disp_flush_ready(disp);
}

/* Reading input device (simulated encoder here) */
bool read_encoder(lv_indev_drv_t * indev, lv_indev_data_t * data)
{
    static int32_t last_diff = 0;
    int32_t diff = 0; /* Dummy - no movement */
    int btn_state = LV_INDEV_STATE_REL; /* Dummy - no press */

    data->enc_diff = diff - last_diff;;
    data->state = btn_state;

    last_diff = diff;

    return false;
}

void setup()
{
    pinMode(15, OUTPUT);
    digitalWrite(15, LOW);
    delay(1);
    Serial.begin(115200); /* prepare for possible serial debug */
    airSensor.begin();
    delay(100);
    airSensor.setMeasurementInterval(2);
    Serial.println("SCD30 Example");
    Wire.begin(25,26);
    
    lv_init();

#if USE_LV_LOG != 0
    lv_log_register_print_cb(my_print); /* register print function for debugging */
#endif

    tft.begin(); /* TFT init */
    tft.setRotation(2); /* Landscape orientation */

    lv_disp_buf_init(&disp_buf, buf, NULL, LV_HOR_RES_MAX * 10);

    /*Initialize the display*/
    lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv);
    disp_drv.hor_res = 240;
    disp_drv.ver_res = 320;
    disp_drv.flush_cb = my_disp_flush;
    disp_drv.buffer = &disp_buf;
    lv_disp_drv_register(&disp_drv);

    /*Initialize the (dummy) input device driver*/
    lv_indev_drv_t indev_drv;
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_ENCODER;
    indev_drv.read_cb = read_encoder;
    lv_indev_drv_register(&indev_drv);



  lv_main();    
}


void loop()
{

    lv_task_handler(); /* let the GUI do its work */
    delay(5);

    String co2 = String(airSensor.getCO2());
    String temp = String(airSensor.getTemperature());
    String hum = String(airSensor.getHumidity());

      int c = co2.length();
      int t = temp.length();
      int h = hum.length();

      
     char co2C[c+1];
     char tempC[t+1];
     char humC[h+ 1];

     strcpy(co2C, co2.c_str());
     strcpy(tempC, temp.c_str());
     strcpy(humC, hum.c_str());
     
    lv_label_set_text(label_co2, co2C);
    lv_label_set_text(label_temp, tempC);
    lv_label_set_text(label_hum, humC);
    delay(2000);
}



static void lv_main(){
    
    //LV_THEME_MATERIAL_FLAG_LIGHT
    //LV_THEME_MATERIAL_FLAG_DARK
    
    lv_theme_t * th = lv_theme_material_init(LV_THEME_DEFAULT_COLOR_PRIMARY, LV_THEME_DEFAULT_COLOR_SECONDARY, LV_THEME_MATERIAL_FLAG_LIGHT, LV_THEME_DEFAULT_FONT_SMALL , LV_THEME_DEFAULT_FONT_NORMAL, LV_THEME_DEFAULT_FONT_SUBTITLE, LV_THEME_DEFAULT_FONT_TITLE);     
    lv_theme_set_act(th);

    lv_obj_t * scr = lv_obj_create(NULL, NULL);
    lv_scr_load(scr);

    bg_top = lv_obj_create(scr, NULL);
    lv_obj_clean_style_list(bg_top, LV_OBJ_PART_MAIN);
    lv_obj_set_style_local_bg_opa(bg_top, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT,LV_OPA_COVER);
    lv_obj_set_style_local_bg_color(bg_top, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT,LV_COLOR_NAVY);
    lv_obj_set_size(bg_top, LV_HOR_RES, 50);

    
    bg_middle1 = lv_obj_create(scr, NULL);
    lv_obj_clean_style_list(bg_middle1, LV_OBJ_PART_MAIN);
    lv_obj_set_style_local_bg_opa(bg_middle1, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT,LV_OPA_COVER);
    lv_obj_set_style_local_bg_color(bg_middle1, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT,LV_COLOR_WHITE);
    lv_obj_set_pos(bg_middle1, 0, 50);
    lv_obj_set_size(bg_middle1, LV_HOR_RES, 240);

    label_co2 = lv_label_create(bg_middle1, NULL);
    lv_label_set_long_mode(label_co2, LV_LABEL_LONG_SROLL_CIRC);
    lv_obj_set_width(label_co2, LV_HOR_RES - 20);
    lv_label_set_text(label_co2, "");
    lv_obj_align(label_co2, NULL,LV_LABEL_ALIGN_LEFT, 10, 20);


    label_temp = lv_label_create(bg_middle1, NULL);
    lv_label_set_long_mode(label_temp, LV_LABEL_LONG_SROLL_CIRC);
    lv_obj_set_width(label_temp, LV_HOR_RES - 20);
    lv_label_set_text(label_temp, "");
    lv_obj_align(label_temp, NULL,LV_LABEL_ALIGN_LEFT, 10, 40);


    label_hum = lv_label_create(bg_middle1, NULL);
    lv_label_set_long_mode(label_hum, LV_LABEL_LONG_SROLL_CIRC);
    lv_obj_set_width(label_hum, LV_HOR_RES - 20);
    lv_label_set_text(label_hum, "");
    lv_obj_align(label_temp, NULL,LV_LABEL_ALIGN_LEFT, 10, 60);
    



    bg_bottom = lv_obj_create(scr, NULL);
    lv_obj_clean_style_list(bg_bottom, LV_OBJ_PART_MAIN);
    lv_obj_set_style_local_bg_opa(bg_bottom, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT,LV_OPA_COVER);
    lv_obj_set_style_local_bg_color(bg_bottom, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT,LV_COLOR_ORANGE);
    lv_obj_set_pos(bg_bottom, 0, 290);
    lv_obj_set_size(bg_bottom, LV_HOR_RES, 30);

    label_status = lv_label_create(bg_bottom, NULL);
    lv_label_set_long_mode(label_status, LV_LABEL_LONG_SROLL_CIRC);
    lv_obj_set_width(label_status, LV_HOR_RES - 20);
    lv_label_set_text(label_status, "");
    lv_obj_align(label_status, NULL, LV_ALIGN_CENTER, 0, 0);
    
    LV_IMG_DECLARE(logo);
    lv_obj_t * img_src = lv_img_create(lv_scr_act(), NULL); /*Crate an image object*/
    lv_img_set_src(img_src, &logo);  /*Set the created file as image (a red fl  ower)*/
    lv_obj_set_pos(img_src, 45, 5);      /*Set the positions*/
    lv_obj_set_drag(img_src, true);
}

You can use lv_snprintf() for this kind of situation

uint8_t SensorBuff[BUFFER_SIZE]={0};
uint8_t SensorValue;
/** Get the sensor value and store into SensorValue variable */
/** load it into buffer using lv_snprintf() */
lv_snprintf(SensorBuff, sizeof(SensorBuff), "%d",SensorValue);
/** Send the buffer as a text to the label */
lv_label_set_text(LabelObj, SensorBuff);

Thank you

To avoid the extra buffer you can just use lv_label_set_text_fmt, which acts like printf but on a label.

Hi, if I use your method I have the next exception:

exit status 1
cannot convert ‘String’ to ‘const char*’ for argument ‘2’ to ‘void lv_label_set_text_fmt(lv_obj_t*, const char*, …)’

void loop()
{

    lv_task_handler(); /* let the GUI do its work */
    delay(5);

    String co2 = String(airSensor.getCO2());
    String temp = String(airSensor.getTemperature());
    String hum = String(airSensor.getHumidity());

    Serial.println(co2);
    Serial.println(temp);
    Serial.println(hum);
    
   

     lv_label_set_text_fmt(label_co2, co2);
     lv_label_set_text_fmt(label_temp, temp);
     lv_label_set_text_fmt(label_temp, temp);
     
  
    delay(2000);
}

Thanks

As the error message states:

cannot convert ‘String’ to ‘const char*’

Look at you previous example, where you used strcpy.

Sorry, I tried but the sensor value it’s a int or a string if i parse it, how can I do make work your example? I recive the next exception:

void loop()
{

      lv_task_handler(); /* let the GUI do its work */
    delay(5);

    String co2 = String(airSensor.getCO2());

      int c = co2.length();
      

    uint8_t SensorBuff[c] = {0};
    lv_snprintf(SensorBuff, sizeof(SensorBuff), "%d",co2);
    
    lv_label_set_text_fmt(label_co2, SensorBuff);
  
    delay(2000);
}

invalid conversion from ‘uint8_t* {aka unsigned char*}’ to ‘char*’ [-fpermissive]

Sorry if I don’t understand your example well.

Thanks.

Yes, do you mean that I must use my first example with lv_label_set_text_fmt?

I tried but nothing appear at the display.

void loop()
{

      lv_task_handler(); /* let the GUI do its work */
    delay(5);

    String co2 = String(airSensor.getCO2());
    String temp = String(airSensor.getTemperature());
    String hum = String(airSensor.getHumidity());

      int c = co2.length();
      int t = temp.length();
      int h = hum.length();

      
     char co2C[c+1];
     char tempC[t+1];
     char humC[h+ 1];

     strcpy(co2C, co2.c_str());
     strcpy(tempC, temp.c_str());
     strcpy(humC, hum.c_str());
     
    lv_label_set_text_fmt(label_co2, co2C);
    lv_label_set_text_fmt(label_temp, tempC);
    lv_label_set_text_fmt(label_hum, humC);
    delay(2000);
}

Thanks a lot

The function lv_label_set_text_fmt needs a pointer of type char*.
But you passed a pointer to a String object. That is not the same.
If you have a String object and need a char* from it,
you have to use the .c_str (), as you have it in strcpy. (… co2.c_str()

c_str () means please give me the char* pointer of the object (e.g. the co2) of type String

In your example it would have been

lv_label_set_text_fmt (label_co2, co2.c_str ());

But lv_label_set_text_fmt is more ment for doing this way:

if SensorValue is e.g. uint16_t SensorValue;

lv_label_set_text_fmt (label_co2, "CO2 value = %d", SensorValue);

but if SensorValue is already a string (char[]) but not a String!:

lv_label_set_text_fmt (label_co2, "CO2 value = %s", SensorValue);

You have to take care about the types. In C a string is an array of chars. In other languages a string is an object which holds internally an array of chars. But you need a specific function to get the internal array.
I

I tried the two options you say me, but the display is empty and not display the sensor data, what I’m doing wrong? Sorry if I’m very newby.

Display

Code 1

void loop()
{

      lv_task_handler(); /* let the GUI do its work */
    delay(5);

    String co2 = String(airSensor.getCO2());
    String temp = String(airSensor.getTemperature());
    String hum = String(airSensor.getHumidity());

     
    lv_label_set_text_fmt(label_co2, co2.c_str());
    lv_label_set_text_fmt(label_temp, temp.c_str());
    lv_label_set_text_fmt(label_hum, hum.c_str());
    delay(2000);
}

Code 2

void loop()
{

      lv_task_handler(); /* let the GUI do its work */
    delay(5);

    String co2 = String(airSensor.getCO2());
    String temp = String(airSensor.getTemperature());
    String hum = String(airSensor.getHumidity());

      int c = co2.length();
      int t = temp.length();
      int h = hum.length();

      
     char co2C[c+1];
     char tempC[t+1];
     char humC[h+ 1];

      sprintf(co2C, "%s", co2);
       sprintf(tempC, "%s", temp);
        sprintf(humC, "%s", hum);
     
    lv_label_set_text_fmt (label_co2, co2C);
    lv_label_set_text_fmt (label_temp, tempC);
    lv_label_set_text_fmt (label_temp, humC);
    
    
    delay(2000);
    
}

Thanks

Is function lv_main() called?

Is loop() called within a loop? Loop itself does not contain a loop.

I do not know what kind of development environment you have, but I would recommend to use the debugging facilities this environment provides. It means setting breakpoints and do single stepping through your code.
Especially for a newbie, I would say, it’s essential.

Yes lv_main is called, an the loop it’s a special function of arduino that repite in a loop
I’m using Arduino IDE, if I see the data with serial monitor it’s correct, but the display is empty, how can I display the data values in the loop?

Thanks in advance

Serial data
Display

Code:

#include <lvgl.h>
#include <TFT_eSPI.h>
#include <Wire.h>
#include <string.h>.
#include "SparkFun_SCD30_Arduino_Library.h" //Click here to get the library: http://librarymanager/All#SparkFun_SCD30
SCD30 airSensor;



TFT_eSPI tft = TFT_eSPI(); /* TFT instance */
static lv_disp_buf_t disp_buf;
static lv_color_t buf[LV_HOR_RES_MAX * 10];

static lv_obj_t * bg_top;
static lv_obj_t * bg_middle1;
static lv_obj_t * bg_bottom;
static lv_obj_t * label_status;
static lv_obj_t * label_co2;
static lv_obj_t * label_temp;
static lv_obj_t * label_hum;


#if USE_LV_LOG != 0
/* Serial debugging */
void my_print(lv_log_level_t level, const char * file, uint32_t line, const char * dsc)
{

    Serial.printf("%s@%d->%s\r\n", file, line, dsc);
    Serial.flush();
}
#endif

/* Display flushing */
void my_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);

    tft.startWrite();
    tft.setAddrWindow(area->x1, area->y1, w, h);
    tft.pushColors(&color_p->full, w * h, true);
    tft.endWrite();

    lv_disp_flush_ready(disp);
}

/* Reading input device (simulated encoder here) */
bool read_encoder(lv_indev_drv_t * indev, lv_indev_data_t * data)
{
    static int32_t last_diff = 0;
    int32_t diff = 0; /* Dummy - no movement */
    int btn_state = LV_INDEV_STATE_REL; /* Dummy - no press */

    data->enc_diff = diff - last_diff;;
    data->state = btn_state;

    last_diff = diff;

    return false;
}

void setup()
{
    pinMode(15, OUTPUT);
    digitalWrite(15, LOW);
    delay(1);
    Serial.begin(115200); /* prepare for possible serial debug */
    airSensor.begin();
    delay(100);
    airSensor.setMeasurementInterval(2);
    Serial.println("SCD30 Example");
    Wire.begin(25,26);
    
    lv_init();

#if USE_LV_LOG != 0
    lv_log_register_print_cb(my_print); /* register print function for debugging */
#endif

    tft.begin(); /* TFT init */
    tft.setRotation(2); /* Landscape orientation */

    lv_disp_buf_init(&disp_buf, buf, NULL, LV_HOR_RES_MAX * 10);

    /*Initialize the display*/
    lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv);
    disp_drv.hor_res = 240;
    disp_drv.ver_res = 320;
    disp_drv.flush_cb = my_disp_flush;
    disp_drv.buffer = &disp_buf;
    lv_disp_drv_register(&disp_drv);

    /*Initialize the (dummy) input device driver*/
    lv_indev_drv_t indev_drv;
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_ENCODER;
    indev_drv.read_cb = read_encoder;
    lv_indev_drv_register(&indev_drv);



  lv_main();    
}


void loop()
{

      lv_task_handler(); /* let the GUI do its work */
    delay(5);

    int co2 = airSensor.getCO2();
    float temp = airSensor.getTemperature();
    float hum = airSensor.getHumidity();

     char co2C[5];
     char tempC[5];
     char humC[5];


      sprintf(co2C, "%i", co2);
       sprintf(tempC, "%f", temp);
        sprintf(humC, "%f", hum);

     Serial.println(co2C);
      Serial.println(co2);
     Serial.println(tempC);
     Serial.println(temp);
     Serial.println(humC);
     Serial.println(hum);
     
    lv_label_set_text_fmt(label_co2, co2C);
    lv_label_set_text_fmt(label_temp, tempC);
    lv_label_set_text_fmt(label_temp, humC);
    
    
    delay(2000);
    
}



static void lv_main(){
    
    //LV_THEME_MATERIAL_FLAG_LIGHT
    //LV_THEME_MATERIAL_FLAG_DARK
    
    lv_theme_t * th = lv_theme_material_init(LV_THEME_DEFAULT_COLOR_PRIMARY, LV_THEME_DEFAULT_COLOR_SECONDARY, LV_THEME_MATERIAL_FLAG_LIGHT, LV_THEME_DEFAULT_FONT_SMALL , LV_THEME_DEFAULT_FONT_NORMAL, LV_THEME_DEFAULT_FONT_SUBTITLE, LV_THEME_DEFAULT_FONT_TITLE);     
    lv_theme_set_act(th);

    lv_obj_t * scr = lv_obj_create(NULL, NULL);
    lv_scr_load(scr);

    bg_top = lv_obj_create(scr, NULL);
    lv_obj_clean_style_list(bg_top, LV_OBJ_PART_MAIN);
    lv_obj_set_style_local_bg_opa(bg_top, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT,LV_OPA_COVER);
    lv_obj_set_style_local_bg_color(bg_top, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT,LV_COLOR_NAVY);
    lv_obj_set_size(bg_top, LV_HOR_RES, 50);

    
    bg_middle1 = lv_obj_create(scr, NULL);
    lv_obj_clean_style_list(bg_middle1, LV_OBJ_PART_MAIN);
    lv_obj_set_style_local_bg_opa(bg_middle1, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT,LV_OPA_COVER);
    lv_obj_set_style_local_bg_color(bg_middle1, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT,LV_COLOR_WHITE);
    lv_obj_set_pos(bg_middle1, 0, 50);
    lv_obj_set_size(bg_middle1, LV_HOR_RES, 240);

    label_co2 = lv_label_create(bg_middle1, NULL);
    lv_label_set_long_mode(label_co2, LV_LABEL_LONG_SROLL_CIRC);
    lv_obj_set_width(label_co2, LV_HOR_RES - 20);
    lv_label_set_text(label_co2, "");
    lv_obj_align(label_co2, NULL,LV_LABEL_ALIGN_LEFT, 10, 20);


    label_temp = lv_label_create(bg_middle1, NULL);
    lv_label_set_long_mode(label_temp, LV_LABEL_LONG_SROLL_CIRC);
    lv_obj_set_width(label_temp, LV_HOR_RES - 20);
    lv_label_set_text(label_temp, "");
    lv_obj_align(label_temp, NULL,LV_LABEL_ALIGN_LEFT, 10, 40);


    label_hum = lv_label_create(bg_middle1, NULL);
    lv_label_set_long_mode(label_hum, LV_LABEL_LONG_SROLL_CIRC);
    lv_obj_set_width(label_hum, LV_HOR_RES - 20);
    lv_label_set_text(label_hum, "");
    lv_obj_align(label_temp, NULL,LV_LABEL_ALIGN_LEFT, 10, 60);
    



    bg_bottom = lv_obj_create(scr, NULL);
    lv_obj_clean_style_list(bg_bottom, LV_OBJ_PART_MAIN);
    lv_obj_set_style_local_bg_opa(bg_bottom, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT,LV_OPA_COVER);
    lv_obj_set_style_local_bg_color(bg_bottom, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT,LV_COLOR_ORANGE);
    lv_obj_set_pos(bg_bottom, 0, 290);
    lv_obj_set_size(bg_bottom, LV_HOR_RES, 30);

    label_status = lv_label_create(bg_bottom, NULL);
    lv_label_set_long_mode(label_status, LV_LABEL_LONG_SROLL_CIRC);
    lv_obj_set_width(label_status, LV_HOR_RES - 20);
    lv_label_set_text(label_status, "");
    lv_obj_align(label_status, NULL, LV_ALIGN_CENTER, 0, 0);
    
    LV_IMG_DECLARE(logo);
    lv_obj_t * img_src = lv_img_create(lv_scr_act(), NULL); /*Crate an image object*/
    lv_img_set_src(img_src, &logo);  /*Set the created file as image (a red fl  ower)*/
    lv_obj_set_pos(img_src, 45, 5);      /*Set the positions*/
    lv_obj_set_drag(img_src, true);
}

Hi Alvaro,
Sorry for the delay in response.
Instead of

uint8_t SensorBuff[c] = {0};

can you use

char SensorBuff[c] = {0};

or include #include<stdint.h> if you are using

uint8_t SensorBuff[c] = {0};

Also regarding SensorBuff[c] your value of ‘c’ depends on the range of the values that your sensor can go up to.

for example, I like to print the speed of the vehicle. Range of the vehicle speed in general can range from 0 to 180. So if I would have to create a buffer I would create SensorBuff[4]. the last index if for '/0'

These inputs might help you I guess. Let me know if you still not able to resolve. Thank you

Thanks I finally solved it, it wall all because I wasn’t calling:

tick.attach_ms(LVGL_TICK_PERIOD, lv_tick_handler);

Thanks everyone for your support