Forum: Mikrocontroller und Digitale Elektronik IR-Emfänger TSOP 4838 an ATmega328P


von IR-Bastelei (Gast)


Lesenswert?

Moin,

ich möchte meinem Mikrocontroller signale per IR zusenden. Hierfür würde 
ich gerne IRSND und IRMP nutzen. Ich habe mir einen Emfänger (TSOP4838) 
und eine IR-LED besorgt. Ich bin noch ein Anfänger auf diesem Gebiet und 
weiß noch nicht genau wie ich das Ganze an den Mikrocontroller 
anschließe. Die Schaltung im IRSND-Beitrag mit Transistor und Co. habe 
ich schon aufgebaut und kann auch über ein GPIO-Pin die LED toggeln.

Jetzt meine Frage, an welche Anschlüsse vom MIkrocontroller muss die 
Schaltung damit das funktioniert? LED an einen PWM-Ausgang und der 
Emfänger dann an einen ADC-EIngang?

Danke

von Falk B. (falk)


Lesenswert?

@ IR-Bastelei (Gast)

>Jetzt meine Frage, an welche Anschlüsse vom MIkrocontroller muss die
>Schaltung damit das funktioniert?

Gibt es keine Schaltpläne bei den IRSND/IRMP Projekten?

>LED an einen PWM-Ausgang und der

Ja.

>Emfänger dann an einen ADC-EIngang?

Nein, der kommt an ein normales, digitales IO-Pin. Denn der Ausgang des 
IR-Empfängers ist auch "nur" digital.

von IR-Bastelei (Gast)


Lesenswert?

Ich habe das Ganze jetzt einmal angeschlossen und habe mit dem 
Programmieren angefangen. Ich habe beim Sender wie im IRSND-Beitrag 
geschrieben nur die "irsnd.h" in mein Projekt inkludiert. Ansonsten habe 
ich mich zunächst an dem mitgelieferte Beispiel orientiert. Leider 
bekomme ich beim Übersetzen folgende Fehlermeldungen:

Error  1  undefined reference to `irsnd_ISR' 
...IR_Sender_Empfänger\Sender\Sender\Release\Sender.c

Error  2  undefined reference to `irsnd_init' 
...\IR_Sender_Empfänger\Sender\Sender\Release\Sender.c

Error  3  undefined reference to `irsnd_send_data' 
...\IR_Sender_Empfänger\Sender\Sender\Release\Sender.c  1  1  Sender

Error  4  ld returned 1 exit status  collect2.exe

Software ist Atmel Studio 6.2. Weiß jemand wieso er die Referenzen nicht 
findet? Ich habe alle Dateien aus dem IRSND-Archiv in den Projektordner 
entpackt. Die Header-Dateien scheint der Compiler ja auch zu finden. 
Danke

von Falk B. (falk)


Lesenswert?

Man muss auch alle verwendeten Dateien in den Projektbaum einfügen. Nur 
DIESE weden compiliert.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

IR-Bastelei schrieb:
> LED an einen PWM-Ausgang ...

Ja. In irsndconfig.h sind die Pins aufgeführt, die möglich sind.

> und der Emfänger dann an einen ADC-EIngang?

Wie Falk schon sagte: Irgendein I/O-Pin, einstellbar in irmpconfig.h.

Um welchen µC handelt es sich überhaupt?

von Christian S. (roehrenvorheizer)


Lesenswert?

ATmega328p

MfG

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

In irsndconfig.h findest Du folgende Zeilen:
1
/*----------------------------------------------------------------------------------------------------------------------
2
 * AVR ATMega/ATTiny section:
3
 *
4
 * Change hardware pin here:                    IRSND_OC2  = OC2  on ATmegas         supporting OC2,  e.g. ATmega8
5
 *                                              IRSND_OC2A = OC2A on ATmegas         supporting OC2A, e.g. ATmega88
6
 *                                              IRSND_OC2B = OC2B on ATmegas         supporting OC2B, e.g. ATmega88
7
 *                                              IRSND_OC0  = OC0  on ATmegas         supporting OC0,  e.g. ATmega162
8
 *                                              IRSND_OC0A = OC0A on ATmegas/ATtinys supporting OC0A, e.g. ATtiny84, ...
9
 *                                              IRSND_OC0B = OC0B on ATmegas/ATtinys supporting OC0B, e.g. ATtiny84, ...
10
*------------------------------------------------------------------------------------------------------------------------
11
*/
12
#elif defined(ATMEL_AVR)
13
#  define IRSND_OCx                             IRSND_OC2B              // use OC2B

Im Kommentar steht eigentlich alles drin.

Der ATmega328 ist nur ein größerer ATmega88. Also hast Du zur Auswahl: 
OC2A und OC2B. Notfalls geht auch noch OC0A und OC0B, dann muss man halt 
den Timer0 statt Timer2 zur Modulation verwenden. Das ist auch im 
IRSND-Artikel so dokumentiert.

Am einfachsten ist es mit
1
#  define IRSND_OCx                             IRSND_OC2B              // use OC2B
bzw.
1
#  define IRSND_OCx                             IRSND_OC2A              // use OC2A

Gehe dann einfach so vor wie im Artikel beschrieben.

von IR-Bastelei (Gast)


Angehängte Dateien:

Lesenswert?

Danke zusammen.

Ja genau. Wie im Beitragtitel geschrieben handelt es sich um einen bzw. 
zwei Mega 328P.
Die Pins habe ich mittlerweile auch gefunden und in den Configdateien 
von IRSND und IRMP angepasst. Mit der Fotokamera habe ich auch schonmal 
kontrolliert. Die LED blinkt jede Sekunde wie programmiert auf. Über den 
zweiten MC möchte ich die empfangenen Daten per UART weiterleiten. UART 
funktioniert auch allerdings kommt auf dem MC der die Auswertung des 
IR-Detektors per IRMP übernehmen soll noch nichts an. Bzw. in meinem 
Hterm kommt nichts über die serielle Schnittstelle an. Ich lade die 
beiden .c-Files mal mit hoch, aber an sich ist das nahezu identisch mit 
dem was auch im Beispiel passiert.  Die IR-LED hängt an PD3 also OC2B 
und der Output des Detektors am PB6.

Danke schonmal

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Das solltest Du aus den .c-Dateien Empfaenger.c und Sender.c rausnehmen:

#define F_CPU 8000000UL

und stattdessen in den Projekt-Einstellungen setzen, damit für alle 
c-Files dieselben Einstellungen gelten. Ich weiß auch nicht, wie Du 
irmp.c und irsnd.c überhaupt ohne diese globale Einstellung übersetzen 
konntest. Diese meckern nämlich dann. Oder hast Du diese auch mit diesem 
#define "geimpft"?

Das ist das falsche Vorgehen. Wenn Du mal den Takt änderst, musst Du das 
in allen c-Dateien korrigieren. Fehler sind da vorprogrammiert.

Das hier:

#define BAUD 9600UL

benutzt Du leider gar nicht im Source.

Stattdessen das hier:
1
void UARTinit(){
2
  UBRR0H = (unsigned char) (51 >> 8);
3
  UBRR0L = (unsigned char) 51;
4
  UCSR0B = (1<<TXEN0) | (1<<RXEN0);
5
  UCSR0C = (1<<UCSZ00) | (1<<UCSZ01);
6
  
7
}

Hier kann niemand ohne größere Anstrengungen nachvollziehen, ob die 
Baudrate tatsächlich 9600Bd ergibt. Ohne es nachrechnen zu wollen: Ich 
bezweifele, dass dies die richtigen Werte für UBBR0H bzw. UBRR0L sind.

Benutze besser das hier, das ist portabel und läuft auf allen AVRs:
1
#define BAUD 9600L // vor include setzen!
2
include <util/setbaud.h>
3
4
#ifdef UBRR0H
5
6
#define UART0_UBRRH                             UBRR0H
7
#define UART0_UBRRL                             UBRR0L
8
#define UART0_UCSRA                             UCSR0A
9
#define UART0_UCSRB                             UCSR0B
10
#define UART0_UCSRC                             UCSR0C
11
#define UART0_UDRE_BIT_VALUE                    (1<<UDRE0)
12
#define UART0_UCSZ1_BIT_VALUE                   (1<<UCSZ01)
13
#define UART0_UCSZ0_BIT_VALUE                   (1<<UCSZ00)
14
#ifdef URSEL0
15
#define UART0_URSEL_BIT_VALUE                   (1<<URSEL0)
16
#else
17
#define UART0_URSEL_BIT_VALUE                   (0)
18
#endif
19
#define UART0_TXEN_BIT_VALUE                    (1<<TXEN0)
20
#define UART0_UDR                               UDR0
21
#define UART0_U2X                               U2X0
22
23
#else
24
25
#define UART0_UBRRH                             UBRRH
26
#define UART0_UBRRL                             UBRRL
27
#define UART0_UCSRA                             UCSRA
28
#define UART0_UCSRB                             UCSRB
29
#define UART0_UCSRC                             UCSRC
30
#define UART0_UDRE_BIT_VALUE                    (1<<UDRE)
31
#define UART0_UCSZ1_BIT_VALUE                   (1<<UCSZ1)
32
#define UART0_UCSZ0_BIT_VALUE                   (1<<UCSZ0)
33
#ifdef URSEL
34
#define UART0_URSEL_BIT_VALUE                   (1<<URSEL)
35
#else
36
#define UART0_URSEL_BIT_VALUE                   (0)
37
#endif
38
#define UART0_TXEN_BIT_VALUE                    (1<<TXEN)
39
#define UART0_UDR                               UDR
40
#define UART0_U2X                               U2X
41
42
#endif //UBRR0H
43
44
void
45
uart_init (void)
46
{
47
    UART0_UBRRH = UBRRH_VALUE;
48
    UART0_UBRRL = UBRRL_VALUE;
49
50
#if USE_2X
51
    UART0_UCSRA |= (1<<UART0_U2X);
52
#else
53
    UART0_UCSRA &= ~(1<<UART0_U2X);
54
#endif
55
56
    UART0_UCSRC = UART0_UCSZ1_BIT_VALUE | UART0_UCSZ0_BIT_VALUE | UART0_URSEL_BIT_VALUE;
57
    UART0_UCSRB |= UART0_TXEN_BIT_VALUE;                                                            // enable UART TX
58
}

P.S.
Die CKDIV-Fuse hast Du entsprechend eingestellt, damit der ATmega auch 
wirklich mit 8MHz und nicht 1MHz läuft?

von IR-Bastelei (Gast)


Lesenswert?

Frank M. schrieb:
> und stattdessen in den Projekt-Einstellungen setzen

ja hatte ich an andere Stelle im Forum bereits gelesen, konnte es aber 
in AS 6.2 nicht finden wo genau das geht. In den anderen .c-Dateien habe 
ich nix umgestellt. Gab allerdings beim Übersetzen weder eine Warnung 
noch einen Fehler.

Frank M. schrieb:
> #define BAUD 9600UL
>
> benutzt Du leider gar nicht im Source.

ich weiß..der Berechnugsteil ist darunter auskommentiert. Den Wert 51 
habe ich dem Datenblatt entnommen. Die UART-Übertragung funktioniert 
soweit auch ohne Fehler. Sicher, wenn der Takt sich später ändert muss 
man es  jedesmal manuell umstellen. Bin ja noch am Anfang.

Frank M. schrieb:
> Die CKDIV-Fuse hast Du entsprechend eingestellt

Jap der Haken ist rausgenommen sind somit 8 MHz :)

von IR-Bastelei (Gast)


Lesenswert?

Kann mir jemand einen Tip geben, an welcher Stelle ich in Atmel Studio 
die Taktfrequenz global für das ganze Projekt einstellen kann?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Forumssuche nach "Atmel Studio F_CPU" bringt:

Beitrag "Atmel Studio 7: F_CPU"

von IR-Bastelei (Gast)


Lesenswert?

Sooo..ich habe den Takt jetzt global auf 8000000UL gestellt. Danke 
Frank.

Leider kommt bei mir im Hterm immer noch nichts an. Teststrings kann ich 
generell per UART senden die kommen dann auch an. Also muss der Fehler 
irgendwo anders liegen. Leider finde ich ihn nicht.  Es ist ja ansonsten 
komplett das Beispielprogramm.

Ich habe mal testweise eine String in der Interrupt-Routine ausgegeben. 
Der kommt nicht an. Also scheint irgendwie auch der Interrupt nicht 
ausgelöst zu werden.

von IR-Bastelei (Gast)


Lesenswert?

Okay... wenn man die Interrups ( sei() ) nicht anschaltet kann es auch 
nicht funktionieren. Jetzt siehts top aus . Danke nochmals ! :)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Viel Spaß!

von IR-Bastelei (Gast)


Lesenswert?

Frank M. schrieb:
> Viel Spaß!

Danke! Macht es.

Ich habe allerdings schon wieder ein Problem, dass ich nicht verstehe.
Ich übertrage immer nacheinander 3 Buchstaben. Das funktioniert auch 
alles top. Aber nur wenn ich an einen der zwei Mikrocontroller mein ISP 
(Diamex ISP) angeschlossen habe. Sobald ich ihn entferne kommt über den 
UART nix mehr in hterm an. Habe schon kontrolliert die IR-LED blink 
munter weiter. Es ist auch egal an welchem Chip der ISP hängt. 
Emfängerseite oder Senderseite. Ist er dran funktioniert es, wenn er ab 
ist nicht. Wie kann das sein?

An den beiden Chips hängt außer der Grundbeschaltung sonst nix dran. Von 
V_cc zu GND hängen jeweils 100 nF Kerkos und ansonsten die 
LED-/Transistorschaltung auf der Senderseite und der Detektor an der 
Empfängerseite. Empfägerseitig ist noch der UART zu USB Adapter 
(FT232R). Spannungsversorgung kommt aus zwei 18650 Zellen mit 7805 
Spannungsregler dahiner. Jemand eine Idee was der Grund sein könnte?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

IR-Bastelei schrieb:
> Aber nur wenn ich an einen der zwei Mikrocontroller mein ISP (Diamex
> ISP) angeschlossen habe.

Das hört sich nach einer fehlenden Masseverbindung an.

von IR-Bastelei (Gast)


Lesenswert?

Frank M. schrieb:
> Das hört sich nach einer fehlenden Masseverbindung an.

Wieder einmal korrekt gelegen. Das UART Modul hatte kein Verbindung zu 
GND. Jetzt behoben und es funktioniert.

Ich hab nun schon ein bisschen mit der Bibliothek experimentiert und 
muss sagen, dass ich echt begeistert bin. Hut ab!

Ich übertrage momentan im NEC Protokoll. Was ich mich frage ist, ob es 
Protokolle gibt, die Daten schneller übertragen können. Klar ich könnte 
jetzt bei allen die Bitzeiten zusammenrechnen aber eventuell lässt sich 
das ja beschleunigen :) Sagen wir einmal ich möchte maximal dreistellige 
Zahlen übertragen. Im NEC Protokoll ist eine Frame 67,5 ms lang das 
bedeutet ja pro Sekunde 14 Übertragungen (Eigl. 14,8 aber kommen ja noch 
die Stopbits dazu) Ist das schon das maximale was per Infrarot geht oder 
kann man mehr rausholen?

Desweiteren steh ich ein wenig auf dem Schlauch was das Format der 
Übertragung angeht. Das Kommando, sagen wir einmal beim NEC Protokoll, 
ist  8 Bit lang (+ Invertierung). Demnach sollten ja theoretisch Werte 
im Bereich von 0-255 mit einem Sendevorgang übertragbar sein, oder? 
Jetzt lassen sich soweit ich das verstanden habe die Daten ja "nur" in 
hex-Darstellung übertragen. Ich würde aber gerne mit Zahlen im 
Dezimalformat arbeiten. Wie kann ich denn beispielsweise eine 
übertragene "0x009A" nach dem Senden als  "154" darstellen. Und was ist 
wenn beispielsweise die Zahl "456" übertragen werden soll. Macht es dann 
Sinn die Zahl in "45" + "6" zu trennen, in zwei Sendevorgängen zu 
übertragen und anschließend wieder zusammenzufügen?

Danke

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

IR-Bastelei schrieb:
> Ich übertrage momentan im NEC Protokoll. Was ich mich frage ist, ob es
> Protokolle gibt, die Daten schneller übertragen können.

Beim NEC Protokoll in der Standard-Fassung gilt:
1
8 Bit Adresse + 8 Bit invertierte Adresse + 8 Bit Daten + 8 Bit invertierte Daten

Wenn Du die Adresse (8 bit) immer gleich hältst, kannst Du pro Frame nur 
8 Bit Daten, also ein Byte übertragen.

Beim NEC-Protokoll in der Extended Fassung gilt:
1
16 Bit Adresse + 8 Bit Daten + 8 Bit invertierte Daten

Wenn Du Dich hier auf eine 8-Bit-Adresse beschränkst, kannst Du in den 
zweiten 8 Bit weitere 8 Bit Daten reinstecken. Damit erhöhst Du die 
Datenrate auf 16 Bits (= 2 Bytes) pro Frame. Allerdings ist das 
Verfrachten von jeweils 8 Bit in die Geräteadresse ein wenig tricky und 
daher nicht so elegant.

Alternative wäre ein anderes Protokol mit weniger Overhead, z.B. LEGO:

https://www.mikrocontroller.net/articles/IRMP#LEGO

Das verwendet überhaupt keine Adresse, sondern lediglich 16 Bit Daten, 
die Du komplett nutzen kannst. Solange Du keine weitere 
LEGO-Fernbedienung in demselben Raum verwendest, sollte es also kein 
Kollisions-Problem geben. Zudem ist der LEGO-Frame recht kurz, nämlich 
zwischen 8,0 (alles Nullen) und 12,5 msec (alles Einsen).

Damit solltest Du 5 mal soviele Frames wie bei NEC versenden können. 
Nutzt Du die Datenbreite von 16 Bit gegenüber 8 Bit beim 
Standard-NEC-Protokoll, bist Du bereits bei der 10-fachen 
Geschwindigkeit.

LEGO war jetzt nur ein Beispiel, andere von IRMP unterstützte Protokolle 
findest Du hier:

https://www.mikrocontroller.net/articles/IRMP#Die_IR-Protokolle_im_Detail

Da kannst Du dann die jeweiligen Framelängen mit dem Taschenrechner 
zusammenrechnen. Ich halte LEGO jedoch wegen der fehlenden Adresse schon 
für recht schmal und damit auch für schnell. Wegen der fehlenden 
Redundanz hast Du aber keine so hohe Datensicherheit wie bei NEC.

Welche Datenrate schwebt Dir denn vor?

: Bearbeitet durch Moderator
von Stefan F. (Gast)


Lesenswert?

> Macht es dann Sinn die Zahl in "45" + "6" zu trennen, in zwei
> Sendevorgängen zu übertragen und anschließend wieder zusammenzufügen?

Im Prinzip ja. Nur würde ich sie nicht dezimal trennen, sondern binär. 
Denn das kann der µC viel schneller mit weniger Aufwand.

465 = 0000 0001 1100 1000

Also zwei Bytes. Die sendest du einfach nacheinander.
0000 0001
1100 1000

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

IR-Bastelei schrieb:
> Sagen wir einmal ich möchte maximal dreistellige Zahlen übertragen.

Wie Stefan schon schrieb: Ich würde sie nicht im ASCII-Format, also 
"456", sondern binär übertragen. Dann brauchst Du nicht 3 Bytes für die 
3 ASCII-Ziffern, sondern lediglich 2 Bytes, also genau 16 Bits. Dann 
hast Du einen Zahlenbereich von 0 bis 65535 statt nur 0 bis 999.

Dafür schreibst Du im Sender:
1
    uint16_t value = 456; // irgendein Wert zwischen 0 und 65535
2
3
    irmp_data.protocol = IRMP_LEGO_PROTOCOL; // use LEGO protocol
4
    irmp_data.address  = 0;                  // not used by LEGO
5
    irmp_data.command  = value;              // value 0...65535
6
    irmp_data.flags    = 0;                  // no repetition
7
8
    while (irsnd_is_busy ())
9
    {
10
        ;
11
    }
12
13
    irsnd_send (&irmp_data, 0);

Und im Empfänger:
1
    uint16_t value;       // Empfangener Wert
2
3
    if (irmp_get_data (&irmp_data) && irmp_data.protocol == IRMP_LEGO_PROTOCOL)
4
    {
5
        value = irmp_data.command;
6
        // do something with value
7
    }

Nicht vergessen, das LEGO-Protokoll in irmpconfig.h und irsndconfig.h zu 
aktivieren ;-)

: Bearbeitet durch Moderator
von IR-Bastelei (Gast)


Lesenswert?

Frank M. schrieb:
> Welche Datenrate schwebt Dir denn vor?

Das ganze soll irgendwann mal ein Spiel werden, bei dem es teilweise 
auch auf Reaktionszeit ankommt. Genaueres dazu kann ich noch nicht 
sagen, da sehr in der Überlegungsphase. Deswegen gilt leider nur der 
unqualifizierte Spruch: "Je schneller , desto besser". Gleichzeitig 
sollte es aber auch zuverlässig sein. Da es mehrere Spieler geben wird, 
die Signale empfangen ist eine Adressierung schon wichtig. Allerdings 
könnte ich von den 16 Bit ja die ersten 4 für die Adressierung 
hernehmen, was dann maximal 16 Spieler ermöglicht. Die Übrigen 12 Bit 
reichen an Datenvolumen mehr als aus. Sollte ja eigentlich 
funktionieren.

Stefan U. schrieb:
> Also zwei Bytes. Die sendest du einfach nacheinander.
> 0000 0001
> 1100 1000

Klingt sinnvoll. Ich habe die Protokolle nicht implementiert, aber 
soweit ich das verstanden habe müssen die Daten im Hexadezimalsystem 
übertragen werden?!

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

IR-Bastelei schrieb:
> Da es mehrere Spieler geben wird, die Signale empfangen ist eine
> Adressierung schon wichtig.

Das muss aber nicht unbedingt die IR-Geräteadresse sein. Wenn Du das 
(schnellere) LEGO-Protokoll nutzt, kannst Du die vorhandenen 16 Bit ja 
selbst unterteilen, nämlich:

- 4 Bit Spieler-Adresse ((möglicher Bereich 0...15)
- 12 Bit Wert (möglicher Bereich 0...4095)

Dann wäre obiges LEGO-Beispiel folgendermaßen abzuändern:
1
    uint16_t player = 3;  // irgendein Wert zwischen 0 und 15
2
    uint16_t value = 456; // irgendein Wert zwischen 0 und 4095
3
4
    irmp_data.protocol = IRMP_LEGO_PROTOCOL;       // use LEGO protocol
5
    irmp_data.address  = 0;                        // not used by LEGO
6
    irmp_data.command  = (player << 12) | value;   // value 0...65535
7
    irmp_data.flags    = 0;                        // no repetition
8
9
    while (irsnd_is_busy ())
10
    {
11
        ;
12
    }
13
14
    irsnd_send (&irmp_data, 0);

Und im Empfänger:
1
#define MY_PLAYER_ID  3   // Ich bin Spieler Nr. 3
2
3
    uint16_t player;      // Empfangener Spieler
4
    uint16_t value;       // Empfangener Wert
5
6
    if (irmp_get_data (&irmp_data) && irmp_data.protocol == IRMP_LEGO_PROTOCOL)
7
    {
8
        player = (irmp_data.command & 0xF000) >> 12); // upper 4 bit
9
        value  = irmp_data.command & 0x0FFF;          // lower 12 bit
10
11
        if (player == MY_PLAYER_ID)
12
        {
13
            // do something with player and value
14
        }
15
    }

IR-Bastelei schrieb:
> aber soweit ich das verstanden habe müssen die Daten im
> Hexadezimalsystem übertragen werden?!

Nein, die Übertragung ist binär. Einfach den gewünschten Wert in 
irmp_data.command reinschreiben bzw. rauslesen, siehe Beispiel.

P.S.
Ich persönlich würde nur 15 Spieler (1...15) vorsehen und die Spielernr. 
0 als Broadcast-Adresse vorsehen. Dann kannst Du bei einem 
Reaktionsspiel zum Beispiel allen Empfängern einen gemeinsamen 
Start-Befehl schicken, falls das sinnvoll ist.

: Bearbeitet durch Moderator
von IR-Bastelei (Gast)


Lesenswert?

Frank M. schrieb:
> Das muss aber nicht unbedingt die IR-Geräteadresse sein. Wenn Du das
> (schnellere) LEGO-Protokoll nutzt, kannst Du die vorhandenen 16 Bit ja
> selbst unterteilen, nämlich:
>
> - 4 Bit Spieler-Adresse ((möglicher Bereich 0...15)
> - 12 Bit Wert (möglicher Bereich 0...4095)

Vielen Dank. So war das

IR-Bastelei schrieb:
> Allerdings
> könnte ich von den 16 Bit ja die ersten 4 für die Adressierung
> hernehmen, was dann maximal 16 Spieler ermöglicht. Die Übrigen 12 Bit
> reichen an Datenvolumen mehr als aus. Sollte ja eigentlich
> funktionieren.

auch gemeint.

Frank M. schrieb:
> Dann kannst Du bei einem
> Reaktionsspiel zum Beispiel allen Empfängern einen gemeinsamen
> Start-Befehl schicken, falls das sinnvoll ist.

Gute Idee soetwas kann nie schaden ! Dankesehr. Ich werde die Tage mal 
ein bisschen mit dem LEGO Protokoll experimentieren. Beim schnellen 
Überfliegen der anderen Protokolle ist mir kein "schnelleres" ins Auge 
gesprungen.

von Sascha W. (sascha-w)


Lesenswert?

IR-Bastelei schrieb:
> Beim schnellen
> Überfliegen der anderen Protokolle ist mir kein "schnelleres" ins Auge
> gesprungen.
Es steht dir natürlich frei ein eigenes Protokoll zu erfinden was genau 
die benötigte Datenmenge mit entsprechender Bitrate überträgt.
IRMP ist ja darauf ausgelegt Signale von handelsüblichen Fernbedienungen 
zu dekodieren um eigene Elektronik damit zu steuern, oder Signale zu 
kodieren um mit eigener Elektronik vorhandene Geräte zu steuern.
Dabei kannst du dich ja an ein vorhandenes Protokoll anlehnen und dieses 
für deine Zwecke anpassen. Entscheidend ist ja nur wie die Bits kodiert 
sind (Pulsdauer, Manchaster, ...), wie die Päambel aussieht und welche 
Prüfinformationen hinzugefügt werden.

Sascha

von IR-Bastelei (Gast)


Angehängte Dateien:

Lesenswert?

Sascha W. schrieb:
> Es steht dir natürlich frei ein eigenes Protokoll zu erfinden was genau
> die benötigte Datenmenge mit entsprechender Bitrate überträgt.

Danke werde ich drüber nachdenken. Gibt es dort Grenzen, wie lang/kurz 
die Pulsdauer für 1/0 etc. sein dürfen?

Frank M. schrieb:
> Dann wäre obiges LEGO-Beispiel folgendermaßen abzuändern:

Ich habe mein Programm entsprechend umgeändert. Leider scheint das noch 
nicht ganz so zu funktionieren. Erstmal was habe ich geändert:

1. In dem Data-Struct das Protokoll auf LEGO geändert und die Adresse 
rausgenommen. ( =0)

2. LEGO-Protokoll in beiden Konfigdateien aktiviert und den Interrupt 
auf "20000" gestellt.

Bei mir in Hterm kommt zwar was an aber zum einen sehr unregelmäßig, 
wirkt fast willkürlich und zum anderen auch nicht das Richtige.Schreibe 
ich beispielsweise in die Variable "value" eine "1245" und lass mir das 
im Ascii-Format im Hterm anzeigen kommt dort eine "04DD". (Auch wenn das 
die hex-Darstellung der Zahl ist aber zumindest die Umrechnung stimmt) 
So weit so gut. Stell ich die Einstellung aber auf Dezimal werden die 
Zeichen der Ascii-Tabelle einsprechend einzelnd umgerechnet (siehe 
Screenshot). Wie bekomme ich es hin, dass ich tatsächlich die 
Dezimalzahl übertragen bekomme und woran könnte es liegen dass die 
Übertragung so langsam (gefühlt kommen Daten alle 2 Sekunden und dann 
manchmal viele auf einmal) und unregelmäßig kommen?

Danke nochmal für eure Hilfe!

von Stefan F. (Gast)


Lesenswert?

Die Dezimal Zahl 1245 ist in hexadezimaler Darstelleung 04DD.

Finde heraus, was der Unterschied zwischen einer Zahl und einer 
Zeichenkette ist. Danach findest du heraus, wie die drei gängigen 
Darstellungsformen für Zahlen funktionieren: Dezimal, Hexadezimal und 
Binär.

> Wie bekomme ich es hin, dass ich tatsächlich die
> Dezimalzahl übertragen bekomme

Deine Schnittstelle überträgt Bits. Wie die Dezimalzahl in Bits codiert 
wird und Empfängerseitig wieder decodiert wird, bleibt Dir überlassen. 
Es hängt ganz von deinem Programm ab.

Wenn du in HTerm die Anzeige auf "Decimal" stellst, dann geht HTerm 
davon aus, daß jeweils 8 Bits eine Zahl bedeuten. Soweit ich mitbekommen 
habe, hast du dich jedoch dazu entschlossen, mehr als 8 Bits für eine 
Zahl zu übertragen. Daher passt die Darstellungsform von HTerm nicht zu 
deinem Sende-Programm.

Daß HTerm überhaupt Dezimale Ausgabe unterstützt, ist schon eine 
Besonderheit. Der gemeinsame Nenner, den alle Terminalprogramme 
Standardmäßig unterstützen ist ASCII Codierung (siehe Wikipedia).

Im C Programm kannst du die Funktionen atoi(), itoa(), printf() und 
eventuell scanf() benutzen, um zwischen Binärer und Dezimaler 
Darstellung zu konvertieren.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

IR-Bastelei schrieb:
> Wie bekomme ich es hin, dass ich tatsächlich die Dezimalzahl übertragen
> bekomme

Du bekommst eine Zahl übertragen und nichts anderes. Dass dies im 
Binärformat geschieht, brauchst Du nicht zu wissen. Du steckst eine Zahl 
rein und Du bekommst dieselbe Zahl auch wieder raus.

Ob das eine Dezimal- oder Hexadezimalzahl ist, ist lediglich eine Frage 
der Darstellung bei der Ausgabe, nicht programmintern. Da ist es 
einfach eine Zahl - und nichts anderes.

Wenn Du schreibst
1
  int ch = 10;

oder Du schreibst
1
  int ch = 0x0A;

dann ist das absolut identisch. In der Variablen ch steht nachher der 
identische Wert.

> und woran könnte es liegen dass die Übertragung so langsam
> (gefühlt kommen Daten alle 2 Sekunden und dann manchmal viele auf
> einmal) und unregelmäßig kommen?

Ich vermute mal, dass dies an der Erhöhung der Interrupts auf 20000/sec 
liegt. Das scheint für Dein Programm ein bisschen viel zu sein und das 
Timing kommt ins Schleudern. Du könntest den Takt per Quarz auf 16 MHz 
verdoppeln. Dann bist Du auf der sicheren Seite.

Es wäre nicht schlecht, wenn Du Deinen bisherigen Code auch mal zeigen 
würdest. Ich hoffe, beim Compilieren ist die Optimierung 
eingeschaltet... oder testest Du im Debug-Modus ohne jegliche 
Optimierung?

von IR-Bastelei (Gast)


Angehängte Dateien:

Lesenswert?

Danke für eure Antworten. Ich hatte einfach einen Denkfehler. Mit dem 
NEC-Protokoll klappt jetzt alles so wie ich mir das vorgestellt habe.

Ich habe das LEGO-Protokoll nochmal ausprobiert. Es bleibt aber das 
Verzögerungsproblem. Dann liegt es vielleicht echt an dem Timing. Einen 
externen Quarz möchte ich eigentlich vermeiden. Deswegen such ich noch 
andere Protokolle. Ich habe das DENON ausprobiert, welches von den Bits 
auch passen würde allerdings wollte das auch nicht so recht. Außerdem 
das NETBOX-Protokoll aber da kam gar nix an. Steht aber ja auch bei, 
dass es ein Prototyp ist.

Der Gedanke ein Protokoll zu schreiben oder anzupassen kommt mir immer 
naheliegender. Dafür muss ich aber erstmal den gesamten Code durchgehen 
um zu schauen wo ich da anfange. An sich wäre eine Datenbreite von 12-13 
Bits ideal. 2-3 als Adressbits und 10 Bits als Nutzdaten. Meinen Code 
häng ich nochmal an.

von Stefan F. (Gast)


Lesenswert?

Für zuverlässige UART Kommunikation (Hterm) wirst du allerdings kaum um 
einen Quarz herum kommen. Die UART Schnittstelle verlangt einen Takt mir 
maximal 2% Abweichung. Davon musst du noch die Ungenauigkeit des 
Baudraten-Generator subtrahieren.

von IR-Bastelei (Gast)


Lesenswert?

Stefan U. schrieb:
> Für zuverlässige UART Kommunikation (Hterm) wirst du allerdings kaum um
> einen Quarz herum kommen.

Die läuft eigentlich zuverlässig. Hab zumindest bisher keine Probleme 
bemerken können. Ist momentan aber sowieso hauptsächlich zum debuggen..

Frank M. schrieb:
> Ich hoffe, beim Compilieren ist die Optimierung
> eingeschaltet...

steht momentan auf "-O2"

von Stefan F. (Gast)


Lesenswert?

> Die läuft eigentlich zuverlässig.
> Hab zumindest bisher keine Probleme bemerken können.

Dann lege die Platine mal vorher zwei Stunden in die Sonne. Oder im 
Winter auf eine kalte Marmortreppe.

von IR-Bastelei (Gast)


Lesenswert?

Stefan U. schrieb:
> Dann lege die Platine mal vorher zwei Stunden in die Sonne. Oder im
> Winter auf eine kalte Marmortreppe.

Ja das wären natürlich unschöne Zustände. Ist aber erstmal relativ 
unrealistisch. Ich weiß natürlich dass du damit grundlegend 
Temperaturschwankungen meinst. Im Endeffekt kommen die Platinen aber in 
Gehäuse und sind auch nur für den Einsatz im Haus/Tisch. Also sind so 
große Temperaturschwankungen nicht zu erwarten. Probieren würde ich es 
erstmal gerne ohne Quarz. Nachrüsten könnte ich den ja immer noch nach 
einer Testphase. Wie verhalten sich denn Allgemein Quarze bzw. 
Mikrocontroller. Kann so ein Gehäuse mit Platine drin auch mal im 
hektischen Spielgeschehen aus Tischhöhe auf den Boden fallen oder sind 
dann direkt Schäden zu erwarten? Hab gerade bisschen in Datenblättern 
von Quarzen und Atmel geguckt. Konnte da nichts zu finden.

Danke

von Sascha W. (sascha-w)


Lesenswert?

IR-Bastelei schrieb:
> Sascha W. schrieb:
>> Es steht dir natürlich frei ein eigenes Protokoll zu erfinden was genau
>> die benötigte Datenmenge mit entsprechender Bitrate überträgt.
>
> Danke werde ich drüber nachdenken. Gibt es dort Grenzen, wie lang/kurz
> die Pulsdauer für 1/0 etc. sein dürfen?
ja die Grenzen gibt dir der TSOP vor, im Datenblatt findest du Angaben 
zur minimalen und zur maximalen Dauer der Bursts sowie des minimalen 
Zwischenabstands (meist in Perioden der Modulationsfrequenz) damit die 
Demodulation noch funktioniert.

Sascha

von Stefan F. (Gast)


Lesenswert?

> Im Endeffekt kommen die Platinen aber in Gehäuse und sind
> auch nur für den Einsatz im Haus/Tisch. Also sind so
> große Temperaturschwankungen nicht zu erwarten.

Sicher? Mal angenommen, du schaltest das Gerät bei 20°C ein und benutzt 
es ein paar Stunden. 30°C bis 50°C sind durchaus üblich.

> Kann so ein Gehäuse mit Platine drin auch mal im
> hektischen Spielgeschehen aus Tischhöhe auf den Boden
> fallen oder sind dann direkt Schäden zu erwarten?

Du bist doch sicher älter als 3 Jahre und hast mit diesen Situationen 
bereits Erfahrungs gemacht. Dann müsste Dir absolut klar sein, daß 
Geräte häufig wenn nicht gar meisten kaputt gehen, wenn sie vom Tisch 
fallen.

Quarze sind prinzipiell auch Stoßempfindlich, mir ist aber noch nie 
einer zerbrochen.

von IR-Bastelei (Gast)


Lesenswert?

Stefan U. schrieb:
> Sicher? Mal angenommen, du schaltest das Gerät bei 20°C ein und benutzt
> es ein paar Stunden. 30°C bis 50°C sind durchaus üblich.

Sicher kann man sich natürlich nie sein. Das wird sich erst zeigen wenn 
man es testet. Über mehrere Stunden werden die Geräte aber mit hoher 
Wahrscheinlichkeit nicht laufen. Und bei den geringen Strömen die 
fließen werden kann ich mir keine 50 °C vorstellen. Aber wie 
gesagt...wird sich zeigen.

Stefan U. schrieb:
> Du bist doch sicher älter als 3 Jahre

Gerade so. Leider eher in dem Alter in dem das mit dem Zählen nicht mehr 
so ernst genommen wird.

Stefan U. schrieb:
> Dann müsste Dir absolut klar sein, daß
> Geräte häufig wenn nicht gar meisten kaputt gehen, wenn sie vom Tisch
> fallen.

Im Gegenteil. Mir sind schon häufig Geräte runtergefallen und sie 
überleben es meistens. Manchmal sind ICs ja auch  vergossen. Allerdings 
weiß ich nicht, ob das zum Schutz des Innenlebens des Chips oder zum 
Schutz der Lötstellen oder zur Abschirmung ist..

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

IR-Bastelei schrieb:
> Frank M. schrieb:
>> Ich hoffe, beim Compilieren ist die Optimierung
>> eingeschaltet...
>
> steht momentan auf "-O2"

Stell das mal auf '-Os', denn dann sind auch die Delay Routinen passend.
NEC oder RC5 sind schon robuste Protokolle, optimal wäre es, wenn du mit 
einem von den beiden klarkommst.

Stefan U. schrieb:
> Quarze sind prinzipiell auch Stoßempfindlich, mir ist aber noch nie
> einer zerbrochen.

Mir (und meinen Kunden) dagegen schon des öfteren. Auch Resonatoren 
mögen hohe Beschleunigungen nicht.

von IR-Bastelei (Gast)


Lesenswert?

Matthias S. schrieb:
> optimal wäre es, wenn du mit
> einem von den beiden klarkommst.

Puuuhh..ganz schön viel Code. Was ich mich frage : Kann man das 
NEC-Protokoll vielleicht so anpassen, dass eben nicht 16 Bit Adresse + 
16 Bit Kommando übertragen werden, sondern eben 4 Bit Adresse und 20 Bit 
Kommando? Das wären immerhin schon 8 Bit gespart. Ich habe bisher nur 
diesen Abschnitt in "irmpprotocols.h" finden können.
1
#define NEC_START_BIT_PULSE_TIME                9000.0e-6                       // 9000 usec pulse
2
#define NEC_START_BIT_PAUSE_TIME                4500.0e-6                       // 4500 usec pause
3
#define NEC_REPEAT_START_BIT_PAUSE_TIME         2250.0e-6                       // 2250 usec pause
4
#define NEC_PULSE_TIME                           560.0e-6                       //  560 usec pulse
5
#define NEC_1_PAUSE_TIME                        1690.0e-6                       // 1690 usec pause
6
#define NEC_0_PAUSE_TIME                         560.0e-6                       //  560 usec pause
7
#define NEC_FRAME_REPEAT_PAUSE_TIME               40.0e-3                       // frame repeat after 40ms
8
#define NEC_ADDRESS_OFFSET                       0                              // skip 0 bits
9
#define NEC_ADDRESS_LEN                         16                              // read 16 address bits
10
#define NEC_COMMAND_OFFSET                      16                              // skip 16 bits (8 address + 8 /address)
11
#define NEC_COMMAND_LEN                         16                              // read 16 bits (8 command + 8 /command)
12
#define NEC_COMPLETE_DATA_LEN                   32                              // complete length

habe dort einfach mal spaßeshalber versucht die Werte anzupassen. Aber 
dann kam wie ich bereits erwartet hatte nichts mehr an.. Das wäre ja 
auch zu einfach. Wie tief muss man in den Code einsteigen, um ein 
Protokoll dementsprechend anzupassen? Und geht das überhaupt?

Matthias S. schrieb:
> Stell das mal auf '-Os'

Wird gemacht. Werden Delays ansonsten "wegoptimiert" ?

Matthias S. schrieb:
> Auch Resonatoren
> mögen hohe Beschleunigungen nicht

Erfahrung? Oder kennst du Orte an denen man das nachlesen könnte?

Dankesehr nochmals!

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

IR-Bastelei schrieb:
> Puuuhh..ganz schön viel Code.

Ich hatte sowieso schon immer mal dran gedacht, in IRMP und IRSND ein 
spezielles Protokoll mit Pulse-Distance-Coding einzubauen, das lediglich 
dafür gedacht ist, Daten zwischen zwei µCs zu übertragen. Ich würde es 
als Frame mit 16-Bit-Daten realisieren, wo man die Grenze zwischen 
Adresse und Daten frei wählen kann.

Ich kümmere mich heute abend mal darum und melde mich.

> Wie tief muss man in den Code einsteigen, um ein Protokoll
> dementsprechend anzupassen? Und geht das überhaupt?

Das geht schon, ist aber eher etwas für erfahrene Programmierer, da es 
sich hier um eine ziemlich komplexe Statemachine handelt, um den 
empfangenen Code schon während des Empfangs ohne Zwischenspeicherung des 
IR-Frames zu dekodieren.

Aber es wurden durchaus einige exotische Protokolle von anderen Leuten 
im IRMP/IRSND eingebaut und mir dann zur weiteren Verwendung zur 
Verfügung gestellt. Glaub mir: soviele Fernbedienungen habe ich nicht 
;-)

: Bearbeitet durch Moderator
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

IR-Bastelei schrieb:
> Leider scheint das noch nicht ganz so zu funktionieren.

Ich habe beim Durchsehen des IRMP-Sources festgestellt, warum Dein Test 
mit LEGO fehlschlug: 4 der 16 Bit werden intern als CRC benutzt, so dass 
netto nur noch 12 Byte zur freien Verfügung stehen.

Sorry, das hatte ich vergessen und Dich mit dem LEGO-Protokoll auf den 
falschen Weg geführt. Immerhin ist jetzt der Grund klar, warum es mit 
LEGO nicht geklappt hat.

Wie ich ja eben schrieb, dachte ich sowieso daran, mal ein 
IRMP-spezifisches Protokoll zwecks Datenübertragung einzubauen.

Ich habs eben mal gemacht:

- Neue Version 3.0.8
- Neues Protokoll: IRMP16

Die Sources können über den Download-Link von IRMP und IRSND 
heruntergeladen werden.

Das IRMP16-Protokoll benutzt 16 Bit Daten in irmp.command und keine 
Adressbits. Die 16 Bit sind völlig transparent 1:1 frei verwendbar.

Im untenstehenden Anwendungsbeispiel habe ich die 16 Bit aufgeteilt in:

4 Bit Spielernummer 0-15
12 Bit Werte 0-4095

Sender:
1
    uint16_t player = 3;  // irgendein Wert zwischen 0 und 15
2
    uint16_t value = 456; // irgendein Wert zwischen 0 und 4095
3
4
    irmp_data.protocol = IRMP_IRMP16_PROTOCOL;     // use IRMP16 protocol
5
    irmp_data.address  = 0;                        // not used by IRMP16
6
    irmp_data.command  = (player << 12) | value;   // value 0...65535
7
    irmp_data.flags    = 0;                        // no repetition
8
9
    while (irsnd_is_busy ())
10
    {
11
        ;
12
    }
13
14
    irsnd_send (&irmp_data, 0);

Und im Empfänger:
1
#define MY_PLAYER_ID  3   // Ich bin Spieler Nr. 3
2
3
    uint16_t player;      // Empfangener Spieler
4
    uint16_t value;       // Empfangener Wert
5
6
    if (irmp_get_data (&irmp_data) && irmp_data.protocol == IRMP_IRMP16_PROTOCOL)
7
    {
8
        player = (irmp_data.command & 0xF000) >> 12); // upper 4 bit
9
        value  = irmp_data.command & 0x0FFF;          // lower 12 bit
10
11
        if (player == MY_PLAYER_ID)
12
        {
13
            // do something with player and value
14
        }
15
    }

Viel Spaß,

Frank

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

IR-Bastelei schrieb:
> Matthias S. schrieb:
>> Stell das mal auf '-Os'
>
> Wird gemacht. Werden Delays ansonsten "wegoptimiert" ?

Wegoptimiert nicht, aber die Zeiten stimmen nicht. Die avr-libc geht bei 
den Routinen von '-Os' aus, weil das die Einstellung ist, die den 
kleinsten Code erzeugt und deswegen bevorzugt wird.

von Stefan F. (Gast)


Lesenswert?

Hier ist die Soku dazu:
http://www.nongnu.org/avr-libc/user-manual/group__util__delay.html

"In order for these functions to work as intended, compiler 
optimizations must be enabled".

Nach meiner Erfahrung funktiont es mit -Os, -O1 und -O2 einwandfrei.

von IR-Bastelei (Gast)


Angehängte Dateien:

Lesenswert?

Frank M. schrieb:
> Ich habs eben mal gemacht:

Ui das ging schnell. Danke !!

Hab es gerade ausprobiert. Ist super flott allerdings bekomme ich Fehler 
bei der Übertragung. Im Anhang mal ein Auschnitt von dem was bei mir in 
Hterm ankommt. Die zu übertragende Zahl war "899". Woran könnte das 
liegen? Außer dem Protokoll habe ich nichts geändert..

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

IR-Bastelei schrieb:
> Hab es gerade ausprobiert. Ist super flott allerdings bekomme ich Fehler
> bei der Übertragung. Im Anhang mal ein Auschnitt von dem was bei mir in
> Hterm ankommt.

Zeige bitte mal den Source der Senderoutine.

von IR-Bastelei (Gast)


Angehängte Dateien:

Lesenswert?

Frank M. schrieb:
> Zeige bitte mal den Source der Senderoutine.

Kein Problem. Hat sich aber wie gesagt nichts daran geändert.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

IR-Bastelei schrieb:
> Hat sich aber wie gesagt nichts daran geändert.

F_INTERRUPTS ist wieder auf 15000? Sollte dicke reichen.

von IR-Bastelei (Gast)


Lesenswert?

Frank M. schrieb:
> F_INTERRUPTS ist wieder auf 15000? Sollte dicke reichen.

Ja habe ich in beiden config-Dateien wieder auf 15000 stehen.

von IR-Bastelei (Gast)


Lesenswert?

Noch zur Info. Sobald ich das Protokoll wieder auf NEC stelle und den 
Rest komplett identisch lasse funktioniert die Übertragung wieder 
reibungslos.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Dann ändere mal bitte folgenden Block in irmp.c:
1
#define IRMP16_START_BIT_PULSE_LEN_MIN          ((uint_fast8_t)(F_INTERRUPTS * IRMP16_START_BIT_PULSE_TIME * MIN_TOLERANCE_20 + 0.5) - 1)
2
#define IRMP16_START_BIT_PULSE_LEN_MAX          ((uint_fast8_t)(F_INTERRUPTS * IRMP16_START_BIT_PULSE_TIME * MAX_TOLERANCE_20 + 0.5) + 1)
3
#define IRMP16_START_BIT_PAUSE_LEN_MIN          ((uint_fast8_t)(F_INTERRUPTS * IRMP16_START_BIT_PAUSE_TIME * MIN_TOLERANCE_20 + 0.5) - 1)
4
#define IRMP16_START_BIT_PAUSE_LEN_MAX          ((uint_fast8_t)(F_INTERRUPTS * IRMP16_START_BIT_PAUSE_TIME * MAX_TOLERANCE_20 + 0.5) + 1)
5
#define IRMP16_PULSE_LEN_MIN                    ((uint_fast8_t)(F_INTERRUPTS * IRMP16_PULSE_TIME * MIN_TOLERANCE_20 + 0.5) - 1)
6
#define IRMP16_PULSE_LEN_MAX                    ((uint_fast8_t)(F_INTERRUPTS * IRMP16_PULSE_TIME * MAX_TOLERANCE_20 + 0.5) + 1)
7
#define IRMP16_1_PAUSE_LEN_MIN                  ((uint_fast8_t)(F_INTERRUPTS * IRMP16_1_PAUSE_TIME * MIN_TOLERANCE_20 + 0.5) - 1)
8
#define IRMP16_1_PAUSE_LEN_MAX                  ((uint_fast8_t)(F_INTERRUPTS * IRMP16_1_PAUSE_TIME * MAX_TOLERANCE_20 + 0.5) + 1)
9
#define IRMP16_0_PAUSE_LEN_MIN                  ((uint_fast8_t)(F_INTERRUPTS * IRMP16_0_PAUSE_TIME * MIN_TOLERANCE_20 + 0.5) - 1)
10
#define IRMP16_0_PAUSE_LEN_MAX                  ((uint_fast8_t)(F_INTERRUPTS * IRMP16_0_PAUSE_TIME * MAX_TOLERANCE_20 + 0.5) + 1)

Die Toleranzwerte habe ich hier enger gefasst, nämlich von 40 auf 20 
Prozent, also XXX_TOLERANCE_40 auf XXX_TOLERANCE_20 geändert.

Grund: Die Unterschiede der Pausenlängen für 1 und 0 sind recht eng 
beieinander. Bei den meisten Protokollen liegen die weiter auseinander 
(3-4 faches). Ich wollte aber die Frames relativ kurz halten, deshalb 
sind die Pausenverhältnisse lediglich im Verhältnis 1:2 statt 1:3 oder 
gar 1:4. Bei 40% Toleranz gibt es aber schon knapp überlappende 
Bereiche, die sich durch ein leicht abweichendes Timing der beiden µCs 
(ohne Quarz!) durchaus auwirken können.

Wenn das auch nicht reicht, solltest Du folgenden Block in 
irmpprotocols.h austauschen:
1
#define IRMP16_START_BIT_PULSE_TIME              842.0e-6                       //  842 usec pulse (32 x 1/38kHz)
2
#define IRMP16_START_BIT_PAUSE_TIME             1684.0e-6                       // 1684 usec pause (64 x 1/38kHz)
3
#define IRMP16_PULSE_TIME                        421.0e-6                       //  421 usec pulse (16 x 1/38kHz)
4
#define IRMP16_1_PAUSE_TIME                     1263.0e-6                       // 1264 usec pause (48 x 1/38kHz)
5
#define IRMP16_0_PAUSE_TIME                      421.0e-6                       //  421 usec pause (16 x 1/38kHz)
6
#define IRMP16_FRAME_REPEAT_PAUSE_TIME            40.0e-3                       // frame repeat after 40ms

Dann sind die Verhältnisse 1:3 statt 1:2.

Übrigens: Du kannst noch, um die Abstände zwischen den Frames kürzer zu 
halten, den letzten Wert IRMP16_FRAME_REPEAT_PAUSE_TIME von 40.0e-3 auf 
10.0e-3 ändern.

von IR-Bastelei (Gast)


Lesenswert?

Hi Frank,

das anpassen der Toleranzen hat den Job schon erfüllt. Jetzt 
funktioniert es super !

Vielen Dank nochmals für die Mühe

von batman (Gast)


Lesenswert?

Schön, wenn ein Plan funktioniert aber um simple Datenwörter zu 
übertragen, kann man auch gleich die UART nehmen, das ist etwas 
effizienter, als immer die ganze Protokollerkennung und ständiges 
Port-Polling zur Empfangsbereitschaft laufen zu lassen.
Bei der TxD muß man natürlich noch die Modulation einschleifen und 
Frame/Baudrate sinnvoll einrichten.

von IR-Bastelei (Gast)


Lesenswert?

batman schrieb:
> Schön, wenn ein Plan funktioniert aber um simple Datenwörter zu
> übertragen, kann man auch gleich die UART nehmen, das ist etwas
> effizienter, als immer die ganze Protokollerkennung und ständiges
> Port-Polling zur Empfangsbereitschaft laufen zu lassen.
> Bei der TxD muß man natürlich noch die Modulation einschleifen und
> Frame/Baudrate sinnvoll einrichten.

Danke für die Anmerkung. Du meinst den OUT vom TSOP direkt an den TX vom 
UART hängen? Ich bin noch sehr am Anfang meiner Programmierkarriere aber 
wenn du mir ein paar genauere Informationen geben könntest wie du das 
meinst denke ich da gerne drüber nach. Effizient ist immer gut!

von IR-Bastelei (Gast)


Lesenswert?

Hallo zusammen,

ich melde mich mal wieder zurück. Bin bei der Entwicklung schon ein 
wenig weiter und ich bin mir leider relativ sicher, dass am Ende die 
Datenrate welche ich mit IRMP und IRSND erreiche nicht ausreichen wird. 
Mit dem IRMP16-Protokoll sind rein rechnerisch ca. 30 Messwerte 
erreichbar (Alle Bits ==1 ). Die kann ich per "Messung" auch bestätigen. 
Jetzt aber angenommen es sind 8 Spieler mit in der Runde, dann sind es 
schon < 4 Messwerte pro Sekunde, denn es wird so sein, dass ein Spieler 
auch mal Signale an mehrere Spieler gleichzeitig aussenden muss.

Ich habe bereits versucht, die Puls- und Pausenzeiten anzupassen. Ich 
hab mich dabei an der minimalen Pausenzeit des TSOPs orientiert. Laut 
Datenblatt muss die Pause nach einem Puls mindestens 12 Zyklen lang 
sein, was bei 38 kHz ca. 315 µs wären. Darunter ging tatsächlich gar nix 
mehr. Mit 350 µs hat es noch funktioniert. Die anderen Werte habe ich 
natürlich auch dementsprechend angepasst. Außerdem habe ich die Zeit 
zwischen den Frames bis auf 7 ms reduziert. So kam ich letztenendes auf 
ca. 47 Übertragungen pro Sekunden. Auch keine große Steigerung. Ich habe 
auch noch versucht die Bitzahl auf 12 Bit zu reduzieren, allerdings hat 
das nicht so ohne weiteres funktioniert und ich konnte auch nicht 
festellen welche Funktion das verursacht hat. (Die letzten vier Bits 
waren immer abgeschnitten, es konnte also nur Zahlen in 16er Schritten 
übertragen werden. Ich hatte zunächst bei der "Bitreverse"-Funktion 
etwas vermutet konnte es aber nicht beheben)

Ich hab mich jetzt also noch weiter zum Thema Infrarot-Übertragung 
belesen und habe überlegt IrDA zu nutzen. Damit sind ja wesentlich 
höhere Datenraten nötig. Das ganze sollte allerdings nicht unendlich 
kompliziert werden und ich würde gerne meine Atmega328p weiterverwenden. 
Eventuell muss ich dann doch über externe Quarze nachdenken. Ich habe 
mir den Schnittstellen-IC MCP2120 angeschaut. Seh ich das richtig, dass 
ich  meine RX/TX-Leitungen vom MC einfach an den Chip hänge, und der 
übernimmt die Modulation/Demodukation und an der Empfängerseite kommt 
das Gesendete wieder raus? Tranceiver muss natürlich auch noch an den 
IC.

Danke schonmal.

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.