Stromverbrauch ATtiny13A im Sleep-Modus

Gast #1234773
Lesenswert?

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
}
Angehängte Dateien:
Moderator Persönliche Seite #1234839
Lesenswert?

Das hier:
1
    // Alle 512000 Zyklen die Temperatur messen und prüfen ob der Schwellenwert unter- oder überschritten wurde
2
    if (pwm == 255)
3
    {
4
      temp_count++;
5
      if (temp_count == 2000)
6
      {
7
        on = (temp() > TEMP_THRESHOLD);
8
        temp_count = 0;
9
      }
10
    }
11
    ++pwm;

würde ich auch nicht gerade als stromsparende Programmierung
bezeichnen.  Dafür kann man auch einen Timer nehmen und die CPU
solange in den idle sleep schicken.
Gast #1234850
Lesenswert?

>würde ich auch nicht gerade als stromsparende Programmierung
>bezeichnen.  Dafür kann man auch einen Timer nehmen und die CPU
>solange in den idle sleep schicken.

Ich habe den Code etwas gekürzt. Eigentlich wird hier mit Soft-PWM 
gearbeitet, sodass die Hauptschleife wirklich immer laufen muss, wenn 
die Temperatur-Bedingung erfüllt ist.
Moderator Persönliche Seite #1235680
Lesenswert?

Martin wrote:

> hat keiner mehr eine Idee?

Hab ich doch oben schon geschrieben: Dreck auf der Platine,
insbesondere unter den Bauteilen.  Da ist schon so manches
Mikroampere drin versenkt worden.

Softwaretechnisch kannst du dich auch Stück für Stück
durcharbeiten: erstmal alle Pins auf Ausgang, die LED-Ausgänge
auf High, die Spannungsteiler-Ausgänge auf Low setzen, den
Chip (ohne Watchdog vorerst) in den Sleep schicken.  Der Strom,
den du dabei misst, wird später nicht mehr zu unterbieten sein.
Gast #1236567
Lesenswert?

Die LEDs sollen keinen Vorwiderstand haben, das ist schon in Ordnung so. 
Den Stromverbrauch habe ich mit einem Messverstärker gemessen und dabei 
die gesamte Schaltung berücksichtigt. Im Moment ist die Schaltung noch 
fliegend mit Fädeldraht aufgebaut. Ich möchte gerne 5-10µA erreichen. 
Ist das realistisch?
Gast #1236607
Lesenswert?

Mir fehlen im Listing 2 Register, die Strom sparen:

13.2.2 ACSR– Analog Comparator Control and Status Register
hier
      Bit 7 – ACD: Analog Comparator Disable

und

7.5.3 PRR – Power Reduction Register


Evtl. wird es dann schon etwas besser.

gruß hans
Gast #1236645
Lesenswert?

>Wie und womit gemessen?
siehe obiges Posting
>Den Stromverbrauch habe ich mit einem Messverstärker gemessen

Den Watchdog kann ich natürlich nicht ausschalten... wie soll der µC 
denn sonst aufwachen, wenn es kalt wird?
Gast #1236735
Lesenswert?

Der Messverstärker ist auf den Bereich 100µA eingestellt und ist eine 
Stunde lang gelaufen bevor die Messung gestartet wurde. Es wurden 
geschirmte Kabel für die Messung verwendet. Das Ausgangssignal liegt 
dann zwischen 0V (0µA) und 10V (10µA). Den Wert habe ich mit einem 
Oszilloskop abgelesen, da ich den zeitlichen Verlauf sehen wollte 
(Sleep-Phase/Wach-Phase).

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren