1 | /*
|
2 | Programmname : Arduino Uno-Shild-Lüftersteuerung
|
3 | Author : Michael.V
|
4 | Erstelldatum : 17.01.2018
|
5 | Funktionsbeschreibung : - Zwei Temperatur Sensoren
|
6 | - Zwei PWM-Ausgänge für Ventilatoren
|
7 | - Remote Control ( Anzeige ändern, Auto/manuel umschalten)
|
8 | - Lüfter PWM geteuert .. Manuel/Automatisch(PID-Regler)
|
9 | - I²C - Bus Schnittstelle für Luftfeuchtigkeitssensor oder ähnliches
|
10 | */
|
11 |
|
12 | /*
|
13 | Anzeige
|
14 | - Temperatur 1
|
15 | - Temperatur 2
|
16 | - Stellgröße aus PID regler (Wenn man_auto= 1 wird PID-Wert auf Stellwert 1&2 geschrieben)
|
17 | - Manuelle Stellgröße 1
|
18 | - Manuelle Stellgröße 2
|
19 | - Sollwert (Temperatur bei Temperaturmessstation 2)
|
20 | */
|
21 |
|
22 | // Verwendete Bibliotheken
|
23 | #include <Arduino.h>
|
24 | #include <math.h> // Für Temp u PID Berechnung
|
25 | #include <TimerOne.h> // Für Interrupt Timer^1
|
26 | #include "SevSeg.h" // Für 7-Seg_Anzeige
|
27 | #include <IRremote.h> // Für Fernbedienung
|
28 | #include <Wire.h> // Für PWM comunikation
|
29 |
|
30 | // Register Adresse Lüfter
|
31 | #define Luefter1 0x04
|
32 | #define Luefter2 0x02
|
33 |
|
34 | // I²C Adresse PWM_IC
|
35 | #define pwm_ic 0x62
|
36 |
|
37 | // Channel für Temperatur
|
38 | #define T1 A0
|
39 | #define T2 A1
|
40 |
|
41 | // Objekte
|
42 | IRrecv irrecv(A2); // inizialisiert Empfänger an Pin A2
|
43 | decode_results results; // decodiert empfangendes in results
|
44 | SevSeg sevseg; // 7-Seg-Objekt um Funktionen zu nutzen
|
45 |
|
46 | // Variable für Timer
|
47 | unsigned long timer = millis();
|
48 | unsigned long timer2 = millis();
|
49 |
|
50 | // Variable für Manuel/Automatisch
|
51 | int man_auto;
|
52 |
|
53 | // Verhindert dauerhaftes Aufrufen
|
54 | int counter;
|
55 |
|
56 | // Variablen für Temperatur
|
57 | float temp_1;
|
58 | float temp_2;
|
59 | // Buffer für Temperatur Berechnung
|
60 | float temp1[10];
|
61 | float temp2[10];
|
62 |
|
63 | // Variablen für Lüfter
|
64 | float man_stell_1 =0.00; // Manuele_1 Stellgröße_1
|
65 | float man_stell_2 =0.00; // Manuele_2 Stellgröße_2
|
66 | float auto_stell =0.00; // Stellgröße aus PID-Regler
|
67 | float Sollwert =22.0; // Merkt sich Sollwert
|
68 |
|
69 | // Werte vom letzten durchlauf
|
70 | byte stell_manuel_1_alt=0; // Speichert stell_manuel_1_alt für vergleich
|
71 | byte stell_manuel_2_alt=0; // Speichert stell_manuel_1_alt für vergleich
|
72 | byte stell_auto_alt =0; // Speichert stell_auto_alt für vergleich
|
73 |
|
74 | // Stellgrößen Lüfter
|
75 | byte stell_manuel_1=0; // Für Stellgröße 1
|
76 | byte stell_manuel_2=0; // Für Stellgröße 2
|
77 | byte stell_auto =0; // Für Auto_stellgröße
|
78 |
|
79 | // Standby
|
80 | int standbye=0;
|
81 |
|
82 | // Für 7-Seg Anzeige
|
83 | byte numDigits = 4;
|
84 | byte digitPins[] = {8, 11, 12, 7}; // 7 Seg Anzeige Ziffer
|
85 | byte segmentPins[] = {9, 13, 5, 3, 2, 10, 6, 4}; // 7 Seg segment a,b,c,d,e,f,g,punkt
|
86 | bool resistorsOnSegments = false;
|
87 | byte hardwareConfig = COMMON_CATHODE;
|
88 | bool updateWithDelays = false;
|
89 | bool leadingZeros = false;
|
90 |
|
91 | // Auswahl display
|
92 | int auswahl=0;
|
93 |
|
94 | //Für PID Regler
|
95 | // Diese Werte müssen gespeichert werden
|
96 | static float En=0.0,en1=0.0,en2=0.0;
|
97 | static float Yn=0.0,yn1=0.0;
|
98 | float delta_y;
|
99 |
|
100 | // variable mindest stellgroße
|
101 | int untere_schwelle = 40;
|
102 |
|
103 | // mindest Temperatur Ofen
|
104 | int min_temp_ofen = 30;
|
105 |
|
106 | //////////////////////////////////////////////// Config //////////////////////////////////////////////////////
|
107 |
|
108 | void setup() {
|
109 | // join i2c bus
|
110 | Wire.begin();
|
111 |
|
112 | // aktiviert Serialle-Verbindung für debugg
|
113 | Serial.begin(57600);
|
114 |
|
115 | // inizialisiert Eingänge/Ausgänge
|
116 | ini_io();
|
117 |
|
118 | // inizialisiert 7 Segmnt Anzeige
|
119 | ini_sev_seg();
|
120 |
|
121 | // aktiviert Fernbedienung
|
122 | irrecv.enableIRIn();
|
123 |
|
124 | // Interrut Timer setzen refresh Display
|
125 | Timer1.initialize(3000); // Timer 0.3 Sec
|
126 | Timer1.attachInterrupt(Refresh); // Interrupt Rountine
|
127 |
|
128 | // inizialisiert PWM-IC-config
|
129 | ini_pca9533();
|
130 |
|
131 | // Grundeinstellung
|
132 | PWMaus();
|
133 | }
|
134 |
|
135 | ////////////////////////////////////////////////// LOOP ////////////////////////////////////////////////////
|
136 |
|
137 | void loop() {
|
138 |
|
139 | IR_auswerten();
|
140 |
|
141 | // Refresh Werte ~ alle 0.1 sec für Stellgröße Fernbedienung
|
142 | if (millis() - timer >= 100) {
|
143 | timer += 100;
|
144 | auswahl_fuer_display();
|
145 | }
|
146 |
|
147 | // Refresh Werte ~ alle 0.5 sec für Temperatur
|
148 | if (millis() - timer2 >= 500){
|
149 | timer2 += 500;
|
150 | update_temperatur();
|
151 | luefterstellen();
|
152 | }
|
153 |
|
154 | }
|
155 |
|
156 |
|
157 | ////////////////////////////////////////////////// Funktionen //////////////////////////////////////////////
|
158 |
|
159 |
|
160 |
|
161 |
|
162 |
|
163 | void update_temperatur(){
|
164 |
|
165 | // 10 Temperatur Messungen T1
|
166 | for(int i=0 ; i<10 ; i++){
|
167 | temp1[i]=Temperatur(T1);
|
168 | }
|
169 | // aufaddieren T1 Werte
|
170 | for (int j=0 ; j<10 ; j++){
|
171 | temp_1+=temp1[j];
|
172 | }
|
173 | // 10 Temperatur Messungen T2
|
174 | for(int k=0 ; k<10 ; k++){
|
175 | temp2[k]=Temperatur(T2);
|
176 | }
|
177 | // aufaddieren T2 Werte
|
178 | for (int l=0 ; l<10 ; l++){
|
179 | temp_2+=temp2[l];
|
180 | }
|
181 | // Mittelwertberechnung
|
182 | temp_1/=10;
|
183 | temp_2/=10;
|
184 |
|
185 | // PID Werte werden berechnet wenn Temperatur Wert 1 > Sollwert Istwert
|
186 | // Wenn Ofen <30°C ist muss kein PID Wert berechnet werden
|
187 | if ((int)temp_1 > min_temp_ofen){
|
188 | if (man_auto == 1) auto_stell=PIDRegler(Sollwert,temp_2);
|
189 | }
|
190 | if (auswahl == 0 ) sevseg.setNumber(temp_1, 2); // Übergibt Temperatur 1 an 7-Seg-Anzeige
|
191 | if (auswahl == 1 ) sevseg.setNumber(temp_2, 2); // Übergibt Temperatur 2 an 7-Seg-Anzeige
|
192 | }
|
193 |
|
194 | // Funktion für Temperaturauswertung
|
195 | float Temperatur(char Sensor){
|
196 | int B = 4275; // Werte aus Datenblatt für genaue Berechnung
|
197 | int R0 = 100000; // Werte aus Datenblatt für genaue Berechnung
|
198 | int a = analogRead(Sensor); // Ließt Wert vom Analogen-Eingang
|
199 | float R = 1023.0/a-1.0; // Werte aus Datenblatt für genaue Berechnung
|
200 | R = R0*R;
|
201 | float temp = 1.0/(log(R/R0)/B+1/298.15)-273.15; //Werte aus Datenblatt für genaue Berechnung
|
202 | return temp; // Gibt Temperatur zurück und springt ins Hautprogramm zurück
|
203 | }
|
204 |
|
205 | // wird alle 0.3 Sekunden Aufgerufen um Zahlen zu updaten
|
206 | void Refresh(){
|
207 | if (auswahl==5){
|
208 | digitalWrite( 8 ,HIGH); // Schaltet Ziffer 1 aus
|
209 | digitalWrite(11 ,HIGH); // Schaltet Ziffer 2 aus
|
210 | digitalWrite(12 ,HIGH); // Schalter Ziffer 3 aus
|
211 | digitalWrite( 7 ,HIGH); // Schaltet Ziffer 4 aus
|
212 | }
|
213 | if (auswahl!=5) sevseg.refreshDisplay(); // bewirkt das Zahlen angezigt werden-- nur bei auswahl != 5
|
214 | }
|
215 |
|
216 | float PIDRegler(float T1,float T2){
|
217 |
|
218 | // Empfindlichkeit des PID-Reglers
|
219 | float Tn = 1.0;
|
220 | float Tv = 1.0;
|
221 | float Kp = 1.0;
|
222 | // Variablen für P,I,D
|
223 | float P,I,D;
|
224 | // Zeitkostante
|
225 | float delta_t=0.5;
|
226 |
|
227 |
|
228 | En = T1 - T2; // T1 = Temperatur_1 = Sollwert hier
|
229 | // T2 = Temperatur_2 = Istwert
|
230 | // En = Regelabweichung
|
231 |
|
232 | // Berechnugn P I D
|
233 | P = En - en1;
|
234 | D = (delta_t / Tn) * En;
|
235 | I = Tv * (En - 2 * en1 + en2);
|
236 |
|
237 | // Berechnung neuer Stellgröße
|
238 | delta_y = Kp * ( P + D + I);
|
239 | Yn = yn1 + delta_y;
|
240 |
|
241 | // Speichert alte Werte
|
242 | en2 = en1;
|
243 | en1 = En;
|
244 | yn1 = Yn;
|
245 |
|
246 | // Begrenzt Yn auf 100
|
247 | if (Yn > 100.0) Yn=99.99;
|
248 | if (Yn < 0.0) Yn= 0.0;
|
249 |
|
250 | // Gibt Stellgröße zurück und springt ins Hautprogramm zurück
|
251 | return Yn;
|
252 | }
|
253 |
|
254 | void resetPID(void){
|
255 | en2=0;
|
256 | en1=0;
|
257 | yn1=0;
|
258 | En=0;
|
259 | Yn=0;
|
260 | delta_y=0;
|
261 | }
|
262 |
|
263 | void PWMaus(void){
|
264 | Wire.beginTransmission(0x62); // I²C Adresse
|
265 | Wire.write(0x05); // Wähl Register-PWM aus
|
266 | Wire.write(0x00); //
|
267 | Wire.endTransmission();
|
268 |
|
269 | }
|
270 | void PWMan(void){
|
271 | Wire.beginTransmission(0x62); // I²C Adresse
|
272 | Wire.write(0x05); // Wähl Register-PWM aus
|
273 | Wire.write(0x0E); //
|
274 | Wire.endTransmission();
|
275 | }
|
276 |
|
277 | void PWMNULL(void){
|
278 | Wire.beginTransmission(0x62); // I²C Adresse
|
279 | Wire.write(0x02); // Wähl Register-PWM0 aus
|
280 | Wire.write(0x00); // Gibt Pulsweite vor für Ventilator 1
|
281 | Wire.endTransmission();
|
282 |
|
283 | Wire.beginTransmission(0x62); // I²C Adresse
|
284 | Wire.write(0x04); // Wähl Register-PWM1 aus
|
285 | Wire.write(0x00); // Gibt Pulsweite vor für Ventilator 1
|
286 | Wire.endTransmission();
|
287 | }
|
288 |
|
289 |
|
290 | void IR_auswerten(void){
|
291 |
|
292 | // Fernbedienung
|
293 | if (irrecv.decode(&results)){
|
294 | // Gibt decodierten Fernbedienungscode in Dezimal über Seriellen-Monitor aus
|
295 | Serial.println(results.value, DEC);
|
296 | // Vergleicht Result mit Vorgaben
|
297 | if (results.value == 3772797103 ) {PWMNULL(); PWMaus();} // PWM Auschalten - Ferbedienung Taste
|
298 | if (results.value == 3772784863 ) {auswahl=0; standbye=0; } // Auswahl T1 - Ferbedienung Taste 1
|
299 | if (results.value == 3772817503 ) {auswahl=1; standbye=0; } // Auswahl T2 - Ferbedienung Taste 2
|
300 | if (results.value == 3772780783 ) {auswahl=2; standbye=0; PWMan();} // Stellgröße_manuel_1 - Ferbedienung Taste 4
|
301 | if (results.value == 3772813423 ) {auswahl=3; standbye=0; PWMan();} // Stellgröße_manuel_2 - Ferbedienung Taste 5
|
302 | if (results.value == 3772788943 ) {auswahl=4; standbye=0; } // Sollwert - Ferbedienung Taste 7
|
303 | if (results.value == 3772805263 ) {auswahl=5; standbye=1; PWMaus();} // Power-AUS - Ferbedienung Taste POWER
|
304 | if (results.value == 3772831783 ) {man_auto=0; auto_stell =0.00; PWMNULL(); PWMan();} // auf manuel schalten - Ferbedienung Taste bla
|
305 | if (results.value == 3772809343 ) {man_auto=1; man_stell_1=0.00; man_stell_2=0.00; PWMNULL(); PWMan(); resetPID();} // auf PID_Regler schalten schalten - Ferbedienung Taste bla
|
306 | if (results.value == 3772795063 ) { // Stellgröße +1
|
307 | if(auswahl==2) man_stell_1++; // Erhöt man_stell bei aufruf um 1
|
308 | if(auswahl==3) man_stell_2++;
|
309 | if(auswahl==4) Sollwert++;
|
310 | if (man_stell_1 > 99) man_stell_1 = 99; // Begrenzt Wert auf 99
|
311 | if (man_stell_2 > 99) man_stell_2 = 99; // Begrenzt Wert auf 99
|
312 | if (Sollwert < 99) Sollwert = 99; // Begrenzt Wert auf 99
|
313 | }
|
314 | if (results.value == 3772778743 ) { // Stellgröße -1
|
315 | if(auswahl==2) man_stell_1--; // Senkt man_stell bei aufruf um 1
|
316 | if(auswahl==3) man_stell_2--;
|
317 | if(auswahl==4) Sollwert--;
|
318 | if (man_stell_1 < 0) man_stell_1 = 0; // Begrenzt Wert auf 0
|
319 | if (man_stell_2 < 0) man_stell_2 = 0; // Begrenzt Wert auf 0
|
320 | if (Sollwert < 0) Sollwert = 0; // Begrenzt Wert auf 0
|
321 | }
|
322 |
|
323 | irrecv.resume(); //Der nächste Wert soll vom IR-Empfänger eingelesen werden
|
324 | }
|
325 | }
|
326 |
|
327 | void luefterstellen(void){
|
328 | // LED steuerung Automatisch / Manuel
|
329 | if (man_auto == 1 && (int)temp_2 >= min_temp_ofen){
|
330 | digitalWrite(A3, HIGH); // Schaltet LED ein (PID-Regler-AN)
|
331 | }
|
332 | else{
|
333 | digitalWrite(A3, LOW); // Schaltet LED auz (PID-Regler-AUS)
|
334 | }
|
335 |
|
336 | // Autostellgröße skallieren und convertieren
|
337 | stell_auto = convert_to_byte_mapped(auto_stell);
|
338 |
|
339 | // Manuelestellgrößen skallieren und convertieren
|
340 | stell_manuel_1 = convert_to_byte_mapped(man_stell_1);
|
341 | stell_manuel_2 = convert_to_byte_mapped(man_stell_2);
|
342 |
|
343 | // Schaltet erst dazu wenn 20% Leistung benötigt wird --> untere_schwelle = 20%
|
344 | if(stell_manuel_1 > untere_schwelle || stell_manuel_2 > untere_schwelle || stell_auto > untere_schwelle ){
|
345 |
|
346 | // Manuelbetrieb
|
347 | // Überträgt nur neuen PWM Wert-Ventilator 1
|
348 | if(stell_manuel_1_alt != stell_manuel_1 && man_auto == 0 && standbye == 0) {
|
349 | set_value_luefter(pwm_ic,Luefter1,stell_manuel_1);
|
350 | }
|
351 |
|
352 | // Überträgt nur neuen PWM Wert-Ventilator 2
|
353 | if(stell_manuel_2_alt != stell_manuel_2 && man_auto == 0 && standbye == 0) {
|
354 | set_value_luefter(pwm_ic,Luefter2,stell_manuel_2);
|
355 | }
|
356 |
|
357 | // Automatischer Betrieb
|
358 | // Überträgt nur neuen PWM Wert-Ventilator 1 und Ventilator 2
|
359 | if(stell_auto_alt != stell_auto && man_auto == 1 && standbye == 0){
|
360 | set_value_luefter(pwm_ic,Luefter1,stell_auto);
|
361 | set_value_luefter(pwm_ic,Luefter2,stell_auto);
|
362 | }
|
363 |
|
364 | counter=0;
|
365 | }
|
366 | else{
|
367 | // unter 20% bleibt Wert auf 0 wird nur einmal ausgeführt
|
368 | // außer stellgröße war mal größer als untere_schwelle
|
369 | if(counter==0){
|
370 | PWMaus();
|
371 | counter++;
|
372 | }
|
373 | }
|
374 |
|
375 | // Speichert alte Werte
|
376 | stell_manuel_1_alt = stell_manuel_1;
|
377 | stell_manuel_2_alt = stell_manuel_2;
|
378 | stell_auto_alt = stell_auto;
|
379 | }
|
380 |
|
381 | void ini_io(void){
|
382 | for (int i=2;i<14;i++){ // Setzt Pins als Ausgänge 2-13
|
383 | pinMode(i,OUTPUT);
|
384 | }
|
385 |
|
386 | for (int i=2;i<14;i++){ // Grundeinstellung HIGH 2-13
|
387 | pinMode(i,HIGH);
|
388 | }
|
389 |
|
390 | pinMode(A3,OUTPUT); // Setzt A3 als Ausgang
|
391 | }
|
392 |
|
393 | void ini_pca9533(void){
|
394 | // PWM-IC-config
|
395 | Wire.beginTransmission(0x62); // Adresse
|
396 | Wire.write(0x11); // Command - Auto-inc ON - Register 1 - PSC0 - Wahl
|
397 | Wire.write(0x00); // Daten für PSC0 0-> PWM freq 145 HZ
|
398 | Wire.write(0x00); // Daten für PWM0 0-> PEM 0% ON
|
399 | Wire.write(0x00); // Daten für PSC1 0-> PWM freq 145 HZ
|
400 | Wire.write(0x00); // Daten für PWM2 0-> PEM 0% ON
|
401 | Wire.write(0x05); // Daten für LS0-Register 0x0E -> LED0=PWM0 , LED2=PWM2 ,LED3=0, LED4=0
|
402 | Wire.endTransmission();
|
403 | }
|
404 |
|
405 | void ini_sev_seg(void){
|
406 | sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments, updateWithDelays, leadingZeros); // Setzt Segment Setting
|
407 | sevseg.setBrightness(90);
|
408 | }
|
409 |
|
410 | void set_value_luefter(byte adresse, byte reg, byte value){
|
411 | Wire.beginTransmission(adresse); // I²C Adresse
|
412 | Wire.write(reg); // Wähl Register-PWM1 aus
|
413 | Wire.write(value); // Gibt Pulsweite vor für Ventilator 2
|
414 | Wire.endTransmission();
|
415 | }
|
416 |
|
417 | void auswahl_fuer_display(){
|
418 | if (auswahl == 2 && man_auto == 0) sevseg.setNumber(man_stell_1, 2); // Übergibt Manuelle Stellgröße an die 7-Seg_Anzeige
|
419 | if (auswahl == 3 && man_auto == 0) sevseg.setNumber(man_stell_2, 2); // Übergibt Manuelle Stellgröße an die 7-Seg_Anzeige
|
420 | if (auswahl == 2 && man_auto == 1) sevseg.setNumber(auto_stell, 2); // Übergibt Automatisch Stellgröße an die 7-Seg_Anzeige (PID_REGLER)
|
421 | if (auswahl == 3 && man_auto == 1) sevseg.setNumber(auto_stell, 2); // Übergibt Automatisch Stellgröße an die 7-Seg_Anzeige (PID_REGLER)
|
422 | if (auswahl == 4) sevseg.setNumber(Sollwert, 2); // Übergibt Sollwert
|
423 | }
|
424 |
|
425 | byte convert_to_byte_mapped(float value){
|
426 | int temp = (int)value;
|
427 | temp = map(temp, 0,99,0,255);
|
428 | return byte(temp);
|
429 | }
|