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
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 ?
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
@ 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
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.
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
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.