Hallo,
ich habe mich in den letzten Tagen mal mit einem Remake der Steuerung
für meine Lötstation Marke Eigenbau beschäftigt, und möchte euch mein
Ergebnis der Regelung selbst mitteilen - vielleicht kann es ja jemand
gebrauchen.
Konstruktive Kritik ist durchaus erwünscht.
Es handelt sich um einen beschränkten PID-Regler. Beschränkt, weil der
D-Anteil nur bei fallender Temperatur Einfluss auf die Regelung nimmt,
und dabei den I- und P-Anteil begrenzt.
Der D-Faktor ist variabel.
Der P-Faktor beträgt 1,6875 - 27/16tel
Der I-Faktor beträgt 0,25 - 1/4tel
Ich habe komplett auf den Einsatz von float oder double verzichtet -
daher sind die Faktoren oben dementsprechend entstanden.
Erst wollte ich die Temperatur selbst regeln. Durch die Berechnungen,
die notwendig wären, habe ich mich aber dazu entschieden, den ADC-Wert
zu Regeln. So muss ich nur für die noch folgende Anzeige den ADC-Wert in
eine Temperatur umrechnen. - Ich benutze 9 der 10 Bits des Tiny45.
Das Regler-Ergebnis ist die Einschaltdauer in Prozent einer Sekunde.
Genug herumgequatscht! Nun zum Code:
Globale Variablen benutze ich folgende drei:
1 | volatile uint8_t FehlerSumme = 0;
|
2 | volatile uint8_t FehlerAlt = 0;
|
3 | volatile uint8_t FehlerAlt2 = 0;
|
Die Regelung selbst sieht wie folgt aus:
1 | uint8_t regelwert(uint16_t SollTemp, uint16_t IstTemp)
|
2 | {
|
3 | uint8_t RWert = 0;
|
4 | uint8_t DWert = 0;
|
5 | uint8_t IWert = 0;
|
6 | int16_t Fehler = 0;
|
7 | uint16_t PWert = 0;
|
8 |
|
9 | // Regelabweichung ermitteln
|
10 | Fehler = (SollTemp - IstTemp);
|
11 |
|
12 | // Bei sinkender Temperatur gegensteuern / 2 mögliche Stufen
|
13 | if(FehlerAlt < Fehler) DWert = abs(FehlerAlt - Fehler) * 16;
|
14 | if(FehlerAlt2 < Fehler && DWert == 0) DWert = abs(FehlerAlt2 - Fehler) * 4;
|
15 |
|
16 | // Integral-Anteil berechnen, wenn ein bestimmtes Fenster erreicht ist
|
17 | // Edit: 25 durch 32 ersetzt.
|
18 | if(Fehler < 32 && Fehler > -8) FehlerSumme += (int8_t)Fehler;
|
19 |
|
20 | // Integral-Anteil begrenzen
|
21 | // Edit: 160 durch 200 ersetzt
|
22 | if(FehlerSumme > 200) FehlerSumme = 200;
|
23 | if(FehlerSumme < 0) FehlerSumme = 0;
|
24 | if(Fehler < -8 && FehlerSumme >= 4) FehlerSumme -= 4;
|
25 |
|
26 | // Berechnen des Proportional-Anteils, wenn der ermittelte
|
27 | // Fehler positiv ist. Kein Einfluss bei Temperatur
|
28 | // oberhalb der Soll-Temperatur.
|
29 | if(Fehler > 0) PWert = abs((Fehler * 27) / 16);
|
30 |
|
31 | // Berechnen des Integral-Anteils
|
32 | // Edit: Teiler von 8 auf 4 geändert.
|
33 | IWert = FehlerSumme / 4;
|
34 |
|
35 | // PAnteil und IAnteil bei sinkender Temperatur verringern
|
36 | if(DWert > 0) PWert = PWert / 4;
|
37 | if(DWert > 0) IWert = IWert / 2;
|
38 |
|
39 | // DAnteil-Bestimmung ermöglichen
|
40 | FehlerAlt = Fehler;
|
41 | FehlerAlt2 = FehlerAlt;
|
42 |
|
43 | // Darf 100% der Regelung ausmachen, sinkt ab etwa 50 ADC-Werten
|
44 | // vor der Soll-Temperatur!
|
45 | if(abs(PWert) > 100) PWert = 100;
|
46 | // Kann maximal 200/4 werden und zwar erst ab 32 ADC-Werte vor
|
47 | // erreichen der Soll-Temperatur
|
48 | if(abs(IWert) > 40) IWert = 40;
|
49 | // DWert greift mit sehr hohem Faktor bei stark fallender Temperatur
|
50 | // ein, und das auch nur solange die Temperatur fällt.
|
51 | if(abs(DWert) > 60) DWert = 60;
|
52 |
|
53 | // Rueckgabe-Wert zusammensetzen!
|
54 | RWert = PWert + IWert + DWert;
|
55 |
|
56 | // Rueckgabe-Wert begrenzen
|
57 | if(RWert > 100) RWert = 100;
|
58 | if(RWert > 1) return RWert;
|
59 | return 0;
|
60 | }
|
Sobald ich die Zeit finde, werde ich mal eine Regelkurve aufnehmen.
Der 80W-Kolben der WSD81 regelt nach dem Einschalten etwa 3° bis 4° über
Soll-Temperatur und fällt dann langsam auf den Soll-Wert +-2°.
Bei größerer Wärmeabfuhr wird relativ schnell gegengesteuert durch den
D-Anteil - allerings sorgt das nach dem Zurücklegen für eine Überhöhung
von bis zu 20°C - da muss ich noch dran feilen.
In diesem Sinne, Frohes Fest schonmal ;)
Edit: kleines Update der Regler-Werte, läuft jetzt halbwegs
zufriedenstellend an Ersatzstromversorgung (13.8V) statt an
Standardnetzteil (24V).