unsauber.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
*/
10
11
12
// Eingebundende Bibliotheken
13
#include <math.h>         // Für Temp u PID Berechnung
14
#include <TimerOne.h>     // Für Interrupt Timer^1
15
#include "SevSeg.h"       // Für 7-Seg_Anzeige
16
#include <IRremote.h>     // Für Fernbedienung
17
#include <Wire.h>         // Für PWM comunikation
18
#include <avr/wdt.h>      // Watchdog
19
20
// Objekte
21
IRrecv irrecv(A2);        // inizialisiert Empfänger an Pin A2
22
decode_results results;   // decodiert empfangendes in results
23
SevSeg sevseg;            // 7-Seg-Objekt um Funktionen zu nutzen
24
25
// Funktionsprototypen
26
float Temperatur(char Sensor);
27
float PIDRegler(float T1,float T2,float delta);
28
void Refresh();
29
void PWMan();
30
void PWMaus();
31
32
static int auswahl=0;
33
float temp1[10];
34
float temp2[10];
35
36
//Für PID Regler
37
  // Diese Werte müssen gespeichert werden
38
static float En=0.0,en1=0.0,en2=0.0;
39
static float Yn=0.0,yn1=0.0;
40
float delta_y;
41
42
43
44
void setup() {
45
  Wire.begin(); // join i2c bus (address optional for master)
46
  
47
  Serial.begin(9600);
48
  
49
  int i;
50
  for (i=2;i<14;i++){     // Setzt Pins als Ausgänge 2-13
51
    pinMode(i,OUTPUT);
52
    }
53
  for (i=2;i<14;i++){     // Grundeinstellung HIGH 2-13
54
    pinMode(i,HIGH);
55
    }
56
  pinMode(A3,OUTPUT);     // Setzt A3 als Ausgang
57
  
58
  // Für 7-Seg Anzeige
59
  byte numDigits = 4;
60
  byte digitPins[] = {8, 11, 12, 7};               // 7 Seg Anzeige Ziffer   
61
  byte segmentPins[] = {9, 13, 5, 3, 2, 10, 6, 4}; // 7 Seg segment a,b,c,d,e,f,g,punkt
62
  bool resistorsOnSegments = false; 
63
  byte hardwareConfig = COMMON_CATHODE; 
64
  bool updateWithDelays = false; 
65
  bool leadingZeros = false; 
66
  sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments, updateWithDelays, leadingZeros); // Setzt Segment Setting
67
  sevseg.setBrightness(90);                   // Helligkeit  
68
69
  // aktiviert Fernbedienung
70
  irrecv.enableIRIn(); // Start the receiver
71
  
72
  // Interrut Timer setzen refresh Display
73
  Timer1.initialize(3000);                    // Timer 0.3 Sec
74
  Timer1.attachInterrupt(Refresh);           // Interrupt Rountine
75
76
  // PWM-IC-config
77
  Wire.beginTransmission(0x62);  // Adresse
78
  Wire.write(0x11);              // Command - Auto-inc ON - Register 1 - PSC0 - Wahl
79
  Wire.write(0x00);              // Daten für PSC0 0-> PWM freq 145 HZ
80
  Wire.write(0x00);              // Daten für PWM0 0-> PEM 0% ON 
81
  Wire.write(0x00);              // Daten für PSC1 0-> PWM freq 145 HZ
82
  Wire.write(0x00);              // Daten für PWM2 0-> PEM 0% ON
83
  Wire.write(0x05);              // Daten für LS0-Register 0x0E -> LED0=PWM0 , LED2=PWM2 ,LED3=0, LED4=0
84
  Wire.endTransmission(); 
85
86
  // Watchdog
87
  wdt_enable(WDTO_15MS);        // Wachtdog wird auf 15ms Eingestellt
88
  PWMaus();
89
}
90
91
void loop() {
92
  
93
  static unsigned long timer = millis();  // für Refresh        
94
  static unsigned long timer2 = millis();  // für Refresh
95
  
96
  static int man_auto=0;                  // Auswahl manuel/automatisch
97
  static int counter=0;
98
        
99
  static float man_stell_1=0.00;             // Manuele_1 Stellgröße_1
100
  static float man_stell_2=0.00;             // Manuele_2 Stellgröße_2     
101
  static float auto_stell=0.00;                  // Stellgröße aus PID-Regler
102
  static float Sollwert=24.0;               // merkt sich Sollwert
103
  
104
  static byte stell_manuel_1_alt;         // Speichert stell_manuel_1_alt für vergleich
105
  static byte stell_manuel_2_alt;         // Speichert stell_manuel_1_alt für vergleich
106
  static byte stell_auto_alt;             // Speichert stell_auto_alt für vergleich
107
108
  float temp_1;
109
  float temp_2;              // Für Temperatur
110
  
111
  int stell_manuel_1;               // Für Stellgröße 1
112
  int stell_manuel_2;               // Für Stellgröße 2
113
  int stell_auto=0;                   // Für Auto_stellgröße
114
  int standbye=0;
115
  
116
  // Refresh Werte ~ alle 0.1 sec für Stellgrüße Fernbedienung
117
  if (millis() - timer >= 100) {
118
     timer += 100;
119
     
120
     if (auswahl == 2 && man_auto == 0) sevseg.setNumber(man_stell_1, 2);     // Übergibt Manuelle Stellgröße an die 7-Seg_Anzeige
121
     if (auswahl == 3 && man_auto == 0) sevseg.setNumber(man_stell_2, 2);     // Übergibt Manuelle Stellgröße an die 7-Seg_Anzeige
122
     if (auswahl == 2 && man_auto == 1) sevseg.setNumber(auto_stell, 2);      // Übergibt Automatisch Stellgröße an die 7-Seg_Anzeige (PID_REGLER)
123
     if (auswahl == 3 && man_auto == 1) sevseg.setNumber(auto_stell, 2);      // Übergibt Automatisch Stellgröße an die 7-Seg_Anzeige (PID_REGLER)
124
     if (auswahl == 4)                  sevseg.setNumber(Sollwert, 2);       // Übergibt Sollwert
125
  }
126
  
127
  // Refresh Werte ~ alle 0.5 sec für temperatur
128
  if (millis() - timer2 >= 500) {
129
     timer2 += 500;
130
131
     for(int i=0 ; i<10 ; i++){
132
      temp1[i]=Temperatur(A0);
133
     }
134
     for (int j=0 ; j<10 ; j++){
135
      temp_1+=temp1[j];
136
     }
137
     for(int k=0 ; k<10 ; k++){
138
      temp2[k]=Temperatur(A1);
139
     }
140
     for (int l=0 ; l<10 ; l++){
141
      temp_2+=temp2[l];
142
     }
143
          
144
     temp_1/=10;
145
     temp_2/=10;
146
147
     if ((int)temp_1 > Sollwert){
148
        if (man_auto == 1) auto_stell=PIDRegler(Sollwert,temp_2);
149
      }
150
     if (auswahl == 0 ) sevseg.setNumber(temp_1, 2);                       // Übergibt Temperatur 1 an 7-Seg-Anzeige
151
     if (auswahl == 1 ) sevseg.setNumber(temp_2, 2);                       // Übergibt Temperatur 2 an 7-Seg-Anzeige
152
  }
153
  // Fernbedienung  
154
  if (irrecv.decode(&results))                      //Wenn Daten empfangen wurden,
155
  {
156
    Serial.println(results.value, DEC);                                // Gibt decodierten Fernbedienungscode in Dezimal über Seriellen-Monitor wieder
157
    if (results.value == 3772797103 ) {PWMNULL();PWMaus();}                          // PWM Auschalten
158
    if (results.value == 3772784863 ) {auswahl=0; standbye=0; }          // Auswahl T1
159
    if (results.value == 3772817503 ) {auswahl=1; standbye=0; }          // Auswahl T1
160
    if (results.value == 3772780783 ) {auswahl=2; standbye=0; PWMan();}  // Stellgröße_manuel_1
161
    if (results.value == 3772813423 ) {auswahl=3; standbye=0; PWMan();}  // Stellgröße_manuel_2
162
    if (results.value == 3772788943 ) {auswahl=4; standbye=0; }              // Sollwert
163
    if (results.value == 3772805263 ){
164
        auswahl=5;    // Anzeige auschalten
165
        PWMaus();
166
        standbye=1;
167
      }
168
    if (results.value == 3772831783 ) {man_auto=0; auto_stell=0.00;PWMNULL();PWMan();}                     // auf manuel schalten
169
    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
170
    if (results.value == 3772795063 )               // Stellgröße +1
171
    {
172
      if(auswahl==1) temp_2++;
173
      if(auswahl==2) man_stell_1++;                 // Erhöt man_stell bei aufruf um 1  
174
      if(auswahl==3) man_stell_2++;
175
      if(auswahl==4) Sollwert++;                                                           
176
      if (man_stell_1 > 99) man_stell_1 = 99;        // Begrenzt Wert auf 99
177
      if (man_stell_2 > 99) man_stell_2 = 99;        // Begrenzt Wert auf 99
178
      //if (differenz > 30) differenz = 30;            // Begrenzt Wert auf 30
179
    }
180
    if (results.value == 3772778743 )               // Stellgröße -1
181
    { 
182
      if(auswahl==1) temp_2--;
183
      if(auswahl==2) man_stell_1--;                 // Senkt man_stell bei aufruf um 1
184
      if(auswahl==3) man_stell_2--;
185
      if(auswahl==4) Sollwert--;                                 
186
      if (man_stell_1 < 0) man_stell_1 = 0;         // Begrenzt Wert auf 0
187
      if (man_stell_2 < 0) man_stell_2 = 0;         // Begrenzt Wert auf 0
188
      if (Sollwert   < 0) Sollwert   = 0;         // Begrenzt Wert auf 99
189
    }
190
       
191
    irrecv.resume();                                //Der nächste Wert soll vom IR-Empfänger eingelesen werden
192
  }
193
194
  // Anzeige Automatisch / Manuel
195
  if (man_auto ==1 ) digitalWrite(A3, HIGH);       // Schaltet LED ein (PID-Regler-AN)
196
  if (man_auto ==0 ) digitalWrite(A3, LOW);        // Schaltet LED auz (PID-Regler-AUS)
197
198
  // Autostellgröße skallieren und convertieren
199
 
200
   stell_auto = int(auto_stell);
201
   stell_auto = map(stell_auto, 0,99,0,255);
202
   //stell_auto = 255 - stell_auto;
203
   stell_auto = byte(stell_auto);
204
  
205
206
  // Manuelestellgrößen skallieren und convertieren
207
  
208
   stell_manuel_1 = int(man_stell_1);
209
   stell_manuel_1 = map(stell_manuel_1, 0,99,0,255);
210
   //stell_manuel_1 = 255 - stell_manuel_1;
211
   stell_manuel_1 = byte(stell_manuel_1);
212
213
   stell_manuel_2 = int(man_stell_2);
214
   stell_manuel_2 = map(stell_manuel_2, 0,99,0,255);
215
   //stell_manuel_2 = 255 - stell_manuel_2;
216
   stell_manuel_2 = byte(stell_manuel_2);
217
  
218
219
if (stell_manuel_1 > 40 || stell_manuel_2 > 40 || stell_auto > 40 )  // Schaltet erst dazu wenn 20% Leistung benötigt wird
220
{
221
  // Überträgt nur neuen PWM Wert-Ventilator 1
222
  if (stell_manuel_1_alt != stell_manuel_1 && man_auto ==0 && standbye == 0) { 
223
      Wire.beginTransmission(0x62);                           // I²C Adresse 
224
      Wire.write(0x04);                                       // Wähl Register-PWM1 aus   
225
      Wire.write(stell_manuel_1);                             // Gibt Pulsweite vor  für Ventilator 2           
226
      Wire.endTransmission();   
227
      }
228
  // Überträgt nur neuen PWM Wert-Ventilator 2
229
  if (stell_manuel_2_alt != stell_manuel_2 && man_auto ==0 && standbye == 0) {  
230
      Wire.beginTransmission(0x62);                           // I²C Adresse
231
      Wire.write(0x02);                                       // Wähl Register-PWM0 aus 
232
      Wire.write(stell_manuel_2);                             // Gibt Pulsweite vor für VFentilator 1           
233
      Wire.endTransmission();   
234
      }
235
  // Überträgt nur neuen PWM Wert-Ventilator 1 und Ventilator 2
236
  if (stell_auto_alt != stell_auto && man_auto == 1 && standbye == 0)     // Automatischer Betrieb
237
  {
238
     Wire.beginTransmission(0x62);                               // I²C Adresse
239
     Wire.write(0x02);                                           // Wähl Register-PWM0 aus 
240
     Wire.write(stell_auto);                                     // Gibt Pulsweite vor für VFentilator 1           
241
     Wire.endTransmission(); 
242
243
     Wire.beginTransmission(0x62);                               // I²C Adresse
244
     Wire.write(0x04);                                           // Wähl Register-PWM1 aus 
245
     Wire.write(stell_auto);                                     // Gibt Pulsweite vor für VFentilator 1           
246
     Wire.endTransmission();       
247
  }
248
  counter=0;
249
}
250
else   // unter 20% bleibt wert auf 0
251
{
252
253
  if (counter==0){
254
    PWMaus();
255
    counter++;
256
   } 
257
}
258
259
260
261
wdt_reset();                                    // reset Watchdog
262
263
stell_manuel_1_alt = stell_manuel_1;            // Merkt sich Stellwert
264
stell_manuel_2_alt = stell_manuel_2;            // Merkt sich Stellwert
265
stell_auto_alt     = stell_auto;                // Merkt sich Stellwert
266
}
267
268
float Temperatur(char Sensor)                     // Funktion für Temperatur
269
{
270
    static int B = 4275;                          // Werte aus Datenblatt für genaue Berechnung          
271
    static int R0 = 100000;                       // Werte aus Datenblatt für genaue Berechnung
272
    int a = analogRead(Sensor);                   // Ließt Wert vom Analogen-Eingang
273
    float R = 1023.0/a-1.0;                       // Werte aus Datenblatt für genaue Berechnung 
274
    R = R0*R;
275
    float temp = 1.0/(log(R/R0)/B+1/298.15)-273.15;  //Werte aus Datenblatt für genaue Berechnung 
276
    return temp;                                     // Gibt Temperatur zurück und springt ins Hautprogramm zurück         
277
}
278
279
void Refresh()  // ISR alle 3ms
280
{
281
if (auswahl==5)
282
    {
283
      digitalWrite( 8 ,HIGH);  // Schaltet Ziffer 1 aus 
284
      digitalWrite(11 ,HIGH);  // Schaltet Ziffer 2 aus
285
      digitalWrite(12 ,HIGH);  // Schalter Ziffer 3 aus
286
      digitalWrite( 7 ,HIGH);  // Schaltet Ziffer 4 aus
287
    }
288
if (auswahl!=5) sevseg.refreshDisplay();     // bewirkt das Zahlen angezigt werden-- nur bei auswahl != 5 
289
}                                           
290
291
float PIDRegler(float T1,float T2)    // PID-Regler
292
{
293
294
295
  // Empfindlichkeit des PID-Reglers
296
float Tn = 1.0;
297
float Tv = 1.0;
298
float Kp = 1.0;
299
  // Variablen für P,I,D
300
float P,I,D;
301
  // Zeitkostente 
302
float delta_t=0.5;
303
304
305
En = T1 - T2;       // T1 = Temperatur_1 = Sollwert hier
306
                    // delat = erlaubte Regelabweichung   
307
                    // T2 = Temperatur_2 = Istwert
308
                    // En = Regelabweichung
309
// Berechnugn P I D
310
P = En - en1;
311
D = (delta_t / Tn) * En;
312
I = Tv * (En - 2 * en1 + en2);
313
314
// Berechnung neuer Stellgröße
315
delta_y = Kp * ( P + D + I);
316
Yn = yn1 + delta_y;
317
318
// Speichert alte Werte
319
en2 = en1;
320
en1 = En;
321
yn1 = Yn;
322
323
// Begrenzt Yn auf 100
324
if (Yn > 100.0) Yn=99.99;
325
if (Yn <   0.0) Yn=  0.0;
326
327
328
return Yn;          // Gibt Stellgröße zurück und springt ins Hautprogramm zurück
329
}
330
331
void resetPID(){
332
   en2=0;
333
   en1=0;
334
   yn1=0;
335
   En=0;
336
   Yn=0;
337
   delta_y=0; 
338
}
339
void PWMaus()
340
{
341
   Wire.beginTransmission(0x62);   // I²C Adresse 
342
   Wire.write(0x05);               // Wähl Register-PWM aus   
343
   Wire.write(0x00);               //           
344
   Wire.endTransmission(); 
345
346
}
347
void PWMan()
348
{
349
   Wire.beginTransmission(0x62);   // I²C Adresse 
350
   Wire.write(0x05);               // Wähl Register-PWM aus   
351
   Wire.write(0x0E);               //            
352
   Wire.endTransmission();  
353
}
354
355
void PWMNULL(){
356
     Wire.beginTransmission(0x62);                               // I²C Adresse
357
     Wire.write(0x02);                                           // Wähl Register-PWM0 aus 
358
     Wire.write(0x00);                                     // Gibt Pulsweite vor für VFentilator 1           
359
     Wire.endTransmission(); 
360
361
     Wire.beginTransmission(0x62);                               // I²C Adresse
362
     Wire.write(0x04);                                           // Wähl Register-PWM1 aus 
363
     Wire.write(0x00);                                     // Gibt Pulsweite vor für VFentilator 1           
364
     Wire.endTransmission();       
365
366
367
}
368
369
370
/// END ///