mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Atmega 32 RC5


Autor: Vali H. (davali)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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

Autor: Timmo H. (masterfx)
Datum:

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

Autor: Vali H. (davali)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Vali H. (davali)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Hubert G. (hubertg)
Datum:

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

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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!)

#include <avr/io.h>
#include <avr/interrupt.h>
#include "LCD.h"
#define F_CPU 1000000

#define NUM_RC5_BITS 14

volatile unsigned char code_B[NUM_RC5_BITS];
volatile unsigned char wartezeit;
unsigned char anzahl_bits;

static void code_ausgeben(void);

int main(void) 
{
  // INT0 auf fallende Flanke vorbereiten
  GICR |= (1<<INT0);
  MCUCR |= (1<<ISC01);
  sei();
  
  while(1)
  {
    if(wartezeit >= 13) // 1 Bit = 14 * 127 µs gewartet?
    {
      anzahl_bits++;
      code_B[anzahl_bits] = (PIND & (1<<PD2)); // Bit pollen
      wartezeit = 0; // nächste Wartezeit beginnt
    }

    if(anzahl_bits == NUM_RC5_BITS-1) // 14 Bits empfangen?
    {
      TCCR0 &= ~(1<<CS00); // TIMER abschalten
      code_ausgeben();
      anzahl_bits = 0; // nächste Runde
      GICR |= (1<<INT0); // INT0 wieder zulassen
    }   
  }
}

ISR(TIMER0_OVF_vect) 
{
  wartezeit++;
  TCNT0 = 128;
}

ISR(INT0_vect) 
{
  // INT0 abschalten
  GICR &= ~(1<<INT0);

  // PD2 auf Port D Eingang
  DDRD &= ~(1<<PD2);

  // 1. Startbit ist bekannt
  code_B[0] = 1;

  // erstes Halbbit (0-6) ist bereits "eingelesen"
  wartezeit = 7; 

  // TIMER starten
  TCCR0 |= (1<<CS00);
  TIMSK |= (1<<TOIE0);
  TCNT0 = 128;
}

static void code_ausgeben(void)
{
  char buffer[20];
  int16_t code = 0;
  uint8_t i;

  for(i=0; i<=NUM_RC5_BITS-1; i++)
  {
    /* 
       Sollen hier die Startbits entfernt werden?
       Wenn ja ist das falsch. Es ginge z.B. wenn 
       i statt bei 0 bei 2 startet.
    */
    // code_B[i] >>= 2; 

    code <<= 1;
    code |= code_B[i];
  }
      
  itoa(code,buffer,10);
  lcd_init();
  lcd_string(buffer);
}

Autor: Vali H. (davali)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Vali H. (davali)
Datum:

Bewertung
0 lesenswert
nicht 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
 if(wartezeit >= 13) // 1 Bit = 14 * 127 µs gewartet?
    {
      anzahl_bits++;
      code_B[anzahl_bits] = (PIND & (1<<PD2)); // Bit pollen
      wartezeit = 0; // nächste Wartezeit beginnt
    }

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

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Vali H. (davali)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan B. (stefan) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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_Fun...

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.

Autor: Vali H. (davali)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Vali H. (davali)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.