ESP32 Analog style VU meter with GC9A01 Round Dispalys + Peak Meters
Simple to build ESP32 VU meter on Round Dispalys with Peak Meters.
Components and supplies
2
1N4007 1A 1000V Diode
2
ESP32
2
Resistor 220ohm
2
LED(Light Emitting Diode) White,Green,Red,Yellow,Blue Color
2
2.2" TFT Display
2
10k Resistor
Tools and machines
1
Soldering kit
Apps and platforms
1
Arduino IDE
Project description
Code
Code R
cpp
1// GCA901_Nano_voltage_meter 2// 3// grid voltage variation monitor (230V - 250V AC) 4// rolling averaged voltage (of 10 readings) is sent to display 5// NOTE: here voltage generated with random function 6// 7// microcontroller: Arduino Nano 8// display 240*240 circular SPI 3.3V TFT with GC9A01 controller 9// 10// note: random function drives fluctuations of the parameter named 'volt' 11// CG9A01 Arduino Nano 12// RST -------- NC 13// CST -------- 10 14// DC --------- 9 15// SDA -------- 11 - green wire 16// SCL -------- 13 - yellow wire 17// 18// Floris Wouterlood 19// September 1, 2023 20// public domain 21 22// made for a 240*240 pixel circular display 23// all x-y-coordinates relative to center = x = 120 and y = 120 24 25 #include "SPI.h" 26 #include "Adafruit_GFX.h" 27 #include "Adafruit_GC9A01A.h" 28 29 #define TFT_DC 2 30 #define TFT_CS 15 31 32 Adafruit_GC9A01A tft (TFT_CS, TFT_DC); 33 34 #define BLACK 0x0000 // some extra colors 35 #define BLUE 0x001F 36 #define RED 0xF800 37 #define GREEN 0x07E0 38 #define CYAN 0x07FF 39 #define MAGENTA 0xF81F 40 #define YELLOW 0xFFE0 41 #define WHITE 0xFFFF 42 #define ORANGE 0xFBE0 43 #define GREY 0x84B5 44 #define BORDEAUX 0xA000 45 #define AFRICA 0xAB21 // 0xce5f //0xAB21 // current dial color 46 const int vlez = 34; 47 #define DEG2RAD 0.0174532925 48 //int vlez; 49 int sig = 0; 50 int multiplier; 51 int frametime = 100; 52 int x_pos; 53 int y_pos; 54 int center_x = 120; // center x of dial on 240*240 TFT display 55 int center_y = 120; // center y of dial on 240*240 TFT display 56 float pivot_x, pivot_y,pivot_x_old, pivot_y_old; 57 float p1_x,p1_y,p2_x,p2_y,p3_x, p3_y, p4_x, p4_y, p5_x, p5_y; 58 float p1_x_old,p1_y_old, p2_x_old, p2_y_old, p3_x_old, p3_y_old; 59 float p4_x_old, p4_y_old, p5_x_old, p5_y_old; 60 float angleOffset = 3.14; 61 float arc_x; 62 float arc_y; 63 int radius = 120; // center y of circular scale 64 float angle_circle = 0; 65 float needleAngle = 0; 66 int iteration = 0; 67 int j; 68 float volt = 220; 69 int needle_multiplier = 1; 70 float needle_setter; 71 float currentNeedleValue = 230; // Start with a base voltage or level 72float needleSpeed = 10; // Speed at which the needle returns to the left 73 74 // to start with 75 76void setup() { 77 78 //randomSeed (analogRead(0)); 79 pinMode(12, OUTPUT); 80 81 82 pinMode(vlez, INPUT); 83 tft.begin(); 84 Serial.begin (9600); 85 Serial.println (""); 86 Serial.println (""); 87 tft.setRotation (0); 88 89 tft.fillScreen (BLACK); 90 tft.drawCircle (center_x, center_y,120, BLACK); 91 pivot_x = center_x; 92 pivot_y = center_y+50; 93 94 p1_x_old = center_x; p1_y_old = center_y+50; 95 p2_x_old = center_x; p2_y_old = center_y+50; 96 p3_x_old = center_x; p3_y_old = center_y+50; 97 p4_x_old = center_x; p4_y_old = center_y+50; 98 p5_x_old = center_x; p5_y_old = center_y+30; 99 100 create_dial (); 101 needle_setter = volt; 102 needleAngle = (((needle_setter)*DEG2RAD*1.8)-3.14); 103 needle(); 104 draw_pivot (); 105} 106 107 108void loop (){ 109 110 // Map the analog input (voltage) to the needle range 111 float targetNeedleValue = map(analogRead(vlez), 0, 400, 230, 270); 112 Serial.println(targetNeedleValue); 113 sig = analogRead(vlez); 114 if (sig > 280) {digitalWrite(12, HIGH);} else {digitalWrite(12, LOW);} 115 116 117 // If the target value is greater than the current needle position, move quickly 118 if (targetNeedleValue > currentNeedleValue) { 119 currentNeedleValue = targetNeedleValue; 120 } 121 // If the target value is lower, move more slowly to simulate damping 122 else if (targetNeedleValue < currentNeedleValue) { 123 currentNeedleValue -= needleSpeed; // Decrease the value gradually 124 if (currentNeedleValue < targetNeedleValue) { 125 currentNeedleValue = targetNeedleValue; // Ensure we don't overshoot 126 } 127 } 128 129 // Update the needle position 130 needle_setter = currentNeedleValue; 131 needle(); 132 draw_pivot(); 133 134 delay(frametime); // Control the update rate 135} 136 137 138void needle (){ // dynamic needle management 139 140 tft.drawLine (pivot_x, pivot_y, p1_x_old, p1_y_old, AFRICA); // remove old needle 141 tft.fillTriangle (p1_x_old, p1_y_old, p2_x_old, p2_y_old, p3_x_old, p3_y_old, AFRICA); // remove old arrow head 142 tft.fillTriangle (pivot_x, pivot_y, p4_x_old, p4_y_old, p5_x_old, p5_y_old, AFRICA); // remove old arrow head 143 144 needleAngle = (((needle_setter)*0.01745331*1.8)-3.14); 145 p1_x = (pivot_x + ((radius)*cos(needleAngle))); // needle tip 146 p1_y = (pivot_y + ((radius)*sin(needleAngle))); 147 148 p2_x = (pivot_x + ((radius-15)*cos(needleAngle-0.05))); // needle triange left 149 p2_y = (pivot_y + ((radius-15)*sin(needleAngle-0.05))); 150 151 p3_x = (pivot_x + ((radius-15)*cos(needleAngle+0.05))); // needle triange right 152 p3_y = (pivot_y + ((radius-15)*sin(needleAngle+0.05))); 153 154 p4_x = (pivot_x + ((radius-90)*cos(angleOffset+(needleAngle-0.2)))); // needle triange left 155 p4_y = (pivot_y + ((radius-90)*sin(angleOffset+(needleAngle-0.2)))); 156 157 p5_x = (pivot_x + ((radius-90)*cos(angleOffset+(needleAngle+0.2)))); // needle triange right 158 p5_y = (pivot_y + ((radius-90)*sin(angleOffset+(needleAngle+0.2)))); 159 160 p1_x_old = p1_x; p1_y_old = p1_y; // remember previous needle position 161 p2_x_old = p2_x; p2_y_old = p2_y; 162 p3_x_old = p3_x; p3_y_old = p3_y; 163 164 p4_x_old = p4_x; p4_y_old = p4_y; // remember previous needle counterweight position 165 p5_x_old = p5_x; p5_y_old = p5_y; 166 167 tft.drawLine (pivot_x, pivot_y, p1_x, p1_y, BLACK); // create needle 168 tft.fillTriangle (p1_x, p1_y, p2_x, p2_y, p3_x, p3_y, BLACK); // create needle tip pointer 169 // tft.drawLine (center_x-80, center_y+70, center_x+80,center_y+70, BLACK); // repair floor 170 tft.fillTriangle (pivot_x, pivot_y, p4_x, p4_y, p5_x, p5_y, BLACK); // create needle counterweight 171} 172 173 174void create_dial (){ 175 176 tft.fillCircle (center_x, center_y,120, AFRICA); // general dial field 177 tft.drawCircle (center_x, center_y,118,GREY); 178 tft.drawCircle (center_x, center_y,117,BLACK); 179 tft.drawCircle (center_x, center_y,116,BLACK); 180 tft.drawCircle (center_x, center_y,115,GREY); 181 182 for (j= 30; j<60 ; j+=5) 183 { 184 needleAngle = ((j*DEG2RAD*1.8)-3.14); 185 arc_x = (pivot_x + ((radius+15)*cos(needleAngle))); // needle tip 186 arc_y = (pivot_y + ((radius+15)*sin(needleAngle))); 187 tft.drawPixel (arc_x,arc_y, BLACK); 188 tft.fillCircle (arc_x,arc_y,2, BLACK); 189 } 190 191 for (j= 60; j<75 ; j+=5) 192 { 193 needleAngle = ((j*DEG2RAD*1.8)-3.14); 194 arc_x = (pivot_x + ((radius+15)*cos(needleAngle))); // needle tip 195 arc_y = (pivot_y + ((radius+15)*sin(needleAngle))); 196 tft.drawPixel (arc_x,arc_y, RED); 197 tft.fillCircle (arc_x,arc_y,2, RED); 198 } 199 200 tft.setTextColor (BLACK,AFRICA); 201 tft.setTextSize (4); 202 tft.setCursor (center_x+40, center_y+40); 203 tft.print ("VU"); 204 tft.setTextSize (4); 205 tft.setCursor (center_x-60, center_y+40); 206 tft.print ("R"); 207 208 // tft.drawLine (center_x-80, center_y+70, center_x+80,center_y+70, WHITE); // create floor 209} 210 211 212void draw_pivot (){ 213 214 tft.fillCircle (pivot_x, pivot_y,8,RED); 215 tft.drawCircle (pivot_x, pivot_y,8,BLACK); 216 tft.drawCircle (pivot_x, pivot_y,3,BLACK); 217}
Code L
cpp
...
1// GCA901_Nano_voltage_meter 2// 3// grid voltage variation monitor (230V - 250V AC) 4// rolling averaged voltage (of 10 readings) is sent to display 5// NOTE: here voltage generated with random function 6// 7// microcontroller: Arduino Nano 8// display 240*240 circular SPI 3.3V TFT with GC9A01 controller 9// 10// note: random function drives fluctuations of the parameter named 'volt' 11// CG9A01 Arduino Nano 12// RST -------- NC 13// CST -------- 10 14// DC --------- 9 15// SDA -------- 11 - green wire 16// SCL -------- 13 - yellow wire 17// 18// Floris Wouterlood 19// September 1, 2023 20// public domain 21 22// made for a 240*240 pixel circular display 23// all x-y-coordinates relative to center = x = 120 and y = 120 24 25 #include "SPI.h" 26 #include "Adafruit_GFX.h" 27 #include "Adafruit_GC9A01A.h" 28 29 #define TFT_DC 2 30 #define TFT_CS 15 31 32 Adafruit_GC9A01A tft (TFT_CS, TFT_DC); 33 34 #define BLACK 0x0000 // some extra colors 35 #define BLUE 0x001F 36 #define RED 0xF800 37 #define GREEN 0x07E0 38 #define CYAN 0x07FF 39 #define MAGENTA 0xF81F 40 #define YELLOW 0xFFE0 41 #define WHITE 0xFFFF 42 #define ORANGE 0xFBE0 43 #define GREY 0x84B5 44 #define BORDEAUX 0xA000 45 #define AFRICA 0xAB21 // 0xce5f //0xAB21 // current dial color 46 const int vlez = 34; 47 #define DEG2RAD 0.0174532925 48 //int vlez; 49 int sig = 0; 50 int multiplier; 51 int frametime = 100; 52 int x_pos; 53 int y_pos; 54 int center_x = 120; // center x of dial on 240*240 TFT display 55 int center_y = 120; // center y of dial on 240*240 TFT display 56 float pivot_x, pivot_y,pivot_x_old, pivot_y_old; 57 float p1_x,p1_y,p2_x,p2_y,p3_x, p3_y, p4_x, p4_y, p5_x, p5_y; 58 float p1_x_old,p1_y_old, p2_x_old, p2_y_old, p3_x_old, p3_y_old; 59 float p4_x_old, p4_y_old, p5_x_old, p5_y_old; 60 float angleOffset = 3.14; 61 float arc_x; 62 float arc_y; 63 int radius = 120; // center y of circular scale 64 float angle_circle = 0; 65 float needleAngle = 0; 66 int iteration = 0; 67 int j; 68 float volt = 220; 69 int needle_multiplier = 1; 70 float needle_setter; 71 float currentNeedleValue = 230; // Start with a base voltage or level 72float needleSpeed = 10; // Speed at which the needle returns to the left 73 74 // to start with 75 76void setup() { 77 78 //randomSeed (analogRead(0)); 79 pinMode(12, OUTPUT); 80 81 82 pinMode(vlez, INPUT); 83 tft.begin(); 84 Serial.begin (9600); 85 Serial.println (""); 86 Serial.println (""); 87 tft.setRotation (0); 88 89 tft.fillScreen (BLACK); 90 tft.drawCircle (center_x, center_y,120, BLACK); 91 pivot_x = center_x; 92 pivot_y = center_y+50; 93 94 p1_x_old = center_x; p1_y_old = center_y+50; 95 p2_x_old = center_x; p2_y_old = center_y+50; 96 p3_x_old = center_x; p3_y_old = center_y+50; 97 p4_x_old = center_x; p4_y_old = center_y+50; 98 p5_x_old = center_x; p5_y_old = center_y+30; 99 100 create_dial (); 101 needle_setter = volt; 102 needleAngle = (((needle_setter)*DEG2RAD*1.8)-3.14); 103 needle(); 104 draw_pivot (); 105} 106 107 108void loop (){ 109 110 // Map the analog input (voltage) to the needle range 111 float targetNeedleValue = map(analogRead(vlez), 0, 400, 230, 270); 112 Serial.println(targetNeedleValue); 113 sig = analogRead(vlez); 114 if (sig > 280) {digitalWrite(12, HIGH);} else {digitalWrite(12, LOW);} 115 116 117 // If the target value is greater than the current needle position, move quickly 118 if (targetNeedleValue > currentNeedleValue) { 119 currentNeedleValue = targetNeedleValue; 120 } 121 // If the target value is lower, move more slowly to simulate damping 122 else if (targetNeedleValue < currentNeedleValue) { 123 currentNeedleValue -= needleSpeed; // Decrease the value gradually 124 if (currentNeedleValue < targetNeedleValue) { 125 currentNeedleValue = targetNeedleValue; // Ensure we don't overshoot 126 } 127 } 128 129 // Update the needle position 130 needle_setter = currentNeedleValue; 131 needle(); 132 draw_pivot(); 133 134 delay(frametime); // Control the update rate 135} 136 137 138void needle (){ // dynamic needle management 139 140 tft.drawLine (pivot_x, pivot_y, p1_x_old, p1_y_old, AFRICA); // remove old needle 141 tft.fillTriangle (p1_x_old, p1_y_old, p2_x_old, p2_y_old, p3_x_old, p3_y_old, AFRICA); // remove old arrow head 142 tft.fillTriangle (pivot_x, pivot_y, p4_x_old, p4_y_old, p5_x_old, p5_y_old, AFRICA); // remove old arrow head 143 144 needleAngle = (((needle_setter)*0.01745331*1.8)-3.14); 145 p1_x = (pivot_x + ((radius)*cos(needleAngle))); // needle tip 146 p1_y = (pivot_y + ((radius)*sin(needleAngle))); 147 148 p2_x = (pivot_x + ((radius-15)*cos(needleAngle-0.05))); // needle triange left 149 p2_y = (pivot_y + ((radius-15)*sin(needleAngle-0.05))); 150 151 p3_x = (pivot_x + ((radius-15)*cos(needleAngle+0.05))); // needle triange right 152 p3_y = (pivot_y + ((radius-15)*sin(needleAngle+0.05))); 153 154 p4_x = (pivot_x + ((radius-90)*cos(angleOffset+(needleAngle-0.2)))); // needle triange left 155 p4_y = (pivot_y + ((radius-90)*sin(angleOffset+(needleAngle-0.2)))); 156 157 p5_x = (pivot_x + ((radius-90)*cos(angleOffset+(needleAngle+0.2)))); // needle triange right 158 p5_y = (pivot_y + ((radius-90)*sin(angleOffset+(needleAngle+0.2)))); 159 160 p1_x_old = p1_x; p1_y_old = p1_y; // remember previous needle position 161 p2_x_old = p2_x; p2_y_old = p2_y; 162 p3_x_old = p3_x; p3_y_old = p3_y; 163 164 p4_x_old = p4_x; p4_y_old = p4_y; // remember previous needle counterweight position 165 p5_x_old = p5_x; p5_y_old = p5_y; 166 167 tft.drawLine (pivot_x, pivot_y, p1_x, p1_y, BLACK); // create needle 168 tft.fillTriangle (p1_x, p1_y, p2_x, p2_y, p3_x, p3_y, BLACK); // create needle tip pointer 169 // tft.drawLine (center_x-80, center_y+70, center_x+80,center_y+70, BLACK); // repair floor 170 tft.fillTriangle (pivot_x, pivot_y, p4_x, p4_y, p5_x, p5_y, BLACK); // create needle counterweight 171} 172 173 174void create_dial (){ 175 176 tft.fillCircle (center_x, center_y,120, AFRICA); // general dial field 177 tft.drawCircle (center_x, center_y,118,GREY); 178 tft.drawCircle (center_x, center_y,117,BLACK); 179 tft.drawCircle (center_x, center_y,116,BLACK); 180 tft.drawCircle (center_x, center_y,115,GREY); 181 182 for (j= 30; j<60 ; j+=5) 183 { 184 needleAngle = ((j*DEG2RAD*1.8)-3.14); 185 arc_x = (pivot_x + ((radius+15)*cos(needleAngle))); // needle tip 186 arc_y = (pivot_y + ((radius+15)*sin(needleAngle))); 187 tft.drawPixel (arc_x,arc_y, BLACK); 188 tft.fillCircle (arc_x,arc_y,2, BLACK); 189 } 190 191 for (j= 60; j<75 ; j+=5) 192 { 193 needleAngle = ((j*DEG2RAD*1.8)-3.14); 194 arc_x = (pivot_x + ((radius+15)*cos(needleAngle))); // needle tip 195 arc_y = (pivot_y + ((radius+15)*sin(needleAngle))); 196 tft.drawPixel (arc_x,arc_y, RED); 197 tft.fillCircle (arc_x,arc_y,2, RED); 198 } 199 200 tft.setTextColor (BLACK,AFRICA); 201 tft.setTextSize (4); 202 tft.setCursor (center_x+55, center_y+40); 203 tft.print ("L"); 204 tft.setTextSize (4); 205 tft.setCursor (center_x-70, center_y+40); 206 tft.print ("VU"); 207 208 // tft.drawLine (center_x-80, center_y+70, center_x+80,center_y+70, WHITE); // create floor 209} 210 211 212void draw_pivot (){ 213 214 tft.fillCircle (pivot_x, pivot_y,8,RED); 215 tft.drawCircle (pivot_x, pivot_y,8,BLACK); 216 tft.drawCircle (pivot_x, pivot_y,3,BLACK); 217}
Downloadable files
Schematic
...
file.None

Comments
Only logged in users can leave comments