Retro Analog VU Meter on Round dispalys (ESP32 and GC9A01)
Using the LVGL library and SquareLine Studio, I created a visualization that is not only functional, but also aesthetically enriches any audio system.
Devices & Components
2
3mm LED
2
GC9A01 Round Display
2
ESP32
Hardware & Tools
1
Soldering Iron Kit
Software & Tools
Arduino IDE
Project description
Code
Code
cpp
...
1#include <lvgl.h> 2#include <TFT_eSPI.h> 3#include "ui.h" 4 5#define AUDIO_PIN 34 6 7#define PEAK_LED_PIN 12 8#define PEAK_THRESHOLD 35 9 10static TFT_eSPI tft = TFT_eSPI(); 11static lv_disp_draw_buf_t draw_buf; 12static lv_color_t *buf1; 13static lv_color_t *buf2; 14 15static uint32_t peak_timer = 0; 16const uint32_t peak_hold_duration = 100; // Милисекунди колку да свети LED-от 17 18// Променливи за филтрирање на сигналот 19float smoothed_val = 0; 20const float filter_coeff = 0.1; // Колку е помало, толку е помазна стрелката (0.01 - 0.2) 21 22void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) { 23 uint32_t w = (area->x2 - area->x1 + 1); 24 uint32_t h = (area->y2 - area->y1 + 1); 25 tft.startWrite(); 26 tft.setAddrWindow(area->x1, area->y1, w, h); 27 tft.pushColors((uint16_t *)&color_p->full, w * h, true); 28 tft.endWrite(); 29 lv_disp_flush_ready(disp); 30} 31 32void setup() { 33 Serial.begin(115200); 34 delay(500); 35 Serial.println("Start initializing..."); 36 pinMode(PEAK_LED_PIN, OUTPUT); 37 digitalWrite(PEAK_LED_PIN, LOW); // Почетно исклучена 38 39 tft.begin(); 40 tft.setRotation(0); 41 tft.fillScreen(TFT_BLACK); 42 43 lv_init(); 44 45 // Важно: Постави ја централната точка на ротација за стрелката 46 // Ова зависи од твојот дизајн во SquareLine (пример: средина на сликата) 47 48 49 const uint32_t buf_pixels = 240 * 40; 50 buf1 = (lv_color_t *)heap_caps_malloc(buf_pixels * sizeof(lv_color_t), MALLOC_CAP_DMA); 51 buf2 = (lv_color_t *)heap_caps_malloc(buf_pixels * sizeof(lv_color_t), MALLOC_CAP_DMA); 52 53 lv_disp_draw_buf_init(&draw_buf, buf1, buf2, buf_pixels); 54 55 static lv_disp_drv_t disp_drv; 56 lv_disp_drv_init(&disp_drv); 57 disp_drv.hor_res = 240; 58 disp_drv.ver_res = 240; 59 disp_drv.flush_cb = my_disp_flush; 60 disp_drv.draw_buf = &draw_buf; 61 lv_disp_drv_register(&disp_drv); 62 63 ui_init(); 64 Serial.println("UI Initialized"); 65 // Важно: Постави ја централната точка на ротација за стрелката 66 // Ова зависи од твојот дизајн во SquareLine (пример: средина на сликата) 67 lv_img_set_pivot(ui_Image2, 15, 108); 68 69} 70 71void loop() { 72 // 1. Повикувај го LVGL хандлерот 73 lv_timer_handler(); 74 75 // 2. Читај го сигналот на секои 20ms (50 пати во секунда е доволно) 76 static uint32_t last_millis = 0; 77 if (millis() - last_millis > 20) { 78 last_millis = millis(); 79 80 int raw_val = analogRead(AUDIO_PIN); 81 Serial.println(raw_val); 82 // Едноставен Low-pass филтер за "мрзлива" стрелка 83 smoothed_val = (raw_val * filter_coeff) + (smoothed_val * (1.0 - filter_coeff)); 84 85 if (ui_Image2 != NULL) { 86 // Мапирање на измазнетата вредност 87 // Користиме -450 до 450 (вкупно 90 степени) - прилагоди по потреба 88 int16_t angle = map((int)smoothed_val, 0, 50, -450, 450); 89 90 // Постави го аголот само ако објектот е валиден 91 lv_img_set_angle(ui_Image2, angle); 92 } 93 94 95if (smoothed_val >= PEAK_THRESHOLD) { 96 digitalWrite(PEAK_LED_PIN, HIGH); 97 peak_timer = millis(); // Ресетирај го тајмерот на секој нов пик 98 } 99 // Ако поминало времето на задршка, исклучи ја диодата 100 else if (millis() - peak_timer > peak_hold_duration) { 101 digitalWrite(PEAK_LED_PIN, LOW); 102 } 103 } 104 105 106 delay(5); 107}
Documentation
Sch
...
schematic.jpg

Comments
Only logged in users can leave comments