#include <LiquidCrystal_I2C.h> // Hinzufügen von Bibliothek LiquidCrystal_I2C
#include <Wire.h> // Hinzufügen von Bibliothek Wire
#include <OneWire.h> // Hinzufügen von Bibliothek OneWire
#include <DallasTemperature.h> // Hinzufügen von Bibliothek DallasTemperature
#define ACS724 A1 // definierte ACS724 auf AnalogPort 1
#define buzzer 4 // definiere Buzzer auf digital Pin 13
#define state_red 5 // definiere LED-state_red auf digital Pin 11
#define state_green 6 // definiere LED-state_green auf digital Pin 10
#define state_blue 7 // definiere LED-state_blue auf digital Pin 9
#define IO_red 8 // definiere LED-IO_red auf digital Pin 6
#define IO_green 9 // definiere ILED-IO_green auf digital Pin 5
#define Info 3 // definiere Info-Taster auf digital Pin 4 (extern Pullup!)
#define PWM_FAN 11 // definiere PWN-Pin zur Lüftersteuerung auf digitalen Pin 3
#define DS18B20_WIRE_BUS 12 // definiere Daten-Pin für DS18B20 auf digitalen Pin 2; alternative: const int DS18B20_WIRE_BUS = 2;
#define momentarySwitchPin 2 // definiere I/O-Taster auf digital Pin 8 (extern Pullup!) ->Doppelbelegung
#define latchingSwitchInputPin 2 // definiere I/O Input auf digital Pin 8 ->Doppelbelegung
#define latchingSwitchOutputPin 10 // definiere I/O Ausgangs-Pin zum Relay auf digitalen Pin 7
OneWire DS18B20(DS18B20_WIRE_BUS); // erstelle OneWire-Gerät "DS18B20" auf "DS18B20_WIRE_BUS" (digitaler PIN 2)
DallasTemperature TempSensor(&DS18B20); // ertselle "TempSensor" für OneWire-Gerät "DS18B20"
const int lcd_i2c = 0x27; // aktuelle I2C-Adresse des LCD in konstanten Integer-Variable
LiquidCrystal_I2C lcd(lcd_i2c, 20, 4); // I2C LCD mit 20 Zeichen, 4 Zeilen an der I2C-Adresse aus der Variable "lcd_i2c" (extern Pullup!)
int switchState = HIGH; // erstele Integer-Variable zum Speichern des Switch-Status
int lastSwitchState = HIGH; // erstele Integer-Variable zum Speichern des letzen Switch-Status
int latchingSwitchState = LOW; // erstele Integer-Variable zum Speichern des eingerasteten Switch-Status
int rmpFan = 0; // erstele Integer-Variable zum Speichern der Drehzahl des Lüfters in %
int pwmValue = 0; // erstele Integer-Variable zum Speichern des PWM-Werts für den Lüfter
const int pwmMin = 0; // erstele konstante Integer-Variable für Minimun des PWM-Werts (0% duty cycle)
const int pwmMax = 255; // erstele konstante Integer-Variable für Maximum des PWM-Werts (100% duty cycle)
const float tempMin = 40.00; // erstele konstante Float-Variable (Kommazahl) für Minimum der Temperatur
const float tempMax = 80.00; // erstele konstante Float-Variable (Kommazahl) für Maximum der Temperatur
const float TempOff = 120.00; // erstele konstante Float-Variable (Kommazahl) für Abschalten wegen Überhitzung
const float AmpsOff = 4.50; // erstele konstante Float-Variable (Kommazahl) für Abschalten wegen Überlastung an einen der Ausgänge
float Temp = 0.00; // erstele Float-Variable (Kommazahl) für Temperaturmessung
const float VbusZeroCurrent = 2.50; // erstelle konstante Float-Variable (Kommazahl) für Bus-Spannung vom ACS wenn Stromstaerke = 0A (muss ausgemessen werden)
const float sense = 200; // erstelle konstante Float-Variable (Kommazahl) für Empfindlichkeit vom ACS724 mV/A (2.5A = 800, 5A = 400, 10A = 200, 20A = 100, ... siehe Datasheet)
float Amps1 = 4.00; // erstele Float-Variable (Kommazahl) für Strommessung an Ausgang 1
float Amps2 = 4.00; // erstele Float-Variable (Kommazahl) für Strommessung an Ausgang 2
float Volt1 = 5.00; // erstele Float-Variable (Kommazahl) für Spannungsmessung an Ausgang 1
float Volt2 = -5.00; // erstele Float-Variable (Kommazahl) für Spannungsmessung an Ausgang 2
byte fan[8] = {0b00000, 0b11001, 0b01011, 0b00100, 0b11010, 0b10011, 0b00000, 0b00000}; // erstelle eigenes Symbol für lüfter, 8 bit
byte temp[8] = {0b10100, 0b00101, 0b10100, 0b00101, 0b10100, 0b01110, 0b01010, 0b01110}; // erstelle eigenes Symbol für Thermometer, 8 bit
byte pm[8] = {0b00000, 0b00100, 0b01110, 0b00100, 0b00000, 0b01110, 0b00000, 0b00000}; // erstelle eigenes Symbol für +/-, 8 bit
byte rl[8] = {0b00001, 0b00001, 0b00001, 0b00001, 0b00001, 0b00001, 0b00001, 0b00001}; // erstelle eigenes Symbol für senkr. Strich rechts, 8 bit
byte ll[8] = {0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b10000}; // erstelle eigenes Symbol für senkr. Strich links, 8 bit
void setup(void){
Serial.begin(9600); // initialisiere serielle Konsole mit 9600 bauds (bits pro Sek.)
pinMode(buzzer, OUTPUT); // setze Pin Buzzer als Ausgang
pinMode(state_red, OUTPUT); // setze Pin LED-state_red als Ausgang
pinMode(state_green, OUTPUT); // setze Pin LED-state_green als Ausgang
pinMode(state_blue, OUTPUT); // setze Pin LED-state_blue als Ausgang
pinMode(IO_red, OUTPUT); // setze Pin LED-IO_redIO_red als Ausgang
pinMode(IO_green, OUTPUT); // setze Pin LED-IO_green als Ausgang
pinMode(Info, INPUT); // setze Pin Taster-Info als Eingang (extern Pullup!)
pinMode(momentarySwitchPin, INPUT); // setze Pin Taster-I/O als Eingang (extern Pullup!)
pinMode(latchingSwitchInputPin, INPUT); // setze Pin I/O-Input als Eingang
pinMode(latchingSwitchOutputPin, OUTPUT); // setze Pin I/O-Ausgang für Relay als Ausgang
pinMode(PWM_FAN, OUTPUT); // setze Pin PWM für Lüfter als Ausgang
TempSensor.begin(); // Starte Temperatur-Sensor DS18B20
lcd.init(); // initialisiere lCD-Display
lcd.backlight(); // schalte Hintergrundbeleuchtung vom LCD an
lcd.clear(); // leere LCD-Display
lcd.createChar(0, fan); // bilde eigenes Symbol für lüfter auf LCD-Display,byte "0"
lcd.createChar(1, temp); // bilde eigenes Symbol für Thermometer auf LCD-Display,byte "1"
lcd.createChar(2, pm); // bilde eigenes Symbol für +/- auf LCD-Display,byte "2"
lcd.createChar(3, rl); // bilde eigenes Symbol für senkr. Strich rechts auf LCD-Display,byte "3"
lcd.createChar(4, ll); // bilde eigenes Symbol für senkr. Strich links auf LCD-Display,byte "4"
start(); // rufe externe Funktion "start" auf
}
void loop(void){
CurrentACin();
TempSensor.requestTemperatures();
Temp = TempSensor.getTempCByIndex(0);
if (Temp >= tempMin && Temp <= tempMax && Amps1 <= AmpsOff && Amps2 <= AmpsOff){ // wenn Temperatur zwischen Min und Max und Amps1/2 unter AmpsOff, dann...
state_color(1,1,0); // rufe externe Funktion "state_color" mit Parametern auf, Status LED Gelb
int pwmValue = map(Temp, tempMin, tempMax, pwmMin, pwmMax); // berechne pwmValue mit map-Funktion, map(value, fromLow, fromHigh, toLow, toHigh)
analogWrite(PWM_FAN, pwmValue); // schreibe pmwValue auf den Lüfter-Pin
rmpFan = map(pwmValue, pwmMin, pwmMax, 0, 100); // berechne Lüftergeschwindigkeit in % mit map-Funktion, map(value, fromLow, fromHigh, toLow, toHigh)
}
if (Temp <= tempMin && Amps1 <= AmpsOff && Amps2 <= AmpsOff){ // wenn Temperatur unter Min und Amps1/2 unter AmpsOff, dann...
state_color(0,1,0); // rufe externe Funktion "state_color" mit Parametern auf, Status LED Gruen
int pwmValue = 0; // setze pwmValue = 0
analogWrite(PWM_FAN, pwmValue); // schreibe pmwValue auf den Lüfter-Pin
rmpFan = 0; // setze rmpFan = 0
}
if (Temp >= tempMax && Amps1 <= AmpsOff && Amps2 <= AmpsOff){ // wenn Temperatur über Max und Amps1/2 unter AmpsOff, dann...
state_color(1,0,0); // rufe externe Funktion "state_color" mit Parametern auf, Status LED Rot
int pwmValue = 255; // setze pwmValue = 255
analogWrite(PWM_FAN, pwmValue); // schreibe pmwValue auf den Lüfter-Pin
rmpFan = 100; // setze rmpFan = 100
}
if (Temp >= TempOff){overhead();} // wenn Temperatur über TempOff, dann rufe externe Funktion "overhead" auf
if (Amps1 >= AmpsOff || Amps2 >= AmpsOff){overcurrent();} // wenn Amps1/2 über AmpsOff, dann rufe externe Funktion "overcurrent" auf
switchState = digitalRead(momentarySwitchPin); // read the state of the momentary switch
if (switchState == LOW && latchingSwitchState == HIGH && Temp <= TempOff && Amps1 <= AmpsOff && Amps2 <= AmpsOff){soundOff(buzzer, 1000, 100, 3);} // if pushed (LOW) und Temp, Amps1, Amps2 kleine als [....]Off
if (switchState == LOW && latchingSwitchState == LOW && Temp <= TempOff && Amps1 <= AmpsOff && Amps2 <= AmpsOff){soundOn(buzzer, 100, 1000, 3);} // if pushed (LOW) und Temp, Amps1, Amps2 kleine als [....]Off
if (switchState == HIGH && lastSwitchState == LOW){ // check for a rising edge (transition from LOW to HIGH) on the momentary switch
latchingSwitchState = !latchingSwitchState; // toggle the state of the latching switch
digitalWrite(latchingSwitchOutputPin, latchingSwitchState); // set states
lcd.clear();
}
lastSwitchState = switchState; // update the last switch state
int zustandInfo = digitalRead(Info); // read state taster
if (latchingSwitchState == HIGH && zustandInfo == HIGH && Temp <= TempOff && Amps1 <= AmpsOff && Amps2 <= AmpsOff){run();} // if not pushed (HIGH) und Temp, Amps1, Amps2 kleine als [....]Off
if (latchingSwitchState == LOW && zustandInfo == HIGH && Temp <= TempOff && Amps1 <= AmpsOff && Amps2 <= AmpsOff){off();} // if not pushed (HIGH) und Temp, Amps1, Amps2 kleine als [....]Off
if (zustandInfo == LOW && Temp <= TempOff && Amps1 <= AmpsOff && Amps2 <= AmpsOff) {infos(Temp, rmpFan);} // if pushed (LOW) und Temp, Amps1, Amps2 kleine als [....]Off
Serial.println(TempSensor.getTempCByIndex(0));
Serial.println((String)"Temperature: "+Temp+" °C, Fan Speed: "+rmpFan+" %"); //Ausgabe Temperatur und Fanspeed in Serieller Konsole
}
void CurrentACin(){
for (int counterAVR = 0; counterAVR < 50; counterAVR++){ // 50 mal ausführen für für Erstellung eines Durchschnittswertes
float RawDataACS = analogRead(ACS724); // ADC-Wert aus ACS724 auslesen für die Berechnung
float RawACinAmps = (((((RawDataACS/1023)*5)-VbusZeroCurrent)*1000)/sense)*1000;// "(RawDataACS/1023)*5 = X" -> Umrechnung Rohdaten in Volt; "(X-VbusZeroCurrent)*1000 = Y"ür 0A und Umrechnung in mV; "(Y/sense)*1000" -> konvertiere in mA
float SummeACinAmps = SummeACinAmps + RawACinAmps; // summiere die 50 errechneten Stromstaerken -> Subtraktion ausgemessen Busspannung f
if (counterAVR == 49){ // wenn for-Schleifen 50 mal durchlaufen ist (0 bis 49), dann ...
float ACinAmps = ((SummeACinAmps / 50) / 1000)+ 0.0005; // "(SummeACinAmps / 50) = X" -> berechne Durchschnitswert in mA, "(X/1000)+0.0005" -> Umrechnung in A und auf 3 Nachkomastellen runden
Serial.print("Stromstärke: "); // Ausgabe in serieller Konsole
Serial.print(ACinAmps,3); // Ausgabe Stromstaerke mit 3 Nachkomastellen
Serial.println(" in A"); // Ausgabe in serieller Konsole
SummeACinAmps = 0; // zurücksetzen der Berechnung für nächsten Durchlauf
}
}
}
void start(){
soundStart(buzzer, 100, 1000, 1);
IO_color(1,1);
state_color(0,0,1);
lcd.setCursor(0,0); // tell the LCD1 to write on the top row
lcd.print("STARTING PLEASE WAIT");
lcd.setCursor(0,1);
lcd.print("--------------------");
lcd.setCursor(1,2);
lcd.print("THIS WILL BE TAKES");
lcd.setCursor(3,3);
lcd.print("A SHORT MOMENT");
delay(2500); // display the above for 0,5 second
lcd.clear(); // clear display lcd
lcd.noBacklight();
delay(500);
lcd.backlight();
delay(500);
lcd.noBacklight();
delay(500);
lcd.backlight();
tone(buzzer, 1000, 500);
}
void off(){
IO_color(1,0);
Serial.println("PSU is switched OFF !!!");
lcd.setCursor(0,0);
lcd.print ("--------------------");
lcd.setCursor(0,1);
lcd.print ("PSU IS SWITCHED OFF");
lcd.setCursor(0,2);
lcd.print (" TURN ON TO USE !!! ");
lcd.setCursor(0,3);
lcd.print ("--------------------");
}
void run(){
IO_color(0,1);
Serial.println("PSU ist switched ON !!!");
lcd.setCursor(0,0); // tell the lcd to write on the top row
lcd.print("OUTPUT 1 ");
lcd.setCursor(9,0);
lcd.write(byte(3));
lcd.setCursor(10,0);
lcd.write(byte(4));
lcd.setCursor(11,0);
lcd.print(" OUTPUT 2");
lcd.setCursor(0,1);
lcd.print("---------");
lcd.setCursor(9,1);
lcd.write(byte(3));
lcd.setCursor(10,1);
lcd.write(byte(4));
lcd.setCursor(11,1);
lcd.print("---------");
lcd.setCursor(0,2);
lcd.print(" +");
lcd.setCursor(2,2);
lcd.print(Volt1);
lcd.setCursor(6,2);
lcd.print(" V ");
lcd.setCursor(9,2);
lcd.write(byte(3));
lcd.setCursor(10,2);
lcd.write(byte(4));
lcd.setCursor(11,2);
lcd.print(" ");
lcd.setCursor(12,2);
lcd.print(Volt2);
lcd.setCursor(17,2);
lcd.print(" V");
lcd.setCursor(0,3);
lcd.print(" ");
lcd.setCursor(2,3);
lcd.print(Amps1);
lcd.setCursor(6,3);
lcd.print(" A ");
lcd.setCursor(9,3);
lcd.write(byte(3));
lcd.setCursor(10,3);
lcd.write(byte(4));
lcd.setCursor(11,3);
lcd.print(" ");
lcd.setCursor(13,3);
lcd.print(Amps2);
lcd.setCursor(17,3);
lcd.print(" A");
}
void overhead(){
state_color_alert(); // Status LED Rot blinkend
soundAllert(buzzer, 0.01, 100, 500, 1000);
int pwmValue = 255; // set pwmValue = 255
rmpFan = 100; // set rmpFan = 100
analogWrite(PWM_FAN, pwmValue);
latchingSwitchState = LOW; // toggle the state of the latching switch
digitalWrite(latchingSwitchOutputPin, latchingSwitchState); // set states
Serial.println("OVERHEAT PROTECTION !!!");
Serial.println("Temperatur above 120 °C; Power supply was switched off !!!");
Serial.println("Don't press the main switch while the fan is running !!!");
Serial.println("");
lcd.clear(); // clear display lcd
lcd.setCursor(0,0); // tell the LCD1 to write on the top row
lcd.print("OVERHEAT PROTECTION");
lcd.setCursor(0,1);
lcd.print("--------------------");
lcd.setCursor(1,2);
lcd.print("TEMP. ABOVE 120 ""\xDF""C");
lcd.setCursor(0,3);
lcd.print("PSU SWITCHED OFF !!!");
delay(2000);
lcd.clear();
lcd.setCursor(0,0); // tell the LCD1 to write on the top row
lcd.print("OVERHEAT PROTECTION");
lcd.setCursor(0,1);
lcd.print("--------------------");
lcd.setCursor(0,2);
lcd.print("ONLY SWITCH OFF WHEN");
lcd.setCursor(1,3);
lcd.print("THE FAN IS OFF !!!");
delay(2000); // wait for 2 seconds
lcd.clear();
}
void overcurrent(){
state_color_alert(); // Status LED Rot blinkend
soundAllert(buzzer, 0.01, 100, 500, 2000);
int pwmValue = 255; // set pwmValue = 255
rmpFan = 100; // set rmpFan = 100
analogWrite(PWM_FAN, pwmValue);
latchingSwitchState = LOW; // toggle the state of the latching switch
digitalWrite(latchingSwitchOutputPin, latchingSwitchState); // set states
Serial.println("OVERLOAD PROTECTION !!!");
Serial.println("Current-Output above 4.50 A; Power supply was switched off !!!");
Serial.println("Please reduce the load on the outputs !!!");
Serial.println("");
lcd.clear(); // clear display lcd
}
void infos(float Temp, int rmpFan){
float Temp_float = Temp; // z.B. 123,54 = 123,54
int Temp1 = Temp_float; // -> Intgeger von 123,54 = 123 ->Temp1 (Vorkomastellen)
int Temp2 = (Temp_float-Temp1)*100; // -> (123,54-123)*100 = 54 -> Temp2 (2 Nachkomastellen)
if (Temp2 <= - 0){Temp2= Temp2*(-1);} // wenn Nachkommazahl negative, dann umrechnen von Negativewert zu Positivwert
soundInfo(buzzer, 500, 1000, 5);
state_color(0,0,1);
lcd.clear(); // clear display LCD1
lcd.setCursor(0,0); // tell the LCD1 what to write on the rows an cells
lcd.print("INFORMATIONS 1/3");
lcd.setCursor(0,3);
lcd.write(byte(0));
char displayFan[3]; // create Char with 3 signs
sprintf(displayFan, "%3d", rmpFan); // placeholder for 3 signs, empty signs filled with space character
lcd.setCursor(2,3);
lcd.print(displayFan);
lcd.setCursor(6,3);
lcd.print("%");
lcd.setCursor(9,3);
lcd.write(byte(1));
char displayTemp[6]; // create Char with 6 signs
sprintf (displayTemp, "%3d.%02d", Temp1, Temp2); //placeholder for 3 signs bevor "." and 2 signs after ".", empty signs filled with space character befor after "." filled with "0"
lcd.setCursor(11,3);
lcd.print(displayTemp);
lcd.setCursor(18,3);
lcd.print("\xDF""C");
delay(3000);
}
void IO_color(int red_value, int green_value){
digitalWrite(IO_red,red_value);
digitalWrite(IO_green,green_value);
}
void state_color(int red_value, int green_value, int blue_value){
digitalWrite(state_red,red_value);
digitalWrite(state_green,green_value);
digitalWrite(state_blue,blue_value);
}
void state_color_alert(){
digitalWrite(state_red, HIGH);
delay(300); digitalWrite(state_red, LOW);
delay(300);
digitalWrite(state_red, HIGH);
delay(300);
digitalWrite(state_red, LOW);
delay(300);
digitalWrite(state_red, HIGH);
delay(300);
}
void soundStart(int PinBuzzer, int startFrequenz, int endFrequenz, int geschwindigkeit){
for (unsigned long freq = startFrequenz; freq <= endFrequenz; freq += geschwindigkeit){
tone(PinBuzzer, freq);
delay(1);
}
noTone(PinBuzzer);
}
void soundOn(int PinBuzzer, int startFrequenz, int endFrequenz, int geschwindigkeit){
for (unsigned long freq = startFrequenz; freq <= endFrequenz; freq += geschwindigkeit){
tone(PinBuzzer, freq);
delay(1);
}
noTone(PinBuzzer);
}
void soundOff(int PinBuzzer, int startFrequenz, int endFrequenz, int geschwindigkeit){
for (unsigned long freq = startFrequenz; freq > endFrequenz; freq -= geschwindigkeit){
tone(PinBuzzer, freq);
delay(1);
}
noTone(PinBuzzer);
}
void soundInfo(int PinBuzzer, int startFrequenz, int endFrequenz, int geschwindigkeit){
for (unsigned long freq = startFrequenz; freq <= endFrequenz; freq += geschwindigkeit){
tone(PinBuzzer, freq);
delay(1);
}
noTone(PinBuzzer);
}
void soundAllert(int PinBuzzer, float zwitscherFaktor, int amplitude, int basisHoehe, int dauer){
for (unsigned long i = 0; i <= dauer; i += 1){
int ix = int( sin(i * zwitscherFaktor) * amplitude ) + basisHoehe * 1.1;
tone(PinBuzzer, ix);
delay(1);
}
noTone(PinBuzzer);
}