#include <SimpleTimer.h>
SimpleTimer timer;
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
#define Rvin 36 //Voltage read pins
#define Yvin 39
#define Bvin 34
const int CTR = 35; //CT read pins
const int CTY = 32;
const int CTB = 33;
#define IRK 25
#define IYK 26
#define IBK 27
bool IRKState = 0;
bool IYKState = 0;
bool IBKState = 0;
#define CTRange 20; //set Non-invasive AC Current Sensor range (5A,10A,20A)
int OCS = 20; //Over current setting
int Idelaytime = 1;
int ITimeloopR1 = 0;
int ITimeloopY1 = 0;
int ITimeloopB1 = 0;
unsigned long Ir1currenttime = 0;
unsigned long Ir1previoustime = 0;
unsigned long Iy1currenttime = 0;
unsigned long Iy1previoustime = 0;
unsigned long Ib1currenttime = 0;
unsigned long Ib1previoustime = 0;
int IsecR1 = 0;
int IsecY1 = 0;
int IsecB1 = 0;
// VREF: Analog reference
// For Arduino UNO, Leonardo and mega2560, etc. change VREF to 5
// For Arduino Zero, Due, MKR Family, ESP32, etc. 3V3 controllers, change VREF to 3.3
#define VREF 3.3
int Vdelaytime = 2;
int UnderVolt = 180; //Under Voltage set at 180V phase voltage
int OverVolt = 260; //Over Voltage set at 250V phase voltage
int VTimeloopR1 = 0;
int VTimeloopR2 = 0;
int VTimeloopY1 = 0;
int VTimeloopY2 = 0;
int VTimeloopB1 = 0;
int VTimeloopB2 = 0;
unsigned long vr1currenttime = 0;
unsigned long vr2currenttime = 0;
unsigned long vr1previoustime = 0;
unsigned long vr2previoustime = 0;
unsigned long vy1currenttime = 0;
unsigned long vy2currenttime = 0;
unsigned long vy1previoustime = 0;
unsigned long vy2previoustime = 0;
unsigned long vb1currenttime = 0;
unsigned long vb2currenttime = 0;
unsigned long vb1previoustime = 0;
unsigned long vb2previoustime = 0;
unsigned long blinkcurrentmillis = 0;
unsigned long blinkpreoviousmillis = 0;
long interval = 5000;
int VsecR1 = 0;
int VsecR2 = 0;
int VsecY1 = 0;
int VsecY2 = 0;
int VsecB1 = 0;
int VsecB2 = 0;
#define Bypass 14
#define KBypass 16
bool BypassState = LOW;
bool KBypassState = LOW;
#define VRK1 5
bool VRK1State = LOW;
#define VYK2 18
bool VYK2State = LOW;
#define VBK3 19
bool VBK3State = LOW;
#define VYK4 23
bool VYK4State = LOW;
#define Buzzer 12
#define Faultled 4
bool faultledstate = 1;
#define OKLED 2
#define Fan 13
bool FanState = LOW;
#define DHTPIN 15
const float Kc = 3950; // should match the Kc Coefficient of the thermistor
//Assumes a 10K@25℃ NTC thermistor connected in series with a 10K resistor
void setup()
{
Serial.begin(115200);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
// Clear the buffer
display.clearDisplay();
// Display Text
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 28);
display.println("Hello... Hashva!");
display.display();
display.clearDisplay();
pinMode(CTR, INPUT);
pinMode(CTY, INPUT);
pinMode(CTB, INPUT);
pinMode(Rvin, INPUT);
pinMode(Yvin, INPUT);
pinMode(Bvin, INPUT);
pinMode(DHTPIN, INPUT);
pinMode(Bypass, INPUT_PULLUP);
pinMode(VRK1, OUTPUT);
pinMode(VYK2, OUTPUT);
pinMode(VYK4, OUTPUT);
pinMode(VBK3, OUTPUT);
pinMode(IRK, OUTPUT);
pinMode(IYK, OUTPUT);
pinMode(IBK, OUTPUT);
//During Starting all Relays should TURN OFF
digitalWrite(VRK1, LOW);
digitalWrite(VYK2, LOW);
digitalWrite(VBK3, LOW);
digitalWrite(VYK4, LOW);
digitalWrite(IRK, LOW);
digitalWrite(IYK, LOW);
digitalWrite(IBK, LOW);
pinMode(KBypass, OUTPUT);
pinMode(Faultled, OUTPUT);
pinMode(OKLED, OUTPUT);
pinMode(Buzzer, OUTPUT);
pinMode(Fan, OUTPUT);
timer.setInterval(100, VoltagRead);
timer.setInterval(100, CurrentRead);
timer.setInterval(1000L, TempControl);
delay(1000);
}
// get maximum reading value R Phase
int Rmax() {
int maxR = 0;
for (int R = 0; R < 100; R++) {
int Rphase = analogRead(Rvin); // read from analog channel 0 (A0)
if (maxR < Rphase) maxR = Rphase;
delayMicroseconds(100);
}
return maxR;
}
// get maximum reading value Y Phase
int Ymax() {
int maxY = 0;
for (int Y = 0; Y < 100; Y++) {
int Yphase = analogRead(Yvin); // read from analog channel 1 (A1)
if (maxY < Yphase) maxY = Yphase;
delayMicroseconds(100);
}
return maxY;
}
// get maximum reading value B Phase
int Bmax() {
int maxB = 0;
for (int B = 0; B < 100; B++) {
int Bphase = analogRead(Bvin); // read from analog channel 2 (A2)
if (maxB < Bphase) maxB = Bphase;
delayMicroseconds(100);
}
return maxB;
}
//R Phase CT
float ReadCTRValue()
{
float CTRVal = 0;
float RpeakVoltage = 0;
float RvoltageVirtualValue = 0; //Vrms
for (int i = 0; i < 5; i++)
{
RpeakVoltage += analogRead(CTR); //read peak voltage
delay(1);
}
RpeakVoltage = RpeakVoltage / 5;
RvoltageVirtualValue = RpeakVoltage * 0.707; //change the peak voltage to the Virtual Value of voltage
/*The circuit is amplified by 2 times, so it is divided by 2.*/
RvoltageVirtualValue = (RvoltageVirtualValue / 4095 * VREF ) / 2;
CTRVal = RvoltageVirtualValue * CTRange;
return CTRVal;
}
//Y Phase CT
float ReadCTYValue()
{
float CTYVal = 0;
float YpeakVoltage = 0;
float YvoltageVirtualValue = 0; //Vrms
for (int i = 0; i < 5; i++)
{
YpeakVoltage += analogRead(CTY); //read peak voltage
delay(1);
}
YpeakVoltage = YpeakVoltage / 5;
YvoltageVirtualValue = YpeakVoltage * 0.707; //change the peak voltage to the Virtual Value of voltage
/*The circuit is amplified by 2 times, so it is divided by 2.*/
YvoltageVirtualValue = (YvoltageVirtualValue / 4095 * VREF ) / 2;
CTYVal = YvoltageVirtualValue * CTRange;
return CTYVal;
}
//B Phase CT
float ReadCTBValue()
{
float CTBVal = 0;
float BpeakVoltage = 0;
float BvoltageVirtualValue = 0; //Vrms
for (int i = 0; i < 5; i++)
{
BpeakVoltage += analogRead(CTB); //read peak voltage
delay(1);
}
BpeakVoltage = BpeakVoltage / 5;
BvoltageVirtualValue = BpeakVoltage * 0.707; //change the peak voltage to the Virtual Value of voltage
/*The circuit is amplified by 2 times, so it is divided by 2.*/
BvoltageVirtualValue = (BvoltageVirtualValue / 4095 * VREF ) / 2;
CTBVal = BvoltageVirtualValue * CTRange;
return CTBVal;
}
void loop()
{
display.clearDisplay();
timer.run();
}
void VoltagRead()
{
//Bypass Setup
if (digitalRead(Bypass) == LOW && BypassState == LOW)
{
digitalWrite(KBypass, HIGH);
BypassState = 1;
KBypassState = 1;
}
if (digitalRead(Bypass) == HIGH && BypassState == HIGH)
{
digitalWrite(KBypass, LOW);
BypassState = 0;
KBypassState = 0;
}
//R phase output
char RVolt[10];
// get amplitude (maximum - or peak value)
uint32_t vrout = Rmax();
// get actual voltage (ADC voltage reference = 1.1V)
vrout = vrout * 1100 / 4095;
// calculate the RMS value ( = peak/√2 )
vrout /= sqrt(2);
Serial.print("R= ");
Serial.println(vrout);
//Y phase output
char YVolt[10];
uint32_t vyout = Ymax();
vyout = vyout * 1100 / 4095;
vyout /= sqrt(2);
Serial.print("Y= ");
Serial.println(vyout);
//B phase output
char BVolt[10];
uint32_t vbout = Bmax();
vbout = vbout * 1100 / 4095;
vbout /= sqrt(2);
Serial.print("B= ");
Serial.println(vbout);
//R Phase Timeloop
if (((vrout < UnderVolt) || (vrout > OverVolt)) && digitalRead(Bypass) == HIGH)
{
vr1currenttime = millis();
}
if (((vrout >= UnderVolt) && (vrout <= OverVolt)) || digitalRead(Bypass) == LOW)
{
vr2currenttime = millis();
VTimeloopR1 = LOW;
}
//Y Phase Timeloop
if (((vyout < UnderVolt) || (vyout > OverVolt)) && digitalRead(Bypass) == HIGH)
{
vy1currenttime = millis();
}
if (((vyout >= UnderVolt) && (vyout <= OverVolt)) || digitalRead(Bypass) == LOW)
{
vy2currenttime = millis();
VTimeloopY1 = LOW;
}
//B Phase Timeloop
if (((vbout < UnderVolt) || (vbout > OverVolt)) && digitalRead(Bypass) == HIGH)
{
vb1currenttime = millis();
}
if (((vbout >= UnderVolt) && (vbout <= OverVolt)) || digitalRead(Bypass) == LOW)
{
vb2currenttime = millis();
VTimeloopB1 = LOW;
}
// R Phase Ondelay Timer for K1 Relay ON
if (((vrout < UnderVolt) || (vrout > OverVolt)) && digitalRead(Bypass) == HIGH && VTimeloopR1 == 0 && digitalRead(VRK1) == LOW)
{
VTimeloopR1 = 1;
VsecR1 = Vdelaytime;
}
if (VTimeloopR1 == 1)
{
if ((vr1currenttime - vr1previoustime) > 1000)
{
VsecR1--;
vr1previoustime = vr1currenttime;
if (VsecR1 <= 0)
{
VTimeloopR1 = 0;
digitalWrite(VRK1, HIGH);
VRK1State = HIGH;
VsecR1 = 0;
}
}
}
// R Phase Ondelay Timer for K1 Relay OFF
if(((vrout >= UnderVolt) && (vrout <= OverVolt) || digitalRead(Bypass) == LOW) && VTimeloopR2 == 0 && digitalRead(VRK1) == HIGH)
{
VTimeloopR2 = 1;
VsecR2 = Vdelaytime;
}
if (VTimeloopR2 == 1)
{
if ((vr2currenttime - vr2previoustime) > 1000)
{
VsecR2--;
vr2previoustime = vr2currenttime;
if (VsecR2 <= 0)
{
VTimeloopR2 = 0;
digitalWrite(VRK1, LOW);
VRK1State = LOW;
VsecR2 = 0;
}
}
}
// Y Phase Ondelay Timer for K2 Relay ON
if (((vyout < UnderVolt) || (vyout > OverVolt)) && digitalRead(Bypass) == HIGH && VTimeloopY1 == 0 && digitalRead(VYK2) == LOW)
{
VTimeloopY1 = 1;
VsecY1 = Vdelaytime;
}
if (VTimeloopY1 == 1)
{
if ((vy1currenttime - vy1previoustime) > 1000)
{
VsecY1--;
vy1previoustime = vy1currenttime;
if (VsecY1 <= 0)
{
VTimeloopY1 = 0;
digitalWrite(VYK2, HIGH);
VYK2State = HIGH;
VsecY1 = 0;
}
}
}
// Y Phase Ondelay Timer for K2 Relay OFF
if (((vyout >= UnderVolt) && (vyout <= OverVolt) || digitalRead(Bypass) == LOW) && VTimeloopY2 == 0 && digitalRead(VYK2) == HIGH)
{
VTimeloopY2 = 1;
VsecY2 = Vdelaytime;
}
if (VTimeloopY2 == 1)
{
if ((vy2currenttime - vy2previoustime) > 1000)
{
VsecY2--;
vy2previoustime = vy2currenttime;
if (VsecY2 <= 0)
{
VTimeloopY2 = 0;
digitalWrite(VYK2, LOW);
VYK2State = LOW;
VsecY2 = 0;
}
}
}
// B Phase Ondelay Timer for K3 Relay ON
if (((vbout < UnderVolt) || (vbout > OverVolt)) && digitalRead(Bypass) == HIGH && VTimeloopB1 == 0 && digitalRead(VBK3) == LOW)
{
VTimeloopB1 = 1;
VsecB1 = Vdelaytime;
}
if (VTimeloopB1 == 1)
{
if ((vb1currenttime - vb1previoustime) > 1000)
{
VsecB1--;
vb1previoustime = vb1currenttime;
if (VsecB1 <= 0)
{
VTimeloopB1 = 0;
digitalWrite(VBK3, HIGH);
VBK3State = HIGH;
VsecB1 = 0;
}
}
}
// B Phase Ondelay Timer for K3 Relay OFF
if (((vbout >= UnderVolt) && (vbout <= OverVolt) || digitalRead(Bypass) == LOW) && VTimeloopB2 == 0 && digitalRead(VBK3) == HIGH)
{
VTimeloopB2 = 1;
VsecB2 = Vdelaytime;
}
if (VTimeloopB2 == 1)
{
if ((vb2currenttime - vb2previoustime) > 1000)
{
VsecB2--;
vb2previoustime = vb2currenttime;
if (VsecB2 <= 0)
{
VTimeloopB2 = 0;
digitalWrite(VBK3, LOW);
VBK3State = LOW;
VsecB2 = 0;
}
}
}
//R&B Phase fail for K4 Pickup
if (digitalRead(VRK1) == HIGH && digitalRead(VBK3) == HIGH && digitalRead(VYK2) == LOW)
{
digitalWrite(VYK4, HIGH);
VYK4State = HIGH;
}
else if (digitalRead(VRK1) == LOW || digitalRead(VBK3) == LOW || digitalRead(VYK2) == HIGH)
{
digitalWrite(VYK4, LOW);
VYK4State = LOW;
}
//Fault Indication
if (vrout > UnderVolt && vrout < OverVolt && vyout > UnderVolt && vyout < OverVolt && vbout > UnderVolt && vbout < OverVolt && IRKState==0 && IYKState==0 && IBKState==0)
{
digitalWrite(Faultled, LOW);
digitalWrite(OKLED, HIGH);
faultledstate = 0;
}
if (vrout < UnderVolt || vrout > OverVolt || vyout < UnderVolt || vyout > OverVolt || vbout < UnderVolt || vbout > OverVolt || IRKState==1 || IYKState==1 || IBKState==1)
{
digitalWrite(Faultled, HIGH);
digitalWrite(OKLED, LOW);
faultledstate = 1;
}
//Buzzer
unsigned long blinkcurrentmillis = millis();
if (blinkcurrentmillis - blinkpreoviousmillis > interval)
{
blinkpreoviousmillis = blinkcurrentmillis;
if (vrout < UnderVolt || vrout > OverVolt || vyout < UnderVolt || vyout > OverVolt || vbout < UnderVolt || vbout > OverVolt || IRKState==1 || IYKState==1 || IBKState==1)
{
digitalWrite(Buzzer, HIGH);
delay(600);
digitalWrite(Buzzer, LOW);
delay(500);
}
}
//OLED Display Details
display.setTextSize(1);
display.setTextColor(WHITE);
display.drawCircle(8, 15, 8, WHITE);
display.drawCircle(8, 38, 8, WHITE);
display.setCursor(6, 12);
display.println("V");
display.setCursor(6, 34);
display.println("A");
display.setCursor(0, 0);
display.println(" R Y B");
display.setCursor(29, 12);
display.println(vrout);
display.setCursor(65, 12);
display.println(vyout);
display.setCursor(101, 12);
display.println(vbout);
display.setCursor(0, 44);
display.setCursor(0, 55);
display.println("STS:");
display.display();
if (vrout < UnderVolt)
{
display.setTextColor(WHITE, BLACK); //Its clear part of line
display.setCursor(25, 55);
display.println("* R Under Voltage");
display.display();
delay(100);
}
if (vrout > OverVolt)
{
display.setTextColor(WHITE, BLACK);
display.setCursor(25, 55);
display.println("* R Over Voltage");
display.display();
delay(100);
}
if (vyout < UnderVolt)
{
display.setTextColor(WHITE, BLACK);
display.setCursor(25, 55);
display.println("* Y Under Voltage");
display.display();
delay(100);
}
if (vyout > OverVolt)
{
display.setTextColor(WHITE, BLACK);
display.setCursor(25, 55);
display.println("* Y Over Voltage");
display.display();
delay(100);
}
if (vbout < UnderVolt)
{
display.setTextColor(WHITE, BLACK);
display.setCursor(25, 55);
display.println("* B Under Voltage");
display.display();
delay(100);
}
if (vbout > OverVolt)
{
display.setTextColor(WHITE, BLACK);
display.setCursor(25, 55);
display.println("* B Over Voltage");
display.display();
delay(100);
}
if ( ((vrout >= UnderVolt) && (vrout <= OverVolt)) && ((vyout >= UnderVolt) && (vyout <= OverVolt)) && ((vbout >= UnderVolt) && (vbout <= OverVolt)))
{
display.setTextColor(WHITE, BLACK);
display.setCursor(40, 55);
display.println("~~V Normal~~");
display.display();
delay(100);
}
if (digitalRead(Bypass) == LOW)
{
display.setTextColor(WHITE, BLACK);
display.setCursor(37, 55);
display.println("~~Bypass ON~~ ");
display.display();
delay(100);
}
}
void CurrentRead()
{
//R Phase CT read/control
float CTRVal = ReadCTRValue(); //read AC Current Value of R
Serial.print(CTRVal);
Serial.println(" A/Rphase");
float CTYVal = ReadCTYValue(); //read AC Current Value of Y
Serial.print(CTYVal);
Serial.println(" A/Yphase");
float CTBVal = ReadCTBValue(); //read AC Current Value of B
Serial.print(CTBVal);
Serial.println(" A/Bphase");
//R Phase Time loop Ir
if (CTRVal > OCS)
{
Ir1currenttime = millis();
}
if (CTRVal < OCS)
{
ITimeloopR1 = LOW;
}
//Y Phase Time loop Iy
if (CTYVal > OCS)
{
Iy1currenttime = millis();
}
if (CTYVal < OCS)
{
ITimeloopY1 = LOW;
}
//B Phase Time loop Ib
if (CTBVal > OCS)
{
Ib1currenttime = millis();
}
if (CTBVal < OCS)
{
ITimeloopB1 = LOW;
}
// R Phase Ondelay Timer for IRK Relay ON/OFF
if (CTRVal > OCS && ITimeloopR1 == 0 && IRKState == LOW)
{
ITimeloopR1 = 1;
IsecR1 = Idelaytime;
}
if (ITimeloopR1 == 1)
{
if ((Ir1currenttime - Ir1previoustime) > 1000)
{
IsecR1--;
Ir1previoustime = Ir1currenttime;
if (IsecR1 <= 0)
{
ITimeloopR1 = 0;
digitalWrite(IRK, HIGH);
IRKState = HIGH;
IsecR1 = 0;
}
}
}
if (CTRVal < OCS)
{
digitalWrite(IRK, LOW);
IRKState = 0;
}
//Y Phase CT read/control
// Y Phase Ondelay Timer for IYK Relay ON/OFF
if (CTYVal > OCS && ITimeloopY1 == 0 && IYKState == LOW)
{
ITimeloopY1 = 1;
IsecY1 = Idelaytime;
}
if (ITimeloopY1 == 1)
{
if ((Iy1currenttime - Iy1previoustime) > 1000)
{
IsecY1--;
Iy1previoustime = Iy1currenttime;
if (IsecY1 <= 0)
{
ITimeloopY1 = 0;
digitalWrite(IYK, HIGH);
IYKState = HIGH;
IsecY1 = 0;
}
}
}
if (CTYVal < OCS)
{
digitalWrite(IYK, LOW);
IYKState = 0;
}
//B Phase CT read/control
// B Phase Ondelay Timer for IBK Relay ON/OFF
if (CTBVal > OCS && ITimeloopB1 == 0 && IBKState == LOW)
{
ITimeloopB1 = 1;
IsecB1 = Idelaytime;
}
if (ITimeloopB1 == 1)
{
if ((Ib1currenttime - Ib1previoustime) > 1000)
{
IsecB1--;
Ib1previoustime = Ib1currenttime;
if (IsecB1 <= 0)
{
ITimeloopB1 = 0;
digitalWrite(IBK, HIGH);
IBKState = HIGH;
IsecB1 = 0;
}
}
}
if(CTBVal < OCS)
{
digitalWrite(IBK, LOW);
IBKState = 0;
}
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(22, 34);
display.println(CTRVal);
display.setCursor(59, 34);
display.println(CTYVal);
display.setCursor(96, 34);
display.println(CTBVal);
display.display();
if (CTRVal > OCS)
{
display.setTextColor(WHITE, BLACK);
display.setCursor(25, 55);
display.println("* R OCS Trip");
display.display();
delay(100);
}
if (CTYVal > OCS)
{
display.setTextColor(WHITE, BLACK);
display.setCursor(25, 55);
display.println("* Y OCS Trip");
display.display();
delay(100);
}
if (CTBVal > OCS)
{
display.setTextColor(WHITE, BLACK);
display.setCursor(25, 55);
display.println("* B OCS Trip");
display.display();
delay(100);
}
if((CTRVal <= OCS) && (CTYVal <= OCS) && (CTBVal <= OCS))
{
display.setTextColor(WHITE, BLACK);
display.setCursor(40, 55);
display.println("~~I Normal~~");
display.display();
delay(100);
}
}
void TempControl()
{
//Panel Temperature control
int Tempval = analogRead(DHTPIN);
float Temperature = 1 / (log(1 / (4095. / Tempval - 1)) / Kc + 1.0 / 298.15) - 273.15;
Serial.print("Temperature: ");
Serial.print(Temperature);
Serial.println(" ℃");
if (Temperature > 40)
{
digitalWrite(Fan, HIGH); //K5 for Panel cooling fan
FanState = HIGH;
display.setTextColor(WHITE, BLACK);
display.setCursor(40, 55);
display.println("* T>40 Fan ON");
display.display();
delay(100);
}
else if (Temperature < 40)
{
digitalWrite(Fan, LOW);
FanState = LOW;
}
}