#include <Arduino.h>
#define _ROUNDUP_ // show voltage rounded up
//#define _TIMEDSAMPLES_
//#define _DEBUG_
#include <ZMPT101B.h>
#include "TM1637_Micro.h"
#include "MeanFilter.h"
const float SENSITIVITY = /*385.75f;*/ 112.50f; // wokwi
const float SOURCEFREQ = 50.0f;
const int16_t SAMPLESPERREAD = 20;
const int16_t MAINSVOLTAGE = 220;
const int16_t VOLTAGETOLERANCEPERCENT = 8; // +/- voltage tolerance %
const int16_t LOWVOLTAGE = (MAINSVOLTAGE * (100 - VOLTAGETOLERANCEPERCENT) + 50) / 100; // rounded calculated low voltage
const int16_t HIGHVOLTAGE = (MAINSVOLTAGE * (100 + VOLTAGETOLERANCEPERCENT) + 50) / 100; // rounded calculated high voltage
const int16_t ZEROVOLTCORRECTION = 10;
const int16_t LEDHYSTERESISVOLTAGE = 3;
const int16_t MEANFILTERWINDOW = 3;
const uint8_t ZMPT101B_IN = A0;
const uint8_t GREENLED_OUT = 2; // Green half LED
const uint8_t REDLED_OUT = 3; // Red half LED
const uint8_t TM1637_CLK = 4;
const uint8_t TM1637_DIO = 5;
const uint8_t SHOWMEAN_IN = 6;
const uint8_t VOLTAGELEVELNULL = 0;
const uint8_t VOLTAGELEVELNORMAL = 1;
const uint8_t VOLTAGELEVELLOW = 2;
const uint8_t VOLTAGELEVELHIGH = 3;
#ifdef _TIMEDSAMPLES_
const uint32_t SAMPLEDELAY = 1000UL;
uint32_t voltageLastSampleTime;
#endif
float rmsVolts_f = 0.0;
int16_t rmsVolts = 0;
uint8_t prevVoltageLevel = VOLTAGELEVELNULL;
uint8_t voltageLevel;
bool showMeanVoltage = true;
// ZMPT101B sensor output connected to analog pin ZMPT101B_IN
// and the voltage source frequency is SOURCEFREQ Hz.
ZMPT101B voltageSensor(ZMPT101B_IN, SOURCEFREQ);
TM1637Micro display(TM1637_CLK, TM1637_DIO);
MeanFilter<float> meanFilter(MEANFILTERWINDOW);
/* ---------------------------------------------------------------------------------------------- */
void set_led_color() {
if (rmsVolts > HIGHVOLTAGE - (voltageLevel == VOLTAGELEVELHIGH ? LEDHYSTERESISVOLTAGE : 0)) {
voltageLevel = VOLTAGELEVELHIGH;
} else if (rmsVolts < LOWVOLTAGE + (voltageLevel == VOLTAGELEVELLOW ? LEDHYSTERESISVOLTAGE : 0)) {
voltageLevel = VOLTAGELEVELLOW;
} else {
voltageLevel = VOLTAGELEVELNORMAL;
}
if (voltageLevel != prevVoltageLevel) {
digitalWrite(GREENLED_OUT, voltageLevel != VOLTAGELEVELHIGH);
digitalWrite(REDLED_OUT, voltageLevel != VOLTAGELEVELNORMAL);
prevVoltageLevel = voltageLevel;
}
}
/* ---------------------------------------------------------------------------------------------- */
void show_voltage() {
rmsVolts_f = voltageSensor.getRmsVoltage(SAMPLESPERREAD);
if (showMeanVoltage) {
rmsVolts_f = meanFilter.AddValue(rmsVolts_f);
}
#ifdef _ROUNDUP_
rmsVolts = int(rmsVolts_f + 0.5f);
#else
rmsVolts = int(rmsVolts_f);
#endif
if (rmsVolts < ZEROVOLTCORRECTION) rmsVolts = 0;
display.showNum(rmsVolts);
#ifdef _DEBUG_
Serial.print(rmsVolts);
Serial.println(F(" Vrms"));
#endif
}
/* ---------------------------------------------------------------------------------------------- */
void blink_all(byte g = LOW, byte r = LOW, int num = 8888) {
delay(100);
digitalWrite(GREENLED_OUT, g);
digitalWrite(REDLED_OUT, r);
display.showNum(num);
delay(400);
digitalWrite(GREENLED_OUT, LOW);
digitalWrite(REDLED_OUT, LOW);
display.clear();
}
/* ---------------------------------------------------------------------------------------------- */
void test_all_leds() {
blink_all(HIGH, LOW);
blink_all(HIGH, HIGH);
blink_all(LOW, HIGH);
delay(1000);
}
/* ---------------------------------------------------------------------------------------------- */
void setup() {
pinMode(GREENLED_OUT, OUTPUT);
pinMode(REDLED_OUT, OUTPUT);
pinMode(SHOWMEAN_IN, INPUT_PULLUP);
digitalWrite(GREENLED_OUT, LOW);
digitalWrite(REDLED_OUT, LOW);
showMeanVoltage = digitalRead(SHOWMEAN_IN);
display.init();
display.brightness(/*DARKEST*/TYPICAL);
display.clear();
test_all_leds();
voltageSensor.setSensitivity(SENSITIVITY);
#ifdef _DEBUG_
Serial.begin(115200);
Serial.println(HIGHVOLTAGE);
Serial.println(LOWVOLTAGE);
#endif
#ifdef _TIMEDSAMPLES_
// First voltage reading
voltageLastSampleTime = millis();
show_voltage();
set_led_color();
#endif
}
/* ---------------------------------------------------------------------------------------------- */
void loop() {
#ifdef _TIMEDSAMPLES_
if (millis() - voltageLastSampleTime >= SAMPLEDELAY) {
voltageLastSampleTime += SAMPLEDELAY;
show_voltage();
set_led_color();
}
#else
show_voltage();
set_led_color();
#endif
}
/* ---------------------------------------------------------------------------------------------- */