Lösungsansatz gesucht im Sleepmode

Hallo,

wenn der µC die meiste Zeit schläft und nur aller x Minuten vom RTC Timer aufgeweckt wird an Pin 2, wie kann man den µC zusätzlich über einen Taster aufwecken? Kann man irgendwie einen zweiten Pin zum aufwecken definieren? Ich möchte nun kein externes ODER verbauen. Ist das Software technisch lösbar?
Grund ist, ich möchte per Taster das BT Modul einschalten um dann, so lange wie ich möchte, zwischen Smartphone und Arduino mir Daten anzeigen zu lassen. Bis ich das BT Modul wieder abschalte. Während dessen darf sich der µC nicht schlafen legen.

mein einfacher Testcode:

#include <avr/sleep.h>

#define RESET16U2  22       // Reset für 16U2 an Pin 22

int sleepStatus = 0;        // variable to store a request for sleep
int count = 0;              // counter

int ledPin = 13;            // LED connected to digital pin 13
//int interruptPin = 10;      // LED to show the action of a interrupt
int wakePin = 2;            // active LOW, ground this pin momentary to wake up
//int sleepPin = 12;          // active LOW, ground this pin momentary to sleep
int ledState = LOW;

void wakeUpNow()        // here the interrupt is handled after wakeup
{
  // execute code here after wake-up before returning to the loop() function
  // timers and code using timers (serial.print and more...) will not work here.
  // digitalWrite(interruptPin, HIGH);  // LED an Pin 10 ein
}


void sleepNow()
{
    /* Now is the time to set the sleep mode. In the Atmega8 datasheet
     * http://www.atmel.com/dyn/resources/prod_documents/doc2486.pdf on page 35
     * there is a list of sleep modes which explains which clocks and 
     * wake up sources are available in which sleep modus.
     *
     * In the avr/sleep.h file, the call names of these sleep modus are to be found:
     *
     * The 5 different modes are:
     *     SLEEP_MODE_IDLE         -the least power savings 
     *     SLEEP_MODE_ADC
     *     SLEEP_MODE_PWR_SAVE
     *     SLEEP_MODE_STANDBY
     *     SLEEP_MODE_PWR_DOWN     -the most power savings
     *
     *  the power reduction management <avr/power.h>  is described in 
     *  http://www.nongnu.org/avr-libc/user-manual/group__avr__power.html
     */  
       
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here

  sleep_enable();          // enables the sleep bit in the mcucr register
                           // so sleep is possible. just a safety pin 
  
    /* Now it is time to enable an interrupt. We do it here so an
     * accidentally pushed interrupt button doesn't interrupt
     * our running program. if you want to be able to run
     * interrupt code besides the sleep function, place it in
     * setup() for example.
     *
     * In the function call attachInterrupt(A, B, C)
     * A   can be either 0 or 1 for interrupts on pin 2 or 3.  
     *
     * B   Name of a function you want to execute at interrupt for A.
     *
     * C   Trigger mode of the interrupt pin. can be:
     *             LOW        a low level triggers
     *             CHANGE     a change in level triggers
     *             RISING     a rising edge of a level triggers
     *             FALLING    a falling edge of a level triggers
     *
     * In all but the IDLE sleep modes only LOW can be used.
     */
 
  attachInterrupt(0,wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function
                                     // wakeUpNow when pin 2 gets LOW 
      
  sleep_mode();            // here the device is actually put to sleep!!
 
                           // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP
  sleep_disable();         // first thing after waking from sleep:
                           // disable sleep...
  
  detachInterrupt(0);      // disables interrupt 0 on pin 2 so the
                           // wakeUpNow code will not be executed
                           // during normal running time.
    
}


void setup()
{
  pinMode(RESET16U2,OUTPUT);       // 16U2 wird dauerhaft
  digitalWrite(RESET16U2, LOW);    // im Reset Mode gehalten, spart 2mA
  
  pinMode(ledPin, OUTPUT);         // LED connected to digital pin 13
 
  pinMode(wakePin, INPUT);         // active LOW, ground this pin momentary to wake up
  digitalWrite(wakePin, HIGH);     // Pullup aktiv
      
  attachInterrupt(0,wakeUpNow, LOW);   // use interrupt 0 (pin 2) and run function
                                       // wakeUpNow when pin 2 gets LOW 
                            
}


void loop()
{
  
   if ( digitalRead(2) == LOW ) {
     digitalWrite(ledPin, HIGH);      
   } 
   else {
     digitalWrite(ledPin, LOW); 
     sleepNow();                   // sleep function called here
   }
      
 
}

Der Atmega328 hat zwei Hardware-Interrupts.

Was mit Pin-2 und Interrupt-0 möglich ist, funktioniert auf Atmega328 Controllern ebenfalls mit Pin-3 und Interrupt-1.

Hallo,

das heißt, ich kann zwei Pins für zwei leere wakeup's definieren? Weil das Programm sowieso nach SleepNow() weitermacht. Dann muß ich nur SleepNow() solange überspringen, solange ich das BT Modul aktiv haben möchte. Wäre das zum Bsp. so richtig?

attachInterrupt(0, wakeUpNow_1, LOW); // Interrupt 0 an Pin 2

attachInterrupt(1, wakeUpNow_2, LOW); // Interrupt 1 an Pin 3

und an meinem Mega2560 hab ich noch mehr zur Auswahl?

LOW löst Interrupts aus solange der Zustand Low ist. Du willst entweder RISING oder FALLING

Du kannst auch auf mehr Pins Interrupts auslösen (auf dem UNO auf allen!). Das nennt sich "Pin Change Interrupt". Ist aber komplizierter, da sich jeweils 8 Pins einen Interrupt-Vektor teilen. Da muss man dann abfragen welcher Pin tatsächlich getriggert hat.

Doc, was setzt du für einen Atmega/Attiny ein? Wäre doch relativ relevant, da es hier große Unterschied/Möglichkeiten gibt, diesen aufzuwecken.

Hallo,

ich habe einen Mega2560.

Für den Taster, der mein BT Modul einschalten soll und solange den Sleepmode verhindern soll, käme Falling in Frage. Okay. Ich merke mir den Zustand solange. Wenn ich keinen Denkfehler habe. Wird sich zeigen. :slight_smile:

Für den Normalfall, bin ich mir jetzt nicht sicher ob ich Low oder auch Falling nehmen soll. Das Low Signal kommt von der RTC. Der liegt dann auf Dauer Low, bis ich den Alarm zurücksetze in der RTC. Normalerweise müßte ich auch auf Falling wechseln. Ich möchte ja nicht ständig sinnlos einen Interrupt auslösen. Ich baue meinen Code gerade um, das alles einmal komplett abgearbeitet wird an Funktionen und sich der µC dann wieder schlafen legen soll. Bis zum nächsten aufwecken durch den RTC Timer. Ich hab da momentan paar Gedanken parallel.

Nur grundsätzlich wäre das so richtig?

attachInterrupt(0, wakeUpNow_1, LOW); // Interrupt 0 an Pin 2

attachInterrupt(1, wakeUpNow_2, LOW); // Interrupt 1 an Pin 3

Da gebe ich Serenfly, bzw deiner eigenen Vermutung recht. Wenn dann lediglich den Flankenwechsel erfassen. Das wäre bei dir, wenn ich es richtig verstanden habe, FALLING.

Hallo,

okay, dann nehme ich Falling und baue weiter um.
Danke Euch.

Hallo,

nachdem der Codeumbau soweit vorangeschritten ist, wollte ich nun damit hier weitermachen.

und wollte die Definitionen vor setup () um folgendes ergänzen.

attachInterrupt(1, wakeUpNow2, LOW); // use interrupt 1 (pin ?) and run function
                                     // wakeUpNow when pin 2 gets LOW 
  
detachInterrupt(1);      // disables interrupt 1 on pin ? so the
                         // wakeUpNow code will not be executed
                         // during normal running time.

Jetzt wollte ich schauen, an welchen Pin INT1 beim Mega2560 ist und mußte festellen, dass ist ja komplett anders.

UNO R3:
INT 0 an Pin 2
INT 1 an Pin 3

Mega2560
INT 0 an Pin 21
INT 1 an Pin 20
INT 2 an Pin 19
INT 3 an Pin 18
INT 4 an Pin 2
INT 5 an Pin 3

übersetzt das die Library intern? Weil Pin 2 und vermeintlich INT0 funktioniert ja mit meinem Mega2560.
Nur ist das ja eigentlich nicht INT 0 sondern INT 4.
Ist das nicht gefährlich, so ein durcheinander?
Oder darf ich mir darüber einfach nicht so viele Gedanken machen?

Ist das nicht gefährlich, so ein durcheinander?

Durchaus!
Dokulesen ist hilfreich, wenn man das Risiko mindern möchte.

Oder darf ich mir darüber einfach nicht so viele Gedanken machen?

Richtig!
Unnütze Gedanken sind Energieverplemperung.

Gott gebe mir Gelassenheit, hinzunehmen, was nicht zu ändern ist. Mut zu ändern, was ich ändern kann. Und Weisheit, zwischen beidem zu unterscheiden.

Hallo,

eine Doku in dem Sinne gibts da nicht. Ich denke man hat darauf keinen Einfluss. Das muß die IDE selbst machen. Ich meine, wir schreiben ja im Sketch zum Bps. Pin 10. Beim Uno und beim Mega2560 oder anderen Arduino Boards. Alle machen das gleiche. Nur am µC selbst ist die Belegung völlig verschieden. Da macht sich auch niemand irgendwelche Gedanken.

Das Bsp. ist glaube ich mit dem Kommentaren für den Uno geschrieben bzw. dokumentiert. Meine Frage wäre jetzt ganz gezielt. Muß ich mich nach der PIN Bezeichnung richten oder nach der Interrupt Bezeichnung und dann den richtigen Pin raussuchen? Wobei das mit dem Pin 2 ja funktioniert, wiederum. Also muß die IDE intern einen anderen passenden Interrupt verwenden? Schon verwirrend wenn man mal hinter die Kulissen schaut.

Die Prozessor-Pin Bezeichnungen kannst du auf dem Arduino größtenteils vergessen (egal ob es im Interrupts oder digitale I/Os geht). Du schaust entweder nach welchen Arduino Pin du willst und suchst dann die Interrupt Nummer heraus. Oder umgekehrt.

Hallo,

naja, dass ist ja das verwirrende. Wie sattelt man das Pferd, von hinten oder von vorne?

zum Bsp. lege ich mit der Definition fest, welchen Interrupt ich verwende.

attachInterrupt(0, wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function wakeUpNow when gets LOW
attachInterrupt(1, wakeUpNow, LOW); // use interrupt 1 (pin 3) and run function wakeUpNow when gets LOW

Das Problem ist, die Nummer vom Interrupt und die kommentierte Pin Nummer ist gültig für den Uno.
Ich muß aber die Interruptnummer angeben!
Der Uno hat nur 2 Interrupts, was ich so sehe, die man nutzen kann. INT0 und INT1.

Wenn ich jetzt weis, dass Pin 2 mit der Angabe INT0 beim Mega2560 funktioniert, dann komme ich jetzt nicht weiter. Angenommen ich möchte 4 Interrupts zum aufwecken verwenden. Was soll man machen? Pin 3 mit vermeintlich INT1 könnte noch funktionieren. Wobei das am Mega genauso falsch ist wie mit Pin2. Und dann?

Wenn niemand eine Idee hat, werde ich mal voller Risiko alle INT's aufführen und gucken ob er und an welchen Pin er aufwacht. Ich hoffe das geht gut.

Steht doch da was, was ist:
http://arduino.cc/en/Reference/AttachInterrupt

INT0 und INT1 sind auf dem UNO und auf dem Mega auf den gleichen Pins

Ansonsten kann man bei sowas auch mit bedingter Kompilierung arbeiten. Dann kann man es so machen dass es z.B. auch auf dem Leonardo auf den gleichen Pins geht.

Du kannst auch PinChange Interrupts nehmen. Die gehen auf dem UNO auf allen Pins (auf dem Mega nicht, aber sind trotzdem viele):
http://playground.arduino.cc/Main/PinChangeInt

Oder im Datenblatt schauen wie es per Hand geht. Ist nicht so schwer.

Hallo,

ich hatte nicht in der Arduino Reference geschaut, sondern die Pinouts vor mir von pighixxx. Da ist das Pinout falsch vom 30.01.2013 im Anhang. Hatte ich schon weiter oben laut dem aufgelistet.

Wenn das in der Arduino Reference so ist wie es ist, dann ist alles glas klar. Damit gibts keine Fragen. Haut alles hin.

ArduinoMega.pdf (181 KB)

ATMEGA2560U.pdf (253 KB)

Das ist nicht falsch. Das sind lediglich andere Bezeichnungen. Die die der AVR intern verwendet. Genauso wie die Prozessor Pin Nummern nicht mit den Arduino Pin Nummern übereinstimmen, sind die Prozessor Interrupt Nummern nicht mit den Arduino Interrupt Nummern identisch.

Das liegt auch daran dass der Arduino ganz unterschiedliche Prozessoren unterstützt. Der UNO und Mega sind sehr, sehr ähnlich. Aber schob bei den Tinys gibt es intern starke Unterschiede. Der Prozessor des Leonardos ist auch anders aufgebaut, wenn auch grob ähnlich. Aber der ARM ist völlig anders. Aber alles muss mit den gleichen Funktionen und Bezeichnungen laufen.

Hallo,

das die echte Prozessorpin Nummer nicht mit der Arduino Pin Nummer übereinstimmt ist klar. Das ist nicht das Problem.
Aber die Bezeichnung INT0...5 kann man doch nicht irgendwie verwenden? Die ist doch dem echten Prozesspin zugeordnet.

Damit habe ich ein neues Problem und ich dachte es wäre gelöst. Was stimmt denn nun. Die Arduino Reference oder das Pinout?
Laut pighixxx Pinout liegt INT5 auf Arduino Pin3.
Laut Arduino Reference liegt INT5 auf Arduino Pin 18.
Na was denn nun?

Halte dich an die Reference!

Was auf dem Arduino INT5 heißt ist auf dem AVR intern INT3. Das ist aber für dich egal.

Hallo,

okay, dann eben die Reference. Ich verstehe aber immer noch nicht warum im pighixxx Pinout die INT's anders zugeordnet sind.

Ich habe jetzt das Datenblatt vom Mega2560 vor mir. Okay, pighixxx hat die INT Nummern den echten Prozessor Pins zugeordnet. Nur ist das eigentlich sinnlos, oder? Für wen und für was ist dann das Pinout gedacht?

Die IDE modelt das alles intern um?

Ich meine, wenn ich in der IDE INT0 schreibe, wird im µC INT4 angesprochen?
Wenn ich gezielt laut Datenblatt eine Eigenschaft eines Pins raussuche und will INT5 verwenden, dann muß ich in der IDE INT1 schreiben? Oder wie?

Doc_Arduino:
Nur ist das eigentlich sinnlos, oder? Für wen und für was ist dann das Pinout gedacht?

Bei den externen Interrupts ist es nicht so sinnvoll da man die kaum selbst programmiert, aber bei anderen Dingen ist das sehr nützlich. Vor allem wenn direkt auf die I/O Pins zugreift. Oder für PinChange Interrupts (PCINTxx ). Oder wenn man herausfinden will welche Pins zu welchen Timern gehören.