Introduction: Bluetooth Enabled Analog VU Meter

This was my project for one of my university classes called SMP. As we used the STM32F103RB development board, I based my project onto this, starting off from a simple VU meter. I then added some extra features like Bluetooth support to broadcast values from the ADC to a Android app to create a simple dB chart.

Step 1: Components Used

  • STM32F103RB development board
  • HC-05 zs040 bluetooth module
  • Analog VU meter panel (link)
  • Electret microphone
  • LM324N quad op-amp
  • 2 TIP120 transistors
  • 3 1N4148 diodes
  • Various capacitors and resistors

Although you can drive this circuit off of the board's 5V rail, I also used an external 5V power supply.

Step 2: Envelope Follower

The main piece of this design is the envelope follower which takes the signal from the electret microphone and outputs a voltage proportional to the microphone's signal amplitude.

The raw signal from the microphone is first passed trough an amplifier with a gain of 150.

The signal is then passed trough the actual envelope follower which should output only the positive signal parts.

The last part is subtracting the offset voltage of 1.65V from the output of the envelope follower to provide a signal of 0 V for no sound, 1.65 V for medium-sound and 3.3 V for loud-sound that should be compatible with the built in ADC of the board.

This envelope follower is implemented from this great StackExchange answer.

Step 3: PWM for the Analog Meter

To get the needle of the gauge going, I've configured TIM4 timer of the microcontroller board with a frequency of around 500 Hz.

By successively trying out different duty cycles I've settled with some values that were enough to get the needle to go from 0 to 100.

I will detail the process of displaying an exact value in the next step by applying some math.

Step 4: Microphone Calibration

Having the envelope follower done, I then wrote some simple code to use the ADC and verified that the read value indeed changes accordingly to the loudness inside the room.

In order to "translate" this value into an actual dB reading, I've used an online tone generator with a frequency of 550 Hz and my Android to provide a reference reading.

I have plotted those values and used MatLAB's Curve Fit Tool to get a function that maps ADC readings to actual approximations of the dB levels (or at least close enough to my phone's readings).

We can see that this follows microphone's logarithmic scale.

I also did the same thing to map needle position to PWM values. I gathered those values by incrementing the PWM value by 10 successively until the need hit reading on its scale.

Combining those 2 function I got an easy way to display the reading from ADC to an actual value on the gauge indicator.

Step 5: Android App

The app is using this cool library to communicate via Bluetooth serial to exchange byte info.

The main caveat of this system is that the maximum word length sent over Bluetooth is 8 bits and the ADC value is represented as 12 bits. To overcome this issue, I split one ADC value into 2 separate 6 bit values (MSB and LSB) with the remaining 2 bits used to identify the message type (MSB, LSB, CHK).

Therefore, for a single ADC value that we want to broadcast, we split the actual value into 2 messages. To check the integrity of those messages, I sent a third messages with the XOR of the first 2 messages.

After the value integrity is checked, we can apply the same function to get the dB level and plot it onto our live chart.

Step 6: Summary

While I the micro-controller part of this project works pretty good displaying the loudness inside a room, I encountered some issues when sending data over Bluetooth due to packet loss.

The source code for this project can be found here:

  • Android companion app - repo
  • Microcontroller code - repo

Feel free to contribute if you find this useful in any way.