Skip to content

Commit 813f61e

Browse files
committed
Update the library
1 parent 42dc15e commit 813f61e

File tree

6 files changed

+308
-0
lines changed

6 files changed

+308
-0
lines changed

MCMVoltSense.cpp

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
/*
2+
MCMVoltSense.cpp - Library for Grove AC Voltage Sensor
3+
Author: Christopher Mendez, November 3 2022
4+
*/
5+
6+
#include "MCMVoltSense.h"
7+
8+
#if defined(ARDUINO) && ARDUINO >= 100
9+
#include "Arduino.h"
10+
#else
11+
#include "WProgram.h"
12+
#endif
13+
14+
//----------------------------------------------------------------------------------
15+
// Sets the analog pin, calibration factors for the voltage and phase to be used
16+
//----------------------------------------------------------------------------------
17+
void MCMmeter::VoltageStp(unsigned int _analogVin, double _VoltCal, double _PhaseCal)
18+
{
19+
offsetV = ADC_COUNTS >> 1;
20+
PhaseCal = _PhaseCal;
21+
VoltCal = _VoltCal;
22+
analogVin = _analogVin;
23+
}
24+
25+
//-------------------------------------------------------------------------------------------------
26+
// Voltage calculation from a window sample of the analog input from the Grove AC Voltage Sensor
27+
//-------------------------------------------------------------------------------------------------
28+
void MCMmeter::analogVoltage(unsigned int cycles, unsigned int timeout)
29+
{
30+
31+
cycles = cycles/2; // Converting cycles to zero crossings
32+
33+
int SupplyVoltage = boardVcc();
34+
35+
unsigned int crossCount = 0; // Used to measure number of times threshold is crossed.
36+
unsigned int numberOfSamples = 0; // This is now incremented
37+
38+
//-------------------------------------------------------------------------------------------------------------------------
39+
// 1) Waits for the waveform to be close to 'zero' (mid-scale adc) part in sin curve.
40+
//-------------------------------------------------------------------------------------------------------------------------
41+
unsigned long start = millis(); // timer for the timeout.
42+
43+
while (1) // wait for the sine signal to zero cross, break if timeout
44+
{
45+
startV = analogRead(analogVin); // using the voltage waveform
46+
if ((startV < (ADC_COUNTS * 0.51)) && (startV > (ADC_COUNTS * 0.49)))
47+
break; // check its within range to start from here
48+
if ((millis() - start) > timeout)
49+
break;
50+
}
51+
52+
//-------------------------------------------------------------------------------------------------------------------------
53+
// 2) Voltage measurement loop
54+
//-------------------------------------------------------------------------------------------------------------------------
55+
start = millis();
56+
57+
while ((crossCount < cycles) && ((millis() - start) < timeout))
58+
{
59+
numberOfSamples++; // Count number of times looped.
60+
lastFilteredV = filteredV; // Used for delay/phase compensation
61+
62+
//-----------------------------------------------------------------------------
63+
// A) Read in raw voltage and current samples
64+
//-----------------------------------------------------------------------------
65+
sampleV = analogRead(analogVin); // Read in raw voltage signal
66+
67+
//-----------------------------------------------------------------------------
68+
// B) Apply digital low pass filters to extract the 2.5 V or 1.65 V dc offset,
69+
// then subtract this - signal is now centred on 0 counts.
70+
//-----------------------------------------------------------------------------
71+
offsetV = offsetV + ((sampleV - offsetV) / ADC_COUNTS);
72+
filteredV = sampleV - offsetV;
73+
74+
//-----------------------------------------------------------------------------
75+
// C) Root-mean-square method voltage
76+
//-----------------------------------------------------------------------------
77+
sqV = filteredV * filteredV; // 1) square voltage values
78+
sumV += sqV; // 2) sum
79+
80+
//-----------------------------------------------------------------------------
81+
// E) Phase calibration
82+
//-----------------------------------------------------------------------------
83+
phaseShiftedV = lastFilteredV + PhaseCal * (filteredV - lastFilteredV);
84+
85+
//-----------------------------------------------------------------------------
86+
// G) Find the number of times the voltage has crossed the initial voltage
87+
// - every 2 crosses we will have sampled 1 wavelength
88+
// - so this method allows us to sample an integer number of half wavelengths which increases accuracy
89+
//-----------------------------------------------------------------------------
90+
lastVCross = checkVCross;
91+
if (sampleV > startV)
92+
checkVCross = true;
93+
else
94+
checkVCross = false;
95+
if (numberOfSamples == 1)
96+
lastVCross = checkVCross;
97+
98+
if (lastVCross != checkVCross)
99+
crossCount++;
100+
}
101+
102+
//-------------------------------------------------------------------------------------------------------------------------
103+
// 3) Post loop calculations
104+
//-------------------------------------------------------------------------------------------------------------------------
105+
// Calculation of the root of the mean of the voltage and current squared (rms)
106+
// Calibration coefficients applied.
107+
108+
double V_RATIO = VoltCal * ((SupplyVoltage / 1000.0) / (ADC_COUNTS));
109+
Vrms = V_RATIO * sqrt(sumV / numberOfSamples);
110+
111+
// Reset accumulators
112+
sumV = 0;
113+
//--------------------------------------------------------------------------------------
114+
}
115+
116+
//-------------------------------------------------------------------------------------------------------------------------
117+
// Function that measures the supply voltage of the boards.
118+
//-------------------------------------------------------------------------------------------------------------------------
119+
long MCMmeter::boardVcc()
120+
{
121+
122+
long result;
123+
124+
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__)
125+
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
126+
#elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__)
127+
ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
128+
#elif defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_AT90USB1286__)
129+
ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
130+
ADCSRB &= ~_BV(MUX5); // Without this the function always returns -1 on the ATmega2560
131+
#elif defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
132+
ADMUX = _BV(MUX5) | _BV(MUX0);
133+
#elif defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
134+
ADMUX = _BV(MUX3) | _BV(MUX2);
135+
#endif
136+
137+
#if defined(__AVR__)
138+
delay(2); // Wait for the reference voltage to stabilize
139+
ADCSRA |= _BV(ADSC); // Convert
140+
while (bit_is_set(ADCSRA, ADSC))
141+
;
142+
result = ADCL;
143+
result |= ADCH << 8;
144+
result = READVCC_CALIBRATION_CONST / result; // 1100mV*1024 ADC steps
145+
return result;
146+
#elif defined(__arm__)
147+
return (3300); // Arduino Due
148+
#else
149+
return (3300); // Assuming other architectures works with 3.3V!
150+
#endif
151+
}

MCMVoltSense.h

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
MCMVoltSense.cpp - Library for Grove AC Voltage Sensor
3+
Author: Christopher Mendez, November 3 2022
4+
*/
5+
6+
#ifndef MCMVoltSense_h
7+
#define MCMVoltSense_h
8+
9+
#if defined(ARDUINO) && ARDUINO >= 100
10+
11+
#include "Arduino.h"
12+
13+
#else
14+
15+
#include "WProgram.h"
16+
17+
#endif
18+
19+
// define theoretical vref calibration constant for use in boardVcc()
20+
// 1100mV*1024 ADC steps
21+
// override in your code with value for your specific AVR chip
22+
23+
#ifndef READVCC_CALIBRATION_CONST
24+
#define READVCC_CALIBRATION_CONST 1126400L
25+
#endif
26+
27+
// to enable 12-bit ADC resolution on Arduino Due,
28+
// include the following line in main sketch inside setup() function:
29+
// analogReadResolution(ADC_BITS);
30+
// otherwise will default to 10 bits, as in regular Arduino-based boards.
31+
32+
#if defined(__arm__)
33+
#define ADC_BITS 12
34+
#else
35+
#define ADC_BITS 10
36+
#endif
37+
38+
#define ADC_COUNTS (1<<ADC_BITS)
39+
40+
41+
class MCMmeter
42+
{
43+
public:
44+
45+
void VoltageStp(unsigned int _analogVin, double _VoltCal, double _PhaseCal);
46+
47+
void analogVoltage(unsigned int cycles, unsigned int timeout);
48+
49+
long boardVcc();
50+
//Useful value variables
51+
double Vrms;
52+
53+
private:
54+
55+
//Set Voltage and current input pins
56+
unsigned int analogVin;
57+
58+
//Calibration coefficients
59+
//These need to be set in order to obtain accurate results
60+
double VoltCal;
61+
double PhaseCal;
62+
63+
//--------------------------------------------------------------------------------------
64+
// Variable declaration
65+
//--------------------------------------------------------------------------------------
66+
int sampleV; //sample holds the raw analog read value
67+
68+
double lastFilteredV,filteredV; //Filtered is the raw analog value minus the DC offset
69+
double offsetV; //Low-pass filter output
70+
71+
72+
double phaseShiftedV; //Holds the calibrated phase shifted voltage.
73+
74+
double sqV,sumV; //sq = squared, sum = Sum
75+
76+
int startV; //Instantaneous voltage at start of sample window.
77+
78+
boolean lastVCross, checkVCross; //Used to measure number of times threshold is crossed.
79+
80+
81+
};
82+
83+
#endif
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
2+
#include "MCMVoltSense.h" // Include MCM Volt Sense Library
3+
4+
MCMmeter meter; // Create an instance
5+
6+
void setup() {
7+
8+
Serial.begin(115200);
9+
10+
meter.VoltageStp(A1, 523.56, 1.7); // Voltage: input pin, calibration, phase_shift
11+
12+
}
13+
14+
void loop() {
15+
16+
meter.analogVoltage(40,2000); // Measure the AC voltage. Arguments = (# of AC cycles, timeout)
17+
18+
float Vrms = meter.Vrms; // Save the RMS Voltage into a variable.
19+
20+
Serial.print("Voltage: ");
21+
Serial.print(Vrms,2);
22+
Serial.println(" V");
23+
24+
delay(2000);
25+
26+
}

keywords.txt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#######################################
2+
# Syntax Coloring Map
3+
#######################################
4+
5+
#######################################
6+
# Datatypes (KEYWORD1)
7+
#######################################
8+
9+
MCMmeter KEYWORD1
10+
11+
#######################################
12+
# Methods and Functions (KEYWORD2)
13+
#######################################
14+
15+
VoltageStp KEYWORD2
16+
analogVoltage KEYWORD2
17+
boardVcc KEYWORD2
18+
19+
######################################
20+
# Constants (LITERAL1)
21+
#######################################
22+
Vrms LITERAL1

library.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"name": "MCMVoltSense",
3+
"keywords": "voltage, measurement, energy",
4+
"description": "AC Voltage Measurement Library",
5+
"version": "0.0.1",
6+
"repository":
7+
{
8+
"type": "git",
9+
"url": "https://github.com/mcmchris/mcm-grove-voltage-sensor.git"
10+
},
11+
"frameworks": "arduino",
12+
"platforms":
13+
[
14+
"atmelavr",
15+
"atmelsam"
16+
]
17+
}

library.properties

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
name=MCMVoltSense
2+
version=0.0.1
3+
author=mcmchris
4+
maintainer=mcmchris
5+
sentence=Voltage Measurement Library
6+
paragraph=Voltage Measurement Library
7+
category=Sensors
8+
url=https://github.com/mcmchris/mcm-grove-voltage-sensor.git
9+
architectures=*

0 commit comments

Comments
 (0)