Hallo! Ich habe einen TSOP1736 an einen Atmega32 am externen Interrupt angeschlossen. Ich möchte nun das Signal mit dem µC auswerten. Doch das klappt irgendwie bei mir nicht. Kann mir bitte irgendjemand helfen und sagen was ich falsch mache, ich bin hier schon am verzweifeln :( lg Vali
Ja Interrupt wird ausgelöst, aber der Code wird irgendwie nicht richtig eingelesen. Ich habe die Vermutung das irgendetwas mit dem Timing nicht stimmt, aber ich weiß echt nicht mehr weiter :( lg
Versuche mal mit eigenen Worten zu beschreiben, was das Programm machen soll. Dann kann man feststellen, ob die Logik dahinter richtig ist und dann prüfen, ob es richtig umgesetzt wurde. Z.B. Interrupt wird bei fallender Flanke ausgelöst. Oder Interrupt wird bei Level LOW ausgelöst und dann gesperrt. Wenn ein Interrupt ausgelöst wurde, wird x Millisekunden lang alle y Millisekunden (gesteuert durch Timer) der Pinzustand gepollt. Aus dem gepollten Pinzustand wird abgeleitet, ob ein Bit 1 oder ein Bit 0 empfangen wurde. Wenn nach x Millisekunden kein Levelwechsel am Pin stattgefunden hat, wird das vermeintliche Bit oder die Bitfolge bisher verworfen. Wenn 14 Bits eingelesen wurden ist, wird das Kommando abgeschlossen.
Ok gg Also sobald am INT0 eingang eine negative flanke erkannt wird wird der Timer gestartet und der externe Interrupt deaktiviert. Der Timer arbeitet ohne Vorteiler bei 1MHz, also meiner Meinung nach löst er mit dem Vorladewert 128, alle 127µs einen Timer Overflow Interrupt aus. Als ersten wert für das Code Array wird 1 eingelesen da dieser wert sowieso immer 1 ist. Danach wird 889µs gewartet (sprich 7x Timer Overflow) und der nächste Wert eingelesen. Danach wird 1778µs (Periodendauer) gewartet um den nächsten Wert einzulesen. Sobald der Code fertig eingelesen ist, geht das Programm weiter zur Auswertung. Hier werden die einzelnen Werte in den Arrays in eine einzige Variable (code) vom typ unsigned integer geschrieben. Danach wird der Wert dieser Variable noch aufs LCD ausgegebn. Hier wird der externe Interrupt wieder aktiviert. Und das ganze beginnt wieder von vorne. lg
RC5 Dekoder gibt es doch jede Menge. Schau dir den mal an, läuft bei mir problemlos: /www.mikrocontroller.net/topic/12216#new
Vali H. wrote: > Also sobald am INT0 eingang eine negative flanke erkannt wird wird der > Timer gestartet und der externe Interrupt deaktiviert. Dann bist du in der 2. Hälfte des 1. Startbits. > Der Timer > arbeitet ohne Vorteiler bei 1MHz, also meiner Meinung nach löst er mit > dem Vorladewert 128, alle 127µs einen Timer Overflow Interrupt aus. Ok. > Als ersten wert für das Code Array wird 1 eingelesen da dieser wert > sowieso immer 1 ist. > Danach wird 889µs gewartet (sprich 7x Timer > Overflow) Also die 2. Hälfte vom 1. Bit. > und der nächste Wert eingelesen. Das wäre das 2. Startbit > Danach wird 1778µs > (Periodendauer) gewartet um den nächsten Wert einzulesen. > Sobald der > Code fertig eingelesen ist, Das entscheidet was? 14 Bits insgesamt gelesen? > geht das Programm weiter zur Auswertung. > Hier werden die einzelnen Werte in den Arrays in eine einzige Variable > (code) vom typ unsigned integer geschrieben. > Danach wird der Wert dieser Variable noch aufs LCD ausgegebn. > Hier wird der externe Interrupt wieder aktiviert. Und das ganze beginnt > wieder von vorne. Die Idee ist so OK. Die Idee kann ich im Sourcecode so aber nicht nachvollziehen. Die einzelnen Schritte kommen mir dort etwas konfus vor. Aus dem Bauch raus würde ich sowas erwarten (ungestestet!)
1 | #include <avr/io.h> |
2 | #include <avr/interrupt.h> |
3 | #include "LCD.h" |
4 | #define F_CPU 1000000
|
5 | |
6 | #define NUM_RC5_BITS 14
|
7 | |
8 | volatile unsigned char code_B[NUM_RC5_BITS]; |
9 | volatile unsigned char wartezeit; |
10 | unsigned char anzahl_bits; |
11 | |
12 | static void code_ausgeben(void); |
13 | |
14 | int main(void) |
15 | {
|
16 | // INT0 auf fallende Flanke vorbereiten
|
17 | GICR |= (1<<INT0); |
18 | MCUCR |= (1<<ISC01); |
19 | sei(); |
20 | |
21 | while(1) |
22 | {
|
23 | if(wartezeit >= 13) // 1 Bit = 14 * 127 µs gewartet? |
24 | {
|
25 | anzahl_bits++; |
26 | code_B[anzahl_bits] = (PIND & (1<<PD2)); // Bit pollen |
27 | wartezeit = 0; // nächste Wartezeit beginnt |
28 | }
|
29 | |
30 | if(anzahl_bits == NUM_RC5_BITS-1) // 14 Bits empfangen? |
31 | {
|
32 | TCCR0 &= ~(1<<CS00); // TIMER abschalten |
33 | code_ausgeben(); |
34 | anzahl_bits = 0; // nächste Runde |
35 | GICR |= (1<<INT0); // INT0 wieder zulassen |
36 | }
|
37 | }
|
38 | }
|
39 | |
40 | ISR(TIMER0_OVF_vect) |
41 | {
|
42 | wartezeit++; |
43 | TCNT0 = 128; |
44 | }
|
45 | |
46 | ISR(INT0_vect) |
47 | {
|
48 | // INT0 abschalten
|
49 | GICR &= ~(1<<INT0); |
50 | |
51 | // PD2 auf Port D Eingang
|
52 | DDRD &= ~(1<<PD2); |
53 | |
54 | // 1. Startbit ist bekannt
|
55 | code_B[0] = 1; |
56 | |
57 | // erstes Halbbit (0-6) ist bereits "eingelesen"
|
58 | wartezeit = 7; |
59 | |
60 | // TIMER starten
|
61 | TCCR0 |= (1<<CS00); |
62 | TIMSK |= (1<<TOIE0); |
63 | TCNT0 = 128; |
64 | }
|
65 | |
66 | static void code_ausgeben(void) |
67 | {
|
68 | char buffer[20]; |
69 | int16_t code = 0; |
70 | uint8_t i; |
71 | |
72 | for(i=0; i<=NUM_RC5_BITS-1; i++) |
73 | {
|
74 | /*
|
75 | Sollen hier die Startbits entfernt werden?
|
76 | Wenn ja ist das falsch. Es ginge z.B. wenn
|
77 | i statt bei 0 bei 2 startet.
|
78 | */
|
79 | // code_B[i] >>= 2;
|
80 | |
81 | code <<= 1; |
82 | code |= code_B[i]; |
83 | }
|
84 | |
85 | itoa(code,buffer,10); |
86 | lcd_init(); |
87 | lcd_string(buffer); |
88 | }
|
Danke für deine Bemühungen :) Dein Source sieht schon mal viel übersichtlicher als meiner aus. gg Habe das ganze jetzt mal ander Hardware getestet. Aber da wird bei mir wenn ich "1" auf der Fernbedienung drücke am Display 25484 angezeigt. Was einem Wert von 110001110001100b entspricht. Laut Oszilloskop müsste aber ein Wert von 11000000000001b rauskommen (oszi-bild im anhang). Ich weiß aber nicht wo der Fehler liegt. Der Source von stefan sieht meiner meinung nach richtig aus. lg
Das Pollen ist derzeit ja zu Beginn des zweiten Halbbits und zwar sehr knapp an der Flanke in der Mitte des Bits. Und die Bits kommen in natura vielleicht nicht so exakt... Du könntest mehr in der Mitte des zweiten Halbbits pollen. Dazu könntest du die Zeit nach dem INT0 etwas verlängern, also z.B. statt wartezeit=7 wartezeit=4 in der INT0 ISR benutzen und damit den nächsten Pollzeitpunkt um 3 * 127µs weiter Richtung die Mitte des zweiten Halbbits verschieben. Oder mehrfach im zweiten Halbbit pollen und den mehrfach vorkommenden Wert nehmen.
Ich habe das mit dem pollen weiter in der halbbit mitte probiert. Führt leider irgendwie nicht zum gewünschten ergebnis. Aber ich hab noch eine frage wieso wird in dem Block
1 | if(wartezeit >= 13) // 1 Bit = 14 * 127 µs gewartet? |
2 | {
|
3 | anzahl_bits++; |
4 | code_B[anzahl_bits] = (PIND & (1<<PD2)); // Bit pollen |
5 | wartezeit = 0; // nächste Wartezeit beginnt |
6 | }
|
die wartezeit auf größer gleich 13 abgefragt und nicht 14? Weil sobald wartezeit den wert 1 erreicht sind 127µs vergangen, bei 2 127µs usw. also folglich bei 14 sind es 1778µs oder bin ich mit dieser Annahme falsch unterwegs? lg
Hmm, hast Recht! Das Ergebnis vom Einlesen und das Oszibild passt auch zu dem Fehler. wartezeit startet bei 0. Wenn die Timer ISR 1x gelaufen ist, hat wartezeit den Wert 1. Wenn wartezeit 2x gelaufen ist, hat wartezeit den Wert 2... Wenn wartezeit 14x gelaufen ist, hat wartezeit den Wert 14! Kontrolle des anderen Zählers anzahl_bits. Wenn zwei Bits gespeichert wurden, hat anzahl_bits den Wert 1, Wenn 3 Bits gespeichert wurden 2... wenn 14 Bits gespeichert wurden 13. Ich würde aber trotzdem eher in der Mitte Pollen.
Also ich habe jetzt versucht eher in der Mitte des zweiten Halbbits abzufragen. Daher habe ich wartezeit mal auf 6 gesetzt ( bedeutet ja um 127µs weiter in der mitte). Die Abfrage zum einlesen des Port Status wird nun erst nach 14 Timer Overflows ausgelöst. Nun ist mir aufgefallen das sich im Code Bereich die beiden letzten beiden Bits (Bit 13 und Bit14), egal welche Taste gedrückt wird, nicht ändern. Dies würde ja bedeuten dass die gesamte Routine zu lange dauert und Bit 13 und 14 das Idle Signal des Tsop enthalten. Irgendetwas stimmt bei den ganzen Zeiten nicht. Aber ich weiß einfach nicht was falsch sein soll ?! mfg
Wenn du magst, schau dir meine Änderungen an. Ich habe da weitergemacht, weil mich deine Rechenvorschrift (1. INT dann 2. Pollen über Timer) interessiert hat. Nicht erschrecken, wenn du anfangs nur noch wenig wiedererkennst ;-) Die Änderungen sind: 1/ Umstellung von Atmega32 auf Attiny2313 Weil ich letzteren derzeit im Pollin Funk AVR Board habe. Anschluss TSOP auch an PD2 siehe auch http://www.mikrocontroller.net/articles/Pollin_Funk-AVR-Evaluationsboard#RC5_Empf.C3.A4nger Den Atmega32 Code habe ich mitgeführt und fehlerfrei kompiliert aber nicht auf einem Atmega32 getestet. Das 14 Byte Array ist Verschwendung auf einem µC. Man kann das (und würde in der Praxis bestimmt auch) durch eine 16-Bitvariable ersetzen und gleich die gepollten Bits reinodern. Ich habe das Array drin gelassen, um nicht zuviel zu ändern. 2/ Änderung wo gepollt wird Das Pollen habe ich in die Timer ISR geschafft. Das Pollen ist "zeitkritisch" und hat - vom Bauch her - im Userprogramm nichts zu suchen. 3/ Änderung des Timer Modus Das manuelle Nachladen von TCNT0 habe ich ersetzt. Dazu eignet sicg der CTC Modus, weil der automatisch nachlädt. 4/ Änderung der Ausgabe Ich habe derzeit kein LCD angeschlossen. Die bequemste Ausgabe ist für mich UART. Mein Attiny2313 hat 8 MHz extern und ich kann 9600/8N1 ausgeben. Für den 1 MHz Atmega32 bin ich mit der Baudrate auf 2400 runter - hoffentlich klappt das ohne Quarz, 5/ Einführung eines DEBUG Modus Klingt mehr als es ist - es sind einfach 2 Outputpins (PD5 und PD6). Einer wird beim Eintreten der Timer ISR getoggelt und einer wird kurz HIGH gezogen, wenn der PD3 gepollt wird. Damit sieht man im Logikanalysator, wann gepollt wird (3 Spuren: PD2, PD5 und PD6). Wenn es nicht klar wird, kann ich einen Screenshot machen. 6/ Löschen des INTF0 Flags vorm Enable des INT0 Es scheint so, dass das dieses Flag nicht automatisch gelöscht wird, wenn INT0 in seiner ISR disabled wird. Vielleicht weiss da jemand genaueres? Ich wollte da noch nachsehen, bin aber noch nicht dazu gekommen.
Vielen herzlichen Dank für deine Bemühungen :) Der Code wird nun richtig angezeigt. Aber ein Problem ist nun aufgetreten, welches bei mir zu hause nicht war. Da ich das ganze jetzt in der Schule ausprobiert habe ist mir aufgefallen das dass Programm auch auf irgendwelche Störeinflüsse aus der Umgebung reagiert und dadurch irgendwelchen nonsense ausgibt. Jetzt müsste ich noch eine Funktion einbauen die überprüft ob es sich wirklich um RC5 handelt. Wie realisier ich so etwas am besten? lg
Genau das ist ein Knackpunkt an der einfachen Rechenvorschrift ;-) Irgendwas triggert INT0 und dann werden timergesteuert "stur" 14-Bits gepollt und das soll dann ein RC5 Datagramm sein. Bei dieser Rechenvorschrift (es gibt andere) kann man mehrere Sachen machen, um das empfangene Datagramm gültig/ungültig zu markieren z.B. prüfen, ob die Halbbits korrekt kommen. RC5 ist biphasig, d.h. ein Bit wird durch zwei Pegel definiert. Statt wie jetzt ein Halbbit (das erste) für das Gesamtbit zu pollen, kann man beide Halbbits pollen und nur wenn ein Wechsel stattgefunden hat dann das Bit und damit die 14-Bitfolge gültig erklären. Technisch könnte man das so machen, dass jetzt zusätzlich im 2. Halbbit gepollt wird (wartezeit == 7 => Halbbit-2, wartezeit == 14 => Halbbit-1). steckt man das Polling bitweise in Variablen, kann man nach 14-Bits die beiden Pollwerte miteinander exklusiv verodern und wenn dabei 0 sind die Wechsel OK.
Ok vielen Dank. Werde das bei nächster gelegenheit mal ändern. Vielen Dank für die ganze Hilfe hat mir wirklich sehr geholfen. Ich wäre da wohl noch einige Stunden gesessen. lg
Bitte sehr, gern geschehen. Ich bin zur Zeit selbst auf dem IR Trip (soll in Richtung IrDA gehen) und da hat das bei mir auch gut reingepasst.
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.