/*
STM32F103C6 - Dual Accurate VU Meter (dBu scale)
Input DC max ~2.0V from envelope follower
Output 5 LEDs per channel
Accurate 300ms time constant + dBu mapping
*/
const int chL = PA2;
const int chR = PA3;
// LED Left
int ledL[5] = {PB0, PB1, PB10, PB11, PB12};
// LED Right
int ledR[5] = {PB13, PB14, PB15, PA8, PA9};
// ADC voltage reference
const float VREF = 3.3;
// Max envelope voltage for +5 dBu
const float VMAX = 2.0;
// dBu mapping range
const float dBuMin = -20.0;
const float dBuMax = +5.0;
// smoothing (VU 300ms)
float smoothL = 0;
float smoothR = 0;
const float alpha = 0.003; // ~300ms at ~1kHz loop
// LED thresholds in dBu
float vuLevel[5] = {
-14.0, // LED1
-7.0, // LED2
-2.0, // LED3
0.0, // LED4
+3.0 // LED5
};
void setup() {
analogReadResolution(12);
for(int i=0; i<5; i++){
pinMode(ledL[i], OUTPUT);
pinMode(ledR[i], OUTPUT);
}
}
void loop() {
// -------------------------
// 1. Read ADC
// -------------------------
float vL = analogRead(chL) * (VREF / 4095.0);
float vR = analogRead(chR) * (VREF / 4095.0);
if(vL > VMAX) vL = VMAX;
if(vR > VMAX) vR = VMAX;
// -------------------------
// 2. Smooth 300ms (accurate VU behavior)
// -------------------------
smoothL += alpha * (vL - smoothL);
smoothR += alpha * (vR - smoothR);
// -------------------------
// 3. Convert to dBu scale
// -------------------------
float dBuL = dBuMin + (smoothL / VMAX) * (dBuMax - dBuMin);
float dBuR = dBuMin + (smoothR / VMAX) * (dBuMax - dBuMin);
// -------------------------
// 4. Update LEDs
// -------------------------
showVU(ledL, dBuL);
showVU(ledR, dBuR);
delayMicroseconds(900); // ~1 kHz loop for correct smoothing
}
// ------------------------------------
// LED Control based on dBu thresholds
// ------------------------------------
void showVU(int *led, float dBu){
for(int i=0; i<5; i++){
if(dBu >= vuLevel[i]) digitalWrite(led[i], HIGH);
else digitalWrite(led[i], LOW);
}
}