Forum: Compiler & IDEs Sleep Mode Probleme -Atmega169P


von Marcel (Gast)


Angehängte Dateien:

Lesenswert?

Moin zusammen,
ich habe jetzt schon die Wiki-Seiten von Mikrocontroller.net, sowie die 
Erklärung in der sleep.h gelesen, doch irgendwie will mein uC nicht so 
recht mit dem Schlafmodus:

Er geht zwar ohne Probleme in den Schlafmodus über, doch lässt sich 
nicht mehr aufwachen. Das interessante ist, dass wenn ich mehrere Male 
schnell hintereinander eine Taste (PCINT-Interrupt) drücke, dann kann es 
sein, dass er den Tastendruck registiert, doch passiert das nur sehr 
selten

Nebenbei benutze ich noch einen externen Uhrenquarz für eine RTC. Habe 
ein Oszi mal an den Quarz gehalten und der schwingt auch noch wenn er im 
Schlaf ist (Soll ja auch so sein!)

Meinen Source-Code findet ihr im Anhang.

Vielen Dank!

Marcel

von Flo (Gast)


Lesenswert?

ISR(PCINT0_vect)
{
  volatile static uint8_t i;
  if( (PINE & FLAG_CODE_Taster) == i )
  {
    //DISABLE_S1_S2;
    OCR2A = TCNT2 +5; //20ms
    TIMSK2 |= (1<<OCIE2A); //Starte Capture-Interrupt fuer 
Entprellroutine
  }
}

Welchen Wert hat i ?

von Peter D. (peda)


Lesenswert?

Beschreib dochmal, wie das Programm ablaufen soll (Programmablaufplan), 
insbesondere diese ganze Rum-Flag-serei.

Kommentare sind überhaupt nicht überflüssig, sie helfen einem selbst, in 
seinen Programmen den Überblick zu behalten.


Peter

von Falk B. (falk)


Lesenswert?

@  Marcel (Gast)

>sein, dass er den Tastendruck registiert, doch passiert das nur sehr
>selten

Dein Programm ist etwas kryptisch. Vor allem ein cli() nach dem 
et_sleep_mode(SLEEP_MODE_PWR_SAVE); sieht gefährlich aus. Und auch deine 
Verwendung von sleep_enable, sleep_cpu etc. sieht chaotisch aus. Mach es 
wie im Artikel Sleep Mode, und alles ist paletti.

MfG
Falk

von Marcel (Gast)


Lesenswert?

Flo schrieb:
> Welchen Wert hat i ?

Sry, das war ein Fehler meinerseits, War hier nicht sauber genug mit dem 
Copy-Paste:
1
ISR(PCINT0_vect)
2
{  
3
  volatile static uint8_t i;
4
  if( (PINE & FLAG_CODE_IMPULS) == i )
5
  {
6
    timer.stop = TCNT2;
7
    timer.overfl = timer.tmp_overfl;
8
    timer.tmp_overfl=0;
9
    
10
    if( i== 0)
11
    {
12
      i = FLAG_CODE_IMPULS;
13
    }
14
    
15
    else
16
    {
17
      i = 0;
18
    }
19
    
20
    FLAG1_LOC |= (1 << FLAG_IMPULS); //dann setze die Flag erneut
21
  }
22
  
23
  else //Impuls fand statt - entweder falling oder rising Edge
24
  {
25
26
    //DISABLE_S1_S2;
27
    OCR2A = TCNT2 +5; //20ms
28
    TIMSK2 |= (1<<OCIE2A); //Starte Capture-Interrupt fuer Entprellroutine
29
30
  }
31
}

Der Grund ist, dass ich nebenbei noch die Zeit zwischen 2Impulsen messe. 
Wenn i=1 ist. Immer wenn ich eine Rising Edge habe, dann wird es auf 1 
gesetzt. Wenn ich eine Falling habe, dann wieder auf 0.
Detektiere ich ein PCINT und passt der momentane Zustand nicht mit dem 
gespeicherten i, kann nur einer der beiden Taster gedrückt worden sein.

von Marcel (Gast)


Lesenswert?

Falk Brunner schrieb:
> Dein Programm ist etwas kryptisch. Vor allem ein cli() nach dem
> et_sleep_mode(SLEEP_MODE_PWR_SAVE); sieht gefährlich aus. Und auch deine
> Verwendung von sleep_enable, sleep_cpu etc. sieht chaotisch aus. Mach es
> wie im Artikel Sleep Mode, und alles ist paletti.

Ich habe mich hierbei aber genau an die Anweisung in der sleep.h 
gehalten, die macht das wie folgt:

<http://www.nongnu.org/avr-libc/user-manual/group__avr__sleep.html>;
1
    #include <avr/interrupt.h>
2
    #include <avr/sleep.h>
3
4
    ...
5
      set_sleep_mode(<mode>);
6
      cli();
7
      if (some_condition)
8
      {
9
        sleep_enable();
10
        sei();
11
        sleep_cpu();
12
        sleep_disable();
13
      }
14
      sei();

Peter Dannegger schrieb:
> Beschreib dochmal, wie das Programm ablaufen soll (Programmablaufplan),
> insbesondere diese ganze Rum-Flag-serei.

Ja da hast du Recht, etwas verwirrend ist das schon für einen 
Außenstehenden.
1
/**
2
* Ort wo bitweise die Flags gespeichert werden - schneller Zugriff, da unter 0x1F!
3
*/ 
4
#define FLAG1_LOC GPIOR0 
5
6
/**
7
* Wird gesetzt, wenn ein Impuls gekommen ist
8
*/ 
9
#define FLAG_IMPULS   2
10
11
/**
12
* Nach Entprellroutine - Taster1 (Weiter) gedrueckt
13
*/ 
14
#define FLAG_S1_PRESSED  3 
15
16
/**
17
* Nach Entprellroutine - Taster2 (Bestaetigung) gedrueckt
18
*/ 
19
#define FLAG_S2_PRESSED  7

PS: Die Entprellroutine habe ich weitesgehend von dir übernommen :-). 
Mit einer Ausnahme, dass ich diese nur aktiviere, wenn wirklich eine 
Taste gedrückt wurde.
1
ISR(TIMER2_COMP_vect )
2
{
3
  static uint8_t ct0, ct1,rpt, counter;
4
  uint8_t i;
5
  
6
  OCR2A = TCNT2 + 2; //20ms
7
  i = key_state ^ ( (~PINE) & FLAG_CODE_TASTER);    // key changed ?
8
  ct0 = ~( ct0 & i );      // reset or count ct0
9
  ct1 = ct0 ^ (ct1 & i);    // reset or count ct1
10
  i &= ct0 & ct1;      // count until roll over ?
11
  key_state ^= i;      // then toggle debounced state
12
  FLAG1_LOC |= key_state & i;    // 0->1: key press detect
13
  
14
  if( (key_state & (1<<FLAG_S1_PRESSED) ) == 0 )  // check repeat function
15
  {
16
    rpt = 40;    // start delay
17
  }
18
  
19
  
20
  if(++counter == 5)
21
  {
22
    if( (PINE & (1<<FLAG_S1_PRESSED) ) ) //Ist Taster1 nicht gedrückt
23
    {
24
      TIMSK2 &= ~(1<<OCIE2A); //Stoppe Overflow
25
      counter = 0;
26
    }
27
    
28
    else
29
    {
30
      OCR2A = TCNT2 + 51; //200ms
31
    }
32
  }
33
  if( --rpt == 0 )
34
  {
35
    FLAG1_LOC |= (1<<FLAG_S1_LONG);
36
    TIMSK2 &= ~(1<<OCIE2A); //Stoppe Overflow
37
  }
38
}

Vielen Dank für eure schnellen Antworten :-)

Grüße Marcel

von Marcel (Gast)


Lesenswert?

Also ich bin jetzt schonmal ein gutes Stück weitergekommen.
Habe die Entprellroutine rausgenommen und komischer weise registriert er 
jetzt die Tastendrücke, aber unglaublich langsam. Er müsste jetzt 
prellen und gleich 2/3 Tastendrücke registrieren, doch da tut sich mal 
einer, wenn man lange draufdrückt. :(

Gibt es da etwa Probleme das der Taktgeber des uC gleich der Taktgeber 
der RTC ist, denn wenn ich den internen Taktgeber als uC-Takt gebe, dann 
läuft der Tastendruck wesentlich schneller.

Vielen Dank für eure Hilfe

Grüße!
Marcel

von Peter D. (peda)


Lesenswert?

Ich arbeite lieber nach der Methode: teile und herrsche.
Ich würde den Sleep-Mode immer ganz zum Schluß implementieren, wenn die 
anderen Funktionen alle fertig sind.

Der Timer2 im Async-Mode ist etwas tricky. Man muß nach jeder Aktion 
erstmal testen, ob sie beendet wurde, ehe man in Sleep geht. Dazu gibt 
es 3 Flags.

Auch ein Interrupt ist eine Aktion (Löschen des Interrupt-Flags), für 
die es aber kein Updatebit gibt. Man muß dann ein Dummy-Write ausführen 
und warten, bis dieses beendet ist.

Ich würde daher das Entprellen besser mit T0 oder T1 machen. Dann muß 
man aber warten, bis das Entprellen der Aufwachtaste beendet ist:
1
uint8_t get_key_idle( uint8_t key_mask )        // check if ready for power down
2
{
3
  return (KEY_PIN ^ key_state) & key_mask;
4
}
5
...
6
static inline void power_down( void )
7
{
8
  ATOMIC_BLOCK(ATOMIC_FORCEON){
9
    if( get_key_idle( 1<<KEY_ON_OFF )){         // if debounce done
10
      ADCSRA = 0;                               // ADC off
11
      PCICR = 1<<KEY_ON_OFF_ENABLE;             // enable wake up
12
      set_sleep_mode( SLEEP_MODE_PWR_DOWN );
13
    }
14
  }
15
  sleep_cpu();
16
}
17
...
18
ISR( PCINT2_vect )                              // wake up from power down
19
{
20
  set_sleep_mode( SLEEP_MODE_IDLE );
21
  PCICR = 0;
22
}
23
...
24
static inline void power_on_off( void )         // handle key press
25
{
26
  if( get_key_press( 1<<KEY_ON_OFF )){
27
    if( state == OFF )
28
      state = ON;
29
    else
30
      state = OFF;
31
  }
32
}


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.