Benutzer-Werkzeuge

Webseiten-Werkzeuge


arduino:flaschenkuehler:programmversion_0.3

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

arduino/flaschenkuehler/programmversion_0.3.txt · Zuletzt geändert: 18.05.2023 12:34 von 127.0.0.1