[Simulator] How to make the needle of the gauge move with specific time interval?

Description

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

Code Blocks c/c++ compiler

What LVGL version are you using?

the package of the simulator. Do not know the release version.

What do you want to achieve?

After clicking the button I put on the same page, the text on the button should change from “Start” to “Running” and one needle of the gauge should move from 20 to 80, with a time interval of 5 seconds and a value interval of 5. After reaching the value of 80, the text on the button should become Reset.

What have you tried so far?

Using a sleep() function to force the gauge to wait for 5 seconds after changing the value of the needle. But the process of changing the values is not shown when I was running the demo.

Code to reproduce

The code block(s) should be formatted like:

static lv_obj_t * gauge1;
static lv_obj_t * gauge_btn;
static lv_obj_t * gauge_button_label;

static void gauge_create(lv_obj_t * parent)
{
    /*Create a style*/
    static lv_style_t style;
    lv_style_copy(&style, &lv_style_pretty_color);
    style.body.main_color = lv_color_hex3(0x666);     /*Line color at the beginning*/
    style.body.grad_color =  lv_color_hex3(0x666);    /*Line color at the end*/
    style.body.padding.left = 10;                      /*Scale line length*/
    style.body.padding.inner = 8 ;                    /*Scale label padding*/
    style.body.border.color = lv_color_hex3(0x333);   /*Needle middle circle color*/
    style.line.width = 3;
    style.text.color = lv_color_hex3(0x333);
    style.line.color = LV_COLOR_RED;                  /*Line color after the critical value*/

    /*Describe the color for the needles*/
    static lv_color_t needle_colors[3];
    needle_colors[0] = LV_COLOR_BLUE;
    needle_colors[1] = LV_COLOR_ORANGE;
    needle_colors[2] = LV_COLOR_PURPLE;

    /*Create a gauge*/
    gauge1 = lv_gauge_create(parent, NULL);
    lv_gauge_set_style(gauge1, LV_GAUGE_STYLE_MAIN, &style);
    lv_gauge_set_needle_count(gauge1, 3, needle_colors);
    lv_obj_set_size(gauge1, 150, 150);
    lv_obj_align(gauge1, NULL, LV_ALIGN_IN_TOP_MID, 0, 20);

    /*Set the values*/
    lv_gauge_set_value(gauge1, 0, 10);
    lv_gauge_set_value(gauge1, 1, 20);
    lv_gauge_set_value(gauge1, 2, 30);

    gauge_btn = lv_btn_create(parent, NULL);
    lv_obj_set_event_cb(gauge_btn, gauge_button_event_handler);
    lv_obj_align(gauge_btn, NULL, LV_ALIGN_CENTER, 0, -40);

    gauge_button_label = lv_label_create(gauge_btn, NULL);
    lv_label_set_text(gauge_button_label, "Start");
}

static void gauge_button_event_handler(lv_obj_t * obj, lv_event_t event)
{
    static bool clicked = false;

    if(event == LV_EVENT_CLICKED){
        clicked = !clicked;

        if(clicked){
            lv_label_set_text(gauge_button_label, "Running");

            for(int16_t i = 20; i <= 80; i++){
                lv_gauge_set_value(gauge1, 1, i);
                sleep(5);
            }

            lv_label_set_text(gauge_button_label, "Reset");
        }
        else{
            lv_label_set_text(gauge_button_label, "Start");
            lv_gauge_set_value(gauge1, 1, 20);
        }
    }
}

Screenshot and/or video

If possible, add screenshots and/or videos about the current state.

Hi @IvyHu ,

Looking at the code, you are probably using version 6.0 of the LVGL library, it might be worth updating if you can, here is a link to the latest repository.

I believe the problem is, you are calling the blocking sleep() function in the event handler. It is not advisable to call blocking functions from the event handlers as it will prevent the LVGL scheduler from running for the duration of the sleep halting all screen drawing and LVGL processing etc.

To process this type of application you will need to restructure the way you code it. In your event handlers you need to be able to notify another thread of execution that something needs to be changed.

The way I would deal with this type of scenario would be to create a LVGL task function which executes every 50mS or so This would check a global queue of events received from various event handlers and executes the appropriate actions.

This is how to create a task:

lv_task_create((void*)process_gui_event, 50, LV_TASK_PRIO_LOW, NULL ); 

In the event handler again you must not call any blocking functions so for timed actions like your requirement, you will need to trigger and increment a static counter to simulate a sleep condition with that counter incrementing in 50mS increments each time the LVGL scheduler calls the task function. So in your posted example when you counter reaches 100 you would make your call to lv_gauge_set_value(gauge1, 1, i); with you variable ‘i’ also being static and incremented by each entry to the task function once the event is triggered. Obviously you will need a static flag(s) to keep track of the progress of the function also.

If you have plans to implement your application on a micro-controller later and have access to some form of OS on that platform this type of thing can normally be implemented quite easily and efficiently using queues/semaphores/mutexes if available from the OS.

I hope this makes sense, and is helpful.

Kind Regards,

Pete

2 Likes