#include <LiquidCrystal.h>
#include <OneWire.h>
#include <DallasTemperature.h>
// LCD Connections (4-bit mode)
LiquidCrystal lcd(7, 8, 9, 10, 11, 12); // RS, EN, D4, D5, D6, D7
// Temperature Sensor
#define ONE_WIRE_BUS 2
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
// Analog Pins
const int voltagePin = A0;
const int currentPin = A1;
const int frequencyPin = 3;
// Calibration Constants (Adjust during calibration)
const float VOLTAGE_CALIBRATION = 100; // For 220V AC
const float CURRENT_CALIBRATION = 50; // For 30A SCT-013
const float VREF = 5.0; // Arduino reference voltage
const int ADC_RESOLUTION = 1023; // 10-bit ADC
// Measurement Variables
float voltage = 0;
float current = 0;
float power = 0;
float energy = 0;
float frequency = 0;
float temperature = 0;
// Timing Variables
unsigned long lastUpdate = 0;
volatile unsigned long zeroCrossCount = 0;
volatile unsigned long lastZeroCrossTime = 0;
volatile unsigned long currentZeroCrossTime = 0;
volatile bool newZeroCross = false;
void setup() {
lcd.begin(20, 4); // Configure for 20x4 character display
sensors.begin();
Serial.begin(9600);
// Set up zero-crossing detection interrupt on pin 3
pinMode(3, INPUT_PULLUP); // Enable pull-up resistor for better signal
attachInterrupt(digitalPinToInterrupt(3), zeroCrossISR, RISING);
// Initial display
lcd.print("220V Power Monitor");
delay(2000);
lcd.clear();
// Initialize timing variables
lastZeroCrossTime = micros();
}
void loop() {
// Update frequency whenever a new zero-cross is detected
if (newZeroCross) {
noInterrupts();
unsigned long period = currentZeroCrossTime - lastZeroCrossTime;
newZeroCross = false;
interrupts();
if (period > 0) {
frequency = 1000000.0 / period; // Convert microseconds to Hz
lastZeroCrossTime = currentZeroCrossTime;
}
}
if (millis() - lastUpdate >= 1000) { // Update every second
measureACVoltage();
measureCurrent();
calculatePower();
calculateEnergy();
measureTemperature();
updateDisplay();
// Debug output
Serial.print("Frequency: ");
Serial.print(frequency, 1);
Serial.println(" Hz");
lastUpdate = millis();
}
}
void measureACVoltage() {
float sum = 0;
for (int i = 0; i < 500; i++) {
float sensorValue = analogRead(voltagePin);
float voltageInstant = (sensorValue - 512) * (VREF / ADC_RESOLUTION);
sum += sq(voltageInstant);
delayMicroseconds(200);
}
voltage = sqrt(sum / 500) * VOLTAGE_CALIBRATION;
}
void measureCurrent() {
float sum = 0;
for (int i = 0; i < 500; i++) {
float sensorValue = analogRead(currentPin);
float currentInstant = (sensorValue - 512) * (VREF / ADC_RESOLUTION);
sum += sq(currentInstant);
delayMicroseconds(200);
}
current = sqrt(sum / 500) * CURRENT_CALIBRATION;
}
void calculatePower() {
power = voltage * current; // Assuming unity power factor
}
void calculateEnergy() {
energy += power / 3600.0; // Watt-seconds to Watt-hours
}
void measureTemperature() {
sensors.requestTemperatures();
temperature = sensors.getTempCByIndex(0);
}
void zeroCrossISR() {
// Record time of zero-cross in microseconds
currentZeroCrossTime = micros();
newZeroCross = true;
}
void updateDisplay() {
lcd.clear();
// Line 1: Voltage and Current
lcd.setCursor(0, 0);
lcd.print("V:");
lcd.print(voltage, 1);
lcd.print("V I:");
lcd.print(current, 2);
lcd.print("A");
// Line 2: Power and Energy
lcd.setCursor(0, 1);
lcd.print("Power:");
lcd.print(power, 1);
lcd.print("W");
lcd.setCursor(0, 2);
lcd.print("Energy:");
lcd.print(energy, 2);
lcd.print("Wh");
// Line 3: Frequency and Temperature
lcd.setCursor(0, 3);
lcd.print("Frequency:");
if (frequency >= 45 && frequency <= 65) { // Valid frequency range
lcd.print(frequency, 1);
} else {
lcd.print("---Hz"); // Display dashes if frequency is invalid
}
//lcd.print("Hz T:");
//lcd.print(temperature, 1);
//lcd.write(223); // Degree symbol
//lcd.print("C");
}