Alternative Externe Temperatur gesteuerte Lüfterreglung

Begonnen von MaikLommatzsch, 12. Januar 2022, 19:59:07

Vorheriges Thema - Nächstes Thema

0 Mitglieder und 2 Gäste betrachten dieses Thema.

MaikLommatzsch

#30
Moinsen, kleines Update  ;D
Ich hab jetzt richtig viel Zeit in dieses Projekt gesteckt um zu erkennen das der Arduino Nano every absolut ungeeignet ist.
Kein Sketch hat richtig funktioniert und und und. Ich habe dann den Vorgänger aber als Clone besorgt. Ich hab nach ewiger suche einen Text gefunden wo der every als kaum Kompatibel zu fertigen Sketchs sein soll, obwohl er es Hardwareseitig sein soll.
Nun gut, der Clone ließ sich doch recht einfach in Betrieb nehmen und Tada, der nimmt fertige Sketchs und funktioniert einfach.

Somit habe ich den folgenden Sketch fast 1 zu 1 übernehmen können. ein bisschen hab ich schon dran gespielt.
Zitat// Konstanten
const int fanPin = 9;                 // Pin für den Lüfter
const int ntc = A0;                   // Pin für den 10kO NTC Wiederstand
const int ntcNominal = 10000;         // Wiederstand des NTC bei Nominaltemperatur
const int tempNominal = 25;           // Temperatur bei der der NTC den angegebenen Wiederstand hat
const int bCoefficient = 3977;        // Beta Coefficient(B25 aus Datenblatt des NTC)
const int serienWiederstand = 10000;  // Wert des Wiederstands der mit dem NTC in Serie geschalten ist

// Variablen
int fanSpeed = 0;          // Variable für die Lüftergeschwindigkeit
int fanMin = 25;           // Kleinster PWM Wert für den Lüfter befor er abschält
int fanOut = 1;            // Variable zum pürfen ob der Lüfter aus war
int tMin = 20;             // Untere Grenze des Temperaturbereichs
int tMax = 90;             // Obere Grenze des Temperaturbereichs
int abfrageZahl = 5;       // Je mehr abfragen, desto stabiler isr das Ergebnis, dauert aber länger
int abfrage[5];            // Array Variable für das Mitteln der Temperatur
float durchschnitt = 0;    // Variable für das Mitteln der Temperatur
float temp;                // Variable für die Berechnung der temperatur nach Steinhart


void setup()
{
  TCCR1B = TCCR1B & 0b11111000 | 0x01;   // Setzt Timer1 (Pin 9 und 10) auf 31300Hz
  Serial.begin(9600);             // Baudrate für die Ausgabe am Serial Monitor
  pinMode(fanPin, OUTPUT);        // Setzt den Pin des Lüfters als Ausgang
  pinMode(ntc, INPUT);            // Setzt den Pin des NTC Wiederstands als Eingang
}


void loop()
{
  temperaturberechnung();      // Startet die Temperaturerfassungsroutine
   
  // Lüftergeschwindigkeit über den Temperaturbereich einstellen
  // TMin->0% PWM | TMax->100% PWM
  fanSpeed = map(temp, tMin, tMax, 0, 255);   
   
  // Wenn der PWM Wert unter den van FanMin fällt, schält der Lüfter ab
  if (fanSpeed < fanMin)
  {
    fanSpeed = 0;
    fanOut = 1;
  }
   
  // Hysterese
  if (fanOut == 1)
  {
    fanSpeed = 0;
  }
   
  if(temp >= 32)
  {
    if(fanOut == 1)
    {
      fanOut = 0;
      analogWrite(fanPin, 255);
    }
  }
   
  // PWM Wert auf 255 begerenzen 
  if (fanSpeed > 255)
  {
    fanSpeed = 255;
  }
   
  // Lüftergeschwindigkeit über den Seriellen Monitor ausgeben
  Serial.print("Lueftergeschwindigkeit: ");         
  Serial.println(fanSpeed);

  analogWrite(fanPin, fanSpeed);      // Den Lüfter mit dem PWM Wert ansteuern
  delay(500); 
}



void temperaturberechnung()
{
  // Nimmt N Abfragen in einer Reihe, mit einem kurzen delay
  for (int i=0; i < abfrageZahl; i++)
  {
    abfrage = analogRead(ntc);
    delay(10);
  }
   
  // Mittelt alle Abfragen
  durchschnitt = 0;
  for (int i=0; i < abfrageZahl; i++)
  {
    durchschnitt += abfrage;
  }
  durchschnitt /= abfrageZahl;
   
  // Umwandlung des Wertes in Wiederstand
  durchschnitt = 1023 / durchschnitt - 1;
  durchschnitt = serienWiederstand / durchschnitt;
   
  // Umrechnung aller Ergebnisse in die Temperatur mittels einer Steinhard Berechnung
  temp = durchschnitt / ntcNominal;     // (R/Ro)
  temp = log(temp);                     // ln(R/Ro)
  temp /= bCoefficient;                 // 1/B * ln(R/Ro)
  temp += 1.0 / (tempNominal + 273.15); // + (1/To)
  temp = 1.0 / temp;                    // Invertieren
  temp -= 273.15;                       // Umwandeln in °C
   
  // Ausgabe an den Seriellen Monitor
  Serial.print("Temperatur ");
  Serial.print(temp);
  Serial.println(" *C");
   
  delay(500);
}

Stand der dinge:
Im Sketch sind 10K eingetragen, ich nutze aber 100K. Funktioniert trotzdem, ändere ich das in 100K  läuft es nicht.
Ich nutze 5V weil es mit 3,3V nicht geht .
Die Schaltung ist wieder + von Festwiederstand komment.

Lüfter:  Es werden 31Khz ausgegeben, die Led, die den Lüfter simulieren soll wird sogar angesteuert.
Und Endlich mal Glück, der PS3 Lüfter läuft auch mit 31Khz ;D Was das aber nun bewirkt weiss ich nicht, Takeshi wird sicher was dazu sagen können ;)
Das nette ist: Die Test LED kann sogar als Indikator drin bleiben, somit ist das eine LED Problem schonmal gelöst.

Ich hab ein bisschen mit dem der Reglung gespielt und finde das sie so erstmal läuft aber wohl nicht so zweckmäßig ist.
Wir arbeiten im Bereich 20°C/0% Drehzahl | 90°C 100% Drehzahl. In einen entsprechenden PWM Bereich 0= 0% Drehzahl bis 255 = 100% Drehzahl
Ab 20°C ist die Reglung aktiv, ca bei 32°C schaltet sich der Lüfter ein, bei 50°C hat der Lüfter schon über 50% Drehzahl. ( das schon sehr Laut ist).
Da die C04 weit höhere Normal Temps hat , wird der Lüfter wahrscheinlich unerträglich laut laufen. Ich schätze so um die 75%.
Bei ca 90°C werden wir wohl die Abschaltwarung der PS3 erhalten und auch erst bei 90°C haben wir den Lüfter auf 100%.
Ich schätze da müssen dann Lüfterstufen rein die sich in einen bestimmten Bereich einpegeln. ( Hab ich noch keinen Plan von )

Ich habe auch schon ( siehe Fotos) einen Kühler und ein IHS auf 2mm aufgebohrt ( die Pips sind nicht beschädigt) und den Tempsensor dort untergebracht. Ich habe diese Position gewählt, weil ich
aus dem Lüfter Bereich raus wollte.

Mein nächster schritt:

Ich werde das ganze mit einen Schrottboard zusammen bauen und ein bisschen mit dem Lüftgebläse aufheizten und sehen was passiert.
Dann werde ich nochmal berichten ,ggf Änderungen (wenn vorhanden)von euch mit einfließen lassen und eventuell nochmal Testen.


Nebenbei versuche ich noch die Warn LED mit einzubringen und ein I2C LCD oder eine 7 Segment Anzeige mit einzubinden, was ich aber ums verrecken nicht hinbekomme :'(
Solo läuft das prima, bringt nur nichts sich Radom irgendwelche Texte und Zahlen anzeigen zu lassen :<<

Warum die Anzeige? Ich möchte irgendwann natürlich ohne PC die Werte ablesen können, den der Controller soll ja auch mal von der PS3 versorgt werden.

MaikLommatzsch

#31
Moino,
Ich bin jetzt etwas weiter.
Der Test mit Heißluft ist nicht sehr effektiv, es ist sehr schwer Temperatur drauf zu bringen . Was aber soweit fakt ist, der Lüfter ist bei 50°C schon zu laut.
Ich hab es geschafft ein LCD einzubinden, hab ein neues gekauft da das erste defekt war.
Die blaue und rote LED hab ich jetzt auch eingebunden bekommen und läuft wie soll. Blau leuchtet bis 82°C und die rote LED leuchtet ab 83°C ( Rot soll noch vor der PS3 Wartung kommen)
Das 31Khz PWM Signal konnte ich auch auf 25Khz runter setzen. ( Mein Multimeter kann das messen)

Hier der Code
Zitat#include <PWM.h>                      // Bibliothek zur einstellung des PWM Signals
#include <Wire.h>                     // Wire Bibliothek für die I2C verbindung zum LCD
#include <LiquidCrystal_I2C.h>        // LiquidCrystal_I2C Bibliothek zur komunikation zum LCD
LiquidCrystal_I2C lcd(0x27, 20, 4);   // Hier wird das Display benannt (Adresse/Zeichen pro Zeile/Anzahl Zeilen).

// Konstanten
const int fanPin = 9;                 // Pin für den Lüfter
const int ntc = A0;                   // Pin für den 10kO NTC Wiederstand
const int ntcNominal = 10000;         // Wiederstand des NTC bei Nominaltemperatur
const int tempNominal = 25;           // Temperatur bei der der NTC den angegebenen Wiederstand hat
const int bCoefficient = 3977;        // Beta Coefficient(B25 aus Datenblatt des NTC)
const int serienWiederstand = 10000;  // Wert des Wiederstands der mit dem NTC in Serie geschalten ist
int ledBlau  = 12;                    // Pin für die blaue LED (Kalt) an Pin 12
int ledRot   = 11;                    // Pin für die rote LED (Heiss) an Pin 11
int32_t frequency = 25000;            // einstellen der Lüfterfrequenz  25Khz

// Variablen
int fanSpeed = 0;          // Variable für die Lüftergeschwindigkeit
int fanMin = 20;           // Kleinster PWM Wert für den Lüfter befor er abschält
int fanOut = 1;            // Variable zum pürfen ob der Lüfter aus war
int tMin = 15;             // Untere Grenze des Temperaturbereichs
int tMax = 84;             // Obere Grenze des Temperaturbereichs
int abfrageZahl = 5;       // Je mehr abfragen, desto stabiler isr das Ergebnis, dauert aber länger
int abfrage[5];            // Array Variable für das Mitteln der Temperatur
float durchschnitt = 0;    // Variable für das Mitteln der Temperatur
float temp;                // Variable für die Berechnung der temperatur nach Steinhart


void setup()
{

InitTimersSafe();                                       // Frenqenz umwandlung startet
bool success = SetPinFrequencySafe(fanPin, frequency); // Setzt die Frequenz auf Pin

lcd.init();      //Im Setup wird der LCD gestartet
lcd.backlight(); //Hintergrundbeleuchtung einschalten (0 schaltet die Beleuchtung aus).
 
// TCCR1B = TCCR1B & 0b11111000 | 0x01;   // Setzt Timer1 (Pin 9 und 10) auf 31300Hz (Deaktiviert mit //)
  Serial.begin(9600);                    // Baudrate für die Ausgabe am Serial Monitor
  pinMode(fanPin, OUTPUT);              // Setzt den Pin des Lüfters als Ausgang
  pinMode(ntc, INPUT);                  // Setzt den Pin des NTC Wiederstands als Eingang
  pinMode(ledBlau, OUTPUT);             // definiere die blaue LED als Ausgang
  pinMode(ledRot, OUTPUT);             // definiere die blaue LED als Ausgang

}


void loop()
{
// Was am LCD angezeigt werden soll
lcd.setCursor(0,0);       // Text soll beim ersten Zeichen in der ersten Reihe beginnen..
lcd.print("Temperatur:"); // In der ersten Zeile soll ein Text in Zeile 1 angezeigt werden
lcd.print(temp);          // Wert der in der Zeile 1 neben dem Text angezeigt wird
lcd.print("C");           // Text der in der Zeile 1 neben dem Wert angezeigt wird
lcd.setCursor(0,2);       // Dritte Reihe
lcd.print("FanSpeed:");
lcd.print(fanSpeed);
lcd.print("PWM");
 
  temperaturberechnung();      // Startet die Temperaturerfassungsroutine

   // Lüftergeschwindigkeit über den Temperaturbereich einstellen
  // TMin->0% PWM | TMax->100% PWM
  fanSpeed = map(temp, tMin, tMax, 0, 255);   
   
  // Wenn der PWM Wert unter den van FanMin fällt, schält der Lüfter ab
  if (fanSpeed < fanMin)
  {
    fanSpeed = 0;
    fanOut = 1;
  }
   
  // Hysterese
  if (fanOut == 1)
  {
    fanSpeed = 0;
  }
   
  if(temp >= 20) // Temperatur ab wann der Lüfter laufen kann
  {
    if(fanOut == 1)
    {
      fanOut = 0;
      analogWrite(fanPin, 255);
    }
  }
   
  // PWM Wert auf 255 begerenzen 
  if (fanSpeed > 255)
  {
    fanSpeed = 255;
  }
   
  // Lüftergeschwindigkeit über den Seriellen Monitor ausgeben
  Serial.print("Lueftergeschwindigkeit: ");         
  Serial.println(fanSpeed);

  analogWrite(fanPin, fanSpeed);      // Den Lüfter mit dem PWM Wert ansteuern
  delay(250); 
}


void temperaturberechnung()
{
  // Nimmt N Abfragen in einer Reihe, mit einem kurzen delay
  for (int i=0; i < abfrageZahl; i++)
  {
    abfrage = analogRead(ntc);
    delay(10);
  }
   
  // Mittelt alle Abfragen
  durchschnitt = 0;
  for (int i=0; i < abfrageZahl; i++)
  {
    durchschnitt += abfrage;
  }
  durchschnitt /= abfrageZahl;
   
  // Umwandlung des Wertes in Wiederstand
  durchschnitt = 1023 / durchschnitt - 1;
  durchschnitt = serienWiederstand / durchschnitt;
   
  // Umrechnung aller Ergebnisse in die Temperatur mittels einer Steinhard Berechnung
  temp = durchschnitt / ntcNominal;     // (R/Ro)
  temp = log(temp);                     // ln(R/Ro)
  temp /= bCoefficient;                 // 1/B * ln(R/Ro)
  temp += 1.0 / (tempNominal + 273.15); // + (1/To)
  temp = 1.0 / temp;                    // Invertieren
  temp -= 273.15;                       // Umwandeln in °C
   
  // Ausgabe an den Seriellen Monitor
  Serial.print("Temperatur ");
  Serial.print(temp);
  Serial.println(" °C");
  delay(500);

// LED Temperatursteuerung Blau zu Rot
  digitalWrite(ledBlau, HIGH);                       // macht die blaue LED am Start an
  if (temp >= 82) digitalWrite(ledBlau, LOW);       // mache die blaue LED bei 82 °C aus
 
  digitalWrite(ledRot, LOW);                       // macht die rote LED am Start aus
  if (temp >= 83) digitalWrite(ledRot, HIGH);       // mache die rote LED bei 83 °C an

  }

Der PS3 Lüfter springt erst bei PWM 55 an, darum möchte ich ihn erstmal bei Start anlaufen lassen, das bekomm ich noch nicht hin ohne das ich Temp/PWM Steuerung störe

Dann möchte ich die Lüfterkurve für die CPU einbauen
siehe original Code ( Quelle PS3 Developer Wiki )
Zitat
P0: TempD:0.0(0x0000) - TempU:74.0(0x4a00) duty:20%(0x33)
P1: TempD:60.0(0x3c00) - TempU:75.0(0x4b00) duty:25%(0x40)
P2: TempD:61.0(0x3d00) - TempU:76.0(0x4c00) duty:28%(0x48)
P3: TempD:67.0(0x4300) - TempU:77.0(0x4d00) duty:30%(0x4d)
P4: TempD:68.0(0x4400) - TempU:78.0(0x4e00) duty:35%(0x5a)
P5: TempD:71.0(0x4700) - TempU:79.0(0x4f00) duty:40%(0x66)
P6: TempD:71.50(0x4780) - TempU:80.0(0x5000) duty:45%(0x73)
P7: TempD:72.0(0x4800) - TempU:81.0(0x5100) duty:50%(0x80)
P8: TempD:72.50(0x4880) - TempU:82.0(0x5200) duty:60%(0x99)
P9: TempD:73.0(0x4900) - TempU:85.0(0x5500) duty:100%(0xff)

>$ tshutdown get 0
tshutdown get 0
TZone No:00
1st BE Primary Temperature:85.0(0x5500)

Das ist jetzt nur die CPU Einstellung, im Originalen wer aber noch  RSX und SB mit einbezogen, das ist aber erstmal nicht vorgesehen und beschränke mich auf CPU da sie am wärmsten läuft.
Ich denke aber das ich hier Hilfe brauchen werde.


MaikLommatzsch

#32
Schönen Sonntag an euch.
Ich habe es etwas weiter geschafft.
Festgestellt habe ich ja schon das der PS3 Lüfter erst bei PWM 55 anspringt, aber tatsächlich erst bei PWM 0 wieder ausgeht und nicht wie erwartet unter PWM 55.
Selbsthalt kann daher nicht genutzt werden. Im Code lasse ich den PS3 Lüfter nun mit PWM100 anlaufen. Hat er PWM 100 erreicht geht er wieder aus.

Den Code habe ich jetzt im void setup(){ mit eingefügt.

Zitat
// Lüfteranlauf
analogWrite(fanPin, 100);   // Lüfter startet und geht wieder aus ( oder selbsthalt )

Damit der Lüfter aber nicht wieder ausgeht habe ich die tMin für den Lüfter statt auf 0 PWM auf 55 PWM gesetzt.
Da tMin auf 20 °C gesetzt ist, bedeutet das wir ab 20°C dann automatisch ein PWM von 55 anliegen haben. Ist es kälter bleibt der Lüfter nach dem Anlauf ebent aus.
Ich denke aber das 20 °C ein guter Wert ist.
Das sieht im Code dann so aus:

Zitat// Lüftergeschwindigkeit über den Temperaturbereich einstellen
  // TMin->0% PWM | TMax->100% PWM
  fanSpeed = map(temp, tMin, tMax, 55, 255); 

Dann wollte ich mich selbst nochmal ein bisschen testen und habe noch einen Summer mit eingebaut (vom cok002 Schrottboard runter gelötet)

Ich wollte das die Steuerung meldet das sie sich einschaltet und bei Übertemperatur zusätzlich zur roten LED arbeitet.
der Code zur Startmelodie schaut so aus und wird auch unter void setup(){ eingefügt.
Zitat
//Startmelodie
//Die Spannungsausgabe für den Piezo-Lautsprecher wird im Sketch durch den Arduino-Befehl "tone"
//automatisch festgelegt. Erstes Zeichen nach der Klammer ist der Anschnlusspin.
tone(8, 1500); // Im Hauptteil wird nun mit dem Befehl "tone ( x , y )" ein Ton abgegeben.
delay(250);   // mit einer Dauer von 0,5 Sekunden
noTone(8 );    // Der Ton wird abgeschaltet
delay(50);   // Der Lautsprecher bleibt kurz aus
tone(8, 2500);
delay(250);
noTone(8 );
delay(50);
tone(8, 3500);
delay(250);   
noTone(8 ); 
delay(50);
tone(8, 4500);
delay(250);
noTone(8 );
delay(50);
tone(8, 1500);
delay(250);   
noTone(8 );

Den Code für das piepen bei Übertemperatur hab ich unten bei den LEDs mit eingebaut und schaut so aus
Zitat// Übertemperatur Summerwarung
  if (temp >= 82) tone(8, 1500);    // mache den Summer bei 82 °C an
  delay(1100);   // mit einer Dauer von etwas über einer Sekunde
  noTone(8 );    // Der Ton wird abgeschaltet
  delay(25);    // Dauer der Abschaltung

Dann ist mir noch eingefallen ein Art Fehler Code auszugeben.
Erstmal nur wenn der NTC Sensor eine Unterbrechung hat.
Zitat// Sensordefekt Warnung ( LED wechselt von Rot zu Blau und Summer ertönt)
  digitalWrite(ledRot, LOW);                       // macht die rote LED ab Start aus
  if (temp <= 0) digitalWrite(ledRot, HIGH);       // mache die rote LED unter 0 °C an
  if (temp <= 0) tone(8, 1500);                    // Aktiviert den Warnsummer
  delay(1100);   // mit einer Dauer von etwas über einer Sekunde
  noTone(8 );    // Der Ton wird abgeschaltet
  delay(25);    // Dauer der Abschaltung
//Fehlermeldung bei Unterbrechung Sensor
//LED Blau wechselt zu Rot und wieder zu Blau und so weiter ... Und Warnsummer ertönt.
//Selbes Bild erscheint auch unter °0C

Ich finde das ist schon ne ganz nette Geschichte. Jetzt fehlt nur noch ne anständige Kurve.;-)  Ich werde demnächst mal ne Skizze von der Schaltung machen.

MaikLommatzsch

#33
Moino,
Hab nicht viel bisher geschafft.
Zumindest konnte ich den eigentlichen Lüftercode deutlich verkleinern. Ohne Funktion einzubüßen.
Ein bischen experimentiert hab ich auch, aber ich bin nicht zufrieden. Aber eine Richtung gefunden.
So schaut der gekürzte Code jetzt aus:
Zitat// Lüftergeschwindigkeit über den Temperaturbereich einstellen
  // TMin->0% PWM | TMax->100% PWM
  fanSpeed = map(temp, tMin, tMax, 55, 255);   

    analogWrite(fanPin, fanSpeed);      // Den Lüfter mit dem PWM Wert ansteuern

 
// Lüftergeschwindigkeit über den Seriellen Monitor ausgeben
  Serial.print("Lueftergeschwindigkeit: ");         
  Serial.println(fanSpeed);
  delay(250); 
}

Bei den Variablen konnte folgendes raus
Zitatint fanSpeed = 0;          // Variable für die Lüftergeschwindigkeit
int fanMin = 20;           // Kleinster PWM Wert für den Lüfter bevor er abschält

Hier hab ich mal die geplanten originalen Lüfterstufen vereinfachter dargestellt und ganz rechts
die PWM Werte ausgerechnet
Zitat
P0: TempD:00.0 - TempU:74.0     duty:20%       51 (55 min. Anlaufdrehzahl)
P1: TempD:60.0 - TempU:75.0     duty:25%       64
P2: TempD:61.0 - TempU:76.0     duty:28%       71
P3: TempD:67.0 - TempU:77.0     duty:30%       76 
P4: TempD:68.0 - TempU:78.0     duty:35%       89
P5: TempD:71.0 - TempU:79.0     duty:40%      102
P6: TempD:71.5 - TempU:80.0     duty:45%      115
P7: TempD:72.0 - TempU:81.0     duty:50%      128
P8: TempD:72.5 - TempU:82.0     duty:60%      153
P9: TempD:73.0 - TempU:85.0     duty:100%     255

Dann hab ich noch einen, ich hoffe verständlichen Schaltplan gemacht.

Takeshi

Nur kurz nachgefragt: Bist du noch dran? Nicht dass ich jetzt antworte und dann ist das sowieso schon gestorben.

MaikLommatzsch

#35
Ich bin noch dran, bekomm nur die Lüfterstufen nicht hin. Zumindest nicht so wie original.

Ich versuch es mal zu beschreiben.

Ich gebe die stufen ein, dann läuft stufe 0 bis 74 °C dann ab 75 schaltet Stufe 1 dazu. bei 76 stufe 2 u.s.w.
bei 85°C Laufen alle stufen. Das blöde ist: Es werden immer wieder ALLE stufen nacheinander durchgeschaltet 0...1...2..3...4...5...  natürlich delay abhängig.
ist stufe 9 erreicht geht es wieder von vorne los.    es geht auch nicht  das in einer stufe verharrt wird. Beispiel: Ich bleibe in Stufe 0 bis ich 74°C erreiche( läuft) erreiche ich dann 75°C schalte ich in Stufe 1  (Läuft), bleibe aber dann bis zum unterschreiten von 60°C in stufe 1 ( läuft nicht). Bin ich unter 74 °C schalte ich wieder in Stufe 0. Und das soll ja nicht.

Und so ergeht es mir in allen Stufen,  es funktioniert nur der eintritt in eine neu Stufe und ab dann wird jede vorherige immer wieder mit angesteuert.

Takeshi

Ich verstehe bis heute nicht, wieso Sony überhaupt zwischen festen Stufen umschaltet. Ich würde das "analog" machen. Richtig analog funktioniert das natürlich nicht, aber so feinstufig, dass es wie analog wirkt. Eine mögliche Erklärung kann ich mir vorstellen: Dass es als unangenehm wahrgenommen wird, wenn die Drehzahl sich ständig ändert, ein Springen als angenehmer wahrgenommen wird. Aber glaube ich eher nicht.

Ich würde dafür einen (P)I-Regler einsetzen, da fast jede Regelung mit einem PI-Regler realisiert wird. Das P steht für "proportional" und das I für "integral". Klingt komplizierter, als es ist. Du misst die Temperatur und bildest die Differenz zu einem Sollwert, zum Beispiel 60 °C. Hast du 65 °C, kommt "+5" heraus, bei 50 °C kommt "-10" heraus. Diese Differenz addierst du auf eine Variable auf (Summe), die bei 0 startet. Wenn du dauerhaft 61 °C misst, wird die Variable also immer und immer größer. Diese Summe multiplizierst du mit einem Faktor und das Ergebnis ist dann die Pulsweite der PWM.
Du musst darauf achten, dass die Aufaddierung in festen zeitlichen Abständen passiert und dass die Variable nicht zu groß und nicht zu klein wird. Wie du es schaffst die Ausführung des Codes in festen Zeitabständen zu realisieren, kann ich dir nicht sagen, das ist stark abhängig vom verwendeten System.
Die Ausführungshäufigkeit, den Faktor und den Sollwert müsstest du in Tests ermitteln. Mit steigender Häufigkeit muss der Faktor kleiner werden, weil die Summe schneller steigt. Ich denke 100 Ausführungen pro Sekunde reichen locker, eher sogar 10.

MaikLommatzsch

#37
Ich verstehe schon warum Sony das mach. Die a eine bestimmte Temperatur erreichen. Darum fahren sie bis 74C mit 20% und die 20 % auch nur wegen Lüfter Anlauf. Dann wollen sie nicht das zu stark runter gekühlt wird, darum die vielen Stufen. Und der Temperatur Bereich ist dafür da das nicht ständig hin und her geschaltet wird. So verstehe ich das und hoffentlich konnte ich das rüber bringen.

Takeshi, ich denke zu verstehen was du meinst, macht natürlich auch Sinn einen fest Wert zu geben und mit + - darum pegeln zu lassen. Aber, jetzt kommt das aber. Der Code ist mein Problem. Ich poste nachher mal den Code den versucht hab.

Nachtrag: aktueller Code die ersten 3 stufen
Zitatswitch (fanSteps)                   // Anfang Lüfterstufen
{
case 0:                             // Case 0 = Lüfter schaltet in 10 Stufen
      // statements
    if (temp < t74 ) {                          // wenn T innerhalb Stufe 0
        analogWrite(fanPin, fanSpeed0);     // dann Lüfter auf speed0 55 (22%)
----------------------------------------------------------------
        Serial.print("fanSpeed: ");
        Serial.print(fanSpeed0);
        Serial.println(" - Stufe: 0");                     nur Optische Ausgabe
        lcd.setCursor(0,2);                               der Werte  Temp und PWM   
        lcd.print("PWM: ");                              an seriellen Monitor und LCD
        lcd.print(fanSpeed0);
        lcd.print(" - Step: 0 ");
        delay(500);
-------------------------------------------------------------------
}
    if (temp >= t75 and temp < t60 ) {            // wenn T zwischen Stufe 0 und 1
        analogWrite(fanPin, fanSpeed1);      // dann Lüfter auf speed1 64 (25%)
        Serial.print("fanSpeed: ");
        Serial.print(fanSpeed1);
        Serial.println(" - Stufe: 1");
        lcd.setCursor(0,2);       
        lcd.print("PWM: ");
        lcd.print(fanSpeed1);
        lcd.print(" - Step: 1 ");
        delay(500);
}
    if (temp >= t76 and temp < t61)  {         // wenn T zwischen Stufe 2 und 3
        analogWrite(fanPin, fanSpeed2);      // dann Lüfter auf speed2 71 (28%)
        Serial.print("fanSpeed: ");
        Serial.print(fanSpeed2);
        Serial.println(" - Stufe: 2");
        lcd.setCursor(0,2);       
        lcd.print("PWM: ");
        lcd.print(fanSpeed2);
        lcd.print(" - Step: 2 ");
        delay(500);
break; 

Alle folgende Stufen sehen genauso aus, nur andere Werte

Takeshi

#38
Zitat von: MaikLommatzsch am 07. März 2022, 07:32:37
Ich verstehe schon warum Sony das mach. Die a eine bestimmte Temperatur erreichen. Darum fahren sie bis 74C mit 20% und die 20 % auch nur wegen Lüfter Anlauf. Dann wollen sie nicht das zu stark runter gekühlt wird, darum die vielen Stufen. Und der Temperatur Bereich ist dafür da das nicht ständig hin und her geschaltet wird. So verstehe ich das und hoffentlich konnte ich das rüber bringen.

Es ist eigentlich genau umgekehrt. Der von mir beschriebene Ansatz sorgt dafür, dass eine Temperatur gehalten wird, die Konsole also nicht stark herunterkühlt. Außerdem sorgend die diskreten Stufen dafür, dass ständig hin- und hergeschaltet wird. Nehmen wir an, die Stufen gingen in 10-%-Schritten und man bräuchte genau 35 %, um eine Temperatur zu halten. Dann springt die Drehzahl ständig zwischen 30 % und 40 % hin und her. Das konnte ich schon beobachten. Genau so springt die Temperatur, was vermieden werden sollte, da das die Lötverbindungen auf Dauer schädigt.

Ich hätte meinem Code auch noch hinzugefügt, dass die Drehzahl einen festgelegten Wert nie unterschreitet, damit der Lüfter nicht ausgeht. Das hatte ich der Einfachheit halber erst einmal weggelassen.

Zu deinem Code: Wenn ich das richtig interpretiere, dann steht t74 für den Messwert bei 74 °C usw., richtig? Dann bedeutet die
- erste if-Bedingung, dass sie wahr ist, wenn die Temperatur unter 74 °C liegt.
- zweite Bedingung, dass sie wahr ist, wenn die Temperatur über 75 °C liegt UND unter 60 °C.
- dritte Bedingung, dass sie wahr ist, wenn die Temperatur über 76 °C liegt UND unter 61 °C.

Das ergibt keinen Sinn, selbst wenn die größer-/kleiner-Pfeile gedreht werden.

Ich empfehle dir auf korrektes Einrücken des Codes zu achten, denn so ist das sehr verwirrend. Die schließende Klammer einer Anweisung sollte sich immer auf gleicher Ebene befinden wie die Anweisung selbst und alle Befehle auf gleicher logischer Stufe auch auf gleicher Ebene einrücken, also zum Beispiel so:
switch (fanSteps) // Anfang Lüfterstufen
{
    case 0:                                 // Case 0 = Lüfter schaltet in 10 Stufen
    // statements
    if (temp < t74 ) {                      // wenn T innerhalb Stufe 0
        analogWrite(fanPin, fanSpeed0);     // dann Lüfter auf speed0 55 (22%)
----------------------------------------------------------------
        Serial.print("fanSpeed: ");
        Serial.print(fanSpeed0);
        Serial.println(" - Stufe: 0");      // nur Optische Ausgabe
        lcd.setCursor(0,2);                 // der Werte  Temp und PWM   
        lcd.print("PWM: ");                 // an seriellen Monitor und LCD
        lcd.print(fanSpeed0);
        lcd.print(" - Step: 0 ");
        delay(500);
-------------------------------------------------------------------
    }
    if (temp >= t75 and temp < t60 ) {      // wenn T zwischen Stufe 0 und 1
        analogWrite(fanPin, fanSpeed1);     // dann Lüfter auf speed1 64 (25%)
        Serial.print("fanSpeed: ");
        Serial.print(fanSpeed1);
        Serial.println(" - Stufe: 1");
        lcd.setCursor(0,2);       
        lcd.print("PWM: ");
        lcd.print(fanSpeed1);
        lcd.print(" - Step: 1 ");
        delay(500);
    }
    if (temp >= t76 and temp < t61)  {      // wenn T zwischen Stufe 2 und 3
        analogWrite(fanPin, fanSpeed2);     // dann Lüfter auf speed2 71 (28%)
        Serial.print("fanSpeed: ");
        Serial.print(fanSpeed2);
        Serial.println(" - Stufe: 2");
        lcd.setCursor(0,2);       
        lcd.print("PWM: ");
        lcd.print(fanSpeed2);
        lcd.print(" - Step: 2 ");
        delay(500);
    }                                       // Diese Klammer scheint zu fehlen
    break;
...
}


Außerdem für Programmcode besser das Code-Tag benutzen, damit eine Monospace-Schriftart verwendet wird. Das macht es hier ebenfalls leserlicher.
Es sieht so aus, dass du eine Klammer bei der letzten if-Anweisung vergessen hast. Da der Compiler nicht meckert, wird das wo anders wieder durch einen anderen Fehler ausgeglichen, was ebenfalls das unerwünschte Verhalten erklären kann. Guck am besten mal nach.

Du fragst mit der switch-Anweisung den Wert fanSteps ab. Was sagt der Wert aus? Aktuell sieht es so aus, dass der Wert 0 für "Lüfterregelung" steht, mehr nicht. Mit den if-Abfragen unterscheidest du die Temperaturfenster und stellst damit die PWM-Pulsweite ein (fanSpeed1, fanSpeed2 usw).

Es gibt wie immer unzählige Möglichkeiten etwas umzusetzen, hier einige Vorschläge:

- Du korrigierst die if-Bedingungen.
Wenn du die Fenster "...60°C, "60...68 °C" und "68...75 °C" wählst, dann wären das (ich lasse die Ausgabe mal weg):
switch (fanSteps) // Anfang Lüfterstufen
{
    case 0:                                 // Case 0 = Lüfter schaltet in 10 Stufen
    // statements
    if if(temp < t60) {                      // wenn T innerhalb Stufe 0
        analogWrite(fanPin, fanSpeed0);     // dann Lüfter auf speed0 55 (22%)
        delay(500);
    }
    if if(temp >= t60 and temp < t68) {      // wenn T zwischen Stufe 0 und 1
        analogWrite(fanPin, fanSpeed1);     // dann Lüfter auf speed1 64 (25%)
        delay(500);
    }
    if if(temp >= t68 and temp < t75)  {      // wenn T zwischen Stufe 2 und 3
        analogWrite(fanPin, fanSpeed2);     // dann Lüfter auf speed2 71 (28%)
        delay(500);
    }                                       // Diese Klammer scheint zu fehlen
    break;
...
}


Das nur als Beispiel.

- Du baust die if-Abfrage etwas anders auf und verwendest eine Hilfsvariable, die ich mal temp_var nenne.
switch (fanSteps) // Anfang Lüfterstufen
{
    case 0:                                 // Case 0 = Lüfter schaltet in 10 Stufen
    // statements
    temp_var = fanSpeed9                    // Höchste Stufe
    ...
    if if(temp < t75) {                      // wenn T innerhalb Stufe 2
        temp_var = fanSpeed2;
    }
    if if(temp < t68) {                      // wenn T innerhalb Stufe 1
        temp_var = fanSpeed1;
    }
    if if(temp < t60) {                      // wenn T innerhalb Stufe 0
        temp_var = fanSpeed0;
    }
    analogWrite(fanPin, temp_var);
    delay(500);

    break;
...
}

Das kann man auch umdrehen:
switch (fanSteps) // Anfang Lüfterstufen
{
    case 0:                                 // Case 0 = Lüfter schaltet in 10 Stufen
    // statements
    temp_var = fanSpeed0                    // niedrigste Stufe
    if if(temp > t60) {                      // wenn T innerhalb Stufe 1
        temp_var = fanSpeed1;
    }
    if if(temp > t68) {                      // wenn T innerhalb Stufe 2
        temp_var = fanSpeed2;
    }
    if if(temp > t75) {                      // wenn T innerhalb Stufe 3
        temp_var = fanSpeed3;
    }
    analogWrite(fanPin, temp_var);
    delay(500);

    break;
...
}


Im oberen Fall schreibst du erst mal die höchste Lüfterstufe rein und gehst davon aus, dass die Temperatur extrem hoch ist. Sollte sie doch niedriger sein, wird die Drehzahl Stück für Stück verringert.
Unten ist es umgekehrt. Du schreibst die niedrigste Drehzahl als Standardwert rein. Ist die Temperatur größer als die erste Schwelle, schreibe nächste Stufe in die Hilfsvariable. Ist die Temperatur noch höher, ersetze sie durch die nächst höhere Stufe. Am Ende bleibt die höchste Drehzahl in der Hilfsvariable, für die die Bedingung noch stimmt. Bei 70°C wäre die zweite noch wahr, die dritte nicht mehr, also bleibt es bei Stufe 2.
Diese Variante hat einen Vorteil: Bei deiner Variante muss sowieso jede if-Bedingung geprüft werden, selbst wenn darüber schon eine wahr war. In meinem Beispiel ist das genau so, allerdings vergleichst du in jeder Bedingung nur einen einzigen Wert. Willst du die Schwelle verschieben, von 68 auf 66°C, dann änderst du die eine Zahl und bist durch. Dir kann es nicht passieren, dass du die Schwelle nur an einer statt an zweien änderst.

Die Hilfsvariable verhindert, dass beim Durchlaufen der ganzen Stufen sich in Echt die Ansteuerung auch ändert.

Optimal ist das alles nicht, aber da es bei dir nicht auf Laufzeit ankommt und wichtiger ist, dass es überhaupt läuft und du keinen Fehler machst, hielte ich das für besser.

- Die dritte Möglichkeit wäre über switch(), geht aber nur, wenn du Integer-Werte hast und keine Float-Werte.
switch (fanSteps) // Anfang Lüfterstufen
{
    case 0:                                 // Case 0 = Lüfter schaltet in 10 Stufen
    // statements
    switch(temp) {
        case t60:
        case t61:
        case t62:
        case t63:
        case t64:
        case t65:
        case t66:
        case t67:
        case t68:
            temp_var = fanSpeed2;           // wenn T innerhalb Stufe 2
        break;
        case t69:
        case t70:
        case t71:
        case t72:
        case t73:
        case t74:
        case t75:
            temp_var = fanSpeed3;           // wenn T innerhalb Stufe 3
        break;
        case 76:
        ...
        default:
            temp_var = fanSpeed1;           // wenn T innerhalb Stufe 1
    }
    analogWrite(fanPin, temp_var);
    delay(500);

    break;
...
}


Das ist ein schönes Beispiel, um die Funktion von switch-Anweisungen zu veranschaulichen. Wenn temp die Werte 60, 61, 62, ... oder 68 hat, wird Stufe 1 gespeichert. Bei den Werten 69 bis 75 ist es Stufe 3. Trifft kein Wert zu, dann ist die Temperatur unter 60°C und das bedeutet Stufe 0.
Bei einer switch-Anweisung wird die anfangs übergebene Variable mit einem Wert verglichen und wenn der passt, dann wird ab hier der folgende Code ausgeführt, bis ein break; kommt. Nehmen wir an, die Temperatur wäre 62. Da nach "case t62:" kein break; steht, geht es darunter weiter. Die nachfolgenden Abfragen bis "case: t68" sind egal und werden ignoriert. Für alle Temperaturen bis 68 °C wird "fanSpeed2" gespeichert. Hiernach kommt ein "break;", womit alle Vergleiche danach ignoriert werden.
Das funktioniert aber, wie gesagt, nur mit Integer-Variablen. Wenn die Variable temp den Wert 62,1 enthält, trifft kein Wert zu und es endet in Stufe 0.

Auch das ist nicht ganz optimal, es gilt Gleiches wie oben. Welche Variante besser ist, hängt davon ab, wie viele Temperaturbereiche es gibt und wie viele verschiedene Werte die Variable temp annehmen kann. Die Beispiele sollen auch ein kleiner Denkanstoß sein, auf welche Weise man eine Aufgabe in Programmcode umsetzen kann.

MaikLommatzsch

Vieles von dem was ich geschrieben hab ist leider nicht so verstanden worden wie ich es gemeint hab. Sorry das ich mich schriftlich nicht so gut ausdrücken kann.

@Takeshi

Die fehlende Klammer fehlte nicht, ist beim Copy/Paste verloren gegangen:-)  Ich hoffe das der nächste Code für dich besser zu lesen geht.
Ich habe verstanden was du vorgeschlagen hast, leider konnte ich deine Codes nicht umsetzen, sie haben einfach nicht funktioniert und ich kann noch nicht mal wirklich erklären warum.
Aber ich habe dennoch weiter probiert.

Ich bin jetzt so weit das jede der 9 Stufen  wirklich alleine laufen, anlaufen wann sie sollen auch rückwärts.
Es gibt keine Bereiche mehr. Das bedeutet jetzt das zwischen Bereich x und y gependelt werden kann. Das kann bestimmt nervig werden.

Hier der Code ( ohne optische Ausgabe)
Zitatswitch (fanSteps)                  // Anfang Lüfterstufen
   {
   case 0:                            // Case 0 = Lüfter schaltet in 10 Stufen
// statements
   if (temp < t60 ) {                       // bis 60°C bleibt Stufe 0
       analogWrite(fanPin, fanSpeed0);      // dann Lüfter auf speed0 55 (22%)

   }
   if (temp > t60 and temp < t63) {       // Stufe 1 schaltet bei 60°C oder unter 63°C
       analogWrite(fanPin, fanSpeed1);    // dann Lüfter auf speed1 64 (25%)

   }
   if (temp > t63 and temp < t67)  {        // Stufe 2 schaltet bei 63°C oder unter 67°C
       analogWrite(fanPin, fanSpeed2);      // dann Lüfter auf speed2 71 (28%)

   }
   if (temp > t67 and temp < t70 ) {       // Stufe 3 schaltet bei 67°C oder unter 70°C
       analogWrite(fanPin, fanSpeed3);     // dann Lüfter auf speed3 76 (30%)

   }   
   if (temp > t70 and temp < t73 ) {       // Stufe 4 schaltet bei 70°C oder unter 73°C
       analogWrite(fanPin, fanSpeed4);     // dann Lüfter auf speed4 89 (35%)

   }
   if (temp > t73 and temp < t77 ) {       // Stufe 5 schaltet bei 73°C oder unter 77°C
       analogWrite(fanPin, fanSpeed5);     // dann Lüfter auf speed5 102 (40%)

   }
   if (temp > t77 and temp < t80 ) {      // Stufe 6 schaltet bei 77°C oder unter 80°C
       analogWrite(fanPin, fanSpeed6);    // dann Lüfter auf speed6 120 (47%)

   }
   if (temp > t80 and temp < t82) {       // Stufe 7 schaltet bei 80°C oder unter 82°C
       analogWrite(fanPin, fanSpeed7);    // dann Lüfter auf speed7 130 (50%)

   }
   if (temp > t82 and temp <t84 ) {       // Stufe 8 schaltet bei 82°C oder unter 84°C
       analogWrite(fanPin, fanSpeed8);    // dann Lüfter auf speed8 178 (70%)

   }
   if (temp > t84 ) {                     // Stufe 9 schaltet ab 84°C
       analogWrite(fanPin, fanSpeed9);    // dann Lüfter auf speed9 254 (100%)

   }
   break;
   }
// Ende Lüfterstufen 

Anregungen?

Takeshi

Hab in meinem Code gesehen, da steht "if if(...), das erste if muss weg.

Du verwendest kein <= oder >= mehr, wodurch glatte Werte komplett herausfallen. Das würde ich ändern. Wird aber bei meinem nächsten Vorschlag hinfällig.

Du hast keinerlei Hysterese einprogrammiert. Bist du genau auf der Grenze, springt die Stufe ständig hin und her. Dagegen hilft folgender Code:

TempSchwellen = {t60, t63, t67, t70, t73, t77, t80, t82, t84} // 9 Schwellen -> 10 Stufen
Hysterese = 2;
// LStufe kann Werte von 0 bis 9 (10 Werte) annehmen

switch (fanSteps)                      // Anfang Lüfterstufen
{
case 0:                             // Case 0 = Lüfter schaltet in 10 Stufen

switch(LStufe)
{
case 0:
analogWrite(fanPin, fanSpeed0);
if(temp > (TempSchwellen[0] + Hysterese)
{
LStufe++;
}
break;

case 1:
analogWrite(fanPin, fanSpeed1);
if(temp < (TempSchwellen[0] - Hysterese))
{
LStufe--;
}
else if(temp > (TempSchwellen[1] + Hysterese)
{
LStufe++;
}
break;

case 2:
analogWrite(fanPin, fanSpeed2);
if(temp < (TempSchwellen[1] - Hysterese))
{
LStufe--;
}
else if(temp > (TempSchwellen[2] + Hysterese)
{
LStufe++;
}
break;

// ...

case 8:
analogWrite(fanPin, fanSpeed8);
if(temp < (TempSchwellen[7] - Hysterese))
{
LStufe--;
}
else if(temp > (TempSchwellen[8] + Hysterese)
{
LStufe++;
}
break;

case 9:
analogWrite(fanPin, fanSpeed9);
if(temp < (TempSchwellen[8] - Hysterese))
{
LStufe--;
}
break;

default:
LStufe = 9;
}
delay(500);
}


Du erzeugst erst einmal ein Array, das 9 Schwellwerte für die 10 Stufen enthält. Den Wert der Hysterese habe ich willkürlich gesetzt, da müsstest du einen sinnvollen Wert ermitteln. Du musst einmalig die Variable LStufe initialisieren, am besten mit dem Wert 9. Diese Variable enthält die Nummer der Lüfterstufe, die gerade verwendet wird.

Die switch-Abfrage sucht dir jetzt den passenden Programmcode zur aktuellen Stufe raus. Die PWM wird auf den passenden Wert gesetzt. Gehen wir zunächst davon aus, dass die Hysterese 0 ist. Zu jeder Lüfterstufe gibt es nur zwei Schwellwerte, nämlich den nächsten über und unter der aktuellen Temperatur. Also musst du nur die beiden Schwellwerte abfragen. Ist die Temperatur kleiner als der untere Schwellwert, dann soll eine Stufe heruntergeschaltet werden. Umgekehrt, ist die Temperatur größer als der obere Schwellwert, dann hochschalten. Die PWM wird dabei noch nicht gesetzt, aber das ist egal, da die switch-Abfrage in sehr kurzer Zeit wieder durchlaufen wird, was die PWM dann anpasst. Die Temperatur und der Lüfter sind träge, das fällt nicht ins Gewicht. Bist du auf Stufe 0 und die Temperatur schnellt hoch auf 100 °C, dann würden nach und nach Stufe 1, 2, 3, ... bis 9 durchlaufen. Diese Variante ist also etwas "träge", was aber wieder egal ist, denn so schnell ändert sich die Temperatur nicht.
Mit der Variable Hysterese kannst du genau diese einbauen. Angenommen der Lüfter läuft auf Stufe 1. Die Temperatur überschreitet TempSchwellen[1] zzgl. der Hysterese, dann landet die Regelung in Stufe 2. Die Temperatur muss nun 2x um den Wert Hysterese fallen, damit wieder auf Stufe 1 geschaltet wird.

Der ganze Code lässt sich noch viel kompakter gestalten, wird dann aber vermutlich weniger verständlich. Wenn du mit Arrays nicht klarkommst, kannst du entweder versuchen dich mit Arrays auseinanderzusetzen, oder es mit diskreten Variablen umsetzen:
TempSchwellen0 = t60;
TempSchwellen1 = t63;
TempSchwellen2 = t67;
// ...


Der Vorteil der Variante ist auch, du siehst alle Schwellen auf einen Blick und musst wieder nur einen Wert ändern, damit er sich an zwei Stellen auswirkt. Die Hysterese kannst du ebenfalls für alle an einer Stelle anpassen. Und wenn du es noch etwas optimierst, kannst du den ganzen anderen Code mit der Ausgabe unten drunter packen, wie die Delay-Funktion. Du brauchst ja nicht 10 mal den gleichen Code hinschreiben.

MaikLommatzsch

#41
Ok ok, so Langsam raucht der Kopf ;D

Nachdem ich die Fett markierten Satzzeichen ergänzt hatte, wurde der Code nach der Prüfung akzeptiert. Auch mit der Optischen Ausgabe.

Ich fügte dann noch int bei den TempSchwellen ein und ein [9] ein. wo wir dann bei
int TempSchwellen[9]{t60, t63, t67, t70, t73, t77, t80, t82, t84}; angekommen waren.
Dann noch int Hysterese = 2; wobei das Große H nicht gewollt war, warum auch immer, hab es dann klein geschrieben.

int LStufe 0;  durfte auch nicht fehlen. (Bei int LStufe 9; fuhr der Lüfter nach Start immer auf volle pulle und pendelte sich erst ewig später runter)


TempSchwellen = {t60, t63, t67, t70, t73, t77, t80, t82, t84} [b];[/b] // 9 Schwellen -> 10 Stufen
Hysterese = 2;
// LStufe kann Werte von 0 bis 9 (10 Werte) annehmen

switch (fanSteps)                      // Anfang Lüfterstufen
{
case 0:                             // Case 0 = Lüfter schaltet in 10 Stufen

switch(LStufe)
{
case 0:
analogWrite(fanPin, fanSpeed0);
if(temp > (TempSchwellen[0] + Hysterese)[b])[/b]
{
LStufe++;
       Serial.print("fanSpeed: ");
       Serial.print(fanSpeed0);
       Serial.println(" - Stufe: 0");
       lcd.setCursor(0,2);       
       lcd.print("PWM: ");
       lcd.print(fanSpeed0);
       lcd.print(" - Step: 0 ");
}
break;

case 1:
analogWrite(fanPin, fanSpeed1);
if(temp < (TempSchwellen[0] - Hysterese))
{
LStufe--;
}
else if(temp > (TempSchwellen[1] + Hysterese)[b])[/b]
{
LStufe++;
       Serial.print("fanSpeed: ");
       Serial.print(fanSpeed1);
       Serial.println(" - Stufe: 1");
       lcd.setCursor(0,2);       
       lcd.print("PWM: ");
       lcd.print(fanSpeed1);
       lcd.print(" - Step: 1 ");

}
break;


Auf jeden fall Funktionierte da was, nur was genau kann ich leider nicht genau sagen. Da mir die Anzeigen fehlten. leider wurde mir nur die Temperatur ausgegeben.
Hab die Ausgabe auch nicht zum laufen gebracht. Was ich aber feststellen konnte war das die Reaktionszeit sehr träge war.

dann habe ich versucht das Hysterese Thema in meinen Code einzubauen.
Da ich es möglich Kurz mag nannte ich es ds1 steht für DowenSet und hat den Wert 1 erhalten. mehr oder weniger als1 wird leider nicht akzeptiert was ich schade finde, weil so hätte man mit den Wert 10 z.B das haben können was ich von anfang an wollte. ich gehe bei 74°C in die nächste stufe und bleibe mit ds 10 bis 64°C in der höheren Stufe. geht leider nicht, max und min ist 1.
Im Code schaut das dann so aus:

   switch (fanSteps)                  // Anfang Lüfterstufen
   {
   case 0:                                // Case 0 = Lüfter schaltet in 10 Stufen
// statements
   if (temp < t60 ) {                                // bis 60°C bleibt Stufe 0
       analogWrite(fanPin, fanSpeed0);      // dann Lüfter auf speed0 55 (22%)

   }
   if (temp >= t60 and temp <= t63 [b]- ds1[/b] ) {       // Stufe 1 schaltet bei 60°C oder unter 63°C (62°C)
       analogWrite(fanPin, fanSpeed1);                            // dann Lüfter auf speed1 64 (25%)

   }
   if (temp >= t63 and temp <= t67 [b]- ds1[/b] )  {   // Stufe 2 schaltet bei 63°C oder unter 67°C (66°C)
       analogWrite(fanPin, fanSpeed2);                         // dann Lüfter auf speed2 71 (28%)

   }


Ja, somit ist das Stufensägen abgestellt, zumindest mit dem Drehpoti. Wäre interessant zu wissen wie es mit einen echten NTC funktioniert.
Wäre ein Live Versuch jetzt drin?
Gibt es noch Anregungen?


Dann bitte ich um eine Erläuterung was ein = bei >< ausmacht. Den mit oder ohne = konnte ich jetzt keine Änderung feststellen.

Hier nochmal der ganze Code:
#include <PWM.h>                      // Bibliothek zur einstellung des PWM Signals
#include <Wire.h>                     // Wire Bibliothek für die I2C verbindung zum LCD
#include <LiquidCrystal_I2C.h>        // LiquidCrystal_I2C Bibliothek zur komunikation zum LCD
LiquidCrystal_I2C lcd(0x27, 20, 4);   // Hier wird das Display benannt (Adresse/Zeichen pro Zeile/Anzahl Zeilen).

// Konstanten
   const int fanPin = 9;                 // Pin für den Lüfter
   const int ntc = A0;                   // Pin für den 100kO NTC Wiederstand
   const int ntcNominal = 10000;         // Wiederstand des NTC bei Nominaltemperatur
   const int tempNominal = 25;           // Temperatur bei der der NTC den angegebenen Wiederstand hat
   const int bCoefficient = 3977;        // Beta Coefficient(B25 aus Datenblatt des NTC)
   const int serienWiederstand = 10000;  // Wert des Wiederstands der mit dem NTC in Serie geschalten ist
   int ledBlau  = 12;                    // Pin für die blaue LED (Kalt) an Pin 12
   int ledRot   = 11;                    // Pin für die rote LED (Heiss) an Pin 11
   int32_t frequency = 25000;            // einstellen der Lüfterfrequenz  25Khz

// Variablen
   int t60 = 60;               // ab hier werden die benötigten Temeraturen angegeben
   int t63 = 63;
   int t67 = 67;
   int t70 = 70;
   int t73 = 73;
   int t77 = 77;
   int t80 = 80;
   int t82 = 82;
   int t83 = 83;
   int t84 = 84;
   int t85 = 85;

   int ds1 = 1;                // DowenSet um 1°C unterdrückt Stufenschwankungen beim abkühlen
   
   int fanSteps = 0;           // es wird mit Lüfterstufen gearbeitet

   int fanSpeed0 = 55;         // ab hier werden die Lüfter geschwindigkeiten
   int fanSpeed1 = 64;         // für jede Stufe gesetzt
   int fanSpeed2 = 71;
   int fanSpeed3 = 76;
   int fanSpeed4 = 89;
   int fanSpeed5 = 102;
   int fanSpeed6 = 120;
   int fanSpeed7 = 130;
   int fanSpeed8 = 178;
   int fanSpeed9 = 254;       // bei 255 arbeitet der Lüfter stoßweise. darum 254

   int abfrageZahl = 1;       // Je mehr abfragen, desto stabiler isr das Ergebnis, dauert aber länger
   int abfrage[1];            // Array Variable für das Mitteln der Temperatur
   float durchschnitt = 0;    // Variable für das Mitteln der Temperatur
   float temp;                // Variable für die Berechnung der temperatur nach Steinhart


   void setup()
   {
/* Startmelodie
Die Spannungsausgabe für den Piezo-Lautsprecher wird im Sketch durch den Arduino-Befehl "tone"
automatisch festgelegt. Erstes zeichen nach der Klammer ist der Anschnlusspin.*/
   tone(8, 1500); // Im Hauptteil wird nun mit dem Befehl "tone ( Pinnummer , Tonfrequenz )" ein Ton abgegeben.
   delay(250);    // mit einer Dauer von 0,25 Sekunden
   noTone(8 );    // Der Ton wird abgeschaltet
   delay(50);     // Der Lautsprecher kurz aus
   tone(8, 2500);
   delay(250);
   noTone(8 );
   delay(50);
   tone(8, 3500);
   delay(250);   
   noTone(8 ); 
   delay(50);
   tone(8, 4500);
   delay(250);
   noTone(8 );
   delay(50);
   tone(8, 1500);
   delay(250);   
   noTone(8 );

// Lüfteranlauf
   analogWrite(fanPin, 100);   // Lüfter startet und geht wieder aus

// Frequenzustellung
   InitTimersSafe();                                       // Frenqenz umwandlung startet
   bool success = SetPinFrequencySafe(fanPin, frequency); // Setzt die Frequenz auf Pin

   lcd.init();      //Im Setup wird der LCD gestartet
   lcd.backlight(); //Hintergrundbeleuchtung einschalten (0 schaltet die Beleuchtung aus).
 

   Serial.begin(9600);                 // Baudrate für die Ausgabe am Serial Monitor
   pinMode(fanPin, OUTPUT);            // Setzt den Pin des Lüfters als Ausgang
   pinMode(ntc, INPUT);                // Setzt den Pin des NTC Wiederstands als Eingang
   pinMode(ledBlau, OUTPUT);           // definiere die blaue LED als Ausgang
   pinMode(ledRot, OUTPUT);            // definiere die blaue LED als Ausgang

   }
   void loop()
  {
  temperaturberechnung();             // Startet die Temperaturerfassungsroutine

   switch (fanSteps)                  // Anfang Lüfterstufen
   {
   case 0:                            // Case 0 = Lüfter schaltet in 10 Stufen
// statements
   if (temp < t60 ) {                       // bis 60°C bleibt Stufe 0
       analogWrite(fanPin, fanSpeed0);      // dann Lüfter auf speed0 55 (22%)
       Serial.print("fanSpeed: ");
       Serial.print(fanSpeed0);
       Serial.println(" - Stufe: 0");
       lcd.setCursor(0,2);       
       lcd.print("PWM: ");
       lcd.print(fanSpeed0);
       lcd.print(" - Step: 0 ");
   }
   if (temp >= t60 and temp <= t63 - ds1 ) {       // Stufe 1 schaltet bei 60°C oder unter 63°C (62°C)
       analogWrite(fanPin, fanSpeed1);             // dann Lüfter auf speed1 64 (25%)
       Serial.print("fanSpeed: ");
       Serial.print(fanSpeed1);
       Serial.println(" - Stufe: 1");
       lcd.setCursor(0,2);       
       lcd.print("PWM: ");
       lcd.print(fanSpeed1);
       lcd.print(" - Step: 1 ");
   }
   if (temp >= t63 and temp <= t67 - ds1 )  {        // Stufe 2 schaltet bei 63°C oder unter 67°C (66°C)
       analogWrite(fanPin, fanSpeed2);               // dann Lüfter auf speed2 71 (28%)
       Serial.print("fanSpeed: ");
       Serial.print(fanSpeed2);
       Serial.println(" - Stufe: 2");
       lcd.setCursor(0,2);       
       lcd.print("PWM: ");
       lcd.print(fanSpeed2);
       lcd.print(" - Step: 2 ");
   }
   if (temp >= t67 and temp <= t70 - ds1 ) {       // Stufe 3 schaltet bei 67°C oder unter 70°C (69°C)
       analogWrite(fanPin, fanSpeed3);             // dann Lüfter auf speed3 76 (30%)
       Serial.print("fanSpeed: ");
       Serial.print(fanSpeed3);
       Serial.println(" - Stufe: 3");
       lcd.setCursor(0,2);       
       lcd.print("PWM: ");
       lcd.print(fanSpeed3);
       lcd.print(" - Step: 3 ");
   }   
   if (temp >= t70 and temp <= t73 - ds1 ) {       // Stufe 4 schaltet bei 70°C oder unter 73°C (72°C)
       analogWrite(fanPin, fanSpeed4);             // dann Lüfter auf speed4 89 (35%)
       Serial.print("fanSpeed: ");
       Serial.print(fanSpeed4);
       Serial.println(" - Stufe: 4");
       lcd.setCursor(0,2);       
       lcd.print("PWM: ");
       lcd.print(fanSpeed4);
       lcd.print(" - Step: 4 ");
   }
   if (temp >= t73 and temp <= t77 - ds1 ) {       // Stufe 5 schaltet bei 73°C oder unter 77°C (76°C)
       analogWrite(fanPin, fanSpeed5);             // dann Lüfter auf speed5 102 (40%)
       Serial.print("fanSpeed: ");
       Serial.print(fanSpeed5);
       Serial.println(" - Stufe: 5");
       lcd.setCursor(0,2);       
       lcd.print("PWM: ");
       lcd.print(fanSpeed5);
       lcd.print(" - Step: 5 ");
   }
   if (temp >= t77 and temp <= t80 - ds1 ) {      // Stufe 6 schaltet bei 77°C oder unter 80°C (79°C)
       analogWrite(fanPin, fanSpeed6);            // dann Lüfter auf speed6 120 (47%)
       Serial.print("fanSpeed: ");
       Serial.print(fanSpeed6);
       Serial.println(" - Stufe: 6");
       lcd.setCursor(0,2);       
       lcd.print("PWM: ");
       lcd.print(fanSpeed6);
       lcd.print(" - Step: 6 ");
   }
   if (temp >= t80 and temp <= t82 - ds1 ) {       // Stufe 7 schaltet bei 80°C oder unter 82°C (81°C)
       analogWrite(fanPin, fanSpeed7);             // dann Lüfter auf speed7 130 (50%)
       Serial.print("fanSpeed: ");
       Serial.print(fanSpeed7);
       Serial.println(" - Stufe: 7");
       lcd.setCursor(0,2);       
       lcd.print("PWM: ");
       lcd.print(fanSpeed7);
       lcd.print(" - Step: 7 ");
   }
   if (temp >= t82 and temp <= t84 - ds1 ) {       // Stufe 8 schaltet bei 82°C oder unter 84°C (83°C)
       analogWrite(fanPin, fanSpeed8);             // dann Lüfter auf speed8 178 (70%)
       Serial.print("fanSpeed: ");
       Serial.print(fanSpeed8);
       Serial.println(" - Stufe: 8");
       lcd.setCursor(0,2);       
       lcd.print("PWM: ");
       lcd.print(fanSpeed8);
       lcd.print(" - Step: 8 ");
   }
   if (temp > t84 ) {                           // Stufe 9 schaltet ab 84°C
       analogWrite(fanPin, fanSpeed9);          // dann Lüfter auf speed9 254 (100%)
       Serial.print("fanSpeed: ");
       Serial.print(fanSpeed9);
       Serial.println(" - Stufe: 9");
       lcd.setCursor(0,2);       
       lcd.print("PWM: ");
       lcd.print(fanSpeed9);
       lcd.print(" - Step: 9 ");
   }
   break;
   }
// Ende Lüfterstufen
   }
   void temperaturberechnung()
   {
// Nimmt N Abfragen in einer Reihe, mit einem kurzen delay
   for (int i=0; i < abfrageZahl; i++)
   {
   abfrage[i] = analogRead(ntc);
   delay(10);
   }
   
// Mittelt alle Abfragen
   durchschnitt = 0;
   for (int i=0; i < abfrageZahl; i++)
   {
   durchschnitt += abfrage[i];
   }
   durchschnitt /= abfrageZahl;
   
// Umwandlung des Wertes in Wiederstand
   durchschnitt = 1023 / durchschnitt - 1;
   durchschnitt = serienWiederstand / durchschnitt;
   
// Umrechnung aller Ergebnisse in die Temperatur mittels einer Steinhard Berechnung
   temp = durchschnitt / ntcNominal;     // (R/Ro)
   temp = log(temp);                     // ln(R/Ro)
   temp /= bCoefficient;                 // 1/B * ln(R/Ro)
   temp += 1.0 / (tempNominal + 273.15); // + (1/To)
   temp = 1.0 / temp;                    // Invertieren
   temp -= 273.15;                       // Umwandeln in °C
   
// Ausgabe an den Seriellen Monitor
   Serial.print("Temperatur ");
   Serial.print(temp);
   Serial.println(" °C");
// Was am LCD angezeigt werden soll
   lcd.setCursor(0,0);        // Text soll beim ersten Zeichen in der ersten Reihe beginnen..
   lcd.print("Temperatur:");  // In der ersten Zeile soll ein Text in Zeile 1 angezeigt werden
   lcd.print(temp);           // Wert der in der Zeile 1 neben dem Text angezeigt wird
   lcd.print("C ");           // Text der in der Zeile 1 neben dem Wert angezeigt wird


// LED Temperaturwarung Blau zu Rot
   digitalWrite(ledBlau, HIGH);                       // macht die blaue LED am Start an
   if (temp >= 82) digitalWrite(ledBlau, LOW);       // mache die blaue LED bei 82 °C aus
 
   digitalWrite(ledRot, LOW);                       // macht die rote LED am Start aus
   if (temp >= 83) digitalWrite(ledRot, HIGH);       // mache die rote LED bei 83 °C an
 
// Übertemperatur Summerwarung
   if (temp >= 83) tone(8, 1500);    // mache den Summer bei 84 °C an
       delay(1100);   // mit einer Dauer von etwas über einer Sekunde
       noTone(8 );    // Der Ton wird abgeschaltet
       delay(25);     // Dauer der Abschaltung

// Sensordefekt Warnung ( LED wechselt von Rot zu Blau und Summer ertönt)
   digitalWrite(ledRot, LOW);                       // macht die rote LED ab Start aus
   if (temp <= 0) digitalWrite(ledRot, HIGH);       // mache die rote LED unter 0 °C an
   if (temp <= 0) tone(8, 1500);                    // Aktiviert den Warnsummer
       delay(1100);   // mit einer Dauer von etwas über einer Sekunde
       noTone(8 );    // Der Ton wird abgeschaltet
       delay(25);     // Dauer der Abschaltung
// Fehlermeldung bei unterbrechung Sensor
// LED Blau wechselt zu Rot und wieder zu Blau und so weiter ... Und Warnsummer ertönt.
// Selbes Bild erscheint auch unter °0C
}

we3dm4n

Zitat von: MaikLommatzsch am 10. März 2022, 13:46:08
Dann bitte ich um eine Erläuterung was ein = bei >< ausmacht. Den mit oder ohne = konnte ich jetzt keine Änderung feststellen.
Das aktueller Code sagt:
Wenn die Temperatur GRÖßER oder GLEICH 60°C ist, dann Lüfterstufe 1 - in der selben Bedingung steht dann zusätzlich: ...und KLEINER oder GLEICH 63°C MINUS 1
Somit Tempbereich 60°C bis 62°C (inkl. ds1)
Ohne das = wäre es der Temperaturbereich nur 61°C ...somit kein Bereich, sondern nur ein Wert.

Takeshi

#43
Hab die Zitat-Tags mal in Code-Tags geändert, nun nimmt der Post keine 5 Monitor-Seiten ein ;)

Wie gesagt, ich habe keine Ahnung von Arduino, daher weiß ich nicht, ob ein Int davor muss, was anderes oder gar nichts.

we3dm4n hat es ja bereits erklärt. "<" und ">" schließen eine Gleichheit aus. Wenn die Variable var den Wert 60 hat, dann ist die Klammer (var < 60) ist falsch, während (var <= 60) wahr ist. Das st wichtig, da du mit deiner Abfrage-Struktur auf jeden Wert reagieren möchtest. Ohne dem Gleichheitszeichen fallen die exakten Schwellwerte aber raus, das heißt da passiert gar nichts. Das ist in dem Fall vermutlich nicht so dramatisch, weil der Wert Schwankungen unterliegt, aber es ist unsauber und ich würde das auf jeden Fall berücksichtigen, denn wer weiß, was es vielleicht doch für Probleme macht.
Wichtig ist: Du darfst das nur "auf einer Seite" ("größer als" oder "kleiner als") verwenden, sonst gibt es zwei Abfragen, in denen der exakte Schwellwert zu einem "wahr" führt.

Zitat von: MaikLommatzsch am 10. März 2022, 13:46:08   switch (fanSteps)                  // Anfang Lüfterstufen
   {
   case 0:                                // Case 0 = Lüfter schaltet in 10 Stufen
// statements
   if (temp < t60 ) {                                // bis 60°C bleibt Stufe 0
       analogWrite(fanPin, fanSpeed0);      // dann Lüfter auf speed0 55 (22%)

   }
   if (temp >= t60 and temp <= t63 [b]- ds1[/b] ) {       // Stufe 1 schaltet bei 60°C oder unter 63°C (62°C)
       analogWrite(fanPin, fanSpeed1);                            // dann Lüfter auf speed1 64 (25%)

   }
   if (temp >= t63 and temp <= t67 [b]- ds1[/b] )  {   // Stufe 2 schaltet bei 63°C oder unter 67°C (66°C)
       analogWrite(fanPin, fanSpeed2);                         // dann Lüfter auf speed2 71 (28%)

   }

Die Hysterese kannst du in der if-Abfrage nicht einbauen. Das tut nicht das, was du dir vorstellst. Du fragst in einem Durchlauf IMMER alle Temperaturbereiche ab. Hast du eine Überlappung der Temperaturbereiche, wird immer die höhere Lüfterstufe benutzt, denn wenn eine Abfrage wahr ist, ist die nächste auch noch wahr und dann wird sofort die nächst höhere Lüfterstufe eingestellt.
Der Trick an dem Aufbau mit der switch-case-Struktur ist, dass die Grenzen zum Umschalten abhängig von der derzeitigen Lüfterstufe sind. Das ist die einfache Variante, die du auch ganz am Anfang umgesetzt hast:



Das wollen wir haben:



Hat die Konsole 69 °C, kann die Lüfterstufe 3 oder 4 sein, je nachdem, welche Temperatur vorher war. War sie vorher 70 °C, ist die Stufe 4 und sie muss auf 68°C fallen, damit die Stufe auf 3 wechselt. Danach muss sie auf 70 steigen, damit sie wieder auf Stufe 4 wechselt.
Das funktioniert aber nur, wenn du die aktuelle Lüfsterstufe mit verwurstest. Mit den if-Abfragen ausschließlich für die Temperatur, würde bei 69 °C jedes Mal Stufe 3 und direkt danach 4 ausgegeben werden. Bei der nächsten Abfrage das Gleiche. Im Resultat hast du dann immer Stufe 4.
Oder anders erklärt: Du fragst immer ab, ob die Bedingung für die jeweilige Stufe erfüllt ist. Mit 69 °C ist die Bedingung für zwei Stufen erfüllt. Mit der switch-case-Anweisung fragst du zunächst die aktuelle Lüfterstufe ab und entscheidest dann individuell für diese Stufe, ob das Kriterium zum Verlassen der Stufe erfüllt ist. Das ermöglicht für jede Stufe unterschiedliche Kriterien.

Und das hast du da programmiert ;D



Du musst die obere Schwelle normalerweise erhöhen und die untere Schwelle verringern. Stattdessen hast du die obere Schwelle verringert, wodurch eine Lücke entsteht.

Der komplette Programmcode ist schon mal praktisch, so kann man das Ganze viel besser verstehen und Fehler finden. Den Code habe ich erst einmal vernünftig eingerückt. Nicht sauber eingerückt ist wie eine miese Handschrift, die keiner lesen kann, außer man nimmt sich viel Zeit das zu entziffern. Hier ist dein originaler Programmcode ohne inhaltliche Änderungen:
#include <PWM.h>                      // Bibliothek zur einstellung des PWM Signals
#include <Wire.h>                     // Wire Bibliothek für die I2C verbindung zum LCD
#include <LiquidCrystal_I2C.h>        // LiquidCrystal_I2C Bibliothek zur komunikation zum LCD
LiquidCrystal_I2C lcd(0x27, 20, 4);   // Hier wird das Display benannt (Adresse/Zeichen pro Zeile/Anzahl Zeilen).

// Konstanten
const int fanPin = 9;                 // Pin für den Lüfter
const int ntc = A0;                   // Pin für den 100kO NTC Wiederstand
const int ntcNominal = 10000;         // Wiederstand des NTC bei Nominaltemperatur
const int tempNominal = 25;           // Temperatur bei der der NTC den angegebenen Wiederstand hat
const int bCoefficient = 3977;        // Beta Coefficient(B25 aus Datenblatt des NTC)
const int serienWiederstand = 10000;  // Wert des Wiederstands der mit dem NTC in Serie geschalten ist
int ledBlau  = 12;                    // Pin für die blaue LED (Kalt) an Pin 12
int ledRot   = 11;                    // Pin für die rote LED (Heiss) an Pin 11
int32_t frequency = 25000;            // einstellen der Lüfterfrequenz  25Khz

// Variablen
int t60 = 60;                         // ab hier werden die benötigten Temeraturen angegeben
int t63 = 63;
int t67 = 67;
int t70 = 70;
int t73 = 73;
int t77 = 77;
int t80 = 80;
int t82 = 82;
int t83 = 83;
int t84 = 84;
int t85 = 85;

int ds1 = 1;                          // DowenSet um 1°C unterdrückt Stufenschwankungen beim abkühlen
   
int fanSteps = 0;                     // es wird mit Lüfterstufen gearbeitet

int fanSpeed0 = 55;                   // ab hier werden die Lüfter geschwindigkeiten
int fanSpeed1 = 64;                   // für jede Stufe gesetzt
int fanSpeed2 = 71;
int fanSpeed3 = 76;
int fanSpeed4 = 89;
int fanSpeed5 = 102;
int fanSpeed6 = 120;
int fanSpeed7 = 130;
int fanSpeed8 = 178;
int fanSpeed9 = 254;                  // bei 255 arbeitet der Lüfter stoßweise. darum 254

int abfrageZahl = 1;                  // Je mehr abfragen, desto stabiler isr das Ergebnis, dauert aber länger
int abfrage[1];                       // Array Variable für das Mitteln der Temperatur
float durchschnitt = 0;               // Variable für das Mitteln der Temperatur
float temp;                           // Variable für die Berechnung der temperatur nach Steinhart


void setup()
{
/* Startmelodie
Die Spannungsausgabe für den Piezo-Lautsprecher wird im Sketch durch den Arduino-Befehl "tone"
automatisch festgelegt. Erstes zeichen nach der Klammer ist der Anschnlusspin.*/
tone(8, 1500);                     // Im Hauptteil wird nun mit dem Befehl "tone ( Pinnummer , Tonfrequenz )" ein Ton abgegeben.
delay(250);                        // mit einer Dauer von 0,25 Sekunden
noTone(8);                         // Der Ton wird abgeschaltet
delay(50);                         // Der Lautsprecher kurz aus
tone(8, 2500);
delay(250);
noTone(8);
delay(50);
tone(8, 3500);
delay(250);   
noTone(8);
delay(50);
tone(8, 4500);
delay(250);
noTone(8);
delay(50);
tone(8, 1500);
delay(250);   
noTone(8);

// Lüfteranlauf
analogWrite(fanPin, 100);          // Lüfter startet und geht wieder aus

// Frequenzustellung
InitTimersSafe();                                       // Frenqenz umwandlung startet
bool success = SetPinFrequencySafe(fanPin, frequency);  // Setzt die Frequenz auf Pin

lcd.init();                        //Im Setup wird der LCD gestartet
lcd.backlight();                   //Hintergrundbeleuchtung einschalten (0 schaltet die Beleuchtung aus).


Serial.begin(9600);                // Baudrate für die Ausgabe am Serial Monitor
pinMode(fanPin, OUTPUT);           // Setzt den Pin des Lüfters als Ausgang
pinMode(ntc, INPUT);               // Setzt den Pin des NTC Wiederstands als Eingang
pinMode(ledBlau, OUTPUT);          // definiere die blaue LED als Ausgang
pinMode(ledRot, OUTPUT);           // definiere die blaue LED als Ausgang
}

void loop()
{
temperaturberechnung();            // Startet die Temperaturerfassungsroutine

switch (fanSteps)                  // Anfang Lüfterstufen
{
case 0:                        // Case 0 = Lüfter schaltet in 10 Stufen
// statements
if (temp < t60 ) {                              // bis 60°C bleibt Stufe 0
analogWrite(fanPin, fanSpeed0);             // dann Lüfter auf speed0 55 (22%)
Serial.print("fanSpeed: ");
Serial.print(fanSpeed0);
Serial.println(" - Stufe: 0");
lcd.setCursor(0,2);       
lcd.print("PWM: ");
lcd.print(fanSpeed0);
lcd.print(" - Step: 0 ");
}
if (temp >= t60 and temp <= t63 - ds1 ) {       // Stufe 1 schaltet bei 60°C oder unter 63°C (62°C)
analogWrite(fanPin, fanSpeed1);             // dann Lüfter auf speed1 64 (25%)
Serial.print("fanSpeed: ");
Serial.print(fanSpeed1);
Serial.println(" - Stufe: 1");
lcd.setCursor(0,2);       
lcd.print("PWM: ");
lcd.print(fanSpeed1);
lcd.print(" - Step: 1 ");
}
if (temp >= t63 and temp <= t67 - ds1 )  {      // Stufe 2 schaltet bei 63°C oder unter 67°C (66°C)
analogWrite(fanPin, fanSpeed2);             // dann Lüfter auf speed2 71 (28%)
Serial.print("fanSpeed: ");
Serial.print(fanSpeed2);
Serial.println(" - Stufe: 2");
lcd.setCursor(0,2);       
lcd.print("PWM: ");
lcd.print(fanSpeed2);
lcd.print(" - Step: 2 ");
}
if (temp >= t67 and temp <= t70 - ds1 ) {       // Stufe 3 schaltet bei 67°C oder unter 70°C (69°C)
analogWrite(fanPin, fanSpeed3);             // dann Lüfter auf speed3 76 (30%)
Serial.print("fanSpeed: ");
Serial.print(fanSpeed3);
Serial.println(" - Stufe: 3");
lcd.setCursor(0,2);       
lcd.print("PWM: ");
lcd.print(fanSpeed3);
lcd.print(" - Step: 3 ");
}   
if (temp >= t70 and temp <= t73 - ds1 ) {       // Stufe 4 schaltet bei 70°C oder unter 73°C (72°C)
analogWrite(fanPin, fanSpeed4);             // dann Lüfter auf speed4 89 (35%)
Serial.print("fanSpeed: ");
Serial.print(fanSpeed4);
Serial.println(" - Stufe: 4");
lcd.setCursor(0,2);       
lcd.print("PWM: ");
lcd.print(fanSpeed4);
lcd.print(" - Step: 4 ");
}
if (temp >= t73 and temp <= t77 - ds1 ) {       // Stufe 5 schaltet bei 73°C oder unter 77°C (76°C)
analogWrite(fanPin, fanSpeed5);             // dann Lüfter auf speed5 102 (40%)
Serial.print("fanSpeed: ");
Serial.print(fanSpeed5);
Serial.println(" - Stufe: 5");
lcd.setCursor(0,2);       
lcd.print("PWM: ");
lcd.print(fanSpeed5);
lcd.print(" - Step: 5 ");
}
if (temp >= t77 and temp <= t80 - ds1 ) {      // Stufe 6 schaltet bei 77°C oder unter 80°C (79°C)
analogWrite(fanPin, fanSpeed6);            // dann Lüfter auf speed6 120 (47%)
Serial.print("fanSpeed: ");
Serial.print(fanSpeed6);
Serial.println(" - Stufe: 6");
lcd.setCursor(0,2);       
lcd.print("PWM: ");
lcd.print(fanSpeed6);
lcd.print(" - Step: 6 ");
}
if (temp >= t80 and temp <= t82 - ds1 ) {       // Stufe 7 schaltet bei 80°C oder unter 82°C (81°C)
analogWrite(fanPin, fanSpeed7);             // dann Lüfter auf speed7 130 (50%)
Serial.print("fanSpeed: ");
Serial.print(fanSpeed7);
Serial.println(" - Stufe: 7");
lcd.setCursor(0,2);       
lcd.print("PWM: ");
lcd.print(fanSpeed7);
lcd.print(" - Step: 7 ");
}
if (temp >= t82 and temp <= t84 - ds1 ) {       // Stufe 8 schaltet bei 82°C oder unter 84°C (83°C)
analogWrite(fanPin, fanSpeed8);             // dann Lüfter auf speed8 178 (70%)
Serial.print("fanSpeed: ");
Serial.print(fanSpeed8);
Serial.println(" - Stufe: 8");
lcd.setCursor(0,2);       
lcd.print("PWM: ");
lcd.print(fanSpeed8);
lcd.print(" - Step: 8 ");
}
if (temp > t84 ) {                              // Stufe 9 schaltet ab 84°C
analogWrite(fanPin, fanSpeed9);             // dann Lüfter auf speed9 254 (100%)
Serial.print("fanSpeed: ");
Serial.print(fanSpeed9);
Serial.println(" - Stufe: 9");
lcd.setCursor(0,2);       
lcd.print("PWM: ");
lcd.print(fanSpeed9);
lcd.print(" - Step: 9 ");
}

break;
}
// Ende Lüfterstufen
}

void temperaturberechnung()
{
// Nimmt N Abfragen in einer Reihe, mit einem kurzen delay
for (int i=0; i < abfrageZahl; i++)
{
abfrage[i] = analogRead(ntc);
delay(10);
}
   
// Mittelt alle Abfragen
durchschnitt = 0;
for (int i=0; i < abfrageZahl; i++)
{
durchschnitt += abfrage[i];
}
durchschnitt /= abfrageZahl;
   
// Umwandlung des Wertes in Wiederstand
durchschnitt = 1023 / durchschnitt - 1;
durchschnitt = serienWiederstand / durchschnitt;
   
// Umrechnung aller Ergebnisse in die Temperatur mittels einer Steinhard Berechnung
temp = durchschnitt / ntcNominal;                   // (R/Ro)
temp = log(temp);                                   // ln(R/Ro)
temp /= bCoefficient;                               // 1/B * ln(R/Ro)
temp += 1.0 / (tempNominal + 273.15);               // + (1/To)
temp = 1.0 / temp;                                  // Invertieren
temp -= 273.15;                                     // Umwandeln in °C
   
// Ausgabe an den Seriellen Monitor
Serial.print("Temperatur ");
Serial.print(temp);
Serial.println(" °C");
// Was am LCD angezeigt werden soll
lcd.setCursor(0,0);               // Text soll beim ersten Zeichen in der ersten Reihe beginnen..
lcd.print("Temperatur:");         // In der ersten Zeile soll ein Text in Zeile 1 angezeigt werden
lcd.print(temp);                  // Wert der in der Zeile 1 neben dem Text angezeigt wird
lcd.print("C ");                  // Text der in der Zeile 1 neben dem Wert angezeigt wird

// LED Temperaturwarung Blau zu Rot
digitalWrite(ledBlau, HIGH);                        // macht die blaue LED am Start an
if (temp >= 82) digitalWrite(ledBlau, LOW);         // mache die blaue LED bei 82 °C aus

digitalWrite(ledRot, LOW);                          // macht die rote LED am Start aus
if (temp >= 83) digitalWrite(ledRot, HIGH);         // mache die rote LED bei 83 °C an

// Übertemperatur Summerwarung
if (temp >= 83) {
tone(8, 1500);                // mache den Summer bei 84 °C an
}
delay(1100);                      // mit einer Dauer von etwas über einer Sekunde
noTone(8);                        // Der Ton wird abgeschaltet
delay(25);                        // Dauer der Abschaltung

// Sensordefekt Warnung ( LED wechselt von Rot zu Blau und Summer ertönt)
digitalWrite(ledRot, LOW);        // macht die rote LED ab Start aus
if (temp <= 0) {
digitalWrite(ledRot, HIGH);   // mache die rote LED unter 0 °C an
}
if (temp <= 0) {
tone(8, 1500);                // Aktiviert den Warnsummer
}
delay(1100);                      // mit einer Dauer von etwas über einer Sekunde
noTone(8);                        // Der Ton wird abgeschaltet
delay(25);                        // Dauer der Abschaltung
// Fehlermeldung bei unterbrechung Sensor
// LED Blau wechselt zu Rot und wieder zu Blau und so weiter ... Und Warnsummer ertönt.
// Selbes Bild erscheint auch unter °0C
}


Gewöhne dir bitte an einen einheitlichen Stil zu verwenden. Die schließende geschweifte Klammer immer auf gleicher Ebene wie der Ausdruck, nach dem die öffnende Klammer kam. Alles innerhalb der Klammer um einen Tab weiter eingerückt und so weiter.
Vermeide if-Abfragen ohne geschweifte Klammer. Das geht, führt aber gerade bei Anfängern schnell zu Fehlern. Ich bin mir nämlich auch nicht sicher, ob das am Ende so gewollt ist bei "// Übertemperatur Summerwarung", aber genau so war es programmiert.

Nun versuche ich den Code einmal anzupassen. Das kommt in meinem nächsten Beitrag, um das hier erst mal abzuspeichern.

Edit: Ach ja, doch noch was.
Was soll das switch(fanSteps)? Es gibt nur eine Option und es ist immer die gleiche Option, der Wert ändert sich nicht. Ist das "für später"? Ich würde das erst mal herausnehmen, macht es einfacher.

Takeshi

Hier der überarbeitete Programmcode. Ich kann ihn natürlich nicht kompilieren und damit nicht auf grobe Fehler prüfen.

#include <PWM.h>                      // Bibliothek zur einstellung des PWM Signals
#include <Wire.h>                     // Wire Bibliothek für die I2C verbindung zum LCD
#include <LiquidCrystal_I2C.h>        // LiquidCrystal_I2C Bibliothek zur komunikation zum LCD
LiquidCrystal_I2C lcd(0x27, 20, 4);   // Hier wird das Display benannt (Adresse/Zeichen pro Zeile/Anzahl Zeilen).

// Konstanten
const int fanPin = 9;                 // Pin für den Lüfter
const int ntc = A0;                   // Pin für den 100kO NTC Wiederstand
const int ntcNominal = 10000;         // Wiederstand des NTC bei Nominaltemperatur
const int tempNominal = 25;           // Temperatur bei der der NTC den angegebenen Wiederstand hat
const int bCoefficient = 3977;        // Beta Coefficient(B25 aus Datenblatt des NTC)
const int serienWiederstand = 10000;  // Wert des Wiederstands der mit dem NTC in Serie geschalten ist
int ledBlau  = 12;                    // Pin für die blaue LED (Kalt) an Pin 12
int ledRot   = 11;                    // Pin für die rote LED (Heiss) an Pin 11
int32_t frequency = 25000;            // einstellen der Lüfterfrequenz  25Khz

/***********************************************
* Variablen
***********************************************/

// Temperatur und Messung
int abfrageZahl = 1; // Je mehr abfragen, desto stabiler isr das Ergebnis, dauert aber länger
int abfrage[abfrageZahl]; // Array Variable für das Mitteln der Temperatur
float durchschnitt = 0; // Variable für das Mitteln der Temperatur
float temp; // Variable für die Berechnung der temperatur nach Steinhart

// Lüftersteuerung
int fanSpeed[10] = {55, 64, 71, 76, 89, 102, 120, 130, 178, 254};

int Stufe = 9;

TempSchwellen[9] = {45, 50, 55, 60, 65, 70, 75, 80, 85} // Für den Anfang größere Abstufungen, besser zum Testen
// TempSchwellen[9] = {60, 63, 67, 70, 73, 77, 80, 82, 84}

int ds1 = 1;                          // DowenSet um 1°C unterdrückt Stufenschwankungen beim abkühlen

void setup()
{
/* Startmelodie
Die Spannungsausgabe für den Piezo-Lautsprecher wird im Sketch durch den Arduino-Befehl "tone"
automatisch festgelegt. Erstes zeichen nach der Klammer ist der Anschnlusspin.*/
tone(8, 1500);                     // Im Hauptteil wird nun mit dem Befehl "tone ( Pinnummer , Tonfrequenz )" ein Ton abgegeben.
delay(250);                        // mit einer Dauer von 0,25 Sekunden
noTone(8);                         // Der Ton wird abgeschaltet
delay(50);                         // Der Lautsprecher kurz aus
tone(8, 2500);
delay(250);
noTone(8);
delay(50);
tone(8, 3500);
delay(250);   
noTone(8);
delay(50);
tone(8, 4500);
delay(250);
noTone(8);
delay(50);
tone(8, 1500);
delay(250);   
noTone(8);

// Lüfteranlauf
analogWrite(fanPin, 100);          // Lüfter startet und geht wieder aus

// Frequenzustellung
InitTimersSafe();                                       // Frenqenz umwandlung startet
bool success = SetPinFrequencySafe(fanPin, frequency);  // Setzt die Frequenz auf Pin

lcd.init();                        //Im Setup wird der LCD gestartet
lcd.backlight();                   //Hintergrundbeleuchtung einschalten (0 schaltet die Beleuchtung aus).


Serial.begin(9600);                // Baudrate für die Ausgabe am Serial Monitor
pinMode(fanPin, OUTPUT);           // Setzt den Pin des Lüfters als Ausgang
pinMode(ntc, INPUT);               // Setzt den Pin des NTC Wiederstands als Eingang
pinMode(ledBlau, OUTPUT);          // definiere die blaue LED als Ausgang
pinMode(ledRot, OUTPUT);           // definiere die blaue LED als Ausgang
}

void loop()
{
temperaturberechnung();            // Startet die Temperaturerfassungsroutine

// Lüfter schaltet in 10 Stufen
switch(Stufe)
{
case 0:
analogWrite(fanPin, fanSpeed[0]);
if(temp > (TempSchwellen[0] + ds1)
{
Stufe++;
}
break;

case 1:
analogWrite(fanPin, fanSpeed[1]);
if(temp < TempSchwellen[0])
{
Stufe--;
}
else if(temp > (TempSchwellen[1] + ds1)
{
Stufe++;
}
break;

case 2:
analogWrite(fanPin, fanSpeed[2]);
if(temp < TempSchwellen[1])
{
Stufe--;
}
else if(temp > (TempSchwellen[2] + ds1)
{
Stufe++;
}
break;

case 3:
analogWrite(fanPin, fanSpeed[3]);
if(temp < TempSchwellen[2])
{
Stufe--;
}
else if(temp > (TempSchwellen[3] + ds1)
{
Stufe++;
}
break;

case 4:
analogWrite(fanPin, fanSpeed[4]);
if(temp < TempSchwellen[3])
{
Stufe--;
}
else if(temp > (TempSchwellen[4] + ds1)
{
Stufe++;
}
break;

case 5:
analogWrite(fanPin, fanSpeed[5]);
if(temp < TempSchwellen[4])
{
Stufe--;
}
else if(temp > (TempSchwellen[5] + ds1)
{
Stufe++;
}
break;

case 6:
analogWrite(fanPin, fanSpeed[6]);
if(temp < TempSchwellen[5])
{
Stufe--;
}
else if(temp > (TempSchwellen[6] + ds1)
{
Stufe++;
}
break;

case 7:
analogWrite(fanPin, fanSpeed[7]);
if(temp < TempSchwellen[6])
{
Stufe--;
}
else if(temp > (TempSchwellen[7] + ds1)
{
Stufe++;
}
break;

case 8:
analogWrite(fanPin, fanSpeed[8]);
if(temp < TempSchwellen[7])
{
Stufe--;
}
else if(temp > (TempSchwellen[8] + ds1)
{
Stufe++;
}
break;

case 9:
analogWrite(fanPin, fanSpeed[9]);
if(temp < TempSchwellen[8])
{
Stufe--;
}
break;
}

// optische Ausgabe
Serial.print("fanSpeed: ");
Serial.print(fanSpeed[Stufe]);
Serial.println(" - Stufe: ");
Serial.print(Stufe);
lcd.setCursor(0,2);       
lcd.print("PWM: ");
lcd.print(fanSpeed[Stufe]);
lcd.print(" - Step: ");
lcd.print(Stufe); // Wenn das nicht funktioniert, dann lcd.print(Stufe + 0x30); probieren
}

void temperaturberechnung()
{
// Nimmt N Abfragen in einer Reihe, mit einem kurzen delay
for (int i=0; i < abfrageZahl; i++)
{
abfrage[i] = analogRead(ntc);
delay(10);
}
   
// Mittelt alle Abfragen
durchschnitt = 0;
for (int i=0; i < abfrageZahl; i++)
{
durchschnitt += abfrage[i];
}
durchschnitt /= abfrageZahl;
   
// Umwandlung des Wertes in Wiederstand
durchschnitt = 1023 / durchschnitt - 1;
durchschnitt = serienWiederstand / durchschnitt;
   
// Umrechnung aller Ergebnisse in die Temperatur mittels einer Steinhard Berechnung
temp = durchschnitt / ntcNominal;                   // (R/Ro)
temp = log(temp);                                   // ln(R/Ro)
temp /= bCoefficient;                               // 1/B * ln(R/Ro)
temp += 1.0 / (tempNominal + 273.15);               // + (1/To)
temp = 1.0 / temp;                                  // Invertieren
temp -= 273.15;                                     // Umwandeln in °C
   
// Ausgabe an den Seriellen Monitor
Serial.print("Temperatur ");
Serial.print(temp);
Serial.println(" °C");
// Was am LCD angezeigt werden soll
lcd.setCursor(0,0);               // Text soll beim ersten Zeichen in der ersten Reihe beginnen..
lcd.print("Temperatur:");         // In der ersten Zeile soll ein Text in Zeile 1 angezeigt werden
lcd.print(temp);                  // Wert der in der Zeile 1 neben dem Text angezeigt wird
lcd.print("C ");                  // Text der in der Zeile 1 neben dem Wert angezeigt wird

// LED Temperaturwarung Blau zu Rot
digitalWrite(ledBlau, HIGH);                        // macht die blaue LED am Start an
if (temp >= 82) digitalWrite(ledBlau, LOW);         // mache die blaue LED bei 82 °C aus

digitalWrite(ledRot, LOW);                          // macht die rote LED am Start aus
if (temp >= 83) digitalWrite(ledRot, HIGH);         // mache die rote LED bei 83 °C an

// Übertemperatur Summerwarung
if (temp >= 83) {
tone(8, 1500);                // mache den Summer bei 84 °C an
}
delay(1100);                      // mit einer Dauer von etwas über einer Sekunde
noTone(8);                        // Der Ton wird abgeschaltet
delay(25);                        // Dauer der Abschaltung

// Sensordefekt Warnung ( LED wechselt von Rot zu Blau und Summer ertönt)
digitalWrite(ledRot, LOW);        // macht die rote LED ab Start aus
if (temp <= 0) {
digitalWrite(ledRot, HIGH);   // mache die rote LED unter 0 °C an
}
if (temp <= 0) {
tone(8, 1500);                // Aktiviert den Warnsummer
}
delay(1100);                      // mit einer Dauer von etwas über einer Sekunde
noTone(8);                        // Der Ton wird abgeschaltet
delay(25);                        // Dauer der Abschaltung
// Fehlermeldung bei unterbrechung Sensor
// LED Blau wechselt zu Rot und wieder zu Blau und so weiter ... Und Warnsummer ertönt.
// Selbes Bild erscheint auch unter °0C
}


Mich verwundert, dass du schreibst, mit dem Code wäre das alles sehr träge. Wenn das träge ist, dann ist die Abarbeitung so richtig langsam, denn viel zu berechnen ist das noch nicht. Da ist dann ganz wo anders ein Problem.
Wenn der Code oben nicht funktioniert, dann halte ich es für sinnvoller den Fehler zu finden, als es komplett umzuschreiben, mit der Hoffnung, dass der Fehler dabei nicht mitgeschleift wird.

Die switch-case-Anweisung in der Hauptfunktion loop() lässt sich außerdem extrem zusammenstauchen:
void loop()
{
temperaturberechnung();            // Startet die Temperaturerfassungsroutine

// Lüfter schaltet in 10 Stufen
if(Stufe > 0)
{
if(temp < TempSchwellen[Stufe-1])
{
Stufe--;
}
}
if(Stufe < 9)
{
if(temp > (TempSchwellen[Stufe] + ds1)
{
Stufe++;
}
}
analogWrite(fanPin, fanSpeed[Stufe]);

// optische Ausgabe
Serial.print("fanSpeed: ");
Serial.print(fanSpeed[Stufe]);
Serial.println(" - Stufe: ");
Serial.print(Stufe);
lcd.setCursor(0,2);       
lcd.print("PWM: ");
lcd.print(fanSpeed[Stufe]);
lcd.print(" - Step: ");
lcd.print(Stufe); // Wenn das nicht funktioniert, dann lcd.print(Stufe + 0x30); probieren
}


Das geht, da in jedem "case" der gleiche Code steht, mit wenigen Ausnahmen. Einmal werden die Zahlen darin hochgezählt, wobei die Differenz zum Vergleichswert in "case" immer identisch ist. Die Zahl lässt sich also immer in Abhängigkeit von der Zahl hinter "case" ausdrücken und damit mit der Zahl, die in switch() geprüft wird, nämlich die Variable "Stufe". Mal exemplarisch für Stufe 5:
case 5:
analogWrite(fanPin, fanSpeed[5]);
if(temp < TempSchwellen[4])
{
Stufe--;
}
else if(temp > (TempSchwellen[5] + ds1)
{
Stufe++;
}
break;

Das macht das Gleiche wie:
Zitatcase 5:
         // Variable "Stufe" hat den Wert 5
         analogWrite(fanPin, fanSpeed[Stufe]);
         if(temp < TempSchwellen[Stufe-1])
         {
            Stufe--;
         }
         else if(temp > (TempSchwellen[Stufe] + ds1)
         {
            Stufe++;
         }
      break;

Also eigentlich könnte man einfach nur diesen Code für alle Stufen verwenden und braucht dann die switch-case-Anweisung nicht mehr. Weil aber bei der kleinsten Stufe das Herunterzählen und bei der höchsten das Hochzählen fehlt, wird bei der ersten if-Abfrage noch zusätzlich kontrolliert, ob nicht schon die niedrigste Stufe erreicht ist. Bei der zweiten if-Abfrage wird geprüft, ob die höchste schon erreicht ist.
Weil die zweite if-Abfrage niemals wahr sein kann, wenn die erste wahr ist, macht es keinen Unterschied, ob wir bei der zweiten "else if" oder nur "if" verwenden. Einziger Unterschied ist die Abarbeitungszeit. Das "else" darf man also streichen. Und heraus kommt, was ich oben schrieb.