Forum: Mikrocontroller und Digitale Elektronik Atmega 32 RC5


von Vali H. (davali)


Angehängte Dateien:

Lesenswert?

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

von Timmo H. (masterfx)


Lesenswert?

Was genau klappt denn nicht? Wird überhaupt ein Interrupt ausgelöst?

von Vali H. (davali)


Lesenswert?

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

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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.

von Vali H. (davali)


Lesenswert?

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

von Hubert G. (hubertg)


Lesenswert?

RC5 Dekoder gibt es doch jede Menge. Schau dir den mal an, läuft bei mir 
problemlos: /www.mikrocontroller.net/topic/12216#new

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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
}

von Vali H. (davali)


Angehängte Dateien:

Lesenswert?

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

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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.

von Vali H. (davali)


Lesenswert?

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

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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.

von Vali H. (davali)


Lesenswert?

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

von Stefan B. (stefan) Benutzerseite


Angehängte Dateien:

Lesenswert?

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.

von Vali H. (davali)


Lesenswert?

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

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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.

von Vali H. (davali)


Lesenswert?

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

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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
Noch kein Account? Hier anmelden.