Liebe Fachleute! mittels der RC5 Routine von P. Dannegger lese ich die IR Kommandos einer Fernbedienung. Nun möchte ich gern unterschiedliche Aktionen bei kurzem Tastendruck oder bei langem Tastendruck starten. Das Problem bei meier FB ist, dass auch bei einem kurzen Druck mehrere Sequenzen (mit konstantem toggle bit) gesendet werden. Mir schwebt folgendes vor: wird die Taste auf der FB gedrückt und innerhalb 1 sec wieder losgelassen, führe Aktion für kurzen Tastendruck durch. Ist die Taste nach 1 sec. immer noch gedrückt, führe zyklisch die "Langzeitaktion" aus, bis Taste losgelassen wird. Meine Projekt: Atmega8, AVR Studio mit gcc... Möglicherweise ist die Lösung trivial, aber ich habe da irgendwie ein Brett vor dem Kopf. Gibt es dafür evtl. Beispielcode? Ich habe bisher leider nichts finden können. Bin dankbar für jede Hilfe.
Wieviele Sequenzen kommen typisch bei einem kurzen Tastendruck und wieviele typisch bei einem langen Tastendruck? Haben die Sequenzen einen bestimmten zeitlichen Abstand, so dass man sagen kann, "genug Sequenzen für einen kurzen Tastendruck sind da, warten wir mal etwas, ob jetzt Sequenzen kommen, die ein langer Tastendruck schickt".
Ein kurzer Tastendruck erzeugt 1-3 Wiederholsequenzen. Ein langer Tastendruck erzeugt Wiederholsequenzen solange die Taste gedrückt ist. Die Auswertung ist wie folgt geplant: Auswertung eines kurzen Tastendrucks -> einmaliges Ein/Ausschalt Kommando über USART erzeugen Langer Tastendruck -> Wiederholte Kommandosequenzen über USART schicken (z.B. Dimme 5% heller) solange die Wiederholsequenzen von der IR FB eintreffen Das ganze soll ein IR Umsetzer für ein Hausbussystem werden...
Wenn mehr als Sequenzen mit gleichem Togglebit innerhalb einer gewissen Zeit, die für mehr als 3 Sequenzen reicht, kommen, hättest du eine lange Sequenz. Wenn bloß 1-3 Sequenzen innerhalb einer gewissen Zeit, die für mehr als 3 Sequenzen reicht, kommen (oder wenn nach einer Sequenz das Togglebit wechselt), hast du eine kurzen Tastendruck (gehabt). Wieviel "eine gewissen Zeit" in der Praxis bedeutet, würde ich durch Versuche ermitteln. Wie lang muss das sein, um sauber kurz/lang zu trennen und wie kurz darf das sein, um ein geschmeidiges Feedback zu haben. BTW. Hat deine FB nur eine Taste? Warum nicht verschiedene Tasten und Kommandos benutzen?
Stefan B. schrieb: > BTW. Hat deine FB nur eine Taste? Warum nicht verschiedene Tasten und > Kommandos benutzen? Ja, ich kann natürlich auch verschiedene Tasten der FB nutzen. Ich wollte halt auf der FB das Verhalten von 1-Flächenbedienung bei Hausbustastern nachempfinden. Jede Taste der FB sollte dabei einer Lampe, Steckdose oder einem Rollo zugeordnet werden. Also z.B. Taste 1: kurzer Tatsendruck Lampe 1 ein/aus abh. vom letzten Zustand. Langer Druck: Dimme heller/dunkler abh. von letzter Dimmrichtung. Ich habe mir jetzt folgenden Codeschnipsel zurechtgedacht. Muss ich aber erst noch heute abend ausprobieren...
1 | for(;;){ // main loop |
2 | cli(); |
3 | i = rc5_data;// in rc5_data ist immer die letzte IR-Sequenz decodiert |
4 | // ... wird in ISR ermittelt
|
5 | rc5_data = 0; |
6 | sei(); |
7 | |
8 | if(i){ |
9 | _delay_ms(400); |
10 | if(i != rc5_data) { //nach Wartezeit keine neue IR-Sequenz oder andere als vor Wartezeit |
11 | sendcmd(i); // führe hier Einzelkommando aus |
12 | }
|
13 | else{ |
14 | while(i==rc5_data){ //aktueller IR-Code wie vor Wartezeit |
15 | cli(); |
16 | i=rc5_data; |
17 | rc5_data=0; |
18 | sei(); |
19 | sendcmd(i);// führe hier Wiederholkommando aus |
20 | _delay_ms(120); //Zeit lassen für das Eintreffen einer Wiederholsequenz |
21 | //eine IR Sequenz wird periodisch nach ca. 114 ms wiederholt
|
22 | }
|
23 | }
|
24 | }
|
25 | }
|
Die Delays gefallen mir nicht. Du hast doch in der RC5 einen durchlaufenden Timer, nutze den. Man könnte z.B. die RC5-Funktion so aufbohren, dass die ISR zu jedem rc5_data auch eine Art rc5_time liefert. Merke dir beim Eintreffen der ersten Sequenz eine Startzeit und berechne eine Endzeit für >3 Sequenzen. Wie geschrieben kann man durch Bedienversuche herausfinden wie groß diese Erkennzeitspanne optimalerweise ist. Dann zählst du eintreffende Sequenzen und vergleichst die aktuelle Zeit mit der berechneten Endzeit. Wenn >3 Sequenzen gezählt werden und die Endzeit noch nicht erreicht ist, hast du einen langen Tastendruck. Wenn <=3 Sequenzen gezählt sind und die Endzeit überschritten ist, hast du einen kurzen Tastendruck. Im zweiten Schritt würde ich über das Togglebit nachdenken. Wenn sich beim Zählen der Sequenzen das Togglebit ändert, wurde die Taste losgelassen und neu gedrückt. Man kann das unterschiedlich behandeln. Ich tendiere dazu es als kurzen Tastendruck zu behandeln mit EIN Funktion plus normale Auswertung für die jetzt gedrückte Taste.
Du hast Recht, die delays sind alles andere als elegant. Dein Tip war goldrichtig! Ich habe jetzt die ISR so erweitert, dass sowohl ein Wiederholungszähler als auch eine Pausenerkennung drin ist. Wielen Dank für den Hinweis. Nun funktioniert es. Die ISR sieht nun so aus:
1 | #define RC5TIME 1.778e-3 // 1.778msec
|
2 | #define PULSE_MIN (uchar)(F_CPU / 512 * RC5TIME * 0.4 + 0.5)
|
3 | #define PULSE_1_2 (uchar)(F_CPU / 512 * RC5TIME * 0.8 + 0.5)
|
4 | #define PULSE_MAX (uchar)(F_CPU / 512 * RC5TIME * 1.2 + 0.5)
|
5 | |
6 | #define PAUSETIME (60 * RC5TIME) // Wiederholsequenzen nach 50 bit
|
7 | // hier 10 bit bzw. 17.88 ms Reserve
|
8 | |
9 | #define PAUSE_MIN (uint)(F_CPU / 512 * PAUSETIME) //Mind. ISR Durchläufe f. Pausenlänge
|
10 | |
11 | uchar rc5_bit; // bit value |
12 | uchar rc5_time; // count bit time |
13 | uint rc5_tmp; // shift bits in |
14 | uint rc5_data; // store result |
15 | uint pause_ticks; // Anzahl ISR Runden ohne IR Flanken |
16 | uchar rc5_pause; //Pause nach letztem decodierten RC5_data erkannt |
17 | uint rc5_data_old; |
18 | uchar repeat_counter; |
19 | |
20 | SIGNAL (SIG_OVERFLOW0) |
21 | {
|
22 | uint tmp = rc5_tmp; // for faster access |
23 | |
24 | TCNT0 = -2; // 2 * 256 = 512 cycle |
25 | |
26 | if( ++rc5_time > PULSE_MAX ){ // count pulse time |
27 | if( !(tmp & 0x4000) && tmp & 0x2000 ){ // only if 14 bits received |
28 | rc5_data = tmp; |
29 | pause_ticks = 0; |
30 | if(rc5_data==rc5_data_old){repeat_counter++; |
31 | if(repeat_counter>50){repeat_counter=50;}//Überlauf verhindern |
32 | }
|
33 | else{ |
34 | rc5_data_old=rc5_data; |
35 | repeat_counter=0; |
36 | }
|
37 | }
|
38 | tmp = 0; |
39 | }
|
40 | |
41 | if( (rc5_bit ^ xRC5_IN) & 1<<xRC5 ){ // change detect |
42 | rc5_bit = ~rc5_bit; // 0x00 -> 0xFF -> 0x00 |
43 | pause_ticks =0; // Pausenzähler zurücksetzen |
44 | if( rc5_time < PULSE_MIN ) // to short |
45 | tmp = 0; |
46 | |
47 | if( !tmp || rc5_time > PULSE_1_2 ){ // start or long pulse time |
48 | if( !(tmp & 0x4000) ) // not to many bits |
49 | tmp <<= 1; // shift |
50 | if( !(rc5_bit & 1<<xRC5) ) // inverted bit |
51 | tmp |= 1; // insert new bit |
52 | rc5_time = 0; // count next pulse time |
53 | }
|
54 | }
|
55 | if(++pause_ticks > PAUSE_MIN){ // Zeit für Wiederholsequenz überschritten |
56 | rc5_pause = 1; // pause erkannt |
57 | pause_ticks = PAUSE_MIN+1; // Überlauf verhindern |
58 | }
|
59 | else rc5_pause=0; |
60 | |
61 | rc5_tmp = tmp; |
62 | }
|
und in der Hauptschleifewerte ich dass dannso aus:
1 | for(;;){ // main loop |
2 | cli(); |
3 | i = rc5_data;// in rc5_data ist immer die letzte IR-Sequenz decodiert |
4 | sei(); |
5 | if(i && rc5_pause){ |
6 | do_cmd(i,0); //kurzer Tastendruck |
7 | rc5_data=0; |
8 | }
|
9 | |
10 | if(i && (repeat_counter>4)){ |
11 | do_cmd(i,1); // Langer Tastendruck |
12 | rc5_data=0; |
13 | }
|
14 | }
|
Noch ein Hinweis: Viele der billigen China-Universalfernbedienungen implementieren das RC5-Protokoll leider nicht richtig, d.h. sie wechseln bei jeder gesendeten Sequenz das Togglebit, unabhängig davon ob die Taste nun losgelassen wurde oder nicht. btw, das Verhalten Deiner Fernbedienung ist vollkommen normal und richtig so. Sie muss das Kommando öfter senden, schliesslich muss ja sichergestellt sein dass es auch ankommt.
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.