1 | #include <avr/sleep.h>
|
2 | #include <avr/interrupt.h>
|
3 | #include <avr/wdt.h>
|
4 | #include <PinChangeInterrupt.h>
|
5 |
|
6 |
|
7 | // ATMEL ATTINY 25/45/85 / ARDUINO
|
8 | //
|
9 | // +-\/-+
|
10 | // Ain0 (D 5) PB5 1| |8 Vcc
|
11 | // Ain3 (D 3) PB3 2| |7 PB2 (D 2) Ain1
|
12 | // Ain2 (D 4) PB4 3| |6 PB1 (D 1) pwm1
|
13 | // GND 4| |5 PB0 (D 0) pwm0
|
14 | // +----+
|
15 | #define sleepInput A1
|
16 | #define Transistor 1
|
17 | #define LED 4
|
18 | #define Taster 3
|
19 | #define TSignal 0
|
20 | //uint16_t nbr_remaining;
|
21 | byte adcsra_save;
|
22 | volatile uint16_t siVal = 0, resetCNT = 0, nbr_remaining = 0;
|
23 | volatile bool intrInp = false, intrBTN = false;
|
24 | uint16_t timeout = 22 * 1000; //sekunden
|
25 | unsigned long millisalt = 0;
|
26 | uint16_t TagTime = 5 * 60 / 8;
|
27 | uint16_t NachtTime = 30 * 60 / 8;
|
28 | uint16_t SecondScreenTime = 0.4 * 60 / 8;
|
29 |
|
30 |
|
31 | void setup() {
|
32 | wdt_disable();
|
33 |
|
34 | analogReference(DEFAULT);
|
35 | pinMode(sleepInput, INPUT);
|
36 | pinMode(Taster, INPUT_PULLUP);
|
37 | pinMode(TSignal, OUTPUT);
|
38 | pinMode(LED, OUTPUT);
|
39 | pinMode(Transistor, OUTPUT);
|
40 |
|
41 | digitalWrite(LED, LOW);
|
42 | digitalWrite(TSignal, LOW);
|
43 | digitalWrite(Transistor, HIGH);
|
44 |
|
45 |
|
46 | attachPinChangeInterrupt(Taster, TasterHandler, FALLING);
|
47 |
|
48 | delay(1000);
|
49 | digitalWrite(LED, HIGH);
|
50 | delay(2000);
|
51 | digitalWrite(LED, LOW);
|
52 |
|
53 |
|
54 | sleep(1);
|
55 | }
|
56 |
|
57 | void loop() {
|
58 |
|
59 | digitalWrite(LED, HIGH);
|
60 | delay(15);
|
61 | digitalWrite(LED, LOW);
|
62 | delay(15);
|
63 |
|
64 | }
|
65 |
|
66 | ISR(WDT_vect)
|
67 | {
|
68 |
|
69 |
|
70 | //wdtDisable(); // Nur zur Testzwecken
|
71 |
|
72 |
|
73 |
|
74 | }
|
75 |
|
76 |
|
77 | void TasterHandler() {
|
78 |
|
79 |
|
80 | intrBTN = true;
|
81 |
|
82 |
|
83 | }
|
84 |
|
85 |
|
86 | void TasterWake() {
|
87 | // wdt_disable();
|
88 | uint16_t sleepTime = 0, siValMax = 0;
|
89 | millisalt = millis();
|
90 | bool Stop = false;
|
91 | disablePCINT(digitalPinToPCINT(Taster));
|
92 | digitalWrite(TSignal, LOW); // Taster Signal. Wird High gesetzt nach 300ms damit der ESP weiß, dass er den 2. Bildschrim zeigen soll.
|
93 | digitalWrite(Transistor, LOW);
|
94 | digitalWrite(LED, HIGH);
|
95 | delay(300);
|
96 | digitalWrite(TSignal, HIGH);
|
97 | //digitalWrite(LED, LOW);
|
98 |
|
99 |
|
100 | // Auf Antwort vom ESP Warten durch auslesen von "sleepInput". Dadurch weiß der Attiny das er sich nun ausschalten kann. Fällt SleepInput wieder herab hat er das maximum erreicht und beendet den loop. Falls dies nicht funktioniert wird via Millis ein Timeout von 22 Sek. berücksichtigt.
|
101 | do {
|
102 | siVal = analogRead(sleepInput);
|
103 | if (siVal > siValMax) {
|
104 | siValMax = siVal;
|
105 |
|
106 | delay(5);
|
107 | // wdt_reset();
|
108 | }
|
109 | else if ((siValMax > 100) && ((siVal + 50) < siValMax)) {
|
110 | Stop = true;
|
111 | break;
|
112 |
|
113 | }
|
114 | else if (millis() - millisalt >= timeout ) {
|
115 |
|
116 | digitalWrite(LED, HIGH);
|
117 | delay(5000);
|
118 | digitalWrite(LED, LOW);
|
119 | // wdt_reset();
|
120 | sleepTime = TagTime;
|
121 | //intrInp = false;
|
122 | Stop = true;
|
123 | break;
|
124 | }
|
125 |
|
126 |
|
127 | } while (Stop == false);
|
128 |
|
129 |
|
130 | // Auswerten der Ergebnisse:
|
131 | if (siVal > 400) {
|
132 | for (byte i = 0; i < 2; i++) {
|
133 | digitalWrite(LED, HIGH); //FEHLER
|
134 | delay(100);
|
135 | digitalWrite(LED, LOW); //FEHLER
|
136 | delay(200);
|
137 | // wdt_reset();
|
138 | }
|
139 |
|
140 | sleepTime = SecondScreenTime;
|
141 |
|
142 |
|
143 | } else if ((siValMax < 400) && (siValMax > 280)) {
|
144 |
|
145 |
|
146 | for (byte i = 0; i < 30; i++) {
|
147 | digitalWrite(LED, HIGH);
|
148 | delay(5000);
|
149 | // wdt_reset();
|
150 | digitalWrite(LED, LOW);
|
151 | delay(1000);
|
152 | // wdt_reset();
|
153 | }
|
154 | digitalWrite(LED, LOW);
|
155 | sleepTime = 0;
|
156 |
|
157 | } else if (millis() - millisalt >= timeout ) {
|
158 | sleepTime = SecondScreenTime;
|
159 |
|
160 | // wdt_reset();
|
161 | digitalWrite(LED, LOW);
|
162 | delay(500);
|
163 | digitalWrite(LED, HIGH);
|
164 | delay(6000);
|
165 | digitalWrite(LED, LOW);
|
166 | // wdt_reset();
|
167 |
|
168 |
|
169 | }
|
170 |
|
171 |
|
172 | delay(250);
|
173 | enablePCINT(digitalPinToPCINT(Taster));
|
174 | digitalWrite(TSignal, LOW);
|
175 | digitalWrite(Transistor, HIGH);
|
176 | digitalWrite(LED, LOW);
|
177 | // wdt_reset();
|
178 | intrBTN = false;
|
179 | intrInp = false;
|
180 | sleep(sleepTime);
|
181 | }
|
182 |
|
183 |
|
184 | // Funktion die aufgerufen werden soll, wenn der Attiny durch alle Sleepcycles durch ist. Funktioniert nach dem gleichen Prinzip wie die Tasterfunktion weiter oben.
|
185 |
|
186 | void WDTwake(void) {
|
187 | // wdt_disable();
|
188 | // wdt_reset();
|
189 | millisalt = millis();
|
190 | bool Stop = false;
|
191 | uint16_t sleepTime = 0, siValMax = 0;
|
192 |
|
193 | //detachPCINT(digitalPinToPCINT(Taster));
|
194 | disablePCINT(digitalPinToPCINT(Taster));
|
195 | digitalWrite(Transistor, LOW);
|
196 |
|
197 | delay(50);
|
198 |
|
199 | do {
|
200 |
|
201 |
|
202 | siVal = analogRead(sleepInput);
|
203 | if (siVal > siValMax) {
|
204 | siValMax = siVal;
|
205 |
|
206 | delay(5);
|
207 | // wdt_reset();
|
208 | }
|
209 | else if ((siValMax > 100) && ((siVal + 50) < siValMax)) {
|
210 | Stop = true;
|
211 | break;
|
212 |
|
213 | }
|
214 | else if (millis() - millisalt >= timeout ) {
|
215 | digitalWrite(LED, HIGH);
|
216 | delay(5000);
|
217 | // wdt_reset();
|
218 | digitalWrite(LED, LOW);
|
219 | sleepTime = TagTime;
|
220 | //intrInp = false;
|
221 | Stop = true;
|
222 | break;
|
223 | }
|
224 |
|
225 |
|
226 | } while (Stop == false);
|
227 |
|
228 |
|
229 |
|
230 |
|
231 | if ((siValMax < 850) && (siValMax > 400)) {
|
232 | for (byte i = 0; i < 2; i++) {
|
233 |
|
234 | digitalWrite(LED, HIGH); //FEHLER
|
235 | delay(1000);
|
236 | digitalWrite(LED, LOW); //FEHLER
|
237 | delay(200);
|
238 | // wdt_reset();
|
239 | }
|
240 | sleepTime = TagTime; //FIXME
|
241 | //intrInp = false;
|
242 | // break;
|
243 | }
|
244 | else if (siValMax > 900) {
|
245 |
|
246 | for (byte i = 0; i < 4; i++) {
|
247 |
|
248 | digitalWrite(LED, HIGH); //FEHLER
|
249 | delay(1000);
|
250 | digitalWrite(LED, LOW); //FEHLER
|
251 | delay(200);
|
252 | // wdt_reset();
|
253 | }
|
254 |
|
255 | // wdt_reset();
|
256 | sleepTime = NachtTime; //FIXME
|
257 | //intrInp = false;
|
258 | // break;
|
259 | }
|
260 | else if ((siValMax < 400) && (siValMax > 280)) {
|
261 | for (byte i = 0; i < 30; i++) {
|
262 | digitalWrite(LED, HIGH);
|
263 | delay(5000);
|
264 | // wdt_reset();
|
265 | digitalWrite(LED, LOW);
|
266 | delay(1000);
|
267 | // wdt_reset();
|
268 | }
|
269 | sleepTime = 0;
|
270 |
|
271 | }
|
272 | else if (millis() - millisalt >= timeout ) {
|
273 | // wdt_reset();
|
274 | delay(500);
|
275 | digitalWrite(LED, HIGH);
|
276 | delay(5000);
|
277 | digitalWrite(LED, LOW);
|
278 | sleepTime = TagTime;
|
279 | // wdt_reset();
|
280 |
|
281 | }
|
282 |
|
283 |
|
284 | delay(250);
|
285 | //attachPCINT(digitalPinToPCINT(Taster), TasterHandler, CHANGE);
|
286 | enablePCINT(digitalPinToPCINT(Taster));
|
287 | digitalWrite(Transistor, HIGH);
|
288 | digitalWrite(LED, LOW);
|
289 | // wdt_reset();
|
290 | intrBTN = false;
|
291 | intrInp = false;
|
292 | sleep(sleepTime);
|
293 | }
|
294 |
|
295 |
|
296 |
|
297 |
|
298 |
|
299 |
|
300 |
|
301 | // Aktuell nicht mehr im Einsatz. Gedacht als Absicherung, falls er mal wieder hängt. Funktionierte nicht. KA warum.
|
302 | void ResetMCU(void)
|
303 | {
|
304 | for (byte i = 0; i < 10; i++) {
|
305 | digitalWrite(LED, HIGH);
|
306 | delay(50);
|
307 | digitalWrite(LED, LOW);
|
308 | delay(150);
|
309 | }
|
310 | /*
|
311 | cli();
|
312 | wdt_reset(); // reset watchdog timer
|
313 | MCUSR &= ~(1 << WDRF); // clear reset flag
|
314 | WDTCR = (1 << WDE) | (1 << WDCE); // enable watchdog
|
315 | WDTCR = (0 << WDIE) | (1 << WDE) | (1 << WDP1) ; // watchdog interrupt instead of reset
|
316 | //+reset, timeout can be 15,30,60,120,250,500ms or 1,2,4,8s
|
317 | sei();
|
318 | */
|
319 |
|
320 | }
|
321 |
|
322 | //Händisch programmierte WDT Disable Funktion, falls wdt_disable() evtl. nicht korrekt funktioniert. Allerdings macht es keinen Unterschied.
|
323 | void wdtDisable() {
|
324 |
|
325 | cli();
|
326 | wdt_reset(); // reset watchdog timer
|
327 | MCUSR &= ~(1 << WDRF); // clear reset flag
|
328 | WDTCR = (1 << WDE) | (1 << WDCE); // enable watchdog
|
329 | WDTCR = (0 << WDIE) | (0 << WDE) ;// watchdog interrupt instead of reset
|
330 |
|
331 | sei();
|
332 | delay(2);
|
333 |
|
334 | }
|
335 |
|
336 | // Erstellen des Watchdogs
|
337 | void config_wdt(void)
|
338 | {
|
339 | cli();
|
340 | wdt_reset();
|
341 | MCUSR &= ~(1 << WDRF);
|
342 | WDTCR = (1 << WDE) | (1 << WDCE);
|
343 | WDTCR = (1 << WDIE) | (0 << WDE) | (1 << WDP0) | (1 << WDP3);// | (1 << WDP1); // watchdog auf interrupt stellen
|
344 | //+reset, timeout can be 15,30,60,120,250,500ms or 1,2,4,8s
|
345 | sei();
|
346 |
|
347 |
|
348 |
|
349 | }
|
350 |
|
351 |
|
352 |
|
353 | // ATTINY Schlafen legen für (Anzahl Zyklen). Ist dies vorbei, müsste eigentlich ja der Code direkt nach dem befehl sleep_mode() aufgerufen werden?!
|
354 | void sleep(int ncycles) {
|
355 | config_wdt();
|
356 | //adcsra_save = ADCSRA;
|
357 | if (ncycles <= 0) {
|
358 | nbr_remaining = 1;
|
359 | } else {
|
360 | nbr_remaining = ncycles;
|
361 | }
|
362 |
|
363 |
|
364 | cli();
|
365 | set_sleep_mode(SLEEP_MODE_PWR_DOWN);
|
366 | sleep_enable ();
|
367 | //ADCSRA = 0; //vermutlich nicht nötig wegen powerall disable
|
368 | sleep_bod_disable();
|
369 | //power_all_disable ();
|
370 | //noInterrupts ();
|
371 | ADCSRA &= ~_BV(ADEN);
|
372 | sei();
|
373 |
|
374 |
|
375 |
|
376 | do { // while some cycles left, sleep!
|
377 |
|
378 |
|
379 | //config_wdt();
|
380 |
|
381 | wdt_reset();
|
382 |
|
383 | sleep_mode();
|
384 |
|
385 |
|
386 |
|
387 | //wdt_disable();
|
388 | if (intrBTN == true) {
|
389 |
|
390 | break;
|
391 | }
|
392 | nbr_remaining = nbr_remaining - 1;
|
393 | } while (nbr_remaining > 0) ;
|
394 |
|
395 |
|
396 |
|
397 | cli();
|
398 | wdtDisable();
|
399 | ADCSRA |= _BV(ADEN);
|
400 | //ADCSRA = adcsra_save; //läuft eigentlich
|
401 | sei();
|
402 |
|
403 |
|
404 | if ((intrBTN == true)) {
|
405 |
|
406 | for (byte i = 0; i < 4; i++) {
|
407 | digitalWrite(LED, HIGH);
|
408 | delay(100);
|
409 | digitalWrite(LED, LOW);
|
410 | delay(100);
|
411 | }
|
412 |
|
413 | TasterWake();
|
414 |
|
415 | }
|
416 | else if ((nbr_remaining <= 0) && (intrBTN == false) ) {
|
417 |
|
418 | for (byte i = 0; i < 20; i++) {
|
419 | digitalWrite(LED, HIGH);
|
420 | delay(100);
|
421 | digitalWrite(LED, LOW);
|
422 | delay(100);
|
423 | }
|
424 |
|
425 |
|
426 | WDTwake();
|
427 |
|
428 | }
|
429 |
|
430 | // Test "else" um zu schauen ob es zu Fehlern kommt.
|
431 | else {
|
432 | for (byte i = 0; i < 50; i++) {
|
433 | digitalWrite(LED, HIGH);
|
434 | delay(10);
|
435 | digitalWrite(LED, LOW);
|
436 | delay(20);
|
437 | }
|
438 | sleep(1);
|
439 |
|
440 | }
|
441 |
|
442 | // wdt_reset();
|
443 |
|
444 |
|
445 |
|
446 | }
|