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 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 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 ResponsiveAnalogRead verwendet. Was die Bibliothek leistet wird sehr anschaulich auf 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 <Adafruit_GFX.h> // Grafik-Bibliothek für OLED-Display
#include <Adafruit_SSD1351.h> // Bibliothek für OLED-Display (Adafruit OLED Breakout Board 1.27")
#include <SPI.h> // Bibliothek Serial Peripheral Interface (SPI)
#include <PWM.h> // Bibliothek für Änderung der Frequenz der Timer
#include <RunningAverage.h> // Bibliothek für Berechnung von Mittelwerten
#include <ResponsiveAnalogRead.h> // Bibliothek zur Glättung analoger Inpots
#include <PID_v1.h> // Bibliothek für PID-Regler
#include <ButtonEvents.h> // Bibliothek zum Entprellen der Taster
#include <EEPROMex.h> // 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("<Arduino is ready! Turn the potentiometer, please ...>");
Serial.print("<Operating Time of the System: "); Serial.print(operatingTime); Serial.println(" hours>");
Serial.print("<Service Interval: "); Serial.print(serviceInterval); Serial.println(" hours>");
// 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