LDRBlinker.c


1
/************************************************************
2
*
3
*  Einfacher Reaktivlicht-Blinker mit LDR
4
*  Stromverbrauch:
5
*    ca. 4,1µA @ 3V im Tag- und im Nachtmodus
6
*
7
************************************************************/
8
9
/*
10
ATtiny13
11
12
SELFPRGEN=0
13
DWEN=0
14
BODLEVEL=Brown-out detection disabled
15
RSTDISBL=0
16
SPIEN=1
17
EESAVE=0
18
WDTON=0
19
CHKDIV8=1
20
SUT_CKSEL=Int. RC Osc. 9.6 MHz; Start-up time: 14 CK + 64 ms
21
22
Low/High = 0x6A,0xFF
23
24
*/
25
26
/*
27
Vers. 1.01 vom 24.06.2009
28
- Urversion
29
30
Vers. 1.02 vom 15.07.2009
31
- Verbesserte Helligkeitswerte; Timing bei Tag- und Nachtbetrieb unterschiedlich
32
33
Vers. 1.03 vom 19.07.2009
34
- Testmodus, Logikanalysator-Ausgabe, Dauerblinken
35
36
Vers. 1.04 vom 25.02.2010
37
- Timing leicht geändert; Umschaltung zwischen Reaktivlicht-Typen nach LED-Farbe
38
39
Vers. 1.05 vom 26.05.2010
40
- Fehlerkorrektur in WDT_Prescaler_Change
41
- andere Helligkeitsbewertung (heller = höherer Wert)
42
- diverse Verbesserungen, Vereinfachungen und Bereinigungen
43
44
*/
45
46
47
#define F_CPU 600000UL // Taktfrequenz 600 kHz
48
49
#include <avr/io.h>
50
#include <avr/interrupt.h>
51
#include <avr/sleep.h>
52
#include <avr/eeprom.h>
53
#include <avr/wdt.h>
54
//#include <avr/pgmspace.h>
55
#include <util/delay.h>
56
//#include <stdint.h>
57
//#include <string.h>
58
59
// Systemkonstanten
60
61
// System Clock Prescaler [CLKPR]
62
63
#define CLKDIV1         0
64
#define CLKDIV2         1
65
#define CLKDIV4         2
66
#define CLKDIV8         3
67
#define CLKDIV16        4
68
#define CLKDIV32        5
69
#define CLKDIV64        6
70
#define CLKDIV128       7
71
#define CLKDIV256       8
72
73
// ADC-Referenz [REFS0]
74
75
#define RefVcc          0x0  // Vcc als Referenz
76
#define Ref11           0x1  // interne Referenz 1,1V
77
78
// ADC-Messmodus [MUX0]
79
80
#define ADC_PB5         0
81
#define ADC_PB2         1
82
#define ADC_PB4         2
83
#define ADC_PB3         3
84
85
// ADC-Clock-Vorteiler (für ADC-Clock zw. 50kHz und 200kHz) [ADPS0]
86
87
#define ADC_Clk2        1
88
#define ADC_Clk4        2
89
#define ADC_Clk8        3
90
#define ADC_Clk16       4
91
#define ADC_Clk32       5
92
#define ADC_Clk64       6
93
#define ADC_Clk128      7
94
95
// ADC Autotrigger Source [ADTS0]
96
97
#define ADC_FreeRunning 0   // freilaufend
98
#define ADC_AnalogComp  1   // Analog Comparator
99
#define ADC_ExtIRQ0     2   // External Interrupt Request 0
100
#define ADC_CompareA    3   // Timer/Counter Compare Match A
101
#define ADC_TimerOvr    4   // Timer/Counter Overflow
102
#define ADC_CompareB    5   // Timer/Counter Compare Match B
103
#define ADC_PinChange   6   // Pin Change Interrupt Request
104
105
// Timer Clock Divider [CS00]
106
107
#define Tim0CLKoff      0
108
#define Tim0CLK1        1
109
#define Tim0CLK8        2
110
#define Tim0CLK64       3
111
#define Tim0CLK256      4
112
#define Tim0CLK1024     5
113
#define Tim0CLKExtHL    6
114
#define Tim0CLKExtLH    7
115
116
// Timer Clock Divider [CS10]
117
118
#define Tim1CLKoff      0
119
#define Tim1CLK1        1
120
#define Tim1CLK2        2
121
#define Tim1CLK4        3
122
#define Tim1CLK8        4
123
#define Tim1CLK16       5
124
#define Tim1CLK32       6
125
#define Tim1CLK64       7
126
#define Tim1CLK128      8
127
#define Tim1CLK256      9
128
#define Tim1CLK512      10
129
#define Tim1CLK1024     11
130
#define Tim1CLK2048     12
131
#define Tim1CLK4096     13
132
#define Tim1CLK8192     14
133
#define Tim1CLK16384    15
134
135
136
#define WPD_16ms        0b00000000  // 16 ms
137
#define WPD_32ms        0b00000001  // 32 ms
138
#define WPD_64ms        0b00000010  // 64 ms
139
#define WPD_125ms       0b00000011  // 0.125 s
140
#define WPD_250ms       0b00000100  // 0.25 s
141
#define WPD_500ms       0b00000101  // 0.5 s
142
#define WPD_1s          0b00000110  // 1.0 s
143
#define WPD_2s          0b00000111  // 2.0 s
144
#define WPD_4s          0b00100000  // 4.0 s
145
#define WPD_8s          0b00100001  // 8.0 s
146
147
// Definitionen
148
149
#define LED_TEST  0
150
#define LED_ROT   1
151
#define LED_GRUEN 2
152
#define LED_WEISS 3
153
154
// Hier LED-Typ (nach Farbe) wählen !!!
155
156
//#define LEDTYP  LED_TEST
157
#define LEDTYP  LED_ROT
158
//#define LEDTYP  LED_GRUEN
159
160
//#define DataOut       // serielle Datenausgabe zum Logikanalysator
161
//#define Dauerblinken  // ständiges Blinken
162
163
#define Blinkwartezeit  300   // Wartezeit (ms) bevor das Blinken beginnt
164
#define Blinkdauer      60    // Dauer (ms) eines Blinkimpulses
165
#define Blinkpause      (500-Blinkdauer)   // Pause (ms) zwischen zwei Blinkimpulsen
166
167
#if LEDTYP == LED_TEST
168
#define Blinkzahl       1     // Anzahl der Blinkimpulse
169
#elif LEDTYP == LED_ROT
170
#define Blinkzahl       5     // Anzahl der Blinkimpulse
171
#elif LEDTYP == LED_GRUEN
172
#define Blinkzahl       6     // Anzahl der Blinkimpulse
173
#endif
174
175
// Grenze zwischen Tag- und Nachtumschaltung:
176
// 1 Lux (R = 1,4 MOhm), ergibt einen ADC-Wert von ca. 154
177
178
#define HellDiff      10  // Auslöseschwelle
179
#define TagSchwelle   154  // Grenze für Umschaltung zwischen Tag und Nacht
180
181
#define NachtRate     WPD_250ms  // Messrate im Nachtmodus
182
#define NachtRateZt   250  // in ms
183
184
#define TagLimit      (5UL * 60000UL / NachtRateZt)  // 5 Minuten hell = Tag
185
#define NachtLimit    8  // 1 Minute dunkel = Nacht (8 * 8s)
186
187
// Portleitungen
188
189
#define LED           PB3
190
#define LDR           PB4  // ADC2
191
#define LDRSpg        PB0
192
#define Licht         PB1
193
194
#define CLKHI         PORTB |= (1<<0)
195
#define CLKLO         PORTB &= ~(1<<0)
196
#define DATAHI        PORTB |= (1<<1)
197
#define DATALO        PORTB &= ~(1<<1)
198
#define SYNC_ON       PORTB |= (1<<2)
199
#define SYNC_OFF      PORTB &= ~(1<<2)
200
201
#define LED_ON        PORTB |= (1<<LED)
202
#define LED_OFF       PORTB &= ~(1<<LED)
203
204
#define LDR_ON        PORTB |= (1<<LDRSpg)
205
#define LDR_OFF       PORTB &= ~(1<<LDRSpg)
206
207
#define LichtON       PORTB |= (1<<Licht)
208
#define LichtOFF      PORTB &= ~(1<<Licht)
209
210
// globale Variablen
211
212
unsigned int Helligkeit;
213
unsigned int Hintergrund;
214
unsigned char Tagmodus;
215
216
/******************************************
217
*                                         *
218
*  Auslösung erkannt, Aktion durchführen  *
219
*                                         *
220
******************************************/
221
222
void ExecuteAction (const unsigned char Anzahl)
223
{
224
  unsigned char i;
225
226
  _delay_ms(Blinkwartezeit);
227
228
  for (i=0; i<Anzahl; i++)
229
  {
230
    LED_ON;
231
    _delay_ms(Blinkdauer);
232
    LED_OFF;
233
    _delay_ms(Blinkpause);
234
  }
235
}
236
237
/******************************
238
*                             *
239
*  Ein Word seriell ausgeben  *
240
*  (für Logikanalysator)      *
241
*                             *
242
******************************/
243
244
void SerOut (unsigned int Wert)
245
{
246
  unsigned char i;
247
248
  for (i=0; i<16; i++)
249
  {
250
    if (Wert & 0x8000)
251
      DATAHI;
252
    else
253
      DATALO;
254
255
    CLKHI;
256
    Wert = Wert << 1;
257
    CLKLO;
258
  }
259
}
260
261
/*****************************
262
*                            *
263
*  Testwerte seriell an      *
264
*  Logikanalysator ausgeben  *
265
*                            *
266
*****************************/
267
268
void WertOut (void)
269
{
270
  CLKLO;
271
  SerOut(Helligkeit);
272
  SerOut(Hintergrund);
273
  SerOut(Tagmodus);
274
  DATALO;
275
}
276
277
/*************************
278
*                        *
279
*  Watchdog-Zeit ändern  *
280
*                        *
281
*************************/
282
283
void WDT_Prescaler_Change (unsigned char Value)
284
{
285
  cli();
286
  wdt_reset();
287
  WDTCR |= (1<<WDCE) | (1<<WDE);  // Start timed sequence
288
  WDTCR = (0<<WDE) | (1<<WDTIE) | (Value<<WDP0);  // Set new prescaler(time-out) value
289
  sei();
290
}
291
292
/******************
293
*                 *
294
*  Hauptprogramm  *
295
*                 *
296
******************/
297
298
int main(void)
299
{
300
  unsigned int TagCtr;
301
  unsigned int AuslGrw;
302
  #if LEDTYP == LED_TEST
303
  unsigned char Ausloes;
304
  #endif
305
306
  // Clock einstellen
307
308
  CLKPR = 0x80;  // CLKPCE setzen, um Zugriff auf Clock Prescaler zu erreichen
309
  CLKPR = CLKDIV16;  // Clock Prescaler auf /16 stellen (9,6 MHz -> 600 kHz)
310
311
  // Watchdog einstellen
312
313
  WDTCR = (1<<WDCE) | (1<<WDE);  // auf Einstellung vorbereiten
314
  WDTCR = (0<<WDCE) | (0<<WDE) | (1<<WDTIE) | (WPD_8s << WDP0);  // Interrupt mode, Zeit = 8s
315
  WDTCR |= (1<<WDTIF);  // Interruptflag löschen
316
317
  // Ports einstellen
318
319
  PORTB = 0b100000;
320
  DDRB  = 0b001111;
321
  //        |||||+- 0[5]:MOSI/AIN0/OC0A/PCINT0/TXD       LDR-Versorgung (DataOut-Clock)
322
  //        ||||+-- 1[6]:MISO/AIN1/OC0B/INT0/PCINT1/RXD  Licht-Anzeige (DataOut-Data)
323
  //        |||+--- 2[7]:SCK/ADC1/T0/PCINT2              (DataOut-Sync)
324
  //        ||+---- 3[2]:ADC3/CLKI/PCINT3                LED (über 100 Ohm gegen GND)
325
  //        |+----- 4[3]:ADC2/PCINT4                     LDR (gegen GND, 2,2 MOhm an Vcc)
326
  //        +------ 5[1]:RESET/dW/ADC0/PCINT5
327
328
  DIDR0 = (1<<ADC2D);
329
330
  // Timer 0 einstellen
331
332
  // ADC einstellen
333
334
  ADMUX = (RefVcc<<REFS0) | (1<<ADLAR) | (ADC_PB4<<MUX0);  // Referenz = Vcc
335
336
  // Variablen einstellen
337
338
  TagCtr = 0;
339
  Helligkeit = 255;
340
  Hintergrund = 255;
341
  #if LEDTYP == LED_TEST
342
  Ausloes = 0;
343
  #endif
344
  Tagmodus = 1;  // im Tagmodus starten
345
346
  // Hauptprogramm starten  
347
348
  sei();  // Interrupts ermöglichen
349
350
  ExecuteAction(Blinkzahl);  // beim Start zum Test
351
352
  while(1)
353
  {
354
  #ifdef Dauerblinken
355
    ExecuteAction(Blinkzahl);  //  dauernd Aktion durchführen
356
  #else
357
    // ADC abfragen (Tags alle 8s, Nachts alle <NachtRateZt> ms)
358
359
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
360
    sleep_mode();  // durch Watchdog-Timer aufwecken lassen
361
362
    LDR_ON;
363
364
    #ifdef DataOut
365
    SYNC_ON;  // Synchronsignal
366
    #endif
367
368
    ADCSRA = (1<<ADEN) | (1<<ADIE) | (ADC_Clk2<<ADPS0);  // ADC einschalten, ADC-Interrupt
369
    ADCSRA |= (1<<ADSC);  // ADC starten
370
371
    set_sleep_mode(SLEEP_MODE_ADC);
372
    sleep_mode();  // durch ADC aufwecken lassen
373
374
    LDR_OFF;
375
376
    Helligkeit = 255 - ADCH;  // 0 = dunkel, 255 = hell
377
    ADCSRA = 0;  // ADC ausschalten
378
379
    // gemessenen Helligkeitswert auswerten
380
381
    if (Tagmodus)  // aktuell im Tagmodus
382
    { 
383
      if (Helligkeit < TagSchwelle)  // prüfen ob es Nacht ist
384
      {
385
        #ifndef DataOut
386
        LichtOFF;
387
        #endif
388
389
        TagCtr++;
390
391
        if (TagCtr >= NachtLimit)
392
        {
393
          Tagmodus = 0;  // auf Nacht umschalten
394
          TagCtr = 0;
395
396
          WDT_Prescaler_Change(NachtRate);
397
        }
398
      }
399
      else
400
      {
401
        #ifndef DataOut
402
        LichtON;
403
        #endif
404
405
        TagCtr = 0;
406
      }
407
    }
408
    else  // aktuell im Nachtmodus
409
    {  
410
      AuslGrw = Hintergrund + HellDiff;  // zu erreichende Schwelle
411
412
      if (Helligkeit > AuslGrw)  // Auslösung durch Helligkeitssprung?
413
      {
414
        #if LEDTYP == LED_TEST
415
        ExecuteAction(++Ausloes);  //  ja, Aktion durchführen
416
        #else
417
        ExecuteAction(Blinkzahl);  //  ja, Aktion durchführen
418
        #endif
419
        Helligkeit = 255;
420
      }
421
      else
422
      {
423
        if (Helligkeit > TagSchwelle)  // prüfen ob es Tag ist
424
        {
425
          #ifndef DataOut
426
          LichtON;
427
          #endif
428
429
          TagCtr++;
430
431
          if (TagCtr >= TagLimit)
432
          {
433
            Tagmodus = 1;  // auf Tag umschalten
434
            TagCtr = 0;
435
436
            WDT_Prescaler_Change(WPD_8s);
437
          }
438
        }
439
        else
440
        {
441
          #ifndef DataOut
442
          LichtOFF;
443
          #endif
444
    
445
          TagCtr = 0;
446
        }
447
      }
448
    }
449
450
    #ifdef DataOut
451
    SYNC_OFF;
452
    WertOut();
453
    #endif
454
  
455
    Hintergrund = Helligkeit;  // letzten Helligkeitswert als Hintergrundhelligkeit
456
  #endif
457
  }
458
}
459
460
/*****************************
461
*                            *
462
*  Watchdog Timer Interrupt  *
463
*  (nur zum Aufwecken)       *
464
*                            *
465
*****************************/
466
467
EMPTY_INTERRUPT(WDT_vect);
468
469
/****************************
470
*                           *
471
*  ADC conversion complete  *
472
*  (nur zum Aufwecken)      *
473
*                           *
474
****************************/
475
476
EMPTY_INTERRUPT(ADC_vect);