Skip to content

Commit

Permalink
Update the library
Browse files Browse the repository at this point in the history
  • Loading branch information
mcmchris committed Nov 3, 2022
1 parent 42dc15e commit 813f61e
Show file tree
Hide file tree
Showing 6 changed files with 308 additions and 0 deletions.
151 changes: 151 additions & 0 deletions MCMVoltSense.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*
MCMVoltSense.cpp - Library for Grove AC Voltage Sensor
Author: Christopher Mendez, November 3 2022
*/

#include "MCMVoltSense.h"

#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

//----------------------------------------------------------------------------------
// Sets the analog pin, calibration factors for the voltage and phase to be used
//----------------------------------------------------------------------------------
void MCMmeter::VoltageStp(unsigned int _analogVin, double _VoltCal, double _PhaseCal)
{
offsetV = ADC_COUNTS >> 1;
PhaseCal = _PhaseCal;
VoltCal = _VoltCal;
analogVin = _analogVin;
}

//-------------------------------------------------------------------------------------------------
// Voltage calculation from a window sample of the analog input from the Grove AC Voltage Sensor
//-------------------------------------------------------------------------------------------------
void MCMmeter::analogVoltage(unsigned int cycles, unsigned int timeout)
{

cycles = cycles/2; // Converting cycles to zero crossings

int SupplyVoltage = boardVcc();

unsigned int crossCount = 0; // Used to measure number of times threshold is crossed.
unsigned int numberOfSamples = 0; // This is now incremented

//-------------------------------------------------------------------------------------------------------------------------
// 1) Waits for the waveform to be close to 'zero' (mid-scale adc) part in sin curve.
//-------------------------------------------------------------------------------------------------------------------------
unsigned long start = millis(); // timer for the timeout.

while (1) // wait for the sine signal to zero cross, break if timeout
{
startV = analogRead(analogVin); // using the voltage waveform
if ((startV < (ADC_COUNTS * 0.51)) && (startV > (ADC_COUNTS * 0.49)))
break; // check its within range to start from here
if ((millis() - start) > timeout)
break;
}

//-------------------------------------------------------------------------------------------------------------------------
// 2) Voltage measurement loop
//-------------------------------------------------------------------------------------------------------------------------
start = millis();

while ((crossCount < cycles) && ((millis() - start) < timeout))
{
numberOfSamples++; // Count number of times looped.
lastFilteredV = filteredV; // Used for delay/phase compensation

//-----------------------------------------------------------------------------
// A) Read in raw voltage and current samples
//-----------------------------------------------------------------------------
sampleV = analogRead(analogVin); // Read in raw voltage signal

//-----------------------------------------------------------------------------
// B) Apply digital low pass filters to extract the 2.5 V or 1.65 V dc offset,
// then subtract this - signal is now centred on 0 counts.
//-----------------------------------------------------------------------------
offsetV = offsetV + ((sampleV - offsetV) / ADC_COUNTS);
filteredV = sampleV - offsetV;

//-----------------------------------------------------------------------------
// C) Root-mean-square method voltage
//-----------------------------------------------------------------------------
sqV = filteredV * filteredV; // 1) square voltage values
sumV += sqV; // 2) sum

//-----------------------------------------------------------------------------
// E) Phase calibration
//-----------------------------------------------------------------------------
phaseShiftedV = lastFilteredV + PhaseCal * (filteredV - lastFilteredV);

//-----------------------------------------------------------------------------
// G) Find the number of times the voltage has crossed the initial voltage
// - every 2 crosses we will have sampled 1 wavelength
// - so this method allows us to sample an integer number of half wavelengths which increases accuracy
//-----------------------------------------------------------------------------
lastVCross = checkVCross;
if (sampleV > startV)
checkVCross = true;
else
checkVCross = false;
if (numberOfSamples == 1)
lastVCross = checkVCross;

if (lastVCross != checkVCross)
crossCount++;
}

//-------------------------------------------------------------------------------------------------------------------------
// 3) Post loop calculations
//-------------------------------------------------------------------------------------------------------------------------
// Calculation of the root of the mean of the voltage and current squared (rms)
// Calibration coefficients applied.

double V_RATIO = VoltCal * ((SupplyVoltage / 1000.0) / (ADC_COUNTS));
Vrms = V_RATIO * sqrt(sumV / numberOfSamples);

// Reset accumulators
sumV = 0;
//--------------------------------------------------------------------------------------
}

//-------------------------------------------------------------------------------------------------------------------------
// Function that measures the supply voltage of the boards.
//-------------------------------------------------------------------------------------------------------------------------
long MCMmeter::boardVcc()
{

long result;

#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__)
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__)
ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#elif defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_AT90USB1286__)
ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
ADCSRB &= ~_BV(MUX5); // Without this the function always returns -1 on the ATmega2560
#elif defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
ADMUX = _BV(MUX5) | _BV(MUX0);
#elif defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
ADMUX = _BV(MUX3) | _BV(MUX2);
#endif

#if defined(__AVR__)
delay(2); // Wait for the reference voltage to stabilize
ADCSRA |= _BV(ADSC); // Convert
while (bit_is_set(ADCSRA, ADSC))
;
result = ADCL;
result |= ADCH << 8;
result = READVCC_CALIBRATION_CONST / result; // 1100mV*1024 ADC steps
return result;
#elif defined(__arm__)
return (3300); // Arduino Due
#else
return (3300); // Assuming other architectures works with 3.3V!
#endif
}
83 changes: 83 additions & 0 deletions MCMVoltSense.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
MCMVoltSense.cpp - Library for Grove AC Voltage Sensor
Author: Christopher Mendez, November 3 2022
*/

#ifndef MCMVoltSense_h
#define MCMVoltSense_h

#if defined(ARDUINO) && ARDUINO >= 100

#include "Arduino.h"

#else

#include "WProgram.h"

#endif

// define theoretical vref calibration constant for use in boardVcc()
// 1100mV*1024 ADC steps
// override in your code with value for your specific AVR chip

#ifndef READVCC_CALIBRATION_CONST
#define READVCC_CALIBRATION_CONST 1126400L
#endif

// to enable 12-bit ADC resolution on Arduino Due,
// include the following line in main sketch inside setup() function:
// analogReadResolution(ADC_BITS);
// otherwise will default to 10 bits, as in regular Arduino-based boards.

#if defined(__arm__)
#define ADC_BITS 12
#else
#define ADC_BITS 10
#endif

#define ADC_COUNTS (1<<ADC_BITS)


class MCMmeter
{
public:

void VoltageStp(unsigned int _analogVin, double _VoltCal, double _PhaseCal);

void analogVoltage(unsigned int cycles, unsigned int timeout);

long boardVcc();
//Useful value variables
double Vrms;

private:

//Set Voltage and current input pins
unsigned int analogVin;

//Calibration coefficients
//These need to be set in order to obtain accurate results
double VoltCal;
double PhaseCal;

//--------------------------------------------------------------------------------------
// Variable declaration
//--------------------------------------------------------------------------------------
int sampleV; //sample holds the raw analog read value

double lastFilteredV,filteredV; //Filtered is the raw analog value minus the DC offset
double offsetV; //Low-pass filter output


double phaseShiftedV; //Holds the calibrated phase shifted voltage.

double sqV,sumV; //sq = squared, sum = Sum

int startV; //Instantaneous voltage at start of sample window.

boolean lastVCross, checkVCross; //Used to measure number of times threshold is crossed.


};

#endif
26 changes: 26 additions & 0 deletions examples/VoltageSensing/VoltageSensing.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

#include "MCMVoltSense.h" // Include MCM Volt Sense Library

MCMmeter meter; // Create an instance

void setup() {

Serial.begin(115200);

meter.VoltageStp(A1, 523.56, 1.7); // Voltage: input pin, calibration, phase_shift

}

void loop() {

meter.analogVoltage(40,2000); // Measure the AC voltage. Arguments = (# of AC cycles, timeout)

float Vrms = meter.Vrms; // Save the RMS Voltage into a variable.

Serial.print("Voltage: ");
Serial.print(Vrms,2);
Serial.println(" V");

delay(2000);

}
22 changes: 22 additions & 0 deletions keywords.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#######################################
# Syntax Coloring Map
#######################################

#######################################
# Datatypes (KEYWORD1)
#######################################

MCMmeter KEYWORD1

#######################################
# Methods and Functions (KEYWORD2)
#######################################

VoltageStp KEYWORD2
analogVoltage KEYWORD2
boardVcc KEYWORD2

######################################
# Constants (LITERAL1)
#######################################
Vrms LITERAL1
17 changes: 17 additions & 0 deletions library.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "MCMVoltSense",
"keywords": "voltage, measurement, energy",
"description": "AC Voltage Measurement Library",
"version": "0.0.1",
"repository":
{
"type": "git",
"url": "https://github.com/mcmchris/mcm-grove-voltage-sensor.git"
},
"frameworks": "arduino",
"platforms":
[
"atmelavr",
"atmelsam"
]
}
9 changes: 9 additions & 0 deletions library.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name=MCMVoltSense
version=0.0.1
author=mcmchris
maintainer=mcmchris
sentence=Voltage Measurement Library
paragraph=Voltage Measurement Library
category=Sensors
url=https://github.com/mcmchris/mcm-grove-voltage-sensor.git
architectures=*

0 comments on commit 813f61e

Please sign in to comment.