This example demonstrates how to measure voltage using an Arduino UNO and a 100:1 voltage divider. The code can handle both AC and DC voltage inputs and provides the following outputs:
/*
* Arduino UNO with 100:1 Voltage Divider
* Measures AC/DC voltage, calculates peak, RMS, and frequency for AC signals.
* © 2024 Copyright Peter I. Dunne, all rights reserved
* Prepared for educational use
* The ADC is 10 bit, this is of relatively low accuracy, use professional test equipment for accuracy
* Released under the Mozilla Public License
*/
const int voltagePin = A0; // Voltage input connected to A0
const float voltageDividerRatio = 200.0; // 200:1 divider
const float offset = 2.5; // 2.5V offset for AC signals
const float VRef = 5.0; // Reference voltage
const int maxADCValue = 1023; // 10-bit ADC resolution
const int threshold = 512;
const unsigned long interval = 500; // 500ms hold period if AC is detected
// Variables for AC calculations
unsigned long lastZeroCrossingTime = 0;
float sumSquaredVoltage = 0;
int sampleCount = 0;
bool polarity =false; // used by AC, DC detection
bool zcd = false; // zero cross detection, part of the AC component
unsigned long previousACmillis = 0; // Stores the last time the action was taken
int zcp = 512; // zero crossing point
unsigned long previousMillis = 0; // Stores the last time the action was taken
float frequency = 0;
void setup() {
Serial.begin(115200); // Start serial communication
Serial.println("Arduino DMM by Peter Ivan Dunne, ©2024, all rights reserved");
Serial.println("Released under the Mozilla Public License");
Serial.println("https://jazenga.com/educational");
Serial.println("Purpose: to demonstrate use of ADC system as a voltage meter for both AC and DC voltages");
Serial.println("Auto detection of AC and measurement of AC frequency");
}
void loop() {
// Read the analog value from the voltage sensor
int adcValue = analogRead(voltagePin);
// Convert ADC value to voltage
float voltage = (adcValue / float(maxADCValue)) * VRef;
// Adjust for the 2.5V offset
float adjustedVoltage = voltage - offset;
// Calculate the actual input voltage considering the voltage divider
float inputVoltage = adjustedVoltage * voltageDividerRatio;
unsigned long currentMillis = millis();
unsigned long currentMicros = micros();
// phase change detection
// if AC, it can detect the change at any moment
// if AC it assumes AC for not less than the interval, initially set at 500ms
// the timer is reset every time a 0v crossing occurs to ensure it stays in AC mode for as long as AC is present on the input
if (polarity!=adcValue>zcp){
polarity = adcValue>zcp;
if (polarity){
// add hysterisis to prevent false triggering
zcp=threshold-10;
// period is calculated only on the positive edge for greater accuracy
previousACmillis = currentMillis;
unsigned long period = currentMicros - lastZeroCrossingTime; // Time between zero crossings
lastZeroCrossingTime = currentMicros;
// Calculate frequency in Hz
if (period>0){
frequency = 1000000.0 / (period); // Period is in microseconds
} else {
// add hysterisis to prevent false triggering
zcp=threshold+10;
}
zcd = true;
}
}
if ((currentMillis - previousACmillis) <= interval){
// AC signal processing: track peak voltage and sum squared voltage for RMS calculation
sumSquaredVoltage += inputVoltage * inputVoltage; // Sum of squares for RMS calculation
sampleCount++;
// Detect zero crossing (when the voltage crosses 2.5V)
if (zcd && polarity) {
// Output AC parameters
if ((currentMillis - previousMillis) >= interval) {
// Save the last time action was taken
previousMillis = currentMillis;
// Calculate RMS voltage
float rmsVoltage = sqrt(sumSquaredVoltage / sampleCount);
Serial.print(" RMS Voltage: ");
Serial.print(rmsVoltage, 2);
Serial.print(" V, Frequency: ");
Serial.print(frequency, 2);
Serial.println(" Hz");
sumSquaredVoltage = 0;
sampleCount = 0;
}
}
} else {
// For DC, output the voltage directly
// update the output every 500ms
if ((currentMillis - previousMillis) >= interval) {
// Save the last time action was taken
previousMillis = currentMillis;
Serial.print(" DC Voltage: ");
Serial.print(inputVoltage);
Serial.println(" V");
}
}
}