Forum: Projekte & Code AVR Sleep Mode / Knight Rider


von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Anbei mal ein Beispiel, wie man sauber und unkompliziert den 
Power-Down-Mode implementiert, um einen MC ab und wieder einzuschalten.

Gerade Anfänger tun sich damit schwer, weil sie versuchen, die Funktion 
des Gerätes mit dem Sleepmode zu vermanschen. Und das ist nicht nur 
höllisch kompliziert, sondern geht auch oft schief.
Der Spruch "Divide et impera" (teile die Aufgaben auf und Du herrscht 
über das Programm) kann besser nicht bewiesen werden.

Mein Trick ist daher, sich erstmal um den Sleep-Mode überhaupt nicht zu 
kümmern, sondern sich nur auf die reine Funktion zu konzentrieren.

Anbei mal als Beispiel ein einfaches Lauflicht mit verschiedenen Modi 
über ne Tabelle gesteuert. Die Tabelle läßt sich einfach editieren und 
erweitern. Für die Experten habe ich als Aufgabe gelassen, die Tabelle 
in den Flash zu verlagern.
Mit kurzem Tastendruck wird zwischen den Modi umgeschaltet. Mit langem 
Tastendruck wird an und ausgeschaltet, der aktuelle Modus bleibt dabei 
unverändert.
Die Tastenroutine dürfte bekannt sein:
Beitrag "Universelle Tastenabfrage"

Die Ausschaltfunktion wird über die Flagvariable "stop" gesteuert. Ist 
sie wahr, werden die LEDs abgeschaltet und die Knight Rider Routine 
übersprungen. Die CPU läuft aber noch weiter.
Der Code steht in "Without Sleep.zip".


Nachdem also alle Funktionen komplett und getestet sind, gehts ans 
Schlafen programmieren.
Durch die Flagvariable ist das sehr einfach. Solange sie wahr ist, wird 
ständig versucht, zu schlafen:
1
    if( stop ){
2
      try_sleep();

Vor dem Sleep natürlich nicht vergessen, den Aufwachinterrupt zu 
enablen:
1
  PCICR = 1<<PCICR_ENABLE;                      // awake interrupt on
2
  sleep_cpu();
3
  PCICR = 0;

Der Aufwachinterrupt hat nichts weiter zu tun, kann also leer bleiben:
1
EMPTY_INTERRUPT( PCINT_vect );                  // wake up from power down

Den Schlafmodus und den Aufwachpin kann man schon im Init vorbereiten:
1
  PCMSK_REG = 1<<PCINT_BIT;                     // prepare awake pin
2
  set_sleep_mode( SLEEP_MODE_PWR_DOWN);         // prepare sleep
3
  sleep_enable();

Und nun kommt das schwierigste. Die Tastenentprellung braucht einen 
Timer, aber der läuft ja im Power-Down nicht. Daher darf man erst 
schlafen, wenn das Entprellen abgeschlossen ist. Bei meiner Routine ist 
das der Fall, wenn die Aufwachtaste losgelassen ist (= high) und das 
entprellte Bit = low.
Daher muß noch dieser Test erfolgen, bevor man schläft:
1
uint8_t get_key_busy( uint8_t key_mask )
2
{
3
  return (~KEY_PIN | key_state) & key_mask;     // until key released
4
}
5
6
7
void try_sleep()
8
{
9
  if( get_key_busy( 1<<KEY0 ))
10
    return;                                     // still busy
11
  LED_PORT = 0xFF;                              // all LEDs off
12
  PCICR = 1<<PCICR_ENABLE;                      // awake interrupt on
13
  sleep_cpu();
14
  PCICR = 0;
15
}

Alternativ kann man aber auch den Watchdoginterrupt oder den RTC-Timer 
(T2 + Uhrenquarz) zum Entprellen nehmen, die laufen ja auch im 
Power-Down weiter.


So und das wars dann auch schon.
Zum Debuggen ist noch diese Zeile nach dem Sleep drin:
1
      LED_PORT = 0x00;                          // all LEDs on (for debug only)

Bleibt die CPU also nicht im Sleep stehen, leuchten alle LEDs.
Damit sieht man sehr schön, wie beim Drücken die CPU aufwacht. Ist der 
Druck nur kurz, geht sie wieder schlafen.
Diese Zeile kann also nach dem Test entfernt werden.


Zusätzlich habe ich noch einen Timer eingebaut. Wird 1min keine Taste 
gedrückt, wird "stop" auf wahr gesetzt und damit der Power Down Mode 
aktiv.
Der komplette Code steht in "Knightrider.zip".


Peter

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Ich habs noch etwas verbessert.

Der Sleep-Mode kann auch bei gedrückter Taste erfolgen. Dazu wird 
überprüft, ob der entprellte Zustand dem Input entspricht und ob der 
Tastendruck abgeholt wurde.

Das Delay ist für jedes Muster als Parameter einstellbar.

Das Delay wird mit dem Timer gemacht, dadurch kann auch der Idle-Mode 
benutzt werden.

Die Stromaufnahme (ATmega48, 5V, 1MHz) ist:
1
Aktiv:       1,19mA
2
Idle:        0,49mA
3
Power Down: <0,02mA
Ich habs nicht genauer messen können, da im STK500 immer 2,85mA fließen.


Peter

von freund (Gast)


Lesenswert?

Hallo Leute,
Schöne Lösung von Peter!
Habe im Zip eine a.bat gesehen kann mir jemand dieses File erkären

Gruß Freund

von Peter D. (peda)


Lesenswert?

freund schrieb:
> Habe im Zip eine a.bat gesehen kann mir jemand dieses File erkären

Ist zum Compilieren anstelle eines Makefiles ohne IDE.


Peter

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.