Hallo zusammen, ich versuche seit Wochen einen Fernbedienungs-Code mit Hilfe eines TSOP auszuwerten. Ich habe den Eingang des TSOP an RB0 meines PIC, den auch als Interrupt eingerichtet habe. Ich komme hierbei leider auf keinen grünen Zweig. Jetzt mögen viele sagen "schau bei Sprut da ist alles erklärt". Das ist wohl auch richtig, und ich habe auch schon auf vielen anderen Seiten geschaut, aber deshalb weiß ich immer noch nicht wie ich an die Sache herangehen soll. Wie kann ich z.B. sicher gehen, dass der PIC nicht anfängt die Folge von BITs mitten im Code auszuwerten? Ein Flussdiagramm für die Auswertung habe ich nirgends gefunden. Kann mir jemand unter die Arme greifen? Ich programmiere übrigens in Assembler (ich weiß, C wäre einfacher, aber wir programmieren in der Schule nur mit Assembler, und ich möchte das einfach dafür lernen ;-) ) Danke im Vorraus! Tobias
"Ich habe den Eingang des TSOP an RB0 meines PIC, den auch als Interrupt eingerichtet habe." Damit wird die Sache nur unnötig kompliziert. Einfacher ist die Abfrage in einem Timerinterrupt. In der Codesammlung ist ein Beispiel in C mit Funktionsbeschreibung: http://www.mikrocontroller.net/forum/read-4-74473.html#new Wenn Du C verstehst, sollte es nicht schwer sein, das Prinzip in Assembler umzusetzen. "Wie kann ich z.B. sicher gehen, dass der PIC nicht anfängt die Folge von BITs mitten im Code auszuwerten?" Kein Problem, der Code prüft, ob genau 14 Bits empfangen wurden. Peter
Hallo Peter, was spricht dagegen, den Externer Interrupt zu benutzen ? Ich habe im Moment eine Basis-Station für eine Propeller-Uhr fertig und werte dort eine JVC Fernbedienung aus. Da ich keine Beispiele gefunden habe, habe ich folgendes selbst programmiert: ich benutze jetzt den externer Int1, um dann den Timer2 losrennen zu lassen. Trudelt der nächste Int1 ein, werte ich den Timer aus, um zu sehen, wie lange der letzte Impuls gedauert hat. Ich muß zugeben, so ganz 100%ig funktioniert es nicht, ich muß die Taste teilweise öfters drücken, damit das Teil reagiert (angeschlossen ist ein TSOP1738). Würde es Vorteile bringen, alles in den Timer zu packen und den einfach dauernd laufen zu lassen und zu gucken, wie das Signal momentan vom TSOP ist (high oder low) und daraus die Länge des letzten Impulses zu bestimmen ? JVC verpackt die 1er in 2,10ms und die Nuller in 1,05ms Pakete, RC5 wäre mir lieber gewesen, aber leider habe ich bei 6 Fernbedienungen daheim keine einzige die RC5 sendet ;) Gruss, Peter
Hi, ich verwende auch die "Polling" / Timer Variante, - ich habe in meinem aktuellen Projekt es so gemacht, da ich vorhatte mehre verschiedene Protokolle erkennen zu können und außerdem noch andere Interrupts zulassen wollte - USART, & Timer0. Im Hauptprogramm in einer Endlosschleife frage ich immer den Port ab woran der TSOP1738 (ist für meisten IR Signale geeignet) hängt - wenn dieser Eingang auf 0 geht - starte ich den Timer1 (16bit, TMR1H=TMR1L=0) - so wenn jetzt der Eingang wieder auf 1 geht - kann ich anhand der Länge dieses Startimpulses ermitteln welches Protokoll empfangen wurde ... (so mit Pi * Daumen) +- einige us - wenn jetzt die Zeit ca. 889us (850-920us) ist - ist es ja RC5- (wenn die Zeit ca. 1778us beträgt kann es auch RC5 sein wo das 2. Startbit zum 6. Befehlsbit gemacht wurde RC5+!) danach gehts in die spezifische dekodierroutine: - dort lese ich als erstes den aktuellen Zustand des TSOP ein - ist dieser 1 (0)- warte ich in einer Schleife maximal 1000us auf einen Pegelwechsel nach 0 (1) - wenn das nicht geschieht breche ich das Lesen ab. (dafür halte ich Timer1 zuvor an setzte TMR1L und TMR1H so das nach ca. 1000 us ein Überlauf statt findet wenn ich den Timer neu gestartet habe) Habe ich jetzt einen 01 / 10 Pegelwechsel erhalten speichere ich mir das jeweilige Bit in meiner Variablen (2 bytes). Zu diesem Zeitpunkt wird noch die 2. Halbbit des aktuellen Bits übertragen. Jetzt richte ich mir den Timer1 so ein daß er nach 1333 us (889+889/2) überläuft - dann müßte ich mich ja zeitlich gesehen in der Mitte des nächste ersten Halbbits befinden - und ich lese dessen Pegel ein - und das ganze beginnt vor vorne. Bis ich meine 14 Bit zusammen habe. Dieses Vorgehen mag kompliziert erscheinen im vergleich zu anderen RC5 Routinen - welche NOPS und Warteschleifen verwenden um das Timing zu treffen, diese Variante hat aber folgende Vorteile: - andere IRQ's wie z.B. TMR0 und USART stören so gut wie über- haupt nicht - da Zeitmessung über Timer1 erfolgt - auch unsauber gesendete IR Befehle können noch erfolgreich dekodiert werden da er Empfang in der Mitte jedes Bits neu synchronisiert wird. André
@Peter Schwarz "was spricht dagegen, den Externer Interrupt zu benutzen ?" "Ich muß zugeben, so ganz 100%ig funktioniert es nicht" Genau das. Die TSOP haben eine AGC, um sich den Lichtverhältnissen anzupassen. Dadurch kann es zu Pseudoimpulsen kommen. Die Timer-Poll-Version filtert diese heraus. Und wie gsagt, der Timer kann noch nebenbei LEDs multiplexen, Tasten entprellen, Uhrzeit zählen usw., da er nicht angehalten wird. Peter
Hi, JVC - hab ich mir gerade mal angeschaut ist ja "fast" das gleiche wie Nec / Yamaha nur das der Repeat ein wenig anders funktioniert. würde ich meiner Logik so ausschauen: wenn Zeit des StartImpulses ca. 8400us ist. (da ich den 16 bit Timer verwende, mit Vorteiler 4 und bei 10mhz Pic-Takt - müßte ich immer 16 bit vergleiche mach deswegen teile ich die Zeit vor dem Vergleich immer durch 32 (rrf um 5 bit!) - dadurch wird zwar die Zeit nicht mehr ganz genau gemessen aber man kann trotzdem die IR's sequencen gut voneeinander unterscheiden) Repeat-Code! (wenn Zeit des StartImpulses ca. 526us ist - und zuletzt ein JVC Code empfangen wurde d.h. kein Error oder ähnliches aufgetreten ist - gehe direkt zum Empfänger an "Stelle 1" vorher noch den BitZähler mit 16 initialisieren! Decoder: geht das Programm in den JVC decoder und initialisiert Timer1 so das nach ca. 4400 us ein Überlauf eintritt und wartet dann darauf das am TSOP das nächste mal ein L Pegel auftritt - ist dies bis zum Überlauf nicht der Fall wird das Lesen abgebrochen. BitZähler=16; LeseSchleife: ; die 526us "Pause" abwarten lade TMR1L und TMR1H so das nach maximal 600us ein überlauf eintritt warte_auf_nächsten_Pulse: teste TMR1 auf überlauf wenn ja abbruch der Empfangsroutine wenn TSOP = 0 goto warte_auf_nächsten_Pulse Stelle 1: halte Timer1 an löschen TMR1L und H starte Timer1 lese_bit: teste ob im TMR1 größer als 1574 us wenn ja abbruch übertragungsfehler wenn TSOP = 1 goto lese_bit halte Timer1 an (um den vergleich auf 8 Bit zu begrenzen verwende ich hier den gleiche Trick wie beim Startpuls einfach den TMR1H und TMR1L um 3 Bit nach Rechts schieben - clrc rrf TMR1H,F rrf TMR1L,F clrc rrf TMR1H,F rrf TMR1L,F clrc rrf TMR1H,F rrf TMR1L,F dann kann der ganze vergleich mit TMR1L erfolgen, um wieviel Bit nach Rechts geschoben werden muß hängt vom Takt des PIC ab, dem Vorteiler welcher Timer1 inne hat und der maximalen Zeit die gemessen werden soll ab (3bit - sind es bei VT=4 und 10 Mhz) wenn Timer1 im Bereich 1500 bis 1650us dann eine 1 speichern wenn Timer1 im Bereich 480 bis 540us dann eine 0 speichern else übertragungsfehler decfsz BizZähler,F goto LeseSchleife Wichtig! -> warte jetzt noch solange bis der TSOP wieder H-Pegel -> liefert - d.h. das Stop Bit zu Ende ist! André
Nun, eindeutig für die Version mit externem Interrupt spricht, das man so den PIC schlafen legen kann wenn er nichts tun soll. In einem Hifi Vorverstärker minimiert man so störende HF Einstreuung aus dem MC.
Hallo zusammen, vielen Dank für die Tipps! Ich habe mich dann mal an die Arbeit gemacht und mich an der Beschreibung von "André Weber" entlanggehangelt. Nun habe ich ein Problem bei dem ich nicht weiterkomme. Nachdem das Erste Start-Bit bei mir angekommen ist und das 2te Startbit auf High geht fange ich an den Code zu lesen. Bei der Sprungmarke "S1" geht er zu "waitNull" weil eine "1" als Startbit anliegt. Dort springt er aber sofort wieder zu "Main" => bei "T1" weil die Zeit abläuft. Ich habe den Code mal im Anhang mitgesendet. Kann mir da jemand sagen was ich falsch mache? Gruß, Tobias
Hallo, wie ich sehe aktiviert dein Source den TMR0 IRQ und den Externen Interrupt and RB0 - dein Source enthält dafür aber keine Interruptroutine? (GIE = 0? hoffe ich mal) - deaktiviere doch mal komplett, aktiviere nur den Timer und lasse ihn parallel laufen. Das Hauptproblem was ich sehe - vermutlich habe ich es nicht genau genug beschrieben - daß Deine Leseroutine nicht zwischen den BITS wartet, das heißt du beginnst das nächste Bit schon zu lesen - während der TSOP momentan noch die 2. Hälfte des vorigen Halbbits ausgibt d.h. du müßtest zwischen S2: ; weil wenn du S2 anspringst ist ja erst gerade der Flankenwechsel ; des aktuellen Bits geschehen - d.h. du mußt es noch ein wenig ; warten bis etwa die Zeit um es daß von nächsten Halbbit schon ; die hälfte der Zeit vorbei ist - bevor du ein neues Bit zu lesen ; beginnst - movlw 0x90 ; ca 889 + 889/2 us movwf TR0 wait_mitte_nächstes_halb_bit: btfsc TR0,7 goto wait_mitte_nächstes_halb_bit decfsz R0 goto S1 weiterhin solltest du die Länge des Start Impulse messen da deine Routine sonst viel zu häufig auf Störimpulse anspringt - die oft nur wenige us lang sind. Also würde ich den Teil welche du in W1 geschrieben hast wie folgt ändern: (TMR0 VT=8 Pic Takt=4mhz vorausgesetzt) clrf TR0 wait_for_startbit2: btfss PORTB, RB0 ;Skip wenn Pin0 wieder auf "eins" geht btfss TR0,7 ; ok. länger as 128 * 8 us gewartet da ; kommt nichts mehr abbruch goto startbit2 movfw TR0 ; Timer0 wert sichern movwf TMR_TMP ; und zwischen speichern movlw D'100' ; ca 800 us subwf TMR_TMP,W btfss STATUS,C goto MAIN ; wenn C Flag = 0, dann pulse kürzer als 800us movlw D'121' ; ca 960 us subwf TMR_TMP,F btfsc STATUS,C goto MAIN ; wenn C Flag = 1, dann pulse länger als 960us Weitere Probleme sehe ich im Moment nicht, müßte eigentlich so gehen für RC5 - womit hast du es getestet, woher du dir sicher bist das er aufgrund des Timers sofort wieder zurück geht? Hast du mal mit dem Timer die Zeit gemessen, wie lang die Lücke wirklich ist? erhöhe doch einfach die mal die Wartezeit um einige "us" - vielleicht ist deine FB auch zu ungenau? - habe da schon teilweise Abweichungen in den Timings bis zu 15% gesehen - d.h. 1022us wäre durchaus auch noch ok. als Wartezeit - als initialisierte mal TR0 mit 127 statt mit 130 in deiner Warteschleife vielleicht sind es ja wirklich nur die paar us die dir fehlen. Oder verwende mal zur Überlaufprüfung nicht das T0IF Flag sondern werde den Wechsel des Bit7 von TR0 von 1 auf 0 aus, was auch sehr zuverlässig den überlauf anzeigt, speziell wenn man den Timer frei laufen läßt, braucht man sich dann auch nicht um das Interruptflag kümmern;-) Wie hoch ist dein PIC getaktet? Dein Timersetup geht von 4 Mhz aus? André
Hallo André, vielen Dank für Deine Tatkräftige Unterstützung. Interrupts habe ich nun komplett deaktiviert. Das waren z.T. noch Relikte aus vorherigen Versionen. Frage: Timer aktivieren? Ich kann doch nur die Source für den Timer wählen (intern /extern) und den Prescaler einstellen - oder? Zu "S2": Wenn ich S2 anspringe habe ich einen eventuellen Flankenwechsel erkannt. Was aber wenn dies 999µs dauert (ich warte ja max. 1000µs darauf). Dann befinde ich mich doch schon auf dem nächsten Halbbit. Wenn es schneller geht befinde ich mich davor - oder sehe ich das falsch? Ich habe meinen Schritt "S2" mal so wie du sagtest geupdatet. Wie genau funktioniert die Überprüfung vom TR0 - Bit "7" ? bei "wait_for_startbit2" steht unten "goto startbit2" ist damit die Sprungmarke "wait_for_startbit2" gemeint? ist hier nicht ein Fehler bei der Rechnung. Wenn der Pulse kürzer als 800µs war, dann steht im TR0 ein Wert, sagen wir mal ein Wert von 90d. Subtrahieren wir davon 100d dann ist der Wert negativ, das heißt das Carry-Flag wird gesetzt (oder nicht?). Wenn das gesetzt wird, dann müsste man doch zurück zu Main springen und nicht wenn es "0" ist? Wenn das C Flag = 0, dann ist der Pulse länger als 800µs - oder nicht? ----------------------- movfw TR0 ; Timer0 wert sichern movwf TMR_TMP ; und zwischen speichern movlw D'100' ; ca 800 us subwf TMR_TMP,W btfss STATUS,C goto MAIN ; wenn C Flag = 0, dann pulse kürzer als 800us ---------------------------- Und hier dann genau andersherum: Nehmen wir mal an, der Pulse war ca. 1040µs =>130d lang. Subtrahieren wir davon 121d, dann ist das Carry-Flag (weil nicht negativ) nicht gesetzt. Oder habe ich das mit dem Carry-Flag falsch verstanden? ---------------------------- movlw D'121' ; ca 960 us subwf TMR_TMP,F btfsc STATUS,C goto MAIN ; wenn C Flag = 1, dann pulse länger als 960us -------------------------- "womit hast du es getestet, woher du dir sicher bist das er aufgrund des Timers sofort wieder zurück geht?" -- Ich habe einfach an bestimmten Stellen die Routine "RA0_ON" aufgerufen, um zu sehen bis wohin er kommt und wo er hängen bleibt. Oder verwende mal zur Überlaufprüfung nicht das T0IF Flag sondern werde den Wechsel des Bit7 von TR0 von 1 auf 0 aus, was auch sehr zuverlässig den überlauf anzeigt, speziell wenn man den Timer frei laufen läßt, braucht man sich dann auch nicht um das Interruptflag kümmern;-) ----- Wie bereits oben gefragt. Ich Bit7 von TR0 ist doch nicht nur wenns überläuft gesetzt - oder? Wie hoch ist dein PIC getaktet? Dein Timersetup geht von 4 Mhz aus? ---- Jupp, genau 4MHz ;-) André
Ähm ja, jetzt habe ich glatt vergessen Deinen Namen unten drunter zu löschen... :D Wenn man nicht alle Sinne beisammen hat... Gruß, Tobias
Hallo, >Frage: Timer aktivieren? Ich kann doch nur die Source für den Timer >wählen (intern /extern) und den Prescaler einstellen - oder? sorry hab das mit Timer1 und 2 verwechselt die lassen sich mittels TMR1ON bzw. TMR2ON ab und anschalten, d.h. TMR0 läuft immer nur den Interrupt kann man abschalten. >Zu "S2": >Wenn ich S2 anspringe habe ich einen eventuellen Flankenwechsel >erkannt. Was aber wenn dies 999µs dauert (ich warte ja max. 1000µs >darauf). Dann befinde ich mich doch schon auf dem nächsten Halbbit. >Wenn es schneller geht befinde ich mich davor - oder sehe ich das >falsch? nein - bei RC5 besteht ja jedes Bit aus je zwei Halbbits zu 889us Da du ja den Flankenwechsel abgewartet hast kannst du dieses Halbbit ja damit "verbringen" die 0 oder 1 in der Variable GBYTE zu speichern, und zu warten das dieses Halbbit vorübergeht das dauert 889us dann bis du erst genau an der Grenze zum nächsten Halbbit welches Interessant ist, da aber 889us zu warten extrem knapp ist um man evtl. zu früh den Pegel des TSOP abfragt wartet man noch ein wenig mehr (889/2) um etwa in der Mitte des übernnächsten Halbbits wieder aufzusetzen. eine 1 besteht aus: ------------------ 889us ohne IR-Impulse, gefolgt von 889us mit IR-Impulsen - daraus ergibt sich am Ausgang des TOP zunächst -> ein 889us H-Pegel -> gefolgt von 889us L-Pegel Also wenn der Wechsel länger als 1000us dauert, ist die Übertragung sowieso fraglich - ob das ein gültiges RC5 Signal sein - kann deswegen auch der Abbruch! eine 0 besteht aus: ------------------- 889us mit IR-Impulses, gefolgt von 889us ohne IR-Impulse - daraus ergibt sich am Ausgang des TOP zunächst -> ein 889us L-Pegel -> gefolgt von 889us H-Pegel (schau dir mal die Seite an: http://www.sprut.de/electronic/ir/rc5.htm dort ist das mal grafisch dargestellt wie ein RC5 Signal aussieht) >Wenn ich S2 anspringe habe ich einen eventuellen Flankenwechsel >erkannt. das ist aber der Flankenwechsel zwischen 1. und 2. Halbbit d.h. zu diesem Zeitpunkt vergehen noch ca. 889us bis das nächste BIT beginnt. damit man nicht zu früh ausliest habe ich darauf noch einmal die halbe Bitzeit addiert. (889 + 889/2) - dann befindet man sich etwa in der Mitte des 1. Halbbits des nächstes Bits. Anmerkung: Zwischen zwei Bits hast du nicht unbedingt einen Flankenwechsel wenn z.B. bei RC5 ein Binär 01 übertragen wird hast du am TSOP Ausgang 889us-L, 889us-H, 889us-H, 889us-L) einen Flankenwechsel gibt es garantiert nur mitten im Bit bei RC5. > Wie genau funktioniert die Überprüfung vom TR0 - Bit "7" ? da deine Zähler TMR0 Initialisierung in diesem Fall größer als 128 ist ist ja beim setzen immer Bit 7 = 1 gesetzt. jetzt wartet man einfach solange bis Bit 7 = 0 wird - das geschieht beim Überlauf von 255 -> 256 (0) Beispiel: warte: btfss TR0,7 goto Ueberlauf goto warte Ueberlauf: oder kürzer warte: btfsc TR0,7 goto warte geschehen - die Schleife bricht erst ab wenn der Zähler auf 0 überläuft. --> wenn deine Zählerinitialisierung kleine als 128 ist mußt du damit vorsichtig sein, und vorher darauf warten das bit 7 gesetzt wird! -- im FALL RC5 und dem Timersetup ist dies aber nicht notwendig >bei "wait_for_startbit2" steht unten "goto startbit2" ist damit die >Sprungmarke "wait_for_startbit2" gemeint? genau (das passiert dann wenn man sowas blind schreibt) > ist hier nicht ein Fehler bei der Rechnung. - bitte den TMR0 mit Vorteiler 8 einrichten (sonst kommt es vielleicht zu früh zum überlauf!) > Wenn der Pulse kürzer als 800µs war, dann steht im TR0 ein Wert, > sagen wir mal ein Wert von 90d. Subtrahieren wir davon 100d dann > ist der Wert negativ, das heißt das Carry-Flag wird gesetzt (oder > nicht?). eher nicht - aufgrund wie der PIC ein Subtraktion vornimmt wird das C-Flag durch einem unterlauf (sprich wenns <0 wird gelöscht). Beispiel: 90 - 100 sieht binär so aus für den PIC Carry 1 0101 1010 (90) - 0 0110 0100 (100) ------------- 0 1111 0110 (246) --------------------- >Ich habe einfach an bestimmten Stellen die Routine "RA0_ON" >aufgerufen, um zu sehen bis wohin er kommt und wo er hängen bleibt. ok - hab ich übersehen;-) >Wie bereits oben gefragt. Ich Bit7 von TR0 ist doch nicht nur wenns >überläuft gesetzt - oder? - deswegen wertet man ja auch wechsel von 1 nach 0 des bits aus sowie ich es geschrieben habe: movlw 0x90 ; ca 889 + 889/2 us movwf TR0 wait_mitte_nächstes_halb_bit: btfsc TR0,7 ;>>>>>>> solange Bit 7 gesetzt ist goto_wait... goto wait_mitte_nächstes_halb_bit (gehen die Labels mit "ä" drin - wirklich? hab das nie probiert) André
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.