Elecrow's 2nd Electronics Design Contest is Heating Up! Win $6,000 cash + Maker products + Official sponsorship! Share your designs today! [Learn More]

user-img

Markus Edenhauser

  • 1 Projects
  • 1 Followers
  • Mar 11,2025
+ Follow

Timer with LVGL Widget and 1.28 Round Display

A compact and visually engaging timer app using an Elecrow 1.28-inch round display and LVGL. Start the countdown with a button, track progress with an arc widget, and handle I2C input for extended control. Ideal for Arduino projects requiring an interactive timer with touch functionality and hardware integration. ????

Timer with LVGL Widget and 1.28 Round Display
 
  • thumbnail-img
  • thumbnail-img
 

Story

Project Idea

This project involves using an Elecrow 1.28-inch round display in combination with the LVGL (LittlevGL) graphics library and a custom Arduino setup. The goal is to create a timer application where the user can start the countdown using a button. The display shows an arc widget representing the timer's progress and a label indicating the remaining time.

The project also demonstrates handling touch input and I2C communication for additional control features, such as managing external I/O pins for peripheral interaction.

Display 1 Display 2

Setup Requirements

Info: The basic setup, including the configuration of lv_conf.h and User_sSetup.h for TFT_eSPI, has already been completed according to Elecrow's instructions.

https://www.elecrow.com/wiki/ESP32_1.28-inch_Round_Display_Tutorial.html#tutorial-on-arduino-ide

Code

global Variables

The following global variables are used in this project:

  1. bool timerstart = false;
    This variable tracks whether the timer has started or not. It is initially set to false and will be changed to true when the "Go" button is pressed, indicatin:g the start of the timer.

  2. unsigned long previousMillis = millis();
    This variable stores the time at which the timer was last updated. It is used to track the passage of time and trigger updates every second (1000 ms).

  3. lv_obj_t* arc_obj;
    This pointer refers to the arc object on the display, which visually represents the timer's countdown.

  4. lv_obj_t* label_obj;
    This pointer refers to the label object that displays the current timer value on the screen.

Setup

In the setup(), the three LVGL widgets are created and configured as follows:

  1. Arc Widget (Timer)

    lv_obj_t *arc = lv_arc_create(lv_scr_act());
    lv_obj_set_size(arc, 180, 180);
    lv_arc_set_rotation(arc, 135);
    lv_arc_set_bg_angles(arc, 0, 270);
    lv_arc_set_value(arc, 10);
    lv_obj_center(arc);
    

    An arc (progress circle) is created on the screen. Its size is set to 180x180, and it's rotated by 135 degrees. The background angles of the arc are set from 0 to 270 degrees, and the initial value of the arc is set to 10. Finally, the arc is centered on the screen.

  2. Label Widget (Text Display)

    lv_obj_t *label = lv_label_create(arc);
    lv_label_set_text(label, "Timer");
    lv_obj_center(label);
    lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
    label_obj = label;
    

    A label is created inside the arc object, displaying the text "Timer". It is centered, and the label is stored in the label_obj variable for later use.

  3. Button Widget (Go Button)

    lv_obj_t *btn = lv_btn_create(lv_scr_act());
    lv_obj_set_style_bg_color(btn, lv_palette_main(LV_PALETTE_GREEN), 0);
    lv_obj_set_size(btn, 60, 30);
    lv_obj_align_to(btn, arc, LV_ALIGN_CENTER, 0, 35);
    
    lv_obj_t *btn_label = lv_label_create(btn);  
    lv_label_set_text(btn_label, "Go");
    lv_obj_center(btn_label);
    

    A button is created on the screen with a green background. Its size is set to 60x30 pixels, and it's positioned below the arc, centered. Inside the button, a label with the text "Go" is created and centered.

    Finally, event callbacks are added:

    lv_obj_add_event_cb(arc, arc_changed, LV_EVENT_VALUE_CHANGED, label);
    lv_obj_add_event_cb(btn, button_go_event, LV_EVENT_CLICKED, NULL);
    

    The arc gets an event callback for changes in its value (LV_EVENT_VALUE_CHANGED), and the button gets an event callback for clicks (LV_EVENT_CLICKED).

event handler

Here is an explanation of the two event handlers:

arc_changed(lv_event_t *e)

This event handler is triggered when the value of the arc widget changes (due to user interaction with the arc).

static void arc_changed(lv_event_t *e) {
  lv_event_code_t code = lv_event_get_code(e);              // Get the event code
  lv_obj_t *arc = (lv_obj_t *)lv_event_get_target(e);       // Object that generated the event (arc)
  lv_obj_t *label = (lv_obj_t *)lv_event_get_user_data(e);  // Label or other UI elements we want to update (Optional)

  arc_obj = arc;

  if (code == LV_EVENT_VALUE_CHANGED) {
    int timercnt = lv_arc_get_value(arc);                    // Get the new value of the arc
    lv_label_set_text_fmt(label, "%d", timercnt);            // Update the label text with the new value
  }
}
  • lv_event_get_code(e): Retrieves the event code (e.g., whether it's a value change, button click, etc.).
  • lv_event_get_target(e): Gets the object that triggered the event, in this case, the arc widget.
  • lv_event_get_user_data(e): Gets any additional data associated with the event. Here, it's used to pass the label widget, which will be updated with the arc's value.
  • lv_arc_get_value(arc): Retrieves the current value of the arc widget.
  • lv_label_set_text_fmt(label, "%d", timercnt): Updates the label with the new value of the arc.

This handler updates the label with the current value of the arc when the arc's value changes.

button_go_event(lv_event_t *e)

This event handler is triggered when the "Go" button is clicked.

static void button_go_event(lv_event_t *e) {
    LV_LOG_USER("lets go");
    timerstart = true;
}
  • LV_LOG_USER("lets go"): Logs a user message to indicate the button click event occurred.
  • timerstart = true: Sets the timerstart flag to true, which presumably controls the starting of a timer or some other functionality in the application.

This handler simply logs a message and sets the timerstart flag to true when the button is clicked.

Loop

Here’s an explanation of the code in the loop:

unsigned long currentMillis = millis();
if (timerstart) {
  if (currentMillis - previousMillis >= 1000) {
    previousMillis = currentMillis;
    int timercnt = lv_arc_get_value(arc_obj);  // Get the current value of the arc

    if (timercnt > 0) {
      decrement_timer();  // Decrement the timer value
    }
    else if(timercnt <= 0) {
      // When the timer reaches 0, execute the following actions:
      for (int i = 0; i < 5; i++) {
        set_pin_io(0, true);  // Set the pin to high (turn on the hardware)

        tft.fillScreen(TFT_RED);  // Fill the screen with red color
        delay(500);  // Wait for 500 milliseconds

        set_pin_io(0, false);  // Set the pin to low (turn off the hardware)
        tft.fillScreen(TFT_BLACK);  // Fill the screen with black color
        delay(500);  // Wait for 500 milliseconds
      }

      esp_restart();  // Restart the ESP device
    }
  }
}

Explanation:

  • millis(): This function returns the number of milliseconds since the program started. It is used to create non-blocking delays, which ensures that the program can continue running other code while waiting for a timeout.
  • currentMillis - previousMillis >= 1000: This checks if 1 second has passed since the last check. If it has, the previousMillis variable is updated to the current time, and the timer's value is checked.
  • lv_arc_get_value(arc_obj): Retrieves the current value from the arc widget.
  • decrement_timer(): This function is assumed to decrement the timer's value by 1 (not shown here). It would be used to reduce the timer count as time passes.
  • When the timer reaches 0 (or less):
    • A loop runs 5 times.
    • set_pin_io(0, true) turns the pin (possibly a LED or relay) on.
    • tft.fillScreen(TFT_RED) fills the screen with a red color.
    • delay(500) waits for 500 milliseconds.
    • set_pin_io(0, false) turns the pin off.
    • tft.fillScreen(TFT_BLACK) changes the screen to black.
    • esp_restart() restarts the ESP device once the blinking sequence completes.

This loop controls the timer countdown and, when the timer reaches 0, triggers a blinking red and black screen sequence with hardware control (through the pin), followed by a device restart.

The decrement_timer() function is responsible for decrementing the value of the arc widget and updating the corresponding label. Here's how it works:

void decrement_timer() {
  int current_value = lv_arc_get_value(arc_obj);  // Get the current value of the arc widget
  current_value--;  // Decrement the value by 1
  lv_arc_set_value(arc_obj, current_value);  // Set the new value back to the arc widget
  lv_label_set_text(label_obj, String(current_value).c_str());  // Update the label with the new value
}

Explanation:

  1. lv_arc_get_value(arc_obj): This function retrieves the current value of the arc widget (arc_obj), which represents the timer value in this case.
  2. current_value--: Decreases the value of the timer by 1.
  3. lv_arc_set_value(arc_obj, current_value): Sets the updated value back to the arc widget, which visually represents the timer.
  4. lv_label_set_text(label_obj, String(current_value).c_str()): Updates the label (label_obj) with the new value of the timer. The String(current_value).c_str() converts the integer current_value to a C-string to be displayed as text on the label.

This function ensures that both the arc widget and its label stay in sync as the timer decreases.

Topic
View All

Timer with LVGL Widget and 1.28 Round Display

A compact and visually engaging timer app using an Elecrow 1.28-inch round display and LVGL. Start the countdown with a button, track progress with an arc widget, and handle I2C input for extended control. Ideal for Arduino projects requiring an interactive timer with touch functionality and hardware integration. ????

72
 
1
0
0

Share your project on social media to expand its influence! Get more people to support it.

  • Comments( 0 )
  • Like( 1 )
/1000
Upload a photo:
You can only upload 1 files in total. Each file cannot exceed 2MB. Supports JPG, JPEG, GIF, PNG, BMP

You May Also Like

View All
Add to cart
Board Type : GerberFile :
Layer : Dimensions :
PCB Qty :
Different PCB Design
PCB Thickness : PCB Color :
Surface Finish : Castellated Hole :
Copper Weight : 1 oz Production Time :
Total: US $
As a sharing platform, our community will not bear responsibility for any issues with this design and parameters.

PCB Assembly

PCBA Qty: BomFile:
NO. OF UNIQUE PARTS: NO. of Components:
Assembly Cost: US $
As a sharing platform, our community will not bear responsibility for any issues with this design and parameters.
Add to cart
3dPrintingFile : Size :
Unit : Volumn :
3D Printing Qty : Material :
Total: US $12.99
As a sharing platform, our community will not bear responsibility for any issues with this design and parameters.
Add to cart
Acrylic Type : AcrylicFile :
Dimensions: Engrave:
Acrylic Qty :
Acrylic Thickness:
Acrylic Color:
Total: US $12.99
As a sharing platform, our community will not bear responsibility for any issues with this design and parameters.
Add to cart
CNC Milling File : Size:
Unit: Volumn:
CNC Milling Qty : Material:
Type of Aluminum: Surface Finish:
Tolerance:
Surface Roughness:
Total: US $12.99
As a sharing platform, our community will not bear responsibility for any issues with this design and parameters.
Add to cart
Item Price Qty Subtotal Delete
Total: US $0.00
As a sharing platform, our community will not bear responsibility for any issues with this design and parameters.