Forum: Mikrocontroller und Digitale Elektronik Hilferuf - RC5 - kurzer / langer Tastendruck


von Alex (Gast)


Lesenswert?

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.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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".

von Alex (Gast)


Lesenswert?

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...

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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?

von Alex (Gast)


Lesenswert?

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
  }

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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.

von Alex (Gast)


Lesenswert?

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
}

von Christian T. (shuzz)


Lesenswert?

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
Noch kein Account? Hier anmelden.