Hi,
ich betreibe einen ATtiny13 als Temperatursensor. Dieser soll in diesem
Beispiel einfach nur die drei angeschlossenen LEDs anschalten, wenn die
Temperatur unter einen festgelegten Wert sinkt.
Um die Temperatur zu messen kommt ein NTC zusammen mit einem normalen
Widerstand als Spannungsteiler zum Einsatz. Dieser Spannungsteiler wird
nur während der Temperaturmessung mit Strom versorgt.
Folgendes soll passieren: Der ATtiny13 soll alle 8 Sekunden per Watchdog
aufgeweckt werden und die Temperatur messen. Ist diese zu hoch, soll er
sofort wieder in den Sleep-Modus gehen. Ist die Temperatur ausreichend
niedrig, so soll er die LEDs anschalten und ab und zu überprüfen, ob die
Temperatur immernoch ausreichend niedrig ist. Falls ja, soll er das
Reset des Watchdog verhindern.
Der Code funktioniert soweit sehr gut. Es kommt mir allerdings darauf
an, dass die Schaltung mit einer Knopfzelle so lange wie möglich
durchhält. Die LED wird nur sehr selten angehen und daher kommt es vor
allem auf den Stromverbrauch im Standby an. Das Standby setzt sich aus
zwei Phasen zusammen. Der Eigenentlichen Sleep-Phase (8 Sekunden) und
dem kurzen Aufwachen zum Messen der Temperatur (wenige µs).
Ich habe diesen Stromverbrauch nun gemessen und sehe, dass der ATtiny13A
im Sleep-Modus 50µA benötigt, was mir deutlich zu viel vorkommt (laut
Datenblatt im nA-Bereich!).
Wo liegt der Fehler?
1 | #define LED_RED PB3
|
2 | #define LED_GRN PB4
|
3 | #define LED_BLU PB1
|
4 | #define PIN_TEMP_VCC PB0
|
5 | #define PIN_TEMP_MEA PB2
|
6 |
|
7 | #define RED_OFF PORTB |= (1 << PB3);
|
8 | #define GRN_OFF PORTB |= (1 << PB4);
|
9 | #define BLU_OFF PORTB |= (1 << PB1);
|
10 | #define RED_ON PORTB &=~(1 << PB3);
|
11 | #define GRN_ON PORTB &=~(1 << PB4);
|
12 | #define BLU_ON PORTB &=~(1 << PB1);
|
13 |
|
14 | #define TEMP_VCC_ON PORTB |= (1 << PB0);
|
15 | #define TEMP_VCC_OFF PORTB &=~(1 << PB0);
|
16 |
|
17 | #define TEMP_THRESHOLD 600
|
18 |
|
19 | #include <avr/io.h>
|
20 | #include <util/delay.h>
|
21 |
|
22 | #include <avr/sleep.h>
|
23 | #include <avr/wdt.h>
|
24 |
|
25 | // Watchdog initialisieren
|
26 | void initSleep()
|
27 | {
|
28 | wdt_enable(WDTO_8S); // Watchdog einstellen
|
29 | set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Stromsparmodus einstellen
|
30 | }
|
31 |
|
32 | // Reset verhindern
|
33 | void stayAwake()
|
34 | {
|
35 | wdt_reset();
|
36 | }
|
37 |
|
38 | // In den Stromsparmodus wechseln
|
39 | void fallAsleep()
|
40 | {
|
41 | sleep_mode();
|
42 | }
|
43 |
|
44 | // Temperatur messen (ADC)
|
45 | int temp()
|
46 | {
|
47 | TEMP_VCC_ON; // NTC-Spannungsteiler mit Strom versorgen
|
48 |
|
49 | int result;
|
50 | ADMUX = 1;
|
51 |
|
52 | ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);
|
53 | ADCSRA |= (1<<ADSC);
|
54 | while ( ADCSRA & (1<<ADSC) ) {}
|
55 | result = ADCW;
|
56 | result = 0;
|
57 | ADCSRA |= (1<<ADSC);
|
58 | while ( ADCSRA & (1<<ADSC) ) {}
|
59 | result = ADCW;
|
60 | ADCSRA &= ~(1<<ADEN);
|
61 |
|
62 | TEMP_VCC_OFF; // Spannungsteiler stromlos machen
|
63 |
|
64 | return result;
|
65 | }
|
66 |
|
67 | int main()
|
68 | {
|
69 | // Ausgänge
|
70 | DDRB = (1 << LED_RED)
|
71 | | (1 << LED_GRN)
|
72 | | (1 << LED_BLU)
|
73 | | (1 << PIN_TEMP_VCC);
|
74 |
|
75 |
|
76 | // LEDs abschalten
|
77 | BLU_OFF;
|
78 | GRN_OFF;
|
79 | RED_OFF;
|
80 |
|
81 | // Temperaturmesser
|
82 | DDRB &= ~(1 << PIN_TEMP_MEA);
|
83 |
|
84 | // Watchdog und Sleep-Modus initialisieren
|
85 | initSleep();
|
86 |
|
87 | // LEDs anschalten?
|
88 | char on = 1;
|
89 |
|
90 | // Temperaturmess-Verzögerung
|
91 | int temp_count = 0;
|
92 |
|
93 | // PWM-Variable
|
94 | char pwm = 0;
|
95 |
|
96 | // Wenn es zu warm ist -> Sleep
|
97 | if (temp() <= TEMP_THRESHOLD)
|
98 | {
|
99 | fallAsleep();
|
100 | }
|
101 |
|
102 | // Hauptschleife
|
103 | while(1)
|
104 | {
|
105 | // Alle 512000 Zyklen die Temperatur messen und prüfen ob der Schwellenwert unter- oder überschritten wurde
|
106 | if (pwm == 255)
|
107 | {
|
108 | temp_count++;
|
109 | if (temp_count == 2000)
|
110 | {
|
111 | on = (temp() > TEMP_THRESHOLD);
|
112 | temp_count = 0;
|
113 | }
|
114 | }
|
115 | ++pwm;
|
116 |
|
117 | if (on)
|
118 | {
|
119 | stayAwake(); // Reset-Counter zurücksetzen
|
120 | RED_ON;
|
121 | GRN_ON;
|
122 | BLU_ON;
|
123 | /* An dieser Stelle sind eigentlich Animationen mit den LEDs gewesen die aus Gründen der besseren Übersicht gestrichen wurden und ein reines Anschalten anstelle eingefügt. */
|
124 | }
|
125 | else
|
126 | {
|
127 | RED_OFF;
|
128 | GRN_OFF;
|
129 | BLU_OFF; // LEDs ausschalten
|
130 | fallAsleep(); // Einschlafen
|
131 | }
|
132 | }
|
133 | }
|