#include <Arduino.h>
#define _USEMEANFILTER_ // show mean voltage
#define _ROUNDUP_ // show voltage rounded up
//#define _TIMEDSAMPLES_
#include <ZMPT101B.h>
#include "TM1637_Micro.h"
#ifdef _USEMEANFILTER_
#include "MeanFilter.h"
#endif
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 LOWVOLTAGELEVEL = (MAINSVOLTAGE * (100 - VOLTAGETOLERANCEPERCENT) + 50) / 100; // rounded calculated low voltage
const int16_t HIGHVOLTAGELEVEL = (MAINSVOLTAGE * (100 + VOLTAGETOLERANCEPERCENT) + 50) / 100; // rounded calculated high voltage
const int16_t ZEROVOLTCORRECTION = 10;
const int16_t LEDHYSTERESISVOLTAGE = 3;
#ifdef _USEMEANFILTER_
const int16_t MEANFILTERWINDOW = 3;
#endif
const uint8_t ZMPT101B_IN = A1;
const uint8_t GREENLED_OUT = 4; // Green half LED
const uint8_t REDLED_OUT = 3; // Red half LED
const uint8_t TM1637_CLK = 0;
const uint8_t TM1637_DIO = 1;
const uint8_t VOLTAGENULL = 0;
const uint8_t VOLTAGENORMAL = 1;
const uint8_t VOLTAGELOW = 3;
const uint8_t VOLTAGEHIGH = 2;
#ifdef _TIMEDSAMPLES_
const uint32_t SAMPLEDELAY = 1000UL;
uint32_t voltageLastSampleTime;
#endif
float rmsVolts_f = 0.0;
int16_t rmsVolts = 0;
uint8_t prevVoltageLevel = VOLTAGENULL;
uint8_t voltageLevel;
// 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);
#ifdef _USEMEANFILTER_
MeanFilter<float> meanFilter(MEANFILTERWINDOW);
#endif
/* ---------------------------------------------------------------------------------------------- */
void set_led_color() {
if (rmsVolts > HIGHVOLTAGELEVEL - (voltageLevel == VOLTAGEHIGH ? LEDHYSTERESISVOLTAGE : 0)) {
voltageLevel = VOLTAGEHIGH;
} else if (rmsVolts < LOWVOLTAGELEVEL + (voltageLevel == VOLTAGELOW ? LEDHYSTERESISVOLTAGE : 0)) {
voltageLevel = VOLTAGELOW;
} else {
voltageLevel = VOLTAGENORMAL;
}
if (voltageLevel != prevVoltageLevel) {
digitalWrite(GREENLED_OUT, bitRead(voltageLevel, 0));
digitalWrite(REDLED_OUT, bitRead(voltageLevel, 1));
prevVoltageLevel = voltageLevel;
}
}
/* ---------------------------------------------------------------------------------------------- */
void show_voltage() {
rmsVolts_f = voltageSensor.getRmsVoltage(SAMPLESPERREAD);
#ifdef _USEMEANFILTER_
rmsVolts_f = meanFilter.AddValue(rmsVolts_f);
#endif
#ifdef _ROUNDUP_
rmsVolts = int(rmsVolts_f + 0.5f);
#else
rmsVolts = int(rmsVolts_f);
#endif
if (rmsVolts < ZEROVOLTCORRECTION) rmsVolts = 0;
display.showNum(rmsVolts);
}
/* ---------------------------------------------------------------------------------------------- */
void blink_all(byte led) {
delay(100);
digitalWrite(GREENLED_OUT, bitRead(led, 0));
digitalWrite(REDLED_OUT, bitRead(led, 1));
display.showNum(8888);
delay(400);
digitalWrite(GREENLED_OUT, LOW);
digitalWrite(REDLED_OUT, LOW);
display.clear();
}
/* ---------------------------------------------------------------------------------------------- */
void test_all_leds() {
blink_all(1);
blink_all(3);
blink_all(2);
delay(1000);
}
/* ---------------------------------------------------------------------------------------------- */
void setup() {
pinMode(GREENLED_OUT, OUTPUT);
pinMode(REDLED_OUT, OUTPUT);
digitalWrite(GREENLED_OUT, LOW);
digitalWrite(REDLED_OUT, LOW);
display.init();
display.brightness(/*DARKEST*/TYPICAL);
display.clear();
test_all_leds();
voltageSensor.setSensitivity(SENSITIVITY);
#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
}
/* ---------------------------------------------------------------------------------------------- */