====== Flaschenkühler - Programmversion 0.3 ====== In dieser Version soll die Regelung des Peltier-Elements in Angriff genommen werden. Um den PID-Regler einstellen zu können wäre es gut, wenn man die Daten der seriellen Schnittstelle direkt in Excel oder so speichern könnte. Das OLED-Display hat nun drei Anzeigemodi: einfach, erweitert und grafisch. Zwischen den Anzeigemodi kann durch einen langen Druck auf den oberen oder unteren Taster gewechselt werden. Diese Funktion stellt sehr komfortabel die Bibliothek [[https://github.com/fasteddy516/ButtonEvents|ButtonEvents]] zur Verfügung. Im einfachen und erweiterten Anzeigemodus werden die Soll- und Isttemperaturen nun in einer Schrittweite von 0,5°C temperaturabhängig in spezifischen Farbwerte angezeigt. 30°C werden in rot angezeigt, 0°C in türkis. Die Farbwerte habe ich mit [[http://www.barth-dev.de/online/rgb565-color-picker/|diesem Online-Tool]] erzeugt. Ab dieser Programmversion erscheint nach 100 Betriebsstunden eine Aufforderung auf dem Startbildschirm, den Flaschenkühler zu reinigen. Das Reinigungsintervall kann mit einem (schnellen) Doppeldruck auf Taster 1 zurückgesetzt werden. Das Zurücksetzen wird mit einer entsprechenden Anzeige auf dem OLED-Display quittiert. Zur Glättung der analogen Inputs, also der Thermistoren, wird ab dieser Programmversion die Bibliothek [[https://github.com/dxinteractive/ResponsiveAnalogRead|ResponsiveAnalogRead]] verwendet. Was die Bibliothek leistet wird sehr anschaulich auf [[http://damienclarke.me/code/posts/writing-a-better-noise-reducing-analogread|dieser Webseite]] erklärt. Die Anzeige der Isttemperatur auf dem Display wird dadurch sehr viel stabiler. Die Ausführung des Codes verlangsamt sich dadurch zwar um etwa 1 %, andererseits muss nun das Display nicht mehr alle 500 Millisekunden aktualisiert werden, sondern nur noch dann, wenn sich die Isttemperatur tatsächlich verändert hat. Dadurch wird die Ausführung des Programms um ca. 129 % beschleunigt. Eine erhebliche Beschleunigung der Ausführung des Codes (nämlich um ca. 229 %) konnte dadurch erreicht werden, den PID-Regler nicht in jeder Programmschleife einmal auszuführen, sondern nur alle 10 Millisekunden. // Flaschenkühler - Programmversion 0.3 // Diese Version steuert einen PC-Lüfter mit 4-Pin-Anschluss ... // ... liest das Tachosignal aus ... // ... berechnet die Drehzahl des Lüfters ... // ... liest einen Thermistor aus und berechnet die Temperatur ... // ... stellt über ein Poti die ZieltemperatureHotSidee ein ... // ... regelt den Lüfter mit einem PID-Modul ... // ... zeigt verschiedene Werte auf einem OLED-Display an ... // ... zählt die Betriebsstunden (viertelstundengenau) und speichert sie im EEPROM ... // ... pollt die Taster und speichert die Solltemperatur im EEPROM. //------------------------- Eingebundene Bibliotheken ---------------------// #include // Grafik-Bibliothek für OLED-Display #include // Bibliothek für OLED-Display (Adafruit OLED Breakout Board 1.27") #include // Bibliothek Serial Peripheral Interface (SPI) #include // Bibliothek für Änderung der Frequenz der Timer #include // Bibliothek für Berechnung von Mittelwerten #include // Bibliothek zur Glättung analoger Inpots #include // Bibliothek für PID-Regler #include // Bibliothek zum Entprellen der Taster #include // Bibliothek für Lesen und Schreiben des EEPROMS //------------------------- Definition der Inputs und Outputs ---------------------// #define potiPin A0 // Input-Pin für den Lüfter #define thermistorPin A1 // Input-Pin für den Thermistor #define tachoPin 2 // Pin für Tachosignal des Lüfters #define peltierPin 3 // PWM-Pin für Peltier-Element (hier zunächst nur als Funktionstest) #define powerPin 4 // Schaltet den MOSFET für den Lüfter #define dc 5 // #define cs 6 // Chip Select #define rst 7 // Reset #define button1Pin 8 // Taster 1 #define fanPin 9 // PWM-Pin für Lüfter #define button2Pin 12 // Taster 2 //------------------------- Definition der Farben ---------------------// #define BLACK 0x0000 #define BLUE 0x0418 #define BLUEBERRY 0xF810 #define RED 0xF800 #define GREEN 0x07E0 #define CYAN 0x07FF #define MAGENTA 0xF81F #define YELLOW 0xFFE0 #define WHITE 0xFFFF //------------------------- Definition der Variablen ---------------------// float thermistorValue = 0; // Variable in der der Wert des Thermistors gespeichert wird int potiValue = 0; // variable to store the value coming from the sensor // PWM Frequenzen uint16_t frequencyFan = 25000; // PWM-Frequenz für den Lüfter (in Hz) uint16_t frequencyPeltier = 50000; // PWM-Frequenz für den Lüfter (in Hz) // Lüfter int tachoSignal; // Tachosignal uint32_t pulseOn = 0; // Ansteigende Signalflanke (Variablenformat nicht verändern!) uint32_t pulseOff = 0; // Abfallende Signalflanke (Variablenformat nicht verändern!) uint32_t duration; // Zeit in Mikrosekunden zwischen ansteigender und abfallender Flanke (Variablenformat nicht verändern!) bool high = false; // Statevariable int rpm = 0; // Drehzahl des Lüfters in U/Min float rpmAverage = 0; // Gemittelte Drehzahl des Lüfters in U/min bool fanAlert = false; // Wird wahr, wenn der Lüfter blockiert ist bool fanAlertState = true; unsigned long fanAlertDelay = 2000;// Gibt die Verzögerung des Alarms "Lüfterfehlfunktion" in Millisekunden an unsigned long previousMillis = 0; // Temperaturen float temperatureHotSide = 0; float previousTempHotSide = 0; // Wird verwendet um festzustellen, ob die Anzeige der Isttemperatur auf dem OLED-Display aktualisiert werden muss. // Betriebsstundenzähler und Serviceintervall float operatingTime; // Betriebsstunden als Dezimalwert long lastTime = 0; float serviceInterval; // Serviceintervall als Dezimalwert bool serviceIntervalReset = false; // Wird wahr, wenn das Service Intervall zurückgesetzt wird // Adressen im EEPROM int addrOperatingTime = 0; // Startadresse für eine Variable im Datentyp float (4 Byte!) int addrTargetTemp = 4; // Startadresse für eine Variable im Datentyp double (8 Byte!) int addrDisplayMode = 13; // Adresse für den Anzeigemodus (2 Byte reserviert) int addrServiceInterval = 15; // Startadresse für eine Variable im Datentyp float (4 Byte!) // Definiert das OLED Adafruit_SSD1351 tft = Adafruit_SSD1351(cs, dc, rst); // Definiert ein Array, aus dem Farbwerte ausgelesen werden unsigned long colors[] = {0x07FF, 0x07DF, 0x077F, 0x06FF, 0x069F, 0x063F, 0x05DF, 0x057F, 0x053F, 0x049F, 0x043F, 0x03DF, 0x037F, 0x031F, 0x029F, 0x023F, 0x01DF, 0x017F, 0x011F, 0x009F, 0x003F, 0x001F, 0x101F, 0x201F, 0x281F, 0x381F, 0x401F,0x501F, 0x601F, 0x681F, 0x781F, 0x801F, 0x901F, 0x981F, 0xA81F, 0xB81F, 0xC01F, 0xD01F, 0xD81F, 0xE81F, 0xF81F, 0xF81F, 0xF81D, 0xF81B, 0xF81A, 0xF818, 0xF817, 0xF815, 0xF813, 0xF812, 0xF810, 0xF80F, 0xF80D, 0xF80C, 0xF80A, 0xF808, 0xF807, 0xF805, 0xF804, 0xF802, 0xF800}; // Informationsanzeige int displayMode; // Anzeigemodus ("0" = Einfach; "1" = Erweitert; "2" = grafisch) bool refreshPeltier = true; // Wird wahr, wenn der Anzeigebereich für das Peltier-Element aktualisiert werden muss bool refreshTargettemp = true; // Wird wahr, wenn der Anzeigebereich für die Solltemperatur aktualisiert werden muss //bool refreshActualtemp = true; bool refreshFan = true; // Wird wahr, wenn der Anzeigebereich für den Lüfter aktualisiert werden muss int x = 0; // Instantiiert ButtonEvents-Objekte ButtonEvents button1; ButtonEvents button2; // Instantiiert ein RunningAverage-Objekt zur Bechnung von Mittelwerten RunningAverage averageRPM(25); // Mittelwert aus 25 Messungen // Instantiirt ResponsiveAnalogRead-Objekte zur Glättung der analogen Inputs ResponsiveAnalogRead analog(thermistorPin, true); // Definiert den PID-Regler double Setpoint, Input, Output; double Kp=2, Ki=5, Kd=1; PID fanPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, REVERSE); // Definiert die Tracking-Variablen für die IF-Abfragen unsigned long previousMillisCalculateTemperatures = 0; // Auslesen der analogen Inputs und Berechnung der Temperaturen unsigned long previousMillisCalculatePID = 0; // Berechnung der PID-Regler (Lüfter und Peltier-Element) unsigned long previousMillisCalculateFanSpeed = 0; // Berechnung der Drehzahl des Lüfters unsigned long previousMillisDisplayActualtemp = 0; // Ausgabe der Ist-Temperatur an das OLED-Display unsigned long previousMillisDisplayFanSpeed = 0; // Ausgabe der gemittelten Lüfterdrehzahl an das OLED-Display unsigned long previousMillisDisplayGraph = 0; // Ausgabe der gemittelten Lüfterdrehzahl an das OLED-Display unsigned long previousMillisSerialPrint = 0; // Ausgabe an die serielle Schnittstelle // Definiert die Intervalle für die IF-Abfragen in Millisekunden const unsigned long intervalCalculateTemperatures = 10;// Auslesen der analogen Inputs und Berechnung der Temperaturen const unsigned long intervalCalculatePID = 10; // Berechnung der PID-Regler (Lüfter und Peltier-Element) const unsigned long intervalCalculateFanSpeed = 100; // Berechnung der Drehzahl des Lüfters const unsigned long intervalDisplayActualtemp = 500; // Ausgabe der Ist-Temperatur an das OLED-Display const unsigned long intervalDisplayFanSpeed = 500; // Ausgabe der gemittelten Lüfterdrehzahl an das OLED-Display const unsigned long intervalDisplayGraph = 1000; // Ausgabe der gemittelten Lüfterdrehzahl an das OLED-Display const unsigned long intervalSerialPrint = 500; // Ausgabe an die serielle Schnittstelle int loopCounter = 0; //------------------------- Setup ---------------------// void setup() { Serial.begin(115200); // Initialisiert das OLED-Dispaly tft.begin(); // Definiert die Pins pinMode(tachoPin, INPUT_PULLUP); // Tachosignal des Lüfters pinMode(powerPin, OUTPUT); // Schaltet den MOSFET für den Lüfter pinMode(fanPin, OUTPUT); // PWM-Signal für Lüfter pinMode(peltierPin, OUTPUT); // PWM-Signal für Peltier-Element pinMode(button1Pin, INPUT_PULLUP); // Intur Taster 1 pinMode(button2Pin, INPUT_PULLUP); // Input Taster 2 // Initialisiert die ButtonEvents-Objekte button1.attach(button1Pin); button1.debounceTime(10); button1.doubleTapTime(70); button1.holdTime(1000); button2.attach(button2Pin); button2.debounceTime(10); button2.doubleTapTime(70); button2.holdTime(1000); // Initialisiert timer1 und timer2 (timer0 bleibt unberührt) InitTimersSafe(); // Definiert die Frequenzen für die angegebenen Pins bool successFan = SetPinFrequencySafe(fanPin, frequencyFan); bool successPeltier = SetPinFrequencySafe(peltierPin, frequencyPeltier); /* //if the pin frequency was set successfully, turn pin 13 on if(successFan) { pinMode(13, OUTPUT); digitalWrite(13, HIGH); Serial.print("PWM frequency PIN D9 and D10 is set to: "); Serial.println(frequencyFan); } if(successPeltier) { Serial.print("PWM frequency PIN D3 and D11 is set to: "); Serial.println(frequencyPeltier); } */ // Initialisiert die PID-Regler fanPID.SetMode(AUTOMATIC); // Liest die im EEPROM gespeicherten Variablen aus displayMode = EEPROM.read(addrDisplayMode); operatingTime = EEPROM.readFloat(addrOperatingTime); serviceInterval = EEPROM.readFloat(addrServiceInterval); Setpoint = EEPROM.readDouble(addrTargetTemp); //operatingTime = 0; // Soll auf "0" gesetzt werden, bis die Testphase abgeschlossen ist //Setpoint = 0; //serviceInterval = 0; // Meldung "Klar zum Start!" Serial.println(""); Serial.print(""); Serial.print(""); // Startbildschirm tft.fillScreen(BLACK); tft.setCursor(25, 32); tft.setTextColor(WHITE, BLACK); tft.setTextSize(0); tft.print("Flaschenk"); tft.print((char)154); tft.print("hler"); tft.setCursor(20, 55); tft.print("Programmversion"); tft.setCursor(45, 75); tft.setTextSize(2); tft.print("0.3"); if (serviceInterval >= 1.00) { tft.setCursor(0, 96); tft.setTextColor(RED, BLACK); tft.setTextSize(0); tft.print("Reinigung empfohlen!"); } tft.setCursor(10, 108); tft.setTextColor(WHITE, BLACK); tft.setTextSize(0); tft.print("Betriebsstunden:"); tft.setCursor(10, 121); tft.print(operatingTime); tft.print(" Stunden"); delay(2000); tft.fillScreen(BLACK); } //------------------------- Loop ---------------------// void loop() { // Aktuelle Zeit abfragen unsigned long currentMillis = millis(); loopCounter++; //------------------------- Abfrage der Taster ---------------------// // Lesen und entprellen des Tasters button1.update(); button2.update(); if (button1.tapped() == true) { Setpoint = Setpoint + 0.5; EEPROM.updateDouble(addrTargetTemp, Setpoint); //Serial.print("Updated Setpoint: "); Serial.println(Setpoint); refreshTargettemp = true; if (Setpoint >= 30.00) { Setpoint = 30.00; } } if (button1.held() == true) { displayMode++; if (displayMode > 2) { displayMode = 0; } tft.fillScreen(BLACK); // Der Bildschirm muss einmalig gelöscht werden EEPROM.update(addrDisplayMode, displayMode); //Serial.print("Displaymode: "); Serial.println(displayMode); refreshPeltier = true; refreshTargettemp = true; previousTempHotSide = 150; refreshFan= true; x = 0; } if (button1.doubleTapped() == true) { serviceInterval = 0; EEPROM.updateFloat(addrServiceInterval, serviceInterval); Serial.println("Service Interval reseted!"); serviceIntervalReset = true; } if (button2.tapped() == true) { Setpoint = Setpoint - 0.5; EEPROM.updateDouble(addrTargetTemp, Setpoint); //Serial.print("Updated Setpoint: "); Serial.println(Setpoint); refreshTargettemp = true; if (Setpoint <= 0.00) { Setpoint = 0.00; } } if (button2.held() == true) { displayMode--; if (displayMode < 0) { displayMode = 2; } tft.fillScreen(BLACK); // Der Bildschirm muss einmalig gelöscht werden EEPROM.update(addrDisplayMode, displayMode); //Serial.print("Displaymode: "); Serial.println(displayMode); refreshPeltier = true; refreshTargettemp = true; previousTempHotSide = 150; refreshFan= true; x = 0; } //------------------------- Auslesen der analogen Inputs (Thermistoren) und Berechnung der Temperaturen ---------------------// if ((unsigned long)(currentMillis - previousMillisCalculateTemperatures) >= intervalCalculateTemperatures) { // Lese die analogen Inputs aus potiValue = analogRead(potiPin); // Poti analog.update(); // Das ResponsiveAnalogRead-Objekt wird aktualisiert thermistorValue = analog.getValue(); // Das Ergebnis wird ausgelesen // Berechnung der Temperatur thermistorValue = 1023 / thermistorValue - 1; thermistorValue = 10000 / thermistorValue; // Der Wert wird in einen Widerstand umgerechnet //float temperatureHotSide; temperatureHotSide = thermistorValue / 10000; // (R/Ro) temperatureHotSide = log(temperatureHotSide); // ln(R/Ro) temperatureHotSide /= 3950; // 1/B * ln(R/Ro) temperatureHotSide += 1.0 / (25 + 273.15); // + (1/To) temperatureHotSide = 1.0 / temperatureHotSide; // Invert temperatureHotSide -= 273.15; // convert to C previousMillisCalculateTemperatures = currentMillis; } //------------------------- Regelung des Lüfters (TEST) ---------------------// if ((unsigned long)(currentMillis - previousMillisCalculatePID) >= intervalCalculatePID) { Input = temperatureHotSide; // Input ist die temperatureHotSide des Thermistors in *C fanPID.Compute(); // PID-Regler wir aufgerufen pwmWrite(fanPin, Output); // Gibt den Output des PID-Reglers an den Lüfter // Wenn der Output des PID-Reglers Null ist, wird der Lüfter ausgeschaltet. if (Output > 0) { digitalWrite(powerPin, HIGH); //Serial.print("HIGH"); Serial.print("; "); } else { digitalWrite(powerPin, LOW); //Serial.print("LOW"); Serial.print("; "); } //use this functions instead of analogWrite on 'initialized' pins pwmWrite(peltierPin, potiValue / 4); // Nur zu Testzwecken previousMillisCalculatePID = currentMillis; } //------------------------- Tachosignal und Drehzahl des Lüfters ---------------------// // Messung der Pulsweite des Tachosignals tachoSignal = digitalRead(tachoPin); if (tachoSignal == HIGH && high != true) { // Zeit in micros bei ansteigender Flanke pulseOn = micros(); high = true; } else if (tachoSignal == LOW && high == true) { pulseOff = micros(); // Zeit in micros bei fallender Flanke high = false; duration = pulseOff - pulseOn; // Aus der Differenz wir die Dauer berechnet, die das Tachosignal HIGH ist if (duration > 7000 && duration < 150000) { // Liegt die Variable über bzw. unter den angegebenen Werten, liegt ein Messfehler vor rpm = float(100000 * 2 * 60 / duration); // Berechnung der RPM } else { rpm = 0; } //averageRPM.addValue(rpm); } // Berechnung der gemittelten Drehzahl des Lüfters if ((unsigned long)(currentMillis - previousMillisCalculateFanSpeed) >= intervalCalculateFanSpeed) { averageRPM.addValue(rpm); // Aktualisiert das RunningAverage-Objekt // Wenn der Lüfter angehalten wird, soll die Drehzahl "0" angezeigt werden if (Output == 0) { rpm = 0; averageRPM.addValue(rpm); } // Liest die durchschnittliche Drehzahl aus und speichert das Ergebnis in eine Variable rpmAverage = averageRPM.getAverage(); // Meldet eine Fehlfunktion des Lüfters, wenn das Tachosignal "0" ist, obwohl der Lüfter sich drehen sollte if (millis() >= 10000) { // Diese Funktion wird erst nach 10 Sekunden aktiv. if (Output > 0) { // Wenn der Lüfter sich drehen sollte ... if (rpmAverage == 0) { // ... aber die gemittelte Drehzahl gleich "0" ist ... if (millis() - previousMillis > fanAlertDelay) { // ... und eine definierte Zeit verstrichen ist. previousMillis = millis(); fanAlert = true; fanAlertState = true; Serial.println("Fan blocked!"); refreshFan = true; } } else if (rpmAverage > 0) { // ... und die gemittelte Drehzahl größer "0" ist ... fanAlert = false; } } else if (Output == 0) { // Wenn der Lüfter sich nicht drehen soll kann nicht festgestellt werden, ob er blockiert ist. fanAlert = false; previousMillis = millis(); // Muss aktualisiert werden, damit if (fanAlert != fanAlertState) { refreshFan = true; fanAlertState = false; } } } previousMillisCalculateFanSpeed = currentMillis; } //------------------------- Betriebsstunden ---------------------// // Die Betriebsstunden werden alle 15 Minuten im EEPROM gespeichert. Die Einheit der Variable operatinTime ist also 0,25 Stunden. if (millis() - lastTime >= 900000) { // Betriebsstundenzähler operatingTime = operatingTime + 0.25; lastTime = millis(); EEPROM.updateFloat(addrOperatingTime, operatingTime); Serial.print("Updated operatingTime: "); Serial.println(operatingTime); // Serviceintervallzähler serviceInterval = serviceInterval + 0.25; EEPROM.updateFloat(addrServiceInterval, serviceInterval); } //------------------------- Ausgabe an das Display ---------------------// // Anzeige "Serviceintervall zurückgesetzt if (serviceIntervalReset == true) { tft.fillScreen(BLACK); tft.setCursor(15, 65); tft.setTextColor(WHITE, BLACK); tft.setTextSize(0); tft.print("Service Intervall"); tft.setCursor(26, 85); tft.print("zur"); tft.print((char)154); tft.print("ckgesetzt"); delay(2000); tft.fillScreen(BLACK); refreshPeltier = true; refreshTargettemp = true; previousTempHotSide = 150; refreshFan= true; serviceIntervalReset = false; } // Anzeigemodus "0" (einfach) if (displayMode == 0) { // Anzeige Infobereich Zieltemperatur if (refreshTargettemp == true) { tft.setCursor(15, 49); int i = Setpoint * 2; // Berechnet den Index für den Array "colors" if (i < 0) i = 0; // i soll nicht kleiner als "0" werden if (i > 60) i = 60; // i soll nicht größer als "60" werden tft.setTextColor(colors[i], BLACK); tft.setTextSize(0); tft.print("Solltemperatur"); tft.setCursor(15, 62); tft.setTextSize(2); if (Setpoint < 10.00) { tft.print("0"); } tft.print(Setpoint); tft.print(" "); tft.print((char)247); tft.print("C"); tft.setTextColor(BLACK, BLACK); tft.print((char)218); refreshTargettemp = false; } // Anzeige Infobereich Isttemperatur if ((unsigned long)(currentMillis - previousMillisDisplayActualtemp) >= intervalSerialPrint) { if (temperatureHotSide != previousTempHotSide) { tft.setCursor(15, 85); int i = temperatureHotSide * 2; // Berechnet den Index für den Array "colors" if (i < 0) i = 0; // i soll nicht kleiner als "0" werden if (i > 60) i = 60; // i soll nicht größer als "60" werden tft.setTextColor(colors[i], BLACK); tft.setTextSize(0); tft.print("Isttemperatur"); tft.setCursor(15, 98); tft.setTextSize(2); if (temperatureHotSide < 10.00) { tft.print("0"); } tft.print(temperatureHotSide); tft.print(" "); tft.print((char)247); tft.print("C"); tft.setTextColor(BLACK, BLACK); tft.print((char)218); previousTempHotSide = temperatureHotSide; } previousMillisDisplayActualtemp = currentMillis; } } // Anzeigemodus "1" (erweitert) if (displayMode == 1) { // Anzeige Infobereich Peltier-Element if (refreshPeltier == true) { tft.setCursor(0, 32); tft.setTextColor(WHITE, BLACK); tft.setTextSize(0); tft.print("Infos Peltier-Element"); refreshPeltier = false; } // Anzeige Infobereich Zieltemperatur if (refreshTargettemp == true) { tft.setCursor(15, 49); int i = Setpoint * 2; // Berechnet den Index für den Array "colors" if (i < 0) i = 0; // i soll nicht kleiner als "0" werden if (i > 60) i = 60; // i soll nicht größer als "60" werden tft.setTextColor(colors[i], BLACK); tft.setTextSize(0); tft.print("Solltemperatur"); tft.setCursor(15, 62); tft.setTextSize(2); if (Setpoint < 10.00) { tft.print("0"); } tft.print(Setpoint); tft.print(" "); tft.print((char)247); tft.print("C"); tft.setTextColor(BLACK, BLACK); tft.print((char)218); refreshTargettemp = false; } // Anzeige Infobereich Isttemperatur if ((unsigned long)(currentMillis - previousMillisDisplayActualtemp) >= intervalDisplayActualtemp) { if (temperatureHotSide != previousTempHotSide) { tft.setCursor(15, 85); int i = temperatureHotSide * 2; // Berechnet den Index für den Array "colors" if (i < 0) i = 0; // i soll nicht kleiner als "0" werden if (i > 60) i = 60; // i soll nicht größer als "60" werden tft.setTextColor(colors[i], BLACK); tft.setTextSize(0); tft.print("Isttemperatur"); tft.setCursor(15, 98); tft.setTextSize(2); if (temperatureHotSide < 10.00) { tft.print("0"); } tft.print(temperatureHotSide); tft.print(" "); tft.print((char)247); tft.print("C"); tft.setTextColor(BLACK, BLACK); tft.print((char)218); previousTempHotSide = temperatureHotSide; } previousMillisDisplayActualtemp = currentMillis; } // Anzeige Infobereich Lüfter if (fanAlert == true) { if (refreshFan == true) { tft.setCursor(0, 121); tft.setTextSize(0); tft.setTextColor(RED, BLACK); tft.print("L"); tft.print((char)154); tft.print("fterfehlfunktion!"); refreshFan = false; } } else if (fanAlert == false) { if (rpmAverage > 0) { // Wenn die Drehzahl größer "0" ist, aktualisiere den Anzeigebereich all 500 Millisekunden if ((unsigned long)(currentMillis - previousMillisDisplayFanSpeed) >= intervalDisplayFanSpeed) { tft.setCursor(0, 121); tft.setTextSize(0); tft.setTextColor(WHITE, BLACK); tft.print("L"); tft.print((char)154); tft.print("fter "); tft.print(int(rpmAverage)); tft.print(" U/min"); tft.setTextColor(BLACK, BLACK); for (int i=0; i<5; i++) { // Füllt die Zeile mit schwarzen Kästchen; i muss ggf. angepasst werden tft.print((char)218); } refreshFan = true; previousMillisDisplayFanSpeed = currentMillis; } } else if (rpmAverage == 0) { if (refreshFan == true) { tft.setCursor(0, 121); tft.setTextSize(0); tft.setTextColor(WHITE, BLACK); tft.print("L"); tft.print((char)154); tft.print("fter aus"); tft.setTextColor(BLACK, BLACK); for (int i=0; i<12; i++) { // Füllt die Zeile mit schwarzen Kästchen; i muss ggf. angepasst werden tft.print((char)218); } refreshFan = false; } } } } // Anzeigemodus "2" (grafisch) if (displayMode == 2) { // Anzeige Isttemperatur if ((unsigned long)(currentMillis - previousMillisDisplayActualtemp) >= intervalDisplayActualtemp) { if (temperatureHotSide != previousTempHotSide) { tft.setCursor(0, 32); tft.setTextSize(0); int i = temperatureHotSide * 2; // Berechnet den Index für den Array "colors" if (i < 0) i = 0; // i soll nicht kleiner als "0" werden if (i > 60) i = 60; // i soll nicht größer als "60" werden tft.setTextColor(colors[i], BLACK); tft.print("Ist "); if (temperatureHotSide < 10.00) { tft.print("0"); } tft.print(temperatureHotSide); tft.setTextColor(BLACK, BLACK); tft.print((char)218); previousTempHotSide = temperatureHotSide; } previousMillisDisplayActualtemp = currentMillis; } // Anzeige Solltemperatur if (refreshTargettemp == true) { tft.setCursor(64, 32); tft.setTextColor(WHITE, BLACK); tft.setTextSize(0); tft.print("Soll "); if (Setpoint < 10.00) { tft.print("0"); } tft.print(Setpoint); refreshTargettemp = false; } // Anzeige Graphen if ((unsigned long)(currentMillis - previousMillisDisplayGraph) >= intervalDisplayGraph) { x++; if (x >= 128) { x = 0; //tft.fillScreen(BLACK); tft.fillRect(0, 40, 128, 80, BLACK); //tft.drawLine(0, 44, 127, 44, WHITE); //tft.drawLine(0, 114, 127, 114, WHITE); //previousTempHotSide = 150; //refreshTargettemp = true; //refreshFan = true; //refreshPeltier = true; } // Graph Solltemperatur int y = 114 - Setpoint * 2; tft.drawPixel(x, y, WHITE); // Graph Isttemperatur int z = 114 - temperatureHotSide *2; int i = temperatureHotSide * 2; // Berechnet den Index für den Array "colors" if (i < 0) i = 0; // i soll nicht kleiner als "0" werden if (i > 60) i = 60; // i soll nicht größer als "60" werden tft.drawPixel(x, z, colors[i]); // Graph Lüfterdrehzahl int d = 114 - rpmAverage / 21; tft.drawPixel(x, d, BLUE); //Serial.print("x = ");Serial.print(x); //Serial.print("; y = ");Serial.print(y); //Serial.print("; z = ");Serial.print(z); //Serial.print("; d = ");Serial.println(d); // Anzeige Peltier-Element if (refreshPeltier == true) { tft.setCursor(0, 121); tft.setTextColor(BLUEBERRY, BLACK); tft.setTextSize(0); tft.print("Peltier"); refreshPeltier = false; } // Anzeige Lüfter if (rpmAverage > 0) { if ((unsigned long)(currentMillis - previousMillisDisplayFanSpeed) >= intervalDisplayFanSpeed) { tft.setCursor(60, 121); tft.setTextSize(0); tft.setTextColor(BLUE, BLACK); tft.print(" U/min "); tft.print(int(rpmAverage)); tft.setTextColor(BLACK, BLACK); for (int i=0; i<3; i++) { // Füllt die Zeile mit schwarzen Kästchen; i muss ggf. angepasst werden tft.print((char)218); } refreshFan = true; previousMillisDisplayFanSpeed = currentMillis; } } if (rpmAverage == 0) { if (refreshFan == true) { tft.setCursor(60, 121); tft.setTextSize(0); tft.setTextColor(BLUE, BLACK); tft.print(int(rpmAverage)); tft.print(" U/min"); tft.setTextColor(BLACK, BLACK); for (int i=0; i<3; i++) { // Füllt die Zeile mit schwarzen Kästchen; i muss ggf. angepasst werden tft.print((char)218); } refreshFan = false; } } previousMillisDisplayGraph = currentMillis; } } //------------------------- Ausgabe an die serielle Schnittstelle ---------------------// if ((unsigned long)(currentMillis - previousMillisSerialPrint) >= intervalSerialPrint) { // Ausgabe für den seriellen Monitor Serial.print("Setpoint: ");Serial.print(Setpoint); Serial.print("; Input: ");Serial.print(Input); Serial.print("; Output: ");Serial.print(Output); //Serial.print("; pulseOn: ");Serial.print(pulseOn); //Serial.print("; pulseOff: ");Serial.print(pulseOff); //Serial.print("; Duration: "); Serial.print(duration); Serial.print("; RPM: "); Serial.print(rpm); Serial.print("; average RPM: "); Serial.print(rpmAverage); //Serial.print("; fanAlert: "); Serial.print(fanAlert); //Serial.print("; temperatureHotSide: "); Serial.println(temperatureHotSide); Serial.print("; operatingTime: "); Serial.print(operatingTime); Serial.print("; serviceInterval: "); Serial.print(serviceInterval); Serial.print("; Displaymode: "); Serial.print(displayMode); Serial.print("; Loops: "); Serial.println(loopCounter); loopCounter = 0; //Speichere die aktuelle Zeit in die zughörige Variable previousMillisSerialPrint = currentMillis; } } Der Sketch verwendet 24248 Bytes (78%) des Programmspeicherplatzes. Das Maximum sind 30720 Bytes. Globale Variablen verwenden 1504 Bytes (73%) des dynamischen Speichers, 544 Bytes für lokale Variablen verbleiben. Das Maximum sind 2048 Bytes. Tags: #Arduino #Flaschenkühler #OLED #Peltier