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 = 1Bithttp://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
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.