Hallo zusammen, ich habe ein KEIL Board MCB2300 mit LPC2378 und würde gern ankommende IR-Signale von einer Fernbedienung mittels TSOP empfangen und auswerten. Leider schaffe ich es nicht den Empfänger(MCB2300) mit den Pulsen von der FB zu synchronisieren. Die Details und Signalzeiten wären: -JVC FB für Hifianlage (RM-RXUV9RMD) -Startbit = 8,4ms -Pause = 4,2ms -Gerätecode = 8Bit -Kommandocode = 8Bit -Stopbit = 1Bit -Gesamtdauer inkl. Startbit, Pause und Stopbit = 58,98ms (einmalig) -Gesamtdauer exkl. Startbit und Pause = 46,33ms (wiederholend) Ich hatte einfach eine Abtastung ab Drücken einer Taste veranlasst und bei einem gewissen Abtastintervall den Inputwert vom IR EMpfänger ausgelesen. Eine Unterscheidung zweier Tasten würde mir reichen. Doch die Sache "rutscht" einfach durch. Es wird nicht synchron mit dem FB-Signal. Wie kann man soetwas angehen? Geschrieben wird in c.
Thomas Mönig schrieb: > Hallo zusammen, > ich habe ein KEIL Board MCB2300 mit LPC2378 und würde gern ankommende > IR-Signale von einer Fernbedienung mittels TSOP empfangen und auswerten. Schau Dir den Artikel mal an: http://www.mikrocontroller.net/articles/IRMP Die eingesetzte Software läuft auf PICs und AVRs, die Anpassung an anderes µCs ist minimal und gekapselt. Wie wärs mit einer Portierung auf LPC2378? > Die Details und Signalzeiten wären: > -Startbit = 8,4ms > -Pause = 4,2ms > -Gerätecode = 8Bit > -Kommandocode = 8Bit > -Stopbit = 1Bit http://www.mikrocontroller.net/articles/IRMP#Die_IR-Protokolle_im_Detail gibt für das JVC-Protokoll etwas abweichende Werte an - sowohl vom Timing als auch vom Verhältnis der Geräte-/Kommando-Bits.
Danke erstmal für die Hinweise. Du hast Recht, das Geräte/Kommandobits Verhältnis ist 4/12 nicht 8/8. Eine Portierung auf den LPC2378 wäre sicherlich interessant, doch leider weiss ich gar nicht recht wo ich da anfangen soll. Würde mich aber, wenn wieder mehr Zeit ist, gern damit beschäftigen. Da mir allerdings gerade die Zeit wegläuft habe ich erst einmal ein paar Verständnisfragen die Du evtl. beantworten kannst: -Ist eine Abtastung des TSOP-Outputs mit 1ms sinnvoll oder sollte man lieber mit 100µs den Pegel abfragen? -Ich bekomme das empfangene Signal nicht synchronisiert, daher habe ich eine wandernde Abtastung und somit nur Müll. -Kennst Du eine einfache Methode zur Synchronisation des Empfängers mit der FB? Evtl. einen zweiten Timer beim Empfang des Startbits einschalten? Ich hatte ganz simpel die Gesamtzeiten gemessen, durch die Frequenz der Abtastung geteilt und dann gesagt: Ok hier ist Abtastung 15, wenn da eine 1 ist dann... und so weiter. Aber ohne Sync keine Chance. Aber ich schaue jetzt schon so lange auf den c-code und sehe den Wald nicht mehr. Müsste doch machbar sein zu sagen, wenn der Pegel 1 über mehr als 6 Abtsatungen anliegt dann ist dass das Startbit... Aber anscheinend ist es nicht ganz so simpel. Gruß Tom
Thomas Mönig schrieb: > -Ist eine Abtastung des TSOP-Outputs mit 1ms sinnvoll oder sollte man > lieber mit 100µs den Pegel abfragen? 1ms ist auf jeden Fall zu lang, denn die eigentlichen Datenbits sind ja wesentlich kürzer. Auszug aus der Tabelle im IRMP-Artikel für JVC: Start-Bit 9000µs Puls, 4500µs Pause, 6000µs Pause bei Tasten- Wiederholung 0-Bit 560µs Puls, 560µs Pause 1-Bit 560µs Puls, 1690µs Pause Stop-Bit 560µs Puls IRMP pollt den TSOP mit 10kHz (oder in den neueren SVN-Versionen sogar mit 15kHz), das entspricht einer Abtastrate von 100µs. Damit sollte es bei JVC auf jeden Fall gehen. Du solltest dann "sehen" - ca. 80-100 mal Puls beim Startbit - ca. 40-60 mal Pause beim Startbit - ca. 4-7 mal Puls beim Datenbit 0 - ca. 4-7 mal Pause beim Datenbit 0 - ca. 4-7 mal Puls beim Datenbit 1 - ca. 14-20 mal Pause beim Datenbit 1 Da die Fernbedienungen von den dokumentierten Timing-Werten unter Umständen bis zu 40% abweichen können, solltest Du die obigen Minimum-Maximum-Werte abfragen, um damit dann die Bitfolge aus dem Frame zu ermitteln. Wichtig wäre noch: JVC sendet LSB first. > -Ich bekomme das empfangene Signal nicht synchronisiert, daher habe ich > eine wandernde Abtastung und somit nur Müll. Bei 1ms kannst Du die eigentlichen Datenbits auch gar nicht abtasten, diese sind kürzer, siehe oben. > -Kennst Du eine einfache Methode zur Synchronisation des Empfängers mit > der FB? Evtl. einen zweiten Timer beim Empfang des Startbits > einschalten? Achso, Du denkst, das wäre ein bitserielles Protokoll? Nein, ist es nicht, denn bei IR-Fernbedienungen steckt in jedem Bit die Synchronisation ("Puls-Distance"), siehe auch entsprechenden Abschnitt im IRMP-Artikel: http://www.mikrocontroller.net/articles/IRMP#Protokolle Aber fangen wir von vorne an, dann wird das klarer: IRMP lässt einen 10kHz-Timer laufen und zählt die Pulse und die Pausen. Sind diese für das Startbit innerhalb der obigen Grenzen, "weiss" IRMP, dass es sich um das JVC-Protokoll handelt, stellt seine Timing-Tabellen auf die obigen Werte für die Datenbits um und zählt dann einfach die nachfolgenden Puls-/Pausenlängen. Da die meiste Zeit überhaupt kein Signal gesendet wird, belastet die ISR auch überhaupt nicht den Controller. Okay, man könnte es auch mit einem PIN-Change-Interrupt machen und die Zeiten zwischen den Interrupts "zählen". Das wäre etwas ressourcen-schonender. Aber die Polling-Methode ist halb so wild. > Ich hatte ganz simpel die Gesamtzeiten gemessen, durch die Frequenz der > Abtastung geteilt und dann gesagt: Ok hier ist Abtastung 15, wenn da > eine 1 ist dann... und so weiter. Aber ohne Sync keine Chance. Das ist auf jeden Fall die falsche Methode, denn die Bits sind unterschiedliche lang: Bit 0: 567µs Puls + 567µs Pause = 1134µs Länge Bit 1: 567µs Puls + 1690µs Pause = 2257µs Länge Hättest Du Dir den Link http://www.mikrocontroller.net/articles/IRMP#Die_IR-Protokolle_im_Detail aus meiner ersten Antwort auch mal angeschaut, hättest Du das direkt erkannt ;-) Der Sync steckt in jedem Datenbit. Für jedes(!) Bit kommt ja am Anfang ein Puls... und dann eine Pause. Nur die Pausen sind unterschiedlich lang, siehe oben. Anhand der Pausenlängen weisst Du dann, ob es eine 0 oder eine 1 ist. Dieses Verfahren nennt man Pulse-Distance-Protokoll und hat den Vorteil, dass es Dir im Timing gar nicht "davonlaufen" kann... eben weil jedes Bit im Frame auch gleichzeitig für den Empfänger zum Synchronisieren da ist. Alternativ zum Puls-Distance-Protokoll wird auch teilweise das Manchester-Protokoll ("Bi-Phase") genutzt. Auch hier kann bei jedem Bit neu synchronisiert werden. > Aber ich schaue jetzt schon so lange auf den c-code und sehe den Wald > nicht mehr. Müsste doch machbar sein zu sagen, wenn der Pegel 1 über > mehr als 6 Abtsatungen anliegt dann ist dass das Startbit... Aber > anscheinend ist es nicht ganz so simpel. Vielleicht schaust Du Dir einfach mal den IRMP-Artikel näher an, denn da steht auch jede Menge an geballter Info zu den IR-Protokollen drin. Allein das Zusammensuchen/Ermitteln der Eckwerte für die mittlerweile über 30 IR-Protokolle, die IRMP "versteht", hat mich insgesamt fast mehr Zeit als das eigentliche Programmieren gekostet ;-) Manchmal ist ein wenig Studium der Theorie vor der eigentlichen Programmiererei gar nicht so unsinnig....
Hallo Frank, ich habe mir jetzt so einiges durchgelesen. Ich denke das mit der Bitsync ist mir jetzt klarer. Beim IRMP ist doch das IR-Logging für die Routine da, die die Pulse einliest, die als Basis der ganzen Auswertung des IR-Signales dienen. Ich habe jetzt meinerseits versucht eine Routine zuschreiben, allerdingszugeschnitten auf meine verwendete JVC Fernbedienung. Mein Ansatz war jetzt die Bitsynchrionisation sowie die Tatsache dass der oben dargestellte Signalverlauf eingelesen und verarbeitet werden soll. Hierbei hatte ich folgende Überlegungen: Wenn die FB sendet kommt IMMER zuerst das Startbit gefolgt von 16 Datenbits und einem Stopbit. Dann die Burstpause und dann wieder 16 Daten plus Stopbit. Bekannt sind die zeitliche Länge des Starbits mit Puls- und Pausenzeiten sowie die immer gleiche Pulsdauer der Daten- und Stopbits. Da der Abstand der Bursts ebenfalls immer gleich ist, ergeben sich daraus eine minimale Burstpausendauer und eine maximale, da ja die Einsen und Nullen unterschiedliche Pausenzeiten haben. Der Timer steht auf 100µs(also 10000mal/pro sek) und durchläuft mit dieser Schrittzeit den folgenden Code. Meine Idee war erstmal dafür zu sorgen, dass solange der Eingangspegel vom IR-Empfänger 1 ist, eine Variable x auch 1 wird. Da aber ein Zähler dann bei jedem x=1 Wert zählen würde, musste eine Hilfsvariable a her, mit der eine Bedingung geschaffen wird, bei der nur gezählt wird wenn eine pos. oder neg. Flanke, das heisst ein Zustandswechsel 0->1 oder 1->0, kommt.
1 | if(x==1 && a==1){ //positive Flanke bei Betätigen der FB |
2 | a=0; |
3 | }
|
4 | |
5 | if(x==0 && a==0){ //negative Flanke bei Betätigen der FB |
6 | a=1; |
7 | |
8 | }
|
Ich kann doch jetzt beim ersten if mit c++ loslegen zu zählen. Ich weiß dass der Burst 17 steigende Flanken hat und zusätzlich noch die Flanke des Startbits, allerdings nur einmal. Also starte ich c bei -1, wenn die erste steigende Flanke des Startbits kommt ist p=0 und wenn der Datenblock anfängt ist c=1. Wenn c den Wert 17 überschreitet, lasse ich c zu 1 werden und die Zählung beginnt von vorn beim ersten Datenbit. damit habe ich eine Variable die mir jeden empfangenen Puls indexiert, damit ich genau weiß wo ich bin wenn ich dann anschliessend die Länge der Pulse inkl. Pausen messen muss, um sagen zu können ob bei Puls(n) eine log. 1 oder 0 kommt. Nun dachte ich, man könnte sagen: wenn c gleich 1 ist, zähle im 0,1ms Takt. Wenn c zu 2 wird speichere den gezählten Wert in einer Variable "takt" ab und setze den Zähler wieder auf 0. Damit würde ich doch das erste Datenbit auslesen und müsste immer denselben wert erhalten und zwar 21-22 für eine 1 oder 10-11 für eine 0.
1 | |
2 | if(x==1 && a==1){ //positive Flanke bei Betätigen der FB |
3 | a=0; |
4 | c++; //c ist die Variable für den Pulszähler Schrittzeit 0,1ms |
5 | t=0; |
6 | s=1; |
7 | }
|
8 | //--------------------------------------------------------------------------------------------------------------------------------------------------------------
|
9 | if(x==0 && a==0){ //negative Flanke bei Betätigen der FB |
10 | a=1; |
11 | }
|
12 | //--------------------------------------------------------------------------------------------------------------------------------------------------------------
|
13 | if(c>17){ //mit c werden die Pulse vom ersten bis zum letzten in einem Burst gezählt |
14 | b++; //Da ein Burst 17 Pulse hat, wird b nach 17 Pulsen um 1 erhöht und gibt somit die gesendete Burstanzahl an |
15 | c=1; |
16 | }
|
17 | //--------------------------------------------------------------------------------------------------------------------------------------------------------------
|
18 | if(s==1){ //Schalter s für das Starten der Zähler |
19 | t++; |
20 | if(c==1){ //Beispiel: Taktzählung bei Puls Nr.1 |
21 | r++; |
22 | }
|
23 | if(c==2){ |
24 | takte=r; //speichert die gezählte Taktzahl für eine Puls-Pausenzeit in -takte- ab wenn der zweite Puls errreicht ist |
25 | r=0; |
26 | }
|
27 | if(t>=300){ //Bedingung zum Zurücksetzten der Zähler wenn Taste losgelassen wird |
28 | t=0; //Taktzähler wird bei Loslassen einer FB Taste auf 0 gesetzt |
29 | b=0; //Burstzähler wird zurückgesetzt wenn keine Taste betätigt wird |
30 | s=0; //Schalter s wird auf Off geschaltet wenn über 300 Takte ohne Puls vergangen sind |
31 | p=0; //Pulszähler p nach Loslassen einer Taste = 0 |
32 | }
|
33 | }
|
Doch leider haut das nicht so recht hin. Die Werte nehmen entweder 0, 11, 21 oder 208 an, schnell durchlaufend. Es sieht so aus als würde der Zähler nicht fest die erste Puls-Pausezeit zählen, sondern durch die Datenbits inkl. der Burstpause laufen, das kann aber eigentlich nicht sein. Ich weiß nicht warum dort nicht der korrekte Wert für beispielsweise das erste Datenbit ausgegeben wird... Grüße T.M.
Thomas Mönig schrieb: > Beim IRMP ist doch das IR-Logging für die Routine da, die die Pulse > einliest, die als Basis der ganzen Auswertung des IR-Signales dienen. Das IR-Logging wird von IRMP nicht benötigt, normalerweise ist das im IRMP abgeschaltet. Ich benötige das nur, um unbekannte Protokolle zu scannen und anschließend zu analysieren. > Ich habe jetzt meinerseits versucht eine Routine zuschreiben, > allerdingszugeschnitten auf meine verwendete JVC Fernbedienung. In 3 Jahren wirst Du eine andere FB mit einem anderen Protokoll verwenden... aber ok, zum Lernen ist das ja richtig, sich mit einem konkreten Protokoll auseinanderzusetzen. > Wenn die FB sendet kommt IMMER zuerst das Startbit gefolgt von 16 > Datenbits und einem Stopbit. Korrekt. > Dann die Burstpause und dann wieder 16 Daten plus Stopbit. Ja. > Bekannt sind die zeitliche Länge des Starbits mit Puls- und Pausenzeiten > sowie die immer gleiche Pulsdauer der Daten- und Stopbits. Jepp. > Da der Abstand der Bursts ebenfalls immer gleich ist, ergeben sich > daraus eine minimale Burstpausendauer und eine maximale, da ja die > Einsen und Nullen unterschiedliche Pausenzeiten haben. Du meintest nicht "Abstand der Bursts", sondern "Dauer der Bursts", nicht wahr? Ja, dann stimmt es. Ich an Deiner Stelle würde es so machen: 1. Startbit-Pulsdauer zählen (Pin = 0) 2. Startbit-Pausendauer zählen (Pin = 1) 3. Passt Burst-/Pause zu JVC-Startbit? Nein, zurück zu 1 Ja, Weiter zu 4 4. Datenbit-Pulsdauer zählen 5. Datenbit-Pausendauer zählen 6. Passt Pulsdauer zu JVC-Datenbit? Nein, zurück zu 1 Ja, weiter zu 7 7. Passt Pausendauer zum Bit == 0? Nein, Passt Pausendauer zum Bit == 1? Nein, zurück zu 1 Ja, Bit == 1 speichern Ja, Bit == 0 speichern 8. 16 Bits eingelesen? 9. Nein, weiter bei 4 10. Ja, wir haben die 16 Bit, diese aufteilen in Adresse + Kommando > Der Timer steht auf 100µs(also 10000mal/pro sek) und durchläuft mit > dieser Schrittzeit den folgenden Code. Finde ich gut, Das macht IRMP genauso ;-) > Meine Idee war erstmal dafür zu sorgen, dass solange der Eingangspegel > vom IR-Empfänger 1 ist, eine Variable x auch 1 wird. Da aber ein Zähler > dann bei jedem x=1 Wert zählen würde, musste eine Hilfsvariable a her, > mit der eine Bedingung geschaffen wird, bei der nur gezählt wird wenn > eine pos. oder neg. Flanke, das heisst ein Zustandswechsel 0->1 oder > 1->0, kommt. Man muss halt die Pulse (0en) und die Pausen (1en) zählen und sich in einer Variablen den letzten Zustand merken. Also so: 1. Pin einlesen in Variable state 2. Ist state == 0, also Puls? Ja, ist state == last_state? Ja, dann pulsecounter++; Nein, Es gab eine Flanke 1->0! Pulse-/Pausenzählung fertig! Nein, dann pausecounter++ last_state initialisiert man mit 1. > [Jede Menge C-Code...] Tut mir leid, ich habe versucht, durch Deinen Code durchzusteigen, aber Deine nichtssagenden Variablennamen a, x, t, c, r machen es mir unmöglich, Deinen Gedankengängen über mehrere Zeilen zu folgen. Zerlege die Aufgabenstellung in kleine Module und setze jedes einzeln um, als da wären: A. Ein "Paar" Pulsdauer + Pausendauer erkennen. B. Startbit anhand A) erkennen C. Datenbit anhand A) erkennen D. Speichern der Bits E. Aufteilung in Adresse und Kommando Ein weiteres Problem ist, dass dieses alles in einer ISR abläuft. Diese muss man als Statemachine konzipieren, um ein IR-Telegramm einzulesen. Dazu muss man sich merken: 1. Bin ich ganz am Anfang, also bei der Startbit-Erkennung? 2. Bin ich in einer Pulszählung? 3. Bin ich in einer Pausenzählung? 4. Liegt eine Flanke 1->0 vor, habe ich also ein Bit (Puls-/Pausenpaar) zusammen, das ich speichern kann? 5. Habe ich alle 16 bits eingelesen, habe ich also gerade die Flanke des Stop-Bits erwischt? Die Flanke 0->1 interessiert übrigens nicht, da ist keine "Action" nötig. Das gilt jedenfalls bei der Familie der Pulse-Distance-Protokolle. Bei Manchester-Codierungen (RC5, RC6 und anderen) sieht das wieder ganz anders aus.... Viel Glück und viel Spaß beim Programmieren! Frank P.S. Gewöhne Dir bitte längere und aussagekräftigere Variablennamen an, sonst steigst Du später (schon nach einigen Wochen) nicht mehr durch Deinen eigenen Code durch ;-)
Noch ein Tipp: Schau Dir mal den Quellcode von sndrx.c aus dem SOUNDRX-Programmpaket an. Da findest Du eine ganz einfache ISR vor, die genau das oben beschriebene innerhalb von 200 Codezeilen macht. Der einzige Unterschied ist, dass hier nur 8 Bit statt 16 Bit eingelesen werden. Da muss der Datentyp einer Variablen auf uint16_t statt uint8_t erweitert und eine Bedingung (8 -> 16) abgeändert werden. Ausserdem ist da noch ein Ringpuffer enthalten, da bei einer Soundkarten-Datenübertragung die Signale wesentlich flotter reinkommen als bei einer Infrarot-FB. Der Ringbuffer kann natürlich für Deine Zwecke raus. Aber sonst ist diese ISR 1:1 für Deine Zwecke adaptierbar. Die Preprozessor-Konstanten, die die Puls-/Pausenlängen für Start- und Datenbits beschreiben, müssten natürlich an diejenigen Deiner FB angepasst werden... Link: http://www.mikrocontroller.net/articles/SOUNDRX Natürlich kannst Du das auch alles selbst schreiben, sonst könntest Du ja auch direkt IRMP nehmen, welches ja als Programmbibliothek gedacht ist. Zum Studium, wie mans macht, ist es auf keinen Fall verkehrt, in die SOUNDRX-ISR mal reinzuschauen.
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.