Simple and easy to build 2 x 14 bar stereo VU meter to represent audio level.
Devices and components
Arduino-Nano
Alphanumeric LCD, 16 x 2
100k ohm resistance
Through-hole resistor, 22 kohm
100nF capacitor
Materials and tools
Soldering iron (generic)
Software and tools
Arduino IDE
Project description
Easy to build
Fairly accurate representation of sound level
Very good entertainment and learning purposes
Can be driven with low audio level
It's easy to add/attach to existing PA or HiFi system
Linear representation of volume level (from approximately -14 dB to 0 dB)
Not precise enough for real studio performance or for use where accuracy is essential
High update rate may cause screen flickering
Low update rate may cause delay in representation
Main.cpp.ino
arduino
1/*
2 Arduino based VU meter by KTAudio.
3 Developed by ThomAce (Tamas Kamocsai) based on siemenwauters, theredstonelabz and michiel H's VU meter.
4
5 GNU GPL License v3
6
7 Developer: ThomAce (Tamas Kamocsai)
8 Mail: thomacepcg@gmail.com
9 Version: 1.0
10 Last modification date: 2019.09.24
11
12 Original version:
13 https://www.instructables.com/id/ARDUINO-VU-METER/
14
15 Original description:
16 VU meter by siemenwauters, theredstonelabz and michiel H don't forget to like and subscribe to support my work. tnx
17*/
18
19#include <LiquidCrystal.h>
20
21byte Bar[8] = {
22 B11111,
23 B00000,
24 B11111,
25 B11111,
26 B11111,
27 B11111,
28 B00000,
29 B11111
30};
31
32byte L[8] = {
33 B00111,
34 B01000,
35 B10100,
36 B10100,
37 B10100,
38 B10111,
39 B01000,
40 B00111
41};
42
43byte R[8] = {
44 B00111,
45 B01000,
46 B10110,
47 B10101,
48 B10110,
49 B10101,
50 B01000,
51 B00111
52};
53
54byte EndMark[8] = {
55 B10000,
56 B01000,
57 B00100,
58 B00100,
59 B00100,
60 B00100,
61 B01000,
62 B10000
63};
64
65byte EmptyBar[8] = {
66 B11111,
67 B00000,
68 B00000,
69 B00000,
70 B00000,
71 B00000,
72 B00000,
73 B11111
74};
75
76byte peakHoldChar[8] = {
77 B11111,
78 B00000,
79 B01110,
80 B01110,
81 B01110,
82 B01110,
83 B00000,
84 B11111
85};
86
87String main_version = "1.0";
88int left, right; //Variables to store and calculate the channel levels
89const int numReadings = 5; //Refresh rate. Lower value = higher rate. 5 is the defaul
90int indexL = 0; //Actual channel index
91int totalL = 0; //Total channel data
92int maxL = 0; //Maximal level
93int indexR = 0;
94int totalR = 0;
95int maxR = 0;
96int inputPinL = A1; //Input pin Analog 1 for LEFT channel
97int inputPinR = A0; //Input pin Analog 0 for RIGHT channel
98int volL = 0;
99int volR = 0;
100int rightAvg = 0;
101int leftAvg = 0;
102long peakHoldTime = 1500; //peak hold time in miliseconds
103long peakHold = 0;
104int rightPeak = 0;
105int leftPeak = 0;
106long decayTime = 0;
107long actualMillis = 0;
108
109LiquidCrystal lcd(11, 10, 7, 6, 5, 4); //lcd configuration
110
111void setup()
112{
113 lcd.begin(40, 2); //Setting up LCD. 16 chars and 2 rows
114
115 lcd.createChar(1, Bar);
116 lcd.createChar(2, L);
117 lcd.createChar(3, R);
118 lcd.createChar(4, EmptyBar);
119 lcd.createChar(5, EndMark);
120 lcd.createChar(6, peakHoldChar);
121
122 //Showing loading message and loading bar
123
124 String KTAudio = "KTaudio project";
125
126 for (int i = 0; i <= 16; i++)
127 {
128 lcd.setCursor(0, 0);
129 lcd.print(KTAudio.substring(0, i));
130 delay(50);
131 }
132
133 KTAudio = "VU meter " + main_version;
134
135 for (int i = 0; i <= KTAudio.length(); i++)
136 {
137 lcd.setCursor(0, 1);
138 lcd.print(KTAudio.substring(0, i));
139 delay(50);
140 }
141
142 delay(500);
143
144 lcd.clear();
145 lcd.setCursor(0, 0);
146 lcd.print("Loading...");
147
148 for (int i = 0; i < 16; i++)
149 {
150 lcd.setCursor(i, 1);
151 lcd.write(4);
152 }
153
154 for (int i = 0; i < 16; i++)
155 {
156 lcd.setCursor(i, 1);
157 lcd.write(1);
158
159 delay(50);
160 }
161
162 delay(500);
163 lcd.clear();
164
165 decayTime = millis();
166}
167
168void loop()
169{
170 actualMillis = millis();
171
172 lcd.setCursor(0, 0); //L channel index
173 lcd.write(2); //L symbol
174 lcd.setCursor(0, 1); //R channel index
175 lcd.write(3); //R symbol
176 lcd.setCursor(15, 0); //closing tag / end mark index 1
177 lcd.write(5); //closing tag / end mark
178 lcd.setCursor(15, 1); //closing tag / end mark index 2
179 lcd.write(5); //closing tag / end mark
180
181 totalL = analogRead(inputPinL) / 4 - 128; //reducing the detected hum and noise
182
183 if(totalL > maxL)
184 {
185 maxL = totalL;
186 }
187
188 indexL++;
189
190 if (indexL >= numReadings)
191 {
192 indexL = 0;
193 left = maxL;
194 maxL = 0;
195 }
196
197 totalR = analogRead(inputPinR) / 4 - 128; //reducing the detected hum and noise
198
199 if(totalR > maxR)
200 {
201 maxR = totalR;
202 }
203
204 indexR++;
205
206 if (indexR >= numReadings)
207 {
208 indexR = 0;
209 right = maxR;
210 maxR = 0;
211 }
212
213 volR = right / 3;
214
215 if(volR > 14)
216 {
217 volR = 14;
218 }
219
220 if (volR < (rightAvg - 2))
221 {
222 if (decayTime < actualMillis)
223 rightAvg--;
224
225 volR = rightAvg;
226 }
227 else if (volR > (rightAvg + 2))
228 {
229 volR = (rightAvg + 2);
230 rightAvg = volR;
231 }
232 else
233 {
234 rightAvg = volR;
235 }
236
237 if (volR > rightPeak)
238 {
239 rightPeak = volR;
240 }
241
242 drawBar(volR, rightPeak, 1);
243
244 volL = left / 3;
245
246 if(volL > 14)
247 {
248 volL = 14;
249 }
250
251 if (volL < (leftAvg - 2))
252 {
253 if (decayTime < actualMillis)
254 leftAvg--;
255
256 volL = leftAvg;
257 }
258 else if (volL > (leftAvg + 2))
259 {
260 volL = (leftAvg + 2);
261 leftAvg = volL;
262 }
263 else
264 {
265 leftAvg = volL;
266 }
267
268 if (volL > leftPeak)
269 {
270 leftPeak = volL;
271 }
272
273 drawBar(volL, leftPeak, 0);
274
275 if (decayTime < actualMillis)
276 decayTime = (millis() + 50);
277
278 if (peakHold < actualMillis)
279 {
280 peakHold = (millis() + peakHoldTime);
281 rightPeak = -1;
282 leftPeak = -1;
283 }
284}
285
286void drawBar(int data, int peakData, int row)
287{
288 //If the previous peak data is 1 or 0, then not taking care of the value.
289 if (peakData < 2)
290 {
291 peakData = -1;
292 }
293
294 //First char (idx 0) = R or L
295 //Last (16th) char (idx 15) is the closing mark of the bar.
296 //We have 14 chars to write.
297 for (int col = 1; col < 15; col++)
298 {
299 lcd.setCursor(col, row);
300
301 if (col < data)
302 {
303 lcd.write(1); //write bar element
304 }
305 else if (peakData == col)
306 {
307 lcd.write(6); //write the peak marker
308 }
309 else
310 {
311 lcd.write(4); //write "empty"
312 }
313 }
314}
315
Downloadable files
Wiring diagram
Wiring diagram
Wiring diagram
Wiring diagram
Note: Content and images are from: https://projecthub.arduino.cc/, with some modifications.
If you want it removed due to copyright reasons, please leave a comment. Thank you.
I want to share this article more widely so that everyone knows about Arduino and your project.