mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Power Down Mode über Taster


Autor: Dennis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tag,

ich bin auf der suche nach einer Möglichkeit den AVR über einen Taster
in den Power Down Modus zu setzen und über den selben Taster auch
wieder aufzuwecken. Ist das Möglich?

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn Du den Taster an einem der möglichen Interrupt-Pins anschließt,
sollte das kein Problem sein. Welche externen Interrupts den µC
aufwecken können, steht im Datenblatt. Der jeweilige Interrupt muss zum
Aufwecken als Level-Interrupt eingestellt sein, sonst gehts nicht.

Autor: Dennis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das wären bei mir die INT0 und INT1. Das heißt bei ein kurzer Highpegel
an diesem PIN würde ausreichen?

Was genau bedeutet Level-Interrupt?

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Level Interrupt bedeutet, dass der Interrupt nicht durch eine Flanke
sondern bei Low-Level ausgelöst wird. Da im Powerdown-Modus der
Oszillator abgeschaltet ist, kann eine Flanke nicht detektiert werden.
Deshalb gehen zum Aufwecken aus dem Powerdown nur die Level-Interrupts.

Autor: inoffizieller WM-Rahul (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Was genau bedeutet Level-Interrupt?

Level-Interrupt sind pegelabhängig.
Das Gegenstück dazu sind Flanken-Interrupts.
Die (Flanke) kann der AVR aber nur detektieren, wenn ein Takt vorhanden
ist. Je tiefer der AVR schläft, umso weniger Takt ist noch aktiv.
Guck mal im Datenblatt nach Sleepmodes.

Autor: Dennis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also dann sozusagen ein kurzer Highpegel.

Hab mir das Datenblatt gerade mal angeschaut, die Möglichkeiten ihn
daraus aufzuwecken sind klar. Will ihn aber auch durch so einen Pegel
in den Power Down Modus bringen.

Also müsste ich wie folgt vorgehen:

1. Externen Interrupt INT0 aktivieren.
2. Register so setzen dass bei Low-Level der Interrupt INT0
   ausgelöst wird.
3. Ihm im Interrupt sagen dass er in den Power Down Modus gehen soll,
   also durch setzen der entsprechenden Bits im Interrupt.
4. Ausgelöster Interrupt durch Low-Pegel an INT0 bringt den
   Controller in den Power Down Modus.
5. Erneuter Low-Pegel an INT0 weckt ihn wieder auf.

Soweit Richtig?

Autor: Ale (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab bei atmega32l Flanke-int probiert (taste und Kondensator mit
Wiederstand), und hat es nicht detektiert. Nur Level hat geklappt
(INT0). Wenn du bekommst ein Interrupt, du sollst es kurz deaktivieren
und nach nochmal aktivieren, so wird nicht kontinuirlich interrupts
machen.

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Ale:
Den Versuch hättest Du Dir sparen können, es steht nämlich im
Datenblatt, dass nur Level-Interrupts den µC aufwecken können. Außerdem
steht das hier weiter oben auch schon...

@Dennis:
Frage den Taster (mit deaktiviertem Interrupt!) im Hauptprogramm
zyklisch ab (Polling). Wenn er gedrückt ist (Low-Pegel), dann warten,
bis er losgelassen wurde (High-Pegel), entprellen (z.B. mit Wartezeit),
anschließend das Interrupt-Flag löschen (wichtich!), den Level-Interrupt
aktivieren und in den Schlaf schicken. Wenn dann der Interrupt auftritt,
in der ISR den Interrupt wieder deaktivieren und weiter gehts im
Programm. Mach das schlafengehen nicht in der ISR! Das geht nur, wenn
die ISR als unterbrechbar programmiert ist, was nicht empfehlenswert
ist. Im Normalfall wird schließlich beim Einsprung in die ISR das I-Bit
im SREG automatisch gelöscht, was dazu führt, dass kein Interrupt
bearbeitet werden kann und der Controller demzufolge auch nicht wieder
aufwacht!

Autor: Ale (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Johnny,

Im Datenblatt, atmega32 Seite 65, sagt: MCUSR bits ISC01 ISC00: The
level and edges on the external INT0 pin that activate the interrupt
are defined in Table 35.

Ich habe beide probiert, Lo->Hi und Hi->Lo, nur Level hat ein interrupt
gemacht :-(

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es geht hier ums aufwecken des µC aus dem Powerdown-Modus, und das geht
nur mit den Level-Interrupts!

Autor: Ale (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Johnny,

Jaja, meine aber es ist nocht nicht im Powerdown !. Es rennt und mit
einem Taste ich wollte nach Powerdown es bringen. :-(

Autor: Dennis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke jonny,

das hab ich verstanden. Nur wie mache ich es, dass der Controller nach
dem einschalten direkt in den Power-Down Modus geht ohne dass schon ein
Taster gedrückt wurde? Das heißt sobald mein Controller mit Spannung
versorgt wird, soll er in den Power-Down Modus gehen. Erst wenn dann
ein Taster gedrückt wird, soll er aufwachen, seine Arbeit eledigen und
beim erneuten drücken des Tasters wieder zurück in den Power-Down
Modus.

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dann musst Du ihn nach der Initialisierung direkt in den Powerdown
schalten (und natürlich vorher den Level-Interrupt freigeben)

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Ale:
Schau mal nach, ob Du die Tasten richtig entprellt hast. Wenn die
nämlich prellen, dann passiert alles Mögliche, nur nicht das, was Du
willst...

Autor: Dennis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie definiere ich mir denn einen Low-Pegel?

Oder reicht es, wenn der Controller einfach für einen kurzen Augenblick
kein Signal bekommt. Hatte mir dauerhafte 5V am Controller vorgestellt
und bei einem Tastendruck dann halt kurz kein Signal. Wird der
Interrupt dann auch ausgelöst?

Oder kann ich das auch tauschen, das der Interrupt bei einem High-Pegel
ausgelöst wird?

Autor: Winfried (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Low Pegel wäre eine Taste gegen Masse und den Pin per Pullup normal auf
High Pegel halten.

Autor: Dennis (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Also so wie im angehängten Bild?

Autor: Dennis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie groß sollte der Widerstand denn sein? 10K?

Autor: Robert Weber (rweber)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
10K sind ok.

Autor: Dennis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke!

Autor: Dennis (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

hab im Moment kein Board zur Hand. Hab aber versucht schon mal das
Grundgerüst vom Code zu schreiben. Könnte vielleicht mal jemand schauen
ob das soweit in Ordnung ist, bzw. die Register richtig gesetzt sind?
Will es dann Morgen in die praxis umsetzen.

Wäre wirklich super!

Autor: Dennis (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Guten Morgen,

hab jetzt gerade noch mal das Programm etwas umgeschrieben und mal auf
dem STK500 mit nem Mega88 laufen lassen. Nur leider geht der Controller
nicht in den Power-Down-Modus.

Keine Ahnung warum??? Kann mir jemand nen Tip geben?

Autor: inoffizieller WM-Rahul (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
dir fehlt die "Sleep"-Instruction.

Autor: Dennis (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ach jo,

also das hier:

set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_mode();


Hab ich drin, klappt aber immer noch nicht.

Autor: inoffizieller WM-Rahul (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Macht das:
  SMCR &= ~(1 << SM0) | (1 << SM2);          //Power Down Modus
  SMCR |=  (1 << SM1) | (1 << SE);

nicht das Gleiche wie das hier:
  //Power Down & Sleep Enable
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);

Jetzt wäre natürlich schön zu wissen, was die sleep.h macht...

Autor: Dennis (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Bin mir nicht sicher ob die das gleiche machen.

Hab die sleep.h mal angehangen. Ich werd da irgendwie nicht schlau
draus.

Autor: inoffizieller WM-Rahul (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
cli();
      if (some_condition) {
        sleep_enable();
        sei();
  sleep_cpu();
  sleep_disable();
      }
      sei();
    \endcode

Steht so als Beispiel drin...Du hast dir wohl die "falschen" Befehle
herausgesucht...

Autor: Dennis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann es denn sein, dass die Led's am STK500 leuchten obwohl der
Controller im Power-Down-Modus befindet?

Autor: Dennis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie die falschen Befehle?

Autor: inoffizieller WM-Rahul (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Wie die falschen Befehle?

Naja, das von mir gepostete Code-Fragment ist die Langversion deiner
Version.
Ich kann mir vorstellen, dass die LED leuchtet, obwohl der Controller
schläft, da ja "nur" die Taktquellen heruntergefahren werden.
Schalte die LED doch einfach aus, wenn du im regulären Betrieb bist.

Autor: Dennis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also es funktioniert mitlerweile so, dass der Controller nach dem
einschalten in den Power-Down-Modus geht. Durch drücken des Tasters am
PIND3 wird der Controller wieder aufgeweckt. Nun will ich es so haben,
dass beim erneuten drücken dieses Tasters der Controller wieder in den
Power_Down_Modus geht.

Wie mach ich das am besten? Die sleep() in die ISR einbauen wäre glaube
ich keine gute Idee....

Autor: inoffizieller WM-Rahul (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dazu benutzt du den INT-Pin als ganz normalen Eingang, den du
regelmässig abfragst (z.B. Timerbasiert). Natürlich sollte das nicht
dazu führen, dass der Controller nach dem Wecken sofort wieder schlafen
geschickt wird, weil man etwas länger auf der Taste "steht".
Man muß also den Taster entprellen und festlegen, dass er immer noch
gedrückt wird.
Sobald er wieder losgelassen wurde, darf der Controller beim nächsten
Drücken wieder schlafen gehen.

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schau Dir mal mein Posting vom 5.10. um 17.00 Uhr an. Da hab ich das
Prozedere eigentlich schon recht ausführlich beschrieben.
"deaktivierter Interrupt" heißt dabei das, was Rahul geschrieben hat,
nämlich dass Du den Pin einfach im Hauptprogramm zyklisch abfragst.

Autor: Dennis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Puh, alles gar nicht so einfach!

Also bitte noch einmal ausführlich:

Hab alles soweit initialisiert(Power Down, INT1-Interrupt freigegeben
und globale Interrupts freigegeben) Danach soll er direkt in den
Power-Down Modus gehen. Macht er! Wird durch Low Pegel am Int1
aufgeweckt. Programm wird ausgeführt. Macht er!

Nun will ich ihn durch einen erneuten Low pegel am INT1 wieder zum
schlafen schicken.

Jetzt zu deinem Posting vom 05.10.

>Frage den Taster (mit deaktiviertem Interrupt!) im Hauptprogramm
>zyklisch ab (Polling). Wenn er gedrückt ist (Low-Pegel), dann >warten,
bis er losgelassen wurde (High-Pegel), entprellen (z.B. mit >Wartezeit)

Also bei deaktiviertem Interrupt heißt, der INT1 Interrupt muss
deaktiviert sein?

>anschließend das Interrupt-Flag löschen (wichtich!)

Das globale Interrupt-Flag?

Autor: inoffizieller WM-Rahul (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Das globale Interrupt-Flag?

Nein, das, das zum INT0 gehört. Wenn du das globale löscht (cli()),
können keine Interrupts mehr ausgeführt werden.
Das INT0-Flag muß man manuell löschen - bei anderen Interrupts wird das
Flag automatisch mit Eintritt in die ISR gelöscht (oder beim Verlassen -
weiß ich jetzt nicht genau).

Autor: Dennis (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Es läuft immer noch nich!

Hab es jetzt genau so, wie oben mehrfach beschrieben:

1. Direkt nach der Initialisierung wird der Controller schlafen
   geschickt. Durch Druck auf Taster und daraus folgendem Low-Pegel
   an INT1 wacht der Controller wieder auf. Nach dem Aufwachen wird
   der Interrupt deaktiviert und das gewünschte Programm ausgeführt.

SMCR &= ~(1 << SM0) | (1 << SM2);          //Power Down Modus
  SMCR |=  (1 << SM1) | (1 << SE);        //Power Down & Sleep Enable

  EICRA &= ~(1 << ISC11) | (1 << ISC10);      //Low Level of INT1
generates Interrupt Request
  EIMSK |= (1 << INT1);            //External Interrupt Request Enable
  sei();

  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
        sleep_mode();
  EIMSK &= ~(1 << INT1);

Funktioniert!

2. Abfrage des Tasters auf erneutes drücken mit entprellen usw.,
   wenn gedrückt, Interrupt Flag löschen, Level Interrupt
   aktivieren und schlafen schicken.

        EIFR |= (1 << INTF1);            //INT1 Interrupt Flag löschen
  EIMSK |= (1 << INT1);            //External Interrupt Request Enable
  sleep_mode();
  EIMSK &= ~(1 << INT1);            //External Interrupt Request Diable

Klappt nicht! Bin schon echt am verzweifeln.;-(

Hab auch mal den kompletten Code angehangen, vielleicht weiß ja einer
wo der Fehler liegt..

Autor: Dennis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Keiner ne Idee?

Autor: inoffizieller WM-Rahul (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Probier doch erst mal, den Controller per Tastendruck schlafen zu legen
(ohne ihn vorher zu wecken).

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Abfrage des Tasters auf erneutes drücken mit entprellen usw.,
> wenn gedrückt, Interrupt Flag löschen, Level Interrupt
> aktivieren und schlafen schicken.

Nein.
Nicht: 'wenn gedrückt'.
Sondern: 'wenn wieder losgelassen'.

Überleg doch mal: Du möchtest dass dein µC wieder aufwacht
wenn die Taste gedrückt ist. Wichtig: Wenn sie gedrückt ist!
Das ist ein Zustand!

D.h. Du fummelst an der Taste rum und drückst sie. Blitzschnell
fährt dein µC runter und überwacht ob die Taste gedrückt ist.
Die ist aber mit Sicherheit noch gedrückt, denn so schnell
kannst du die Taste gar nicht loslassen, wie der µC in
den Powerdown geht und feststellt, dass die Taste immer noch
gedrückt ist. Also fährt der µC wieder hoch denn: die Taste
ist ja gedrückt.

Genau das ist gemeint mit: Level-Interrupt.
Den µC interessiert es nicht, dass die Taste nur deshalb gedrückt
ist, weil du sie zum runterfahrten drücken musstest. Gedrückt
ist gedrückt. Und seine Anweisung lautet: wenn die Taste gedrückt
ist, dann wieder hochfahren.

Autor: Dennis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ah, jetzt kapier ich!

Also muss ich zwei Abfragen hintereinander. Erst ob die Taste gedrückt
ist und dann ob sie wieder losgelassen wird.

Also ungefähr so:

if(!(PIND & (1 << PIND3)))
{
 if(PIND & (1 << PIND3))
 {
 ........Sachen erledigen
 }
}

Autor: Dennis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ne, das geht ja gar nicht. Die zweite if-Anweisung wird ja üübersprungen
wenn der Taster nocht gedrückt ist.

Wie löst man das denn am besten, ne while-Schleife, die nichts macht
solange der Taster gedrückt ist?

Autor: Dennis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hey, jetzt klappt es! Danke, das mit der Variablen "wakeup" haut hin.

Hab das jetzt so gelöst:

if((!(PIND & (1 << PIND3))) &&  wakeup == 0)
  {
  while(!(PIND & (1 << PIND3)))
  {
  }
  wakeup = 1;
  }


  if((!(PIND & (1 << PIND3))) &&  wakeup == 1)
  {
  while(!(PIND & (1 << PIND3)))
  {
  }
  wakeup = 0;
  EIMSK |= (1 << INT1);
  sleep_mode();

  }


Nun will ich den Teil in mein großes Programm einbauen. Nur da hab jetzt 
das Problem mit dem entprellen.

Hab den Teil von oben wie folgt in mein Programm eingebaut:

if((!(PIND & (1 << PIND3))) &&  wakeup == 0)
  {
  while(!(PIND & (1 << PIND3)))
    {
  }
  taster &= ~(1 << 4);
  }

  else
  taster |= (1 << 4);


  if(( get_key_press( 1<<KEY4 )) && wakeup == 0)          //Interrupt at 
INT1
  {
  wakeup = 1;
  }

  if((!(PIND & (1 << PIND3))) &&  wakeup == 1)
  {
  while(!(PIND & (1 << PIND3)))
    {
  }
  taster &= ~(1 << 4);
  }

  else
  {
  taster |= (1 << 4);

  if(( get_key_press( 1<<KEY4 )) && wakeup == 1)          //Interrupt at 
INT1
  {
  wakeup = 0;
  EIMSK |= (1 << INT1);
  sleep_mode();
  }

Nur irgendwo scheint das so noch nicht ganz zu passen.....

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mit get_key_press kommst du hier nicht vernünftig weiter, da
get_key_pressed nach einem erfolgreichen Aufruf das Flag für gedrückt
löscht.
Was du brauchst ist eine is_key_pressed. Also eine Funktion
die zwar entprellt aber einfach nur den Zustand der Taste liefert.

Blöderweise komme ich jetzt nicht an die PeDa Entprellroutinen
ran, kann also nicht sagen, ob da was dabei ist.


  if( is_key_pressed( 1<<KEY4  ) ) {     // Shutdown gedrückt
    while( is_key_pressed( 1<<KEY4) )    // Warte aufs loslassen
      ;
    sleep
  }

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.