sauber.ino


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
}