Hey friend in this blog post I am making an Ultimate and
Smooth VU Meter using Arduino and 74HC595 ICs (Integrated Circuit) or Serial
Shift Register IC. It is a Stereo VU Meter which work with Two Analog Inputs
for both Stereo Channels (Left and Right) and respond with the Analog Values by
proper Map function to Decibels values on Arduino. It has 40 LEDs which respond
to Analog Values corresponding to each LEDs. I saw a lots of VU Meter and try
to make one but not every VU Meter is efficient and smooth and sometime blink
and Haze effect, so I decided to make one by own which work like Studio
Equipment type and also visualize like real Studio Audio Equipment’s like
Amplifier, Audio Mixing Console, Microphone Tuner, Audio Interface, MIDI
Controller and Many More (I also get the Idea from here and very curious for it,
I like Audio DIY Stuff so Much so also stay tune with me and Subscribe my
Channel). It enchase with the Peak and Hold feature, It show real time peak
values for 1 second in each of the LEDs and slowly (1 sec time dependent) goes
down to starting LED.
You can also enjoy with your
Home Theatre or Home DJ System but please don't turn up the volume too much in
excitement; otherwise, it could break the glass in other people's homes (If you
have DJ in your home). So let’s make it
one.
Part Needed On this project
1x Arduino Microcontroller (Nano or Uno, etc. I
recommend you to add ATMEGA328P-PU IC which is same IC use in Arduino common
boards, it save lots of space in Circuit Board and easy to program).
8x 10 LED Segment bar Graph LED (Choose any
of colours I use 2x Green means 20 LED for bottom, 1x Yellow means 10 LED for
middle part and after 1x Red means 10 Red LED for top, You can choose what
colour you want to choose).
10x 74HC595 IC Serial Shift Register (Always
Solder with IC base for future troubleshooting or upgrades)
40x 220 Ohms Registers
1x PCB Board (Perf Board)
3x 2 Pin Connectors
1x 104J Capacitor
1x 1000uF or 470uF Capacitor 25V (Choose with your voltage
fluctuations need)
Some Wires
Soldering Station and Tools
How it’s Work
A VU (Volume Unit) meter is an
audio measuring device that displays the signal level in audio equipment. It is
typically used to indicate the loudness of audio signals, providing a visual
representation of audio levels. The VU meter measures average levels, making it
suitable for monitoring consistent audio signals. It helps audio engineers
ensure audio signals remain within an optimal range, preventing distortion and
maintaining audio quality.
VU meters consist of several
components:
- Input Stage: This receives the audio signal
from the source.
- Rectifier and Filter: The audio signal is rectified to
convert AC signals into a DC signal that can be measured. A filter smooths
the signal to eliminate rapid fluctuations.
- Meter Movement: The processed signal drives a
needle or LED display, indicating the signal level.
How This Arduino-Based VU
Meter Works
This project creates a stereo
VU meter using an Arduino and 74HC595 shift registers to drive an 80-LED
display (40 LEDs for each channel). Here's how it works:
1. Audio Input: The audio signal is taken directly from
the audio source (left and right channels). Each channel's audio signal is fed
into separate analog pins (A0 for the left and A1 for the right) on the
Arduino.
2. Signal Conditioning: To stabilize the signal and reduce
noise, each audio input is connected to a filter circuit with both analog
inputs.
3. Analog Reading: The Arduino reads the analog input
values from A0 and A1. These values correspond to the amplitude of the audio
signals.
4. Peak Detection: The code includes a peak detection
mechanism. It captures the highest value in a given period, emulating the
"peak hold" feature found in traditional VU meters.
5. Scaling and Mapping: The analog values are scaled and mapped
to a range suitable for driving the LED display. This ensures that the LED
levels correspond accurately to the audio signal levels.
6. LED Display: The processed values are used to
determine how many LEDs should light up. The Arduino uses the 74HC595 shift
registers to control the LEDs. Each shift register controls 8 LEDs, allowing
for efficient control of the 40-LED display. The LEDs light up in sequence,
providing a visual representation of the audio levels.
7. Peak Hold: The peak hold feature keeps the highest
LED lit for a short duration, giving a visual indication of the highest audio
level reached.
This Arduino-based VU meter
project provides a visually appealing and functional way to monitor audio
levels, enhancing the audio experience by providing real-time feedback on the
audio signal's amplitude.
Circuit
Diagram
This
is easy to build circuit diagram but many people find it difficult just by
looking but actually not that is why also divided two parts of circuit diagram:
- one is for the main VU Meter driver circuit and with LED Executions and the
second part is the Adjustable Audio Filter Circuit which reduce unwanted noise.
The Part first is here:-
And the second part is here:-
Always remember that make sure the voltage level
from input of Audio amplifier or etc sound equipment, due to this it can burn
your Arduino or continuously reset which causes damage and add proper Capacitor
with your Input specifications and Arduino 5V power line. After complete the
circuit and double check everything, you can now add cords or wires for power
and Inputs.
Setup and Code
Now after all these steps you need to open Arduino
IDE or if you have not so download from here www.Arduino.cc then install it.
Copy the whole code from here and paste it to your Arduino IDE and Select the Com Port and Board.
/* MIT License Copyright (c) 2024 Akash Sharma Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h>
// OLED display parameters #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 #define OLED_RESET -1 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); // Heart symbol bitmap (16x16 pixels) const unsigned char heartBitmap[] PROGMEM = { 0b00001100, 0b00110000, 0b00011110, 0b01111000, 0b00111111, 0b11111100, 0b01111111, 0b11111110, 0b01111111, 0b11111110, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b01111111, 0b11111110, 0b01111111, 0b11111110, 0b00111111, 0b11111100, 0b00011111, 0b11111000, 0b00001111, 0b11110000, 0b00000111, 0b11100000, 0b00000011, 0b11000000, 0b00000001, 0b10000000 }; const int latchPinLeft = 9; // Pin connected to ST_CP of 74HC595 for left channel const int clockPinLeft = 8; // Pin connected to SH_CP of 74HC595 for left channel const int dataPinLeft = 7; // Pin connected to DS of 74HC595 for left channel const int latchPinRight = 4; // Pin connected to ST_CP of 74HC595 for right channel const int clockPinRight = 3; // Pin connected to SH_CP of 74HC595 for right channel const int dataPinRight = 2; // Pin connected to DS of 74HC595 for right channel const int analogPinLeft = A0; // Pin connected to the audio input for left channel const int analogPinRight = A1; // Pin connected to the audio input for right channel const size_t nb_LEDs = 40; const float decayRate = 0.95; // Decay rate for peak detection float peakValueLeft = 0; // Variable to store the peak value for left channel float peakValueRight = 0; // Variable to store the peak value for right channel int peakLevelLeft = 0; unsigned long peakHoldTimeLeft = 0; const unsigned long peakHoldDuration = 500; // Duration to hold the peak in milliseconds int peakLevelRight = 0; unsigned long peakHoldTimeRight = 0; void setup() { pinMode(latchPinLeft, OUTPUT); pinMode(clockPinLeft, OUTPUT); pinMode(dataPinLeft, OUTPUT); pinMode(analogPinLeft, INPUT); pinMode(latchPinRight, OUTPUT); pinMode(clockPinRight, OUTPUT); pinMode(dataPinRight, OUTPUT); pinMode(analogPinRight, INPUT); // Initialize OLED display if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { Serial.println(F("SSD1306 allocation failed")); for (;;); } display.clearDisplay(); display.display(); } void loop() { processChannel(analogPinLeft, latchPinLeft, clockPinLeft, dataPinLeft, peakValueLeft, peakLevelLeft, peakHoldTimeLeft, "L"); processChannel(analogPinRight, latchPinRight, clockPinRight, dataPinRight, peakValueRight, peakLevelRight, peakHoldTimeRight, "R"); updateOLED(); delay(20); // Adjust the delay for smoother or faster response } void processChannel(int analogPin, int latchPin, int clockPin, int dataPin, float &peakValue, int &peakLevel, unsigned long &peakHoldTime, const char* channel) { // Read the analog input float rawValue = analogRead(analogPin); // Apply peak detection if (rawValue > peakValue) { peakValue = rawValue; } else { peakValue *= decayRate; } // Scale the peak value to ensure it can reach full peak float scaledValue = peakValue * 2.0; // Increase sensitivity // Clip the scaled value to avoid exceeding the maximum range scaledValue = constrain(scaledValue, 0, 1023); // Map the scaled value to the number of LEDs int ledLevel = map(scaledValue, 0, 1023, 0, nb_LEDs); ledLevel = constrain(ledLevel, 0, nb_LEDs); // Ensure the value stays within 0 to nb_LEDs // Create the bit pattern for the LEDs, reversed direction uint64_t ledPattern = 0; for (int i = 0; i < ledLevel; i++) { ledPattern |= ((uint64_t)1) << (nb_LEDs - 1 - i); // Reversing the bit order } // Update peak level if (ledLevel > peakLevel) { peakLevel = ledLevel; peakHoldTime = millis(); // Reset peak hold timer } else if (millis() - peakHoldTime > peakHoldDuration) { peakLevel = max(0, peakLevel - 1); // Gradually decrease peak level peakHoldTime = millis(); // Reset peak hold timer } // Add peak LED to the bit pattern if (peakLevel < nb_LEDs) { ledPattern |= ((uint64_t)1) << (nb_LED); // Adjust for reversed bit order } // Output the bit pattern to the shift registers digitalWrite(latchPin, LOW); shiftOut64(dataPin, clockPin, MSBFIRST, ~ledPattern); digitalWrite(latchPin, HIGH); // Store values for display update storeDisplayValues(channel, rawValue, ledLevel, peakLevel); } // Template function for shifting out 64-bit data void shiftOut64(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint64_t val) { if (bitOrder == LSBFIRST) { for (int i = 0; i < 64; i++) { digitalWrite(dataPin, !!(val &)); digitalWrite(clockPin, HIGH); digitalWrite(clockPin, LOW); } } else { for (int i = 63; i >= 0; i--) { digitalWrite(dataPin, !!(val &)); digitalWrite(clockPin, HIGH); digitalWrite(clockPin, LOW); } } } struct DisplayValues { const char* channel; float analogValue; int ledLevel; int peakLevel; }; DisplayValues leftChannelValues; DisplayValues rightChannelValues; void storeDisplayValues(const char* channel, float analogValue, int ledLevel, int peakLevel) { if (strcmp(channel, "L") == 0) { leftChannelValues = {channel, analogValue, ledLevel, peakLevel}; } else if (strcmp(channel, "R") == 0) { rightChannelValues = {channel, analogValue, ledLevel, peakLevel}; } } void updateOLED() { static unsigned long lastUpdate = 0; const unsigned long updateInterval = 200; // Update interval in milliseconds if (millis() - lastUpdate >= updateInterval) { lastUpdate = millis(); display.clearDisplay(); display.setTextSize(1); display.setTextColor(SSD1306_WHITE); display.setCursor(0, 0); display.print("Left Channel"); display.setCursor(0, 10); display.print("VU Level: "); display.print(leftChannelValues.ledLevel); display.setCursor(0, 20); display.print("Peak Level: "); display.print(leftChannelValues.peakLevel); display.setCursor(0, 30); display.print("Right Channel"); display.setCursor(0, 40); display.print("VU Level: "); display.print(rightChannelValues.ledLevel); display.setCursor(0, 50); display.print("Peak Level: "); display.print(rightChannelValues.peakLevel); // Draw the heart symbol based on the left channel analog value if (leftChannelValues.analogValue > 150) { // Adjust the threshold as needed display.drawBitmap(100, 0, heartBitmap, 16, 16, SSD1306_WHITE); } if (rightChannelValues.analogValue > 150) { // Adjust the threshold as needed display.drawBitmap(100, 40, heartBitmap, 16, 16, SSD1306_WHITE); } display.display(); } }
Enjoy Music
Now you can rock and shock everyone! If you have a big
amplifier (e.g., 50W, 100W, 150W, 2000W, and so on), make sure to always check
the input voltage level. Adjust the input variable for precise tuning of the
LED levels to sync perfectly with your audio or music.
Where is arduino code?
ReplyDeletePlease Comment on Youtube
DeleteNice project! Can you please share the arduino sketch? Thanks!
ReplyDeletePlease Comment on Youtube
DeleteInteresting diy project but without the arduino code, it does not work! Where can I find it sir?
ReplyDeletePlease Comment on Youtube
Delete