Forum: Mikrocontroller und Digitale Elektronik RC5: Taste nur einmal drücken


von Michael H. (Gast)


Lesenswert?

Hallo

Ich verwende hier die bekannte Routine rc5.c mit der über normale 
Fernbedienungen Werte in den ATmega eingelesen werden können.
Das Funktioniert eigentlich auch perfekt.

Mein Problem ist, das ich nicht weis wie ich es hinbekomme jeden 
Tastendruck nur einmal auszulesen, egal wie lange ich die Taste drücke.

Hintergrund:
Ich möchte zunächst die Taste "PROGR" auf der Fernbedienung drücken 
(Code 41) und erst danach eine dreistelige Zahl in eine Variable 
eingeben, sagen wir der Einfachheit 111 (jeweils Code 1)

Leider bleibt es aber nicht bei einer Ziffer wenn ich die Taste einen 
Moment zu lange gedrückt halte. Es ist vielleicht vergleichbar als wenn 
eine Taste prellt.

Wie kann ich das hinbekommen, hat vielleicht jemand eine Idee?

Hier ein Teil des Codes wie ich es bisher habe. Ich habe der Einfacheit 
mal nur den Check auf Taste "1" angegeben:
1
taste=0;
2
taste_nr=0;
3
wert=0;
4
5
//Main
6
while(1){ 
7
  
8
  /* Gibt's was Neues an RC5? */
9
  if (-1 == rc5.flip){         
10
    //zur Zeit nichts zu tun      
11
  }     
12
  else     
13
  {
14
    // Auswertung des Codes wenn Fernbedienung gedrückt
15
        
16
    uint8_t code = rc5.code;
17
    uint8_t addr = rc5.addr; 
18
19
20
     //PROGR Taste gedrückt
21
     if (code == 41){ 
22
       taste_nr = 0; 
23
       wert = 0;
24
       taste = 41; //merken das PROGR gedrückt war
25
     }        
26
 
27
     // taste "1"
28
     if ((code == 1) && (taste == 41)){
29
       taste_nr++;  
30
       //erste Stelle Hunderter      
31
       if (taste_nr == 1) wert = wert + 100;
32
      //zweite Stelle Zehner
33
       if (taste_nr == 2) wert = wert + 10;
34
      //dritte Stelle Einer
35
       if (taste_nr == 3) wert = wert + 1;   
36
     }  
37
38
      
39
    //Wert auf Display ausgeben
40
    itoa ( wert, int_buffer, 10);
41
    set_cursor(1,2);
42
    lcd_string("Wert: ");
43
    lcd_string(int_buffer);        
44
      
45
    //Empfänger bleibt inaktiv, bis rc5.flip auf -1 gesetzt wird !
46
    //RC5 Empfänger darf nächste Taste empfangen
47
    rc5.flip = -1; 
48
        
49
        
50
  } //else rc5.code     
51
} //while

von Karl H. (kbuchegg)


Lesenswert?

Michael H. schrieb:
> Hallo
>
> Ich verwende hier die bekannte Routine rc5.c

Welcher Code soll das sein.
Gib doch mal einen Link oder hänge die Files als Attachment an.

von Karl H. (kbuchegg)


Lesenswert?

AUs wikipedia
1
* Einem Start-Bit, das immer logisch 1 ist und es dem Empfänger erlaubt,
2
  die korrekte Verstärkung für die nachfolgenden Datenbits zu wählen.
3
* Einem Field-Bit, das verwendet wird, um zwischen einem unteren
4
  Kommandobereich mit einem Wertebereich von 0 bis 63 und einem oberen
5
  Kommandobereich mit einem Wertebereich von 64 bis 127 zu unterscheiden.
6
* Einem Steuerbit, das bei jedem Tastendruck auf der Fernbedienung seinen
7
  Zustand wechselt. Damit kann zwischen dem permanenten gedrückt Halten
8
  einer Taste und dem wiederholten Drücken und Loslassen unterschieden 
9
  werden.

letzters, das Steuerbit, ist genau der Dreh und Angelpunkt mit dem du 
dein Problem lösen kannst. Leider kann ich dir nicht mehr helfen, da ich 
nicht weiß, auf welche Routinen du dich eigentlich beziehst.

Eventuell könnte es das hier sein
1
  /* Gibt's was Neues an RC5? */
2
  if (-1 == rc5.flip){         
3
    //zur Zeit nichts zu tun      
4
  }
aber dann müsste die Auswertung anders aussehen. Entscheidend ist nicht 
ein spezifischer Wert, sondern dss sich dieses Bit im Vergleich zur 
letzten gemeldeten Tasten verändert hat. Erst dann hast du die 
Gewissheit, dass die Taste tatsächlich nieder gedrückt wurde und nicht 
einfach nur der Benutzer auf der Taste eingeschlafen ist und der Sender 
auf Autorepeat umgeschaltet hat und denselben Tastendruck wieder und 
immer wieder sendet.

: Bearbeitet durch User
von Achim S. (Gast)


Lesenswert?

die Fernbedienung sendet den selben Code immer wieder, solange du die 
Taste gedrückt hältst. Um zu unterscheiden, ob die selbe Taste zwei mal 
gedrückt wurde oder ob sie lange gedrückt wird gibt es das sog. 
Togglebit im RC5-Code. Das wechselt jedesmal den Pegel, wenn die Taste 
neu gedrückt wird.

http://www.sprut.de/electronic/ir/rc5.htm#2

Wenn du also mehrmals hintereinander das selbe Zeichen empfängst und das 
Togglebit hat immer den gleichen Wert, dann wird die Taste dauerhaft 
gedrückt (d.h. Wiederholungen müssen ignoriert werden).

Wenn du mehrmals hintereinander das selbe Zeichen empfängst und das 
Togglebit wechselt jedesmal den Zustand, dann wurde die Taste immer 
wieder neu gedrückt (und die Wiederholungen des Zeichens dürfen nicht 
ingoriert werden).

von Michael H. (Gast)


Angehängte Dateien:

Lesenswert?

Hallo

Danke an alle für den Input!
Ich habe hier die rc5 Programmteile die ich verwende als Anhang 
drangehängt. Ich glaube die waren von Peter Danneberger (?) und hier im 
Forum.

Ich dachte wirklich ich hätte die Beschreibungen von Euch wie das mit 
dem rc5.flip funktioniert verstanden und mir zu Verdeutlichung das 
Programm so umgestrickt das ich erst einmal "sehen" kann wie sich der 
Wert verändert.

Die Ausgabe auf dem Display ist aber anders als von mir erwartet:
Nach Programmstart wird erst einmal nichts auf dem Display angezeigt, 
das ist ja soweit ok.
Wenn ich jetzt eine Taste auf der Fernbedienung drücke, bleibt sie immer 
auf 1 oder 0 bis ich das Gerät ausschalte. Da ändert sich nichts mehr, 
egal ob ich auf der Fernbedienung eine Taste kurz, lang oder garnicht 
drücke.


So wollte ich das testen:
1
while(1){ 
2
  
3
  code = rc5.code;
4
  addr = rc5.addr;  //wird hier nicht verwendet
5
    
6
    
7
  //rc5.flip hat sich auf -1 geändert
8
  if ((rc5.flip != flip) && (rc5.flip == -1)) {
9
    lcd_string("-1"); //Ausgeben
10
    flip = rc5.flip;  //Wert merken
11
    }
12
    
13
  //rc5.flip hat sich auf 0 geändert
14
  if ((rc5.flip != flip) && (rc5.flip == 0 )) {
15
    lcd_string("0");  //Ausgeben
16
    flip = rc5.flip;  //Wert merken
17
    }
18
19
  //rc5.flip hat sich auf 1 geändert
20
  if ((rc5.flip != flip) && (rc5.flip == 1 )) {
21
    lcd_string("1");  //Ausgeben
22
    flip = rc5.flip;  //Wert merken
23
    }  
24
  
25
} //while

von Michael H. (Gast)


Lesenswert?

Ich denke ich hab´s jetzt. Der Code sieht zwar nicht schön aus,
aber vielleicht hat ja jemand die gleichen Probleme und kann
dann darauf aufbauen.

Danke noch mal für die Unterstützung!
1
flip_alt = -1;
2
  
3
while(1){ 
4
  
5
6
  flip_aktuell = rc5.flip;
7
    
8
  if ((flip_aktuell != -1) && (flip_aktuell == 0) && (flip_alt == flip_aktuell)){
9
          
10
    //flip war vorher 0 und ist jetzt 0
11
    //->es wird immer noch die gleiche Taste gedrückt
12
    rc5.flip = -1;
13
          
14
  }
15
    
16
  if ((flip_aktuell != -1) && (flip_aktuell == 0) && (flip_alt != flip_aktuell)){
17
    
18
    //flip war vorher 1 und ist jetzt 0
19
    //->es wird eine andere Taste gedrückt
20
    flip_alt = flip_aktuell;
21
    rc5.flip = -1;
22
      
23
    //Anzeigen welche Taste gedrückt wird
24
    code = rc5.code;
25
    itoa ( code, int_buffer, 10);
26
    lcd_string(int_buffer);
27
  }
28
    
29
  if ((flip_aktuell != -1) && (flip_aktuell == 1) && (flip_alt == flip_aktuell)){
30
    
31
    //flip war vorher 1 und ist jetzt 1
32
    //->es wird immer noch die gleiche Taste gedrückt
33
    rc5.flip = -1; 
34
          
35
  }    
36
    
37
  if ((flip_aktuell != -1) && (flip_aktuell == 1) && (flip_alt != flip_aktuell)){
38
    
39
    // flip war vorher 1 und ist jetzt 0
40
    //->es wird eine andere Taste gedrückt
41
    flip_alt = flip_aktuell;
42
    rc5.flip = -1;
43
      
44
    //Anzeigen welche Taste gedrückt wird
45
    code = rc5.code;
46
    itoa ( code, int_buffer, 10);
47
    lcd_string(int_buffer);
48
  }        
49
50
} //while

von Karl H. (kbuchegg)


Lesenswert?

Michael H. schrieb:

>   if ((flip_aktuell != -1) && (flip_aktuell == 0) && (flip_alt ==
> flip_aktuell)){


Wenn flip_aktuell 0 sein MUSS (damit die Bedingung in ihrer Gesamtheit 
überhaupt jemals wahr sein kann), dann ist damit automatisch klar, dass 
flip_aktuell nichtg -1 sein kann. Denn es ist ja 0.

Selbiges für die restlichen Abfragen.


Es ist kein Verbrechen, wenn man if ineinander schachtelt.
Welche Fälle hast du?

Zuallerst mal un dam wichtigsten: unterscheiden sich die beiden?

Denn wenn sie es nicht tun, dann setzt du rc5.flip auf -1. Dieses auf -1 
setzen soll verhindern, dass du denselben Code weiterhin auswertest. Es 
ist quasi dein: hab ich schon bearbeitet
1
   flip_aktuell = rc5.flip;
2
3
   if( flip_aktuell != -1 )     // gibt es überhaupt was zu tun
4
   {
5
     if( flip_aktuell != flip_alt )    // ist es ein neuer tastendruck
6
     {
7
       flip_alt = flip_aktuell;
8
       rc5.flip = -1;
9
      
10
       //Anzeigen welche Taste gedrückt wird
11
       code = rc5.code;
12
       itoa ( code, int_buffer, 10);
13
       lcd_string(int_buffer);
14
     }
15
   }

von der Logik her müsste das völlig gleichwertig zu deinem sein. Nur 
kürzer.

von W.S. (Gast)


Lesenswert?

Es ist schon seltsam, wir sind wieder mal beim Entprellen. Das scheint 
ein EWIGES Thema hier zu sein.

Eigentlich gibt fast jede Fernbedienung beim Drücken einer Taste eine 
Salve von Codes aus, die dazu gedacht sind, bei eventuellem Fehlempfang 
die Sache innerhalb von ca. 20 ms korrigieren zu können.

Deshalb:
Den Empfang von der Fernbedienung muß man softwareseitig entprellen, 
indem man aus einer hinreichend großen zeitlichen Lücke zwischen den 
Codes (oder aus einem echten Codewechsel) erkennt, daß die taste wieder 
losgelassen wurde.

Im allereinfachsten Falle macht man es so, daß man nach Empfang eines 
Codes genau diesen Code erstmal von jeglicher Weiterverarbeitung 
ausschließt (falls er nochmal kommt), solange bis er mindestens 70..150 
ms lang nicht wieder erscheint. Erst dann darf man ihn wieder 
erlauben. Sowas ist am besten in dm System-Tick-Interrupt angesiedelt.
Das hohe C wäre natürlich, mit ner umschaltbaren Repetierzeit-Schwelle 
zu arbeiten, aber zumeist braucht man diesen Komfort nicht wirklich.

W.S.

von Michael H. (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> von der Logik her müsste das völlig gleichwertig zu deinem sein. Nur
> kürzer.

Du hast natürlich Recht.

Ich bis nur seit 2 Tagen dabei im Code rumzuwurschteln nach dem Motto 2 
Schritte vor und 3 zurück.
Bis ich vorhin alles weggeworfen habe und stur und ohne Abkürzung alle 
Bedingungen zusammengefaßt habe die möglich sind.
Klar das der Code jetzt noch aufgeräumt und verkürzt werden muß. Ich bin 
nur froh das es bis dahin funktioniert :)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

W.S. schrieb:
> Es ist schon seltsam, wir sind wieder mal beim Entprellen. Das scheint
> ein EWIGES Thema hier zu sein.

Das "Entprellen" von Fernbedienungen hat nur entfernt mit dem Entprellen 
von Tasten zu tun.

> Eigentlich gibt fast jede Fernbedienung beim Drücken einer Taste eine
> Salve von Codes aus, die dazu gedacht sind, bei eventuellem Fehlempfang
> die Sache innerhalb von ca. 20 ms korrigieren zu können.

Fast korrekt: Die meisten FBs machen eine Pause von ca. 40 bis 50 ms 
zwischen den Frames - einige sogar noch etwas mehr. Siehe auch

  http://www.mikrocontroller.net/articles/IRMP#Die_IR-Protokolle_im_Detail

> Deshalb:
> Den Empfang von der Fernbedienung muß man softwareseitig entprellen,
> indem man aus einer hinreichend großen zeitlichen Lücke zwischen den
> Codes (oder aus einem echten Codewechsel) erkennt, daß die taste wieder
> losgelassen wurde.

Das wäre auf jeden Fall die sinnvollste Methode, denn die meisten 
FB-Protokolle sehen ein Toggle-Bit als Hilfestellung (für genau den Fall 
"langer/kurzer Tastendruck") gar nicht vor. Aber das Ignorieren von 
Frames über einen gewissen zeitlichen Bereich ist nicht immer sinnvoll - 
schon gar nicht das Warten auf das Loslassen der Taste. Beim Regeln 
einer Lautstärke wärest Du mit dieser Methode jedenfalls ziemlich 
gekniffen.

IRMP erkennt (protokollunabhängig) an den Pausen zwischen den 
Frames, ob es sich um einen langen Tastendruck oder um mehrere kurze 
Tastendrücke handelt und setzt ein entsprechenendes Repetition-Flag zur 
Unterscheidung. Dies kann die Anwendung abfragen und selbst entscheiden: 
Entweder "Entprellung" für z.B. eine numerische Taste 0-9 (d.h. der User 
muss die Taste erst wieder loslassen, bevor er sie neu senden kann), 
oder kontinuierliches Interpretieren - z.B. für Lautstärkeregelung oder 
Faden von LEDs.

> Im allereinfachsten Falle macht man es so, daß man nach Empfang eines
> Codes genau diesen Code erstmal von jeglicher Weiterverarbeitung
> ausschließt (falls er nochmal kommt), solange bis er mindestens 70..150
> ms lang nicht wieder erscheint.

Auch diese ganze Arbeit nimmt IRMP dem Programmierer vollkommen ab. 
Er bekommt Protokoll, Geräteadresse, Kommando und (Repetition-)Flag - 
fertig.

@TO: RC5 (und damit das Toggle-Bit) ist längst ausgestorben. Auch wenn 
Peters RC5-Decoder schön klein und elegant ist, wäre eine Lektüre des 
IRMP-Artikels zumindest sinnvoll. ;-)

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.