Die Firmware

Hier will ich in nächster noch Informationen reinstellen, die beschreiben wie ich die einzelnen Dinge im PIC gelöst habe und den Aufbau des Kommunikationsprotokolls, für Leute die Y.A.R.D. etwas besser verstehen wollen.
bis dahin gibt es hier erstmal die aktuelle Firmware als compiliertes Hex File und als durchgängig kommentierter Assembler Quellcode, welcher sich mit der kostenlosen MicroLab IDE von Microchip kompilieren läßt.

Aktuelle Firmware hier Downloaden (src+hex)

Das serielle Protokoll

Beschreibung der Datenpakete welche zwischen der Y.A.R.D. Clientsoftware und der Hardware (Mikrocontroller) ausgetauscht werden.

Prinzipieller Aufbau eines Datenpakets

Die Y.A.R.D. Hardware kann zwei Arten von Befehlen empfangen sogenannte Befehle.

Prinzipieller Aufbau eine Multibyte Befehls

Offset Name Beschreibung
0 Commandcode Nr. des Befehlscodes, in den Bits 0-5 steckt der Befehlscode,
Bit 6: gerade Parität über die Bits 0-5
Bit 7: immer 1 als Indikator für Commandbyte
Gültige Commandcodes liegen zwischen 0x01 und 0x37
1 Paketlength Länge des Datenpaketes inkl. Prüfsumme! (aber ohne Commandcode und die Längenangabe!)
Bit 0 - 6 Länge als Wert zwischen 0 - 127
Bit 7: gerade Parität über die Bits 0 - 6
2..Paketlength Daten je nach Command die Parameter
letztes Byte Prüfsumme Wird Berechnet aus alle Bytes des Pakets, mit der Berücksichtigung folgender Ausnahmen:
vom Byte 0: werden nur die Bits 0-5 aufsummiert
vom Byte 1: werden nur die Bits 0-6 aufsummiert
die Datenbytes werden immer komplett aufsummiert
CheckSumme := (Datenpacket[0] and $3F) + (Datenpacket[1] and $7F) + (Datenpacket[2..n])

Y.A.R.D. antwortet immer mit einer Multibyte Responses, auch wenn eigentlich keine Daten zu übermitteln sind, das Längenbyte ist dann immer 1, d.h. das kürzeste Paket was Y.A.R.D. an den PC senden kann ist mindestens 3 Byte lang.

Prinzipieller Aufbau eines Singlebyte Befehls
Im Gegensatz zum Multibytebefehl kommen diese Befehle ohne Parameter aus
(Ich bezeichne diese Befehle auch gerne als Fire and Forget:-))

Offset Name Beschreibung
0 Commandcode Nr. des Befehlscodes, in den Bits 0-5 steckt der Befehlscode,
Bit 6: gerade Parität über die Bits 0-5
Bit 7: immer 1 als Indikator für Commandbyte
Gültige Commandcodes liegen zwischen 0x38 und 0x3F
1 Prüfsumme Wird Berechnet aus alle Bytes des Pakets, mit der Berücksichtigung folgender Ausnahmen:
vom Byte 0: werden nur die Bits 0-5 aufsummiert
CheckSumme := (Datenpacket[0] and $3F)

Die Singlebyte Befehle

CodeBeschreibungAntwort
0x39 GetTime liefert die aktuelle Uhrzeit der Pic-Uhr (+- einige ms die für die Kommunkikation verloren gehen) im Datenpaket steht in Form eines Integers die Zeit in Sekunden seit dem 01.01.2005
OffsetWertBeschreibung
0 0x39 Code
1 0x05 Länge
2 0x?? Bit 0-7
3 0x?? Bit 8-15
4 0x?? Bit 16-23
5 0x?? Bit 24-31
6 0x?? Checksumme
 
0x3A GetWakeupTime liefert die aktuelle eingestellte Weckzeit des PIC im Datenpaket steht in Form eines Integers die Zeit in Sekunden seit dem 01.01.2005
OffsetWertBeschreibung
0 0x3A Code
1 0x05 Länge
2 0x?? Bit 0-7
3 0x?? Bit 8-15
4 0x?? Bit 16-23
5 0x?? Bit 24-31
6 0x?? Checksumme
 
0x3B GetRebootReason liefert den Grund warum Y.A.R.D. den PC eingeschaltet hat
OffsetWertBeschreibung
0 0x3B Code
1 0x02 Länge
2 0x?? Rebootcodes
  • 0: Unknown, d.h. Power On z.B. via Powertaster, d.h. Y.A.R.D. kann nix dafür
  • 1: Power on Return, das PC wurde nach einem Stromausfall gestart, damit die Y.A.R.D. Clientsoftware die Uhr neu stellen kann
  • 2: Power on Timer, der PC wurde nach erreichen der Weckzeit gebootet
  • 3: der PC wurde mit der Fernbedienung eingeschaltet
  • 4: Power on Timer 2, der PC wurde nach erreichen der Weckzeit 2 gebootet
3 0x?? Checksumme
 
0x3C StartIrScanner (Promiscusmode) aktiviert den IR-Scanner, der die nächste Empfangene IR-Sequenz als Timing Meßwerte an den PC sendet, zum anlernen unbekannter FB für den Sendeteil von Y.A.R.D.. keine direkte Response - sondern eine Sequenz die durch eine Response
0x3C 0x01 0x3D - eingeleitet wird
danach folgenen immer Wortweise (16-bit) Messungen der H und L Zeiten des TSOP Ausganges, welche mit 1.6 Multipliziert die Zeit in Mikrosekunden ergibt.
das Ende diese Übertragung wird durch eine Sequence aus
0xFE 0xFE 0xFE 0xFE übertragen - danach endet der Promiscusmode automatisch.
 
0x3D ReadUserPort liefert den Status des Freien Einganges vom PIC
OffsetWertBeschreibung
0 0x3D Code
1 0x02 Länge
2 0x?? Status 0 oder 1 je nach Pegel am Eingang
3 0x?? Checksumme
 
 
0x3E Read Firmware Version
OffsetWertBeschreibung
0 0x3E Code
1 0x02 Länge
2 0x?? Versionsnummer zwischen 0 und 255
3 0x?? Checksumme
 

Die Multibyte Befehle

CodeParameterBeschreibung
0x01
OffsetWertBeschreibung
0 0x01 Code
1 0x05 Länge
2 0x?? Bit 0-7
3 0x?? Bit 8-15
4 0x?? Bit 16-23
5 0x?? Bit 24-31
6 0x?? Checksumme
SetTime: damit wird die Uhr des PIC gestellt, als Paramter wird ein Dword übergeben, welches die Sekunden seit dem 01.01.2005 enthält.
 
0x02
OffsetWertBeschreibung
0 0x02 Code
1 0x06 Länge
2 0x?? 0 oder 1 für Weckzeit 1 oder 2
3 0x?? Bit 0-7
4 0x?? Bit 8-15
5 0x?? Bit 16-23
6 0x?? Bit 24-31
7 0x?? Checksumme
SetWakeupTime: damit wird die Zeit eingestellt zu welcher der PC eingeschaltet werden soll, die Zeit ist ebenfalls in Sekunden seit dem 01.01.2005.
Achtung: die Funktion wurde überladen - d.h. es gibt intern ne 3. und 4. Weckzeit! Weckzeit 3: ist die Zeit zu der der Timer mit dem Wert aus Weckzeit 4 geladen wird? - wozu dass? - ganz einfach darüber kann die Y.A.R.D. Clientsoftware den nächste Zeitpunkt für Umschaltung Sommerzeit / Winterzeit einstellen...
 
Transmitter für das Standardprotokoll konfigurieren - dann wird das Datenpaket wie unten beschrieben geschnürt!
0x04
OffsetWertBeschreibung
0 0x04 Code
1 0x12 Länge
2 0x?? Modulationsfrequenz Parameter: x=round(2500/(f in khz))
3 0x?? ConfigByte
Bit0: Sende StartSequenz 2 mal für Recs80
Bit1: don't Cate
Bit2: UseStartBit
Bit3: UseStartPauseBit
Bit4: 1-Bit-First-Half: Active Output Signal?
Bit5: 1-Bit-Second-Half: Active Output Signal?
Bit6: 0-Bit-First-Half: Active Output Signal?
Bit7: 0-Bit-Second-Half: Active Output Signal?
4 0x?? Transmitteroutine selektieren:
0 - Standard Transmitter
1 - RCMM Transmitter
2 - ITT Nokia Transmitter
3 - RC6 Transmitter
5-6 0x???? 16-bit: Startbit Dauer = round(t in us / 1.6)
7-8 0x???? 16-bit: Startbitpause Dauer = round(t in us / 1.6)
9-10 0x???? 16-bit: Dauer erste Hälfte 1-Bit
11-12 0x???? 16-bit: Dauer zweite Hälfte 1-Bit
13-14 0x???? 16-bit: Dauer erste Hälfte 0-Bit
15-16 0x???? 16-bit: Dauer zweite Hälfte 0-Bit
17-18 0x???? Intermessage Pausedauer
19 0x???? Intermessage Pause nach diesem Bit, -1 oder 255 disabled die Funktion
20 0x?? Checksumme
SetupIrTransmitter: Bevor Y.A.R.D. einen IR-Befehl senden kann muß natürlich der Transmitter auf das jeweilige IR Protokoll konfiguriert werden, diese geschieht in diesem Command.
Hinweise die Zeitwerte berechnen sich nicht alle nach der Formel: 65536-round(t / 1.6us), da bei einigen Werte nach ein paar Takte dazugerechnet bzw. abgezogen werden müssen. (Das erklärt sich nur wenn man den Quellcode den PIC Programmes analysiert.)
 
Transmitter für RCMM konfigurieren - dann wird das Datenpaket wie unten beschrieben geschnürt!
0x04
OffsetWertBeschreibung
0 0x04 Code
1 0x12 Länge
2 0x?? Modulationsfrequenz Parameter: x=round(2500/(f in khz))
3 0x?? don't care set to zero
4 0x?? Transmitteroutine selektieren:
1 - RCMM Transmitter
5-6 0x???? 16-bit: Startbit Dauer = 65536-round(t in us / 1.6)
7-8 0x???? 16-bit: Startbitpause Dauer = 65536-round(t in us / 1.6)
9-10 0x???? 16-bit: Bit Startpulse Dauer
11-12 0x???? 16-bit: Dauer 00-Bit Pause
13-14 0x???? 16-bit: Dauer 01-Bit Pause
15-16 0x???? 16-bit: Dauer 10-Bit Pause
17-18 0x???? 16-bit: Dauer 11-Bit Pause
19 0x?? don't care
20 0x?? Checksumme
SetupIrTransmitter: Bevor Y.A.R.D. einen IR-Befehl senden kann muß natürlich der Transmitter auf das jeweilige IR Protokoll konfiguriert werden, diese geschieht in diesem Command.
Hinweise die Zeitwerte berechnen sich nicht alle nach der Formel: 65536-round(t / 1.6us), da bei einigen Werte nach ein paar Takte dazugerechnet bzw. abgezogen werden müssen. (Das erklärt sich nur wenn man den Quellcode den PIC Programmes analysiert.)
 
 
Transmitter für ITT-Nokia konfigurieren - dann wird das Datenpaket wie unten beschrieben geschnürt!
0x04
OffsetWertBeschreibung
0 0x04 Code
1 0x12 Länge
2 0x?? Modulationsfrequenz Parameter: x=round(2500/(f in khz))
3 0x?? don't care set to zero
4 0x?? Transmitteroutine selektieren:
2 - ITT Nokia Transmitter
5-6 0x???? 16-bit: StartPauseLength = 65536-round(t in us / 1.6)
7-8 0x???? 16-bit: StopPauseLengthStartbitpause Dauer = 65536-round(t in us / 1.6)
9-10 0x???? 16-bit: Bit1Pause
11-12 0x???? 16-bit: PulseLength Achtung: wird nach dieser Gleichung berechnet = round((FPulseLength-2.0)/1.2)+1
13-14 0x???? 16-bit: Bit0Pause
15-16 0x???? don't care 0
17-18 0x???? don't care 0
19 0x?? don't care
20 0x?? Checksumme
SetupIrTransmitter: Bevor Y.A.R.D. einen IR-Befehl senden kann muß natürlich der Transmitter auf das jeweilige IR Protokoll konfiguriert werden, diese geschieht in diesem Command.
Hinweise die Zeitwerte berechnen sich nicht alle nach der Formel: 65536-round(t / 1.6us), da bei einigen Werte nach ein paar Takte dazugerechnet bzw. abgezogen werden müssen. (Das erklärt sich nur wenn man den Quellcode den PIC Programmes analysiert.)
 
 
Transmitter für RC6 konfigurieren - dann wird das Datenpaket wie unten beschrieben geschnürt!
0x04
OffsetWertBeschreibung
0 0x04 Code
1 0x12 Länge
2 0x?? don't care set to zero
3 0x?? don't care set to zero
4 0x?? Transmitteroutine selektieren:
3 - RC6 Transmitter
5-6 0x???? 16-bit: StartPulseLength
7-8 0x???? 16-bit: StartPauseLength
9-10 0x???? 16-bit: TrailerBitLength
11-12 0x???? 16-bit: NormalBitLength
13-14 0x???? don't care 0
15 0x?? nach diesem Bit soll vom TrailerBitLength auf NormalBitLength gewechselt werden
16 0x?? don't care 0
17-18 0x???? don't care 0
19 0x?? don't care
20 0x?? Checksumme
SetupIrTransmitter: Bevor Y.A.R.D. einen IR-Befehl senden kann muß natürlich der Transmitter auf das jeweilige IR Protokoll konfiguriert werden, diese geschieht in diesem Command.
Hinweise die Zeitwerte berechnen sich nicht alle nach der Formel: 65536-round(t / 1.6us), da bei einigen Werte nach ein paar Takte dazugerechnet bzw. abgezogen werden müssen. (Das erklärt sich nur wenn man den Quellcode den PIC Programmes analysiert.)
 
0x05
OffsetWertBeschreibung
0 0x05 Code
1 0x09 Länge
2 0x?? Art des Codes
  • 0: IR-Code zum Einschalten des PC festlegen
  • 1: IR-Code zum Herunterfahren des PC festlegen
  • 2: IR-Code zum harten Ausschalten des PC festlegen
3-9 0x???? Ir-Code der zum Auslösen der Aktion empfangen werden muß
10 0x?? Checksumme
StoreIrCommand: speichert im EEprom des PIC die IR-Codes zum Einschalten/Herunterfahren und Ausschalten des PIC, um einen IR-Code zu löschen muß in den Bytes 3-9 der Wert 0 übergeben werden. (Diese Funktion ist auch die Hintertür zu den restlichen Speicherblöcken des EEproms - wo weitere Konfigurationsparameter versteckt liegen)
 
0x06
OffsetWertBeschreibung
0 0x06 Code
1 0x09 Länge
2 0x?? Anzahl der Datenbits die gesendet werden solle inkl. STOP bit! (sofern vorhanden!)
3-9 0x???? IR-Daten die gesendet werden sollen - Achtung: StopBit muß korrekt gesetzt sein!
10 0x?? Checksumme
SendIr: Sendet die angegebenen Daten als IR-Befehl aus, die Art und Weise wie die Bits in IR codiert werden, muß vorher durch einen SetupIrTransmitter Aufruf festgelegt wurden sein. Dieser Aufruf muß nur wiederholt werden, wenn das IR-Protokoll wechselt.
 
0x07
OffsetWertBeschreibung
0 0x07 Code
1 0x03 Länge
2 0x?? I2C Geräteadresse
3 0x?? Anzahl Bytes
4 0x?? Checksumme
Read I2C: liest Anzahl Bytes vom I2C Bus von dem angegeben I2C-Gerät, aber maximal 127 Byte
 
0x08
OffsetWertBeschreibung
0 0x08 Code
1 0x?? Länge
2 0x?? I2C Geräteadresse
3..x 0x?? ...Daten ...
? 0x?? Checksumme
Write I2C: schreibt Daten auf den I2C Bus das erste Byte im Datenpaket muß dabei die Adresse des I2C Gerätes sein, danach folgen die Daten welche geschrieben werden sollen, derzeit ist allerdings die Anzahl der Nutzdatenbytes auf 14 Byte limiert. (tja irgendwann geht selbst dem größten Pic der speicher aus;-))
Die Firmware wird nochmal geändert, dann kann ich die Anzahl der Nutzbytes auf ca. 32 erhöhen.
 

Y.A.R.D. Meldungen

Sind Antworten die Y.A.R.D. z.T. ohne eine Vorherige Aktion durch die API sendet oder Reaktionen auf Fehlerhafte Pakete etc.

CodeParameterBeschreibung
0x00
OffsetWertBeschreibung
0 0x00 Code
1 0x02 Länge
2 0x?? Fehlercode
3 0x?? Checksumme
Wird gesendet von Y.A.R.D., wenn ein ungültiges Datenpaket empfangen wurde.
  • 0x81 - Checksumme und Commandcode bei Singlebyte stimmen nicht überein
  • 0x82 - Invalid Command Byte - Bit 7 nicht gesetzt
  • 0x83 - Invalid Command Byte - Bit 6 Parität stimmt nicht
  • 0x84 - Invalid Length Byte - Bit 7 Parität stimmt nicht
  • 0x85 - Command Length größer als aktueller Buffer ;-)
  • 0x86 - Prüfsumme für den Command stimmt nicht
 
0x03
OffsetWertBeschreibung
0 0x03 Code
1 0x08 Länge
2 0x?? IR-Protocolcode
3 0x?? Bits 0-7
4 0x?? Bits 8-15
5 0x?? Bits 16-23
6 0x?? Bits 24-31
7 0x?? Bits 32-39
8 0x?? Bits 40-47
9 0x?? Checksumme
Wird gesendet von Y.A.R.D. wenn IR Daten von einem der direkt unterstützen Protokolle empfangen wurden.
als IR-Protocolcode werden folgende Werte geliefert:
  • 0x01 - RC5 z.B. Philipps, Marantz, Hauppauge u.s.w.
  • 0x02 - Sony Sircs 12-bit
  • 0x03 - Sony Sircs 15-bit
  • 0x04 - Sony Sircs 20-bit
  • 0x05 - Yamaha / NEC kodierter Code (32-bit)
  • 0x06 - Japancode (Panasonic) (48-bit)
  • 0x07 - Y.A.R.D. Event durch Pegelwechsel am Freien-IO-Port
Wenn Bits im Datenpaket nicht benötigt werden sind diese auf 0 gesetzt. Daher hat das Paket für alle Protokolle die gleiche Länge.
 


Die Uhr

Um auf einem Mikrocontroller eine Uhr zu programmieren muß man aus dem Takt mit welchem der uC angesteuert wird einen Sekundentakt gewinnen. Das klingt fürs erste ja noch relativ einfach - man teile einfach durch die Frequenz bei 10Mhz - nehme man einen Interrupt bei jedem Takt - und zähle ne Variable von 10 000 000 rückwärts - nur zu dumm das der uC damit etwas überfordert sein wird, da die gesamten Uhrenbrechnung sicherlich nicht innerhalb eines Taktes erfolgen kann.
Natürlich könnte man auch versuchen im Hauptprogramm des uC mit Warteschleifen 1 Sekunde abzuwarten und dann den Sekundenzähler zu erhöhen - dies würde aber ausschließen das der uC nebenbei noch andere sinnvolle Aufgaben übernimmt.

Aus diesem Grund bietet z.b. die uC von Microchip verschiedene Timer an - die mit einem in Hardware vorhanden Vorteiler die Frequenz - also das Auftreten der Interrupts deutlich reduzieren. So jetzt kommen wir zu den Timern des 16F628, der das Herz meiner Schaltung darstellt, dieser besitzt 3 Timer. Diese Timer unterscheiden sich in der Breite ihrer Zählvariablen, Möglichkeit der Vorteilung der Ausgangsfrequenz oder in der Möglichkeit den Zähler nur bis zu einem bestimmten Endwert zu erhöhen.

TimerEigenschaftenVerwendet für
Timer 0
  • 8-Bit Zählerbreite 0 .. 255
  • Vorteiler von 1:1 bis 1:256 möglich
Dieser Timer treibt die Y.A.R.D.-Uhr
Timer 1
  • 16-Bit Zählerbreite 0 .. 65536
  • Vorteiler von 1:1 bis 1:8 möglich
Dieser Timer wird von Y.A.R.D. verwendet um die Dauer von IR-Impulsen während der Dekodierung zu messen. Weiterhin findet er beim Senden von IR Befehlen Verwendung, um die Pulslänge zu steueren. Er eignete sich besonder dafür da man mit ihm relativ lange Zeitabstände messen kann ohne die Genauigkeit sehr weit reduzieren zu müssen.
Timer 2
  • 8-Bit Zählerbreite 0 .. 255
  • 8-Bit Endwert bei dem der Zähler wieder von vorne beginnt, z.B. kann man den Zähler von 0 - 100 laufen lassen.
  • Vorteiler von 1:1, 1:4 oder 1:16 möglich
Diesen Timer und das Pulseweiten Modulationsmodul verwendet Y.A.R.D. für die Modulation der ausgehenden IR Signale.

Damit man aus Timer 0 eine halbwegs brauchbare Uhr erhält sind einige mathematische Verrenkungen notwendig. Als Basisfrequenz wird der Timer mit einem 1/4 des PIC Taktes vorsorgt - im Falle von Y.A.R.D. sind dies 2,5 Mhz. Die genaueste Uhr würde man mit einem Vorteiler von 1:1 erhalten. - Ein sehr gute Erklärung warum das so ist findet Ihr bei Sprut (http://www.sprut.de/electronic/pic/programm/lcduhr/lcduhr.html) Diese Vorgehensweise bereitet mir aber in meinem PIC Probleme - da der PIC viel zu häufig (mehr als 9000 mal je sekunde) in seinem Arbeitsfluss unterbrochen wurde, um die Uhr zu akualisieren.

Aus diesem Grund habe ich den Vorteiler auf den höchst möglichen Wert erhöht - 1 : 256. Damit ergibt sich folgende Teilerkette
10Mhz : 4 : 256 => 9765,625 Hz - mit dieser Frequenz wird der Zähler erhöht. So wenn man den Zähler jetzt von 0 - 256 laufen lassen würde ergäbe das 38,14697265625 Hz für den Aufruf des Intterupts um daraus nen Sekundentakt abzuleiten - kann sich wohl jeder ausrechnen das das nichts wird.
Daher setze ich bei jedem Auftreten des Timer0 Interrupts den Wert auf 6 damit läuft der Zähler von 6 bis 255 bevor er überläuft, das sind genau 250 Überläufe des Vorteilerzählers und es ergibt sich eine Interruptfrequenz von 39,0625 Hz - das sieht doch schon besser aus? - jetzt muß man also damit die Zeit halbwegs gleichmäßig incrementiert wird 15 Sekunden á 39 Interrupts zählen und die 16. Sekunde mit 40 Interrupts. So Ergibt sich für die Zeit von 16 Sekunden - genau 15*39 + 1*40 IRQ = 16 * 39,0625 (625=625)
Jetzt muß man noch den Fehler ausgleichen welcher entsteht, wenn man beim Auftreten des Interrupts den Timer0 Zähler manipuliert - das hat dummerweise zur Folge, daß der Zähler des Vorteilers geresettet wird - daraus folgt wir verlieren bei jedem Interrupt einige Takte im Vorteilerzähler. Ich hab für mein Programm ausgerechnet das dies ca. 11 Zählwerte sind. Das bedeutet alle 23,27 Interrupts verliert man ein Increment des Timer 0 Zählers. Ich habe dann berechnet alle wieviel Sekunden ich genau die Zeit für einen Interrupt verloren habe - das geschieht demnach alle 149 Sekunden. (23,27 IRQS * 250 = 5817,5 IRQS / 39,0625 = 148,928 s) - deswegen verwende ich einen weiteren Zähler der alle 149 Sekunden den Wert 0 erreicht - die nächste Sekunde besteht dann aus nur 38 bzw. 39 Interrupts. Damit ist der Zeitverlust weitesgehend ausgeglichen. Natürlich ergibt das immer noch keine super genaue Uhr - die Abweichnung beträgt nach einiger Justage mit dem Drehkondensator ca. 1-3 Sekunden je Woche. Was aber nicht weiter schlimm ist - da die Uhr bei jedem Systemstart durch die Y.A.R.D. Clientsoftware neu gestellt wird.

Dafür erfüllt die Uhr aber meinem Wunsch den Hauptprozess möglichst wenig zu stören. Da lediglich 39 / 40 Interrupts je Sekunde auftreten.

Die Send/Receivebuffer für Serielle Schnittstelle

Die serielle Kommunikation von Y.A.R.D. läuft ausschließlich über Interrupts und nicht via Polling, um ebenfalls möglichst viel Zeit im Hauptprogramm für andere Zwecke freizuschaufeln. Der Aus- und Eingangsbuffer sowie die notwendigen Indexvariablen befinden sich in Speicherbank 1.

Im wesentlichen handelt es sich um einen Backport der C-Routinen, welche ich hier gefunden habe.


IR-Dekodierroutinen

Hier werde ich beschreiben welchen Lösungsweg ich gewählt habe, um die Protokolle zu dekodieren - die genaue Beschreibung der Protokolle - könnte Ihr auf den Seiten meiner Linksammlung finden.

Prinzipbeschreibung

Es gibt für die Übertragung drei verschiedene Verfahren um eine Bitfolge via IR zu übertragen, bei der ein moduliertes IR-Licht zum Einsatz kommt. Gängige Modulationsfrequenzen sind 32khz, 36khz, 38khz und 40khz.
Biphasen-Protokolle Bei diesen Protokollen werden die Bit-Folgen durch Flankenwechsel innerhalb der Übertragung eines Bits kodiert. RC5, RC6, Motorola
Puls-Abstandsprotokolle Diese Protokolle kodieren die Bits durch die Dauer der Lücke zwischen zwei IR-Bursts. Diese Protokolle verwenden in der Regel auch ein Stop-Bit, um das Ende der Übertragung anzuzeigen. CommonIR, Japan-Code
Pulsdauer-Protokolle Im Gegensatz zu den Puls-Abstandsprotokolle steckt hier die Information in der Dauer des IR-Bursts. Die Pause dazwischen dient nur zur Trennung der Bits. Nachdem ein Bit übertragen wurde muß man ein Mindestzeit abwarten um zu schauen ob da noch mehr gesendet wurde. Diese Protokolle verwenden in der Regel kein Stop-Bit. SIRCS (Sony ist wohl der einzige)
Weiterhin gibt es noch Protokolle die kein moduliertes IR-Licht verwenden - und sich somit mittels TSOP17xx nicht dekodieren lassen. Ein typtischer Vertreter ist das ITT (Nokia) Protokoll. Eine weitere Aussnahme bildet das RC-MM Protokoll wo je Pulse-Abstand zwei Bits übertragen werden.

Protokoll Detektierung

Das Programm prüft im Hauptprogramm ständig ob am Port B,6 (TSOP_PORT) ein L-Pegel anliegt. (L-Pegel weil das Ausgangssignal des TSOP invertiert ist - d.h. H wenn kein IR-Licht auf ihn fällt und L wenn IR-Lich auf den Sensor fällt.) Wenn am Eingang ein L-Pegel (0) anliegt wird in das Unterprogramm General_ReceiveIR_CommandData Dieses Unterprogramm setzt zunächst die Zählervariablen des Timer1 (16-bit) TMR1L und TMR1H auf 0 und startet anschließend den Timer (bsf T1CON,TMR1ON). Danch wird in einer Schleife darauf gewartet das der TSOP_PORT wieder auf High wechselt, wenn dies geschehen ist wird der Timer1 sofort gestoppt.

Der Trick? besteht also darin die Dauer des ersten Impulses den die Fernbedienung sendet auszumessen. Dazu ist der Timer1 mit einem Vorteiler von 1:4 ausgestattet, d.h. ein Zählerwert entspricht bei 10Mhz ext. Takt - ca. 1,6us. Daher kann man mit dem 16-bit Zählerwert des Timers eine Zeitspanne von ca. 104ms ausmessen. Ich habe bisher noch keine FB gefunden die diesen Wert für ihren ersten Impuls überschreitet.

Dieser erster Impuls wird oft (außer RC5) als AGC (Automatic Gain Control) für den Empfänger verwendet, und unterscheidet sich (in seiner Dauer) bei allen IR Protokollen die mir bisher untergekommen sind.

Die so gemessene Dauer steckt in den Register TMR1L und TMR1H - damit bei der Detektierung keine 16-bit Vergleiche notwendig sind reduziere ich die Genauigkeit auf 8-Bit. Zu diesem Zweck wird das Zählerergebnis um 5-Bit nach Rechts geschoben. Da jetzt die oberen 3-Bit von TMR1H einfach ignoriert werden reduziert sich der Messbereich auf maximal 13,1ms mit einer Schrittweite von 51,2us je Zählerwert im Register TMR1L.

Tabelle mit den Messwerten für die Startimpulse:
TMR1L-von TMR1L-bis Protokoll Kodierung
16 / 819,2us 19 / 972,8us RC5 (mit 2-Startbits) Bi-Phasenkodierung d.h. Information steckt in Pegelwechseln
20 / 1024us 38 / 1945,6us RC5 (mit 1-Startbit) 2.Startbit als Datenbit missbraucht Bi-Phasenkodierung d.h. Information steckt in Pegelwechseln
43 / 2201,6us 51 / 2611,2us Sony Sircs (12,15 o. 20bit) Pulsdauerkodierung (d.h. Dauer des Impulses bestimmt Information)
62 / 3174,4us 71 / 3635,2us Japan-Code (Panasonic) Pulsabstandskodierung (d.h. Pause zwischen zwei Impulsen bestimmt Information)
169 / 8652,8us 173 / 8857,6us Yamaha / NEC Pulsabstandskodierung (d.h. Pause zwischen zwei Impulsen bestimmt Information)

Jeder Zählerwert dazwischen, darüber oder drunter führen zum Zurücksetzen des Repeatcounters - was Auswirkung auf die Einschalt und Ausschaltbefehle haben kann. Durch diese Ausfilterung werden auch Störimpulse ausgefiltert, die meist nur wenige Microsekunden lang sind. Der Repeatcounter wird auch zurückgesetzt wenn z.B. 700ms lang keine weitere Wiederholung empfangen wurde.

Protokoll: RC5

Das RC5 Protokoll verwendet zur Kodierung der Daten eine Bi-Phasenkodierung, d.h. jedes Bit wird in 2 Phasen übertragen (Halbbits) übertragen. Der darin enthaltene Pegelwechsel zwischen den Halbbits gibt an ob das Bit 0 oder 1 ist. Wenn zwischen zwei Halbbits kein Pegelwechsel erfolgt wird von einem Fehler ausgegangen.
Eine 0 wird dabei als ein Pegelwechsel 1->0, und eine 1 als Pegelwechsel 0->1 gesendet. Der Empfängerchip (TSOP1738) liefert aber ein invertiertes Signal an den Mikrokontroller, d.h. eine 0 wird als Wechsel von 0->1 und eine 1 als Wechsel von 1->0 empfangen. (Was bei der Programmierung gerne wieder für erheiternde Dekodierergebnisse gesorgt hat - meist merkt man es erst dann wenn man das Empfange wieder senden will und keinerlei Reaktion erfolgt - ich hab aus dem Grund mal meine gesamte Sendelogik neu geschrieben;-) obwohl die am Ende nichts dafür konnte *grübel*)

Jetzt zur Dekodierung:
Man kann die Dekodierung zwar relativ einfach gestalten wenn man nach dem ersten Impuls der ausgemessen wurde einfach immer so lange ab wartet bis genau das richtige Halbbit anliegt und dann das Signal abtastet. So das würde bedeuten nachdem der Startimpuls vorbei ist wartet man (889us/2) = 444,5us, dann müßte das Signal am Eingang des PIC bis zur Mitte des 1. Halbbits vom nächsten Bit verstrichen sein. Diesen Wert liest man aus und speichert ihn ab - danach wartet man etwas weniger als 1,778ms (889us*2) und liest den Wert vom nächste Bit aus das wird dann bis zum letzten Bit (Nr 14) wiederholt. Das Verfahren funktioniert allerdings nur wenn der PIC sonst wenig zu tun - was in meinem Projekt natürlich nicht der Fall ist - da parallel daszu Timer IRQ's und IRQ's vom UART auflaufen - dadurch verzerrt sich die Zeitmessung und driftet zum Ende hin weg - dadurch kommt es zu falsch Erkennungen.

Also mußte ich mir für meinen Fall was anderes einfallen lassen - ich nenne das Verfahren mal BiPhasendekodierung mit Halbbitsynchronisation. Nachdem das 1. Startbit empfangen wurde - wird der Timer 1 so initialisiert, dass der Überlauf nach ca. 444,5us (bzw. nach 1333,5us) erfolgt. Zu diesem Zeitpunkt hat ungefährt die Hälfte des 1. Halbbits den PIC Eingang passiert und man kann den Pegel des 1. Halbbits ermitteln. So jetzt wird der Timer1 mit 0 initialisiert dass er nach spätestens 1333,5us überläuft und gestartet. Danach tritt man je nach dem Wert des gelesen 1. Halbbits in eine Warteschleife ein, die darauf wartet dass der Eingang von 0 nach 1, bzw. von 1 nach 0 wechselt. Damit das Programm nicht auf Grund von Übertragungsfehlern hängen bleibt - wird als weitere Abbruchbedingung noch das Bit7 von TMR1H überwachtet, wenn dieses zu 0 wird ist der Zähler übergelaufen und es wird von einem Übertragungsfehler ausgegangen. (Da es Innerhalb einer Wartezeit kein Flankenwechsel aufgetreten ist.)
Wenn man jetzt den Flankenwechsel erkannt hat speichert man das jeweilige Bit ab. Zeitlicht gesehen befindet man sich dann nur wenige us nach dem Phasenwechsel innerhalb des aktuelle Bits, demnach dauert es jetzt ca. 1333,5us die man noch warten müßte bis man in der Mitte des 1. Halbbits (vom nächten Bit) angekommen ist. Dazu wird wiederum Timer1 entsprechend initialisiert dass er nach genau 1333,5us überläuft, beginnt der Algorithmus von vorne.
Bis man alle 12 bzw. 13 Bit des RC5 Codes dekodiert hat. 12 Bit muß man dekodieren wenn das 2. StartBit als 7. Kommandobit verwendet wird - und somit schon in der Dauer des Startimpulses berücksichtigt wurde, andernfalls müssen 13 Bit dekodiert werden, da auch das 2. Startbit dann zum Datenpaket gehört.

Protokoll: SIRCS

Die Dekodierung dieses Protokoll erfolgt nur durch das Ausmessen der Impulsfolgen.
Nachdem der Startimpulsdauer gemessen wurde - folgt noch eine Pause von ca. 600us bis das 1. Bit übertragen wird. Um jedoch nicht unendlich lange auf das 1. Bit zu warten wird Timer1 so initialisiert das er nach ca. 630 us überläuft, wenn das vor dem Wechsel des Einganges von 1 auf 0 geschieht - wird von einem Übertragungsfehler ausgegangen.

Die eigentlichen Dekodierungsschleife folgt diesem Schema:


So wenn nach dem Empfang die Anzahl der Bits ungleich 12, 15 und 20 ist - liegt auch hier ein Übertragungsfehler vor.

Protokoll: Common IR

Dieses Protokoll basiert auf dem FB Chipsatz von NEC, der in sehr vielen asiatischen Fernbedienungen verbaut wird. (z.B. Goldstar, Mustek, Yamaha) Eine Besonderheit dieses Protokolls ist die doppelte Übertragung von Commandcode und Gerätecode, jeweils invertiert. Weiterhin wird bei diesem Protokoll die Wiederholungssequenz verkürzt, d.h. es wird nur eine bestimmte Pulsfolge gesendet, die als Wiederholung interpretiert wird. (Y.A.R.D. sendet dann an den PC aber trotzdem den kompletten Code wiederholt)

Protokoll: Panasonic/Japan



Aktuelle Firmware

Aktuelle Firmware hier Downloaden (src+hex)
Alle Downloads





Home Firmware Clientsoftware Hardware Teileliste Preisliste Downloads Impressum