/*
Mechanical VU meter
Author: Marco Croce
Version: 1.0 - 09/2021
*/
// library used for the LCD display
#include <LiquidCrystal_I2C.h>
/*
Bit / Pixel Mapping to create the letters
and the symbols to show on the display
*/
byte c0[8] = {B11111, B00000, B00000, B00000, B00000, B00000, B00000, B11111};
byte c1[8] = {B11111, B00000, B10000, B10000, B10000, B10000, B00000, B11111};
byte c2[8] = {B11111, B00000, B11000, B11000, B11000, B11000, B00000, B11111};
byte c3[8] = {B11111, B00000, B11100, B11100, B11100, B11100, B00000, B11111};
byte c4[8] = {B11111, B00000, B11110, B11110, B11110, B11110, B00000, B11111};
byte c5[8] = {B11111, B00000, B11111, B11111, B11111, B11111, B00000, B11111};
byte C[8] = {B11100, B11110, B11111, B11111, B11111, B11111, B11110, B11100};
byte R[8] = {B00000, B11110, B10001, B10001, B11110, B10100, B10010, B10001};
byte L[8] = {B00000, B10000, B10000, B10000, B10000, B10000, B10000, B11111};
// Set the LCD's pin number through the constructor
LiquidCrystal_I2C lcd(0x27, 16, 2);
// Range of dB values
int valori[] = {-75, -50, -40, -30, -20, 0, 5, 10};
/*
Variables:
- valore -> The value of volts read using Arduino
- i -> A simple counter
- dbVU -> The value of dbVU obtained by valore
- livello -> A counter for the rectangles of the VU Meter
*/
int valore = 0, i = 0;
double dbVU;
int livello;
void setup()
{
// set up the LCD's number of columns and rows
lcd.init();
lcd.backlight();
// set up the pin from which to read the value
pinMode(A1, INPUT);
/*
Creation of the custom characters to be used
on the display
*/
lcd.createChar(1, c1);
lcd.createChar(2, c2);
lcd.createChar(3, c3);
lcd.createChar(4, c4);
lcd.createChar(5, c5);
lcd.createChar(6, c0);
lcd.createChar(7, C);
lcd.createChar(8, L);
lcd.createChar(9, R);
// Loading initial screen
lcd.setCursor(0, 0);
lcd.print(" VU METER ");
delay(500);
// Loading line
for ( livello = 0; livello < 16; livello++ )
{
lcd.setCursor(livello, 1);
lcd.write(5);
delay(100);
}
delay(500);
lcd.clear();
delay(500);
}
void loop()
{
// Letter L - LEFT
lcd.setCursor(0, 0);
lcd.write(8);
// Letter R - RIGHT
lcd.setCursor(0, 1);
lcd.write(9);
// Delimitation symbol C
lcd.setCursor(15, 0);
lcd.write(7);
lcd.setCursor(15, 1);
lcd.write(7);
delay(100);
// Voltage reading from the pin A1
do
{
valore = analogRead(A1);
} while ( valore <= 5 );
/*
1) valore*0.0049 -> Arduino reads 4.9 mV to unit, so this is
the conversion to volt
More info at: https://www.arduino.cc/reference/it/language/functions/analog-io/analogread/
2) valore*0.0049/1.2 -> 1.2 represents the value of SOL ( Standard Operative Level ), used
to indicate the maximum level to avoid the saturation, for VU Meter is 1.2 Volt
3) 20*log( valore*0.0049/1.2 ) -> This is the formula to converts values from volt to
db for VU Meter, dbVU
*/
dbVU = (log10((double)valore * 0.0049 / 1.2)) * 20;
// Setting the new rectangles
for (int i = 0, livello = 1; i < 7; i++)
{
if (valori[i] < dbVU) {
lcd.setCursor(livello, 0);
lcd.write(5);
lcd.setCursor(livello++, 1);
lcd.write(5);
delay(50);
lcd.setCursor(livello, 0);
lcd.write(5);
lcd.setCursor(livello++, 1);
lcd.write(5);
}
}
// Removing the old rectangles
for (int i = 7, livello = 14; i > 0; i--)
{
if (valori[i] > dbVU)
{
lcd.setCursor(livello, 0);
lcd.write(6);
lcd.setCursor(livello--, 1);
lcd.write(6);
delay(50);
lcd.setCursor(livello, 0);
lcd.write(6);
lcd.setCursor(livello--, 1);
lcd.write(6);
}
}
delay(100);
}