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 ///
|