Aus RN-Wissen.de
Wechseln zu: Navigation, Suche
Balkonkraftwerk Speicher und Wechselrichter Tests und Tutorials

(WebLinks: ===WebLinks=== --> ==WebLinks==)
 
(78 dazwischenliegende Versionen von 6 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
Dieser Artikel befindet sich möglichrweise im Aufbau. Siehe [[Diskussion:Codesammlung_avr-gcc]]
+
Dieser Code implementiert einen Interrupt-getriebenen RC5-Empfänger.
  
=IR-Empfang=
+
Auf eine Flanke an einem externen INT hin werden die nachfolgenden Pulslängen gemessen und in einer Struktur bereitgestellt, falls es sich um [[RC5-Code]] handelt und die Empfängeradresse übereinstimmt.
==RC5 Decoder für AVR Mega==
+
===Beschreibung===
+
  
Dieser Code impementiert einen interrupt-getriebenen RC5-Empfänger.
+
{{FarbigerRahmen|
 +
Bitte beachte auch die Hinweise zu [[avr-gcc#Inkompatibilität|Inkompatibilitäten von avr-gcc]]!
 +
}}
  
Auf eine Flanke an einem externen INT hin werden die nachfolgenden Pulslängen gemessen und in einer Struktur bereitgestellt, falls es sich um RC5-Code handelt und die Empfängeradresse übereinstimmt.
+
=Abgrenzung=
  
Nicht alle Fernbedienungen halten sich genau an die RC5-Spezifikation und haben oft einen mehr oder weniger starken Jitter auf dem Signal. In konstanten Zeitabständen auf den Port zu schauen und anhand des gelesenen Wertes das RC5-Signal aufzubauen, funktioniert daher nicht zuverlässig.
+
Nicht alle Fernbedienungen halten sich genau an die RC5-Spezifikation und haben oft einen mehr oder weniger starken Jitter auf dem Signal. In konstanten Zeitabständen auf den Port zu schauen und anhand des gelesenen Wertes das RC5-Signal aufzubauen, funktioniert daher nicht zuverlässig bei allen Fernbedienungen.
  
====Resourcen====
+
Der Ansatz, den diese Implementierung verfolgt, ist aufwändiger und ergibt ein längeres Programm, hat aber dafür nicht den beschriebenen Nachteil.
  
{| {{Blauetabelle}}  
+
=Resourcen=
  |'''Resource'''
+
 
|'''Verbrauch (mit <code>-Os</code>)'''
+
{| {{Blauetabelle}} valign="top"
 +
  |- {{Hintergrund1}}
 +
!| Resource || Verbrauch (mit <tt>-Os</tt>)
 
  |-
 
  |-
  |I/O
+
  |I/O ||Timer0, 1 Pin für extern INT
|Timer0, 1 Pin für extern INT
+
 
  |-
 
  |-
  |Interrupts
+
  |Interrupts || Timer0 Overflow, 1 externer IRQ
|Timer0 Overflow, 1 externer IRQ
+
 
  |-
 
  |-
  |Flash
+
  |Flash || ~ 0x170 (370 Bytes)
  | ~ 0x180
+
  |- valign="top"
 +
|SRAM || statisch: 8<br/>Stack: 11
 +
|- valign="top"
 +
|Laufzeit,<br/>Erhöhung der IRQ-Latenz || ?, aber statisch abschätzbar
 
  |-
 
  |-
|SRAM
+
  |externe Hardware ||IR-Empfänger wie TSOP17xx, TSOP18xx, SFH 506-xx o.ä.
| statisch: 8<br>Stack: 11
+
|-
+
|Laufzeit
+
| ?
+
|-
+
  |externe Hardware
+
|IR-Empfänger wie TSOP17xx, TSOP18xx o.ä.
+
 
  |}
 
  |}
  
=====Schaltplan=====
+
=Schaltplan=
 +
 
 +
Das ist ein minimaler Anschlussplan für einen TSOP17xx. Um einen IR-Empfänger zu entstören und in verrauschter Umgebung einzusetzen, sei auf das jeweilige Datenblatt verwiesen.
 +
 
 +
<center>
 
{| {{Blaueschmaltabelle}}
 
{| {{Blaueschmaltabelle}}
 
  |[[Bild:Tsop-avr-connect.png|Anschluss TSOP17xx an AVR, R1 ca 10k&Omega;]]
 
  |[[Bild:Tsop-avr-connect.png|Anschluss TSOP17xx an AVR, R1 ca 10k&Omega;]]
Zeile 42: Zeile 42:
 
  |<div align="center">IR-Empfänger vom Typ TSOP17xx an AVR<br>R1 ca 10 k&Omega;</div>
 
  |<div align="center">IR-Empfänger vom Typ TSOP17xx an AVR<br>R1 ca 10 k&Omega;</div>
 
  |}
 
  |}
 +
</center>
  
====Interface====
+
Für RC5 empfiehlt sich die 36kHz-Variante, also z.B. ein TSOP1736.
 +
 
 +
Weitere IR-Empfänger-ICs sind SFH 506-xx
 +
 
 +
=Funktionsweise=
 +
 
 +
Diese RC5-Software braucht eine Zeitbasis, für welche Timer0 verwendet wird.
 +
Timer0 wird deshalb verwendet, weil er bei vielen AVRs der "schwächste" [[Timer]] ist,
 +
also der Timer, der am wenigsten Funktionalität bietet. So fehlt ihm bei vielen AVR-Modellen ein OutputCompare-Funktion, und er kann keine [[PWM]] erzeugen. Seine Funktionen reichen für einen RC5-Empfänger aber aus.
 +
 
 +
Die am externen Interrupt-Port (der beim Compilieren durch das Makro <tt>RC5_INT</tt> ausgewählt werden kann) gemessenen Zeiten zwischen eintreffenden Flanken, d.h. Wechseln zwischen LOW und HIGH, werden ausgewertet und in Bits umgewandelt. Falls die Zeiten nicht dem [[RC5-Code|RC5-Standard]] entsprechen, werden die Daten verworfen. Wurde ein kompletter RC5-Frame (also Adresse, Kommand, Flip-Bit, etc) empfangen und stimmt die übermittelte Adresse mit der Adresse überein, die bei der Initialisierung des Empfängers mit <tt>rc5_init</tt> angegeben wurde, dann werden die empfangenen Daten in der globalen Struktur <tt>rc5</tt> zur weiteren Auswertung gespeichert.
 +
 
 +
Von Timer0 wird der Overflow-Interrupt genutzt, um ungültigen Code zu erkennen und den Empfänger bei ungültigem Code wieder in einen definierten Zustand zu versetzten. Der externe Interrupt wertet die Zeiten aus, speichert die empfangenen Bits und baut so den Inhalt der <tt>rc5</tt>-Struktur auf.
 +
 
 +
Der Anwender braucht sich nicht um diese Interna zu kümmern. Nach Aufruf der Initialisierung läuft der RC5-Empfang "nebenher".
 +
 
 +
In der <tt>rc5</tt>-Struktur können die empfangenen Daten abgeholt werden, und über ihre <tt>.flip</tt>-Komponente wird der Empfang gesteuert und mitgeteilt, ob neue Daten angekommen sind.
 +
 
 +
=Interface=
 +
;rc5.h:
 
<pre>
 
<pre>
 
#define RC5_INT0 0
 
#define RC5_INT0 0
Zeile 52: Zeile 72:
 
typedef struct
 
typedef struct
 
{
 
{
uint8_t code;
+
        uint8_t code;
uint8_t addr;
+
        uint8_t addr;
volatile char flip;
+
        volatile signed char flip;
 
} rc5_t;
 
} rc5_t;
  
Zeile 61: Zeile 81:
 
</pre>
 
</pre>
  
;<code>void rc5_init (uint8_t addr)</code>: Initialisiert die Hardware für RC5-Empfang. Akzeptiert wird Code, der an Adresse <code>addr</code> geschickt wird. Falls <code>addr = RC5_ALL</code> bzw Bit 7 von <code>addr</code> gesetzt ist, werden alle Adressen akzeptiert.
+
;<tt>void rc5_init (uint8_t addr)</tt>: Initialisiert die Hardware für RC5-Empfang. Akzeptiert wird Code, der an Adresse <tt>addr</tt> geschickt wird. Falls <tt>addr = RC5_ALL</tt> bzw Bit 7 von <tt>addr</tt>   gesetzt ist, werden alle Adressen akzeptiert.
;<code>extern rc5_t rc5</code>: In <code>rc5</code> wird der empfangene RC5-Code geliefert. Über dieses Objekt wird zudem der RC5-Empfang gesteuert. Wird ein Code mit der gewünschten Adresse ampfangen und ist <code>rc5.flip = -1</code>, dann wird der Code gespeichert und <code>rc5.flip</code> gesetzt wie gesendet. Danach wird der Empfänger solange inaktiv, bis der Anwender wieder <code>rc5.flip</code> auf <code>-1</code> setzt.
+
{{FarbigerRahmen|
:;<code>rc5.code</code>: der empfangene RC5-Code, falls <code>rc5.flip != -1</code>
+
Der beteiligte INT-Port wird ''nicht'' auf IN geschaltet und das I-Flag in <tt>SREG</tt> (Global Interrupt Enable/Disable-Flag) wird nicht verändert.
:;<code>rc5.addr</code>: die Adresse, an die gesendet wurde, falls <code>rc5.flip != -1</code>
+
}}
:;<code>rc5.flip</code>: das Flip-Bit
+
 
::;<code>rc5.flip = 0</code>: Code empfangen, RC5-Empfang inaktiv
+
;<tt>extern rc5_t rc5</tt>: In der Struktur <tt>rc5</tt> wird der empfangene RC5-Code geliefert. Über dieses Objekt wird zudem der RC5-Empfang gesteuert. Wird ein Code mit der gewünschten Adresse empfangen und ist <tt>rc5.flip = -1</tt>, dann wird der Code gespeichert und <tt>rc5.flip</tt> gesetzt wie es empfangen wurde.  
::;<code>rc5.flip = 1</code>: dito
+
:Danach wird der Empfänger solange inaktiv, bis der Anwender wieder <tt>rc5.flip</tt> auf <tt>-1</tt> setzt.
::;<code>rc5.flip = -1</code>: RC5-Empfang aktiv, wartet auf nächste Übertragung
+
:;<tt>rc5.code</tt>: der empfangene RC5-Code, falls <tt>rc5.flip != -1</tt>
 +
:;<tt>rc5.addr</tt>: die Adresse, an die gesendet wurde, falls <tt>rc5.flip != -1</tt>
 +
:;<tt>rc5.flip</tt>: das Flip-Bit
 +
::;<tt>rc5.flip = 0</tt>: Code empfangen, RC5-Empfang inaktiv
 +
::;<tt>rc5.flip = 1</tt>: dito
 +
::;<tt>rc5.flip = -1</tt>: RC5-Empfang aktiv, wartet auf nächste Übertragung
  
 
{| {{Blauetabelle}}  
 
{| {{Blauetabelle}}  
|'''Define'''
+
|- {{Hintergrund1}}
|'''default'''
+
!|Define || default || Werte || Beschreibung
|'''Werte'''
+
|'''Beschreibung'''
+
 
  |-
 
  |-
  |<code>RC5_INT</code>
+
  |<tt>RC5_INT</tt> || <tt>RC5_INT0</tt> || <tt>RC5_INT0, RC5_INT1</tt>
|<code>RC5_INT0</code>
+
  |Über dieses Define wird eingestellt, an welchem Port auf RC5-Signale gelauscht wird. Code wird generiert für INT0 resp. INT1, zB gcc-Aufruf mit <tt>-DRC5_INT=RC5_INT1</tt> erzeugt Code für INT1.
|<code>RC5_INT0</code>, <code>RC5_INT1</code>
+
  |Code wird generiert für INT0 resp. INT1, zB gcc-Aufruf mit <code>-DRC5_INT=RC5_INT1</code> erzeugt Code für INT1
+
 
  |-
 
  |-
  |<code>RC5_PRESCALE</code>
+
  |<tt>RC5_PRESCALE</tt> || <tt>1024</tt> || <tt>64, 256, 1024</tt>
|<code>1024</code>
+
  |Legt den Prescaler für Timer0 fest. Standardeinstellung auf 1024, was zu F_CPU=16000000 passt. Für kleinere CPU-Frequenzen muss evtl. ein kleinerer Prescaler gewählt werden; das geht noch nicht automatisch.
|<code>64, 256, 1024</code>
+
  |Legt den Prescaler für Timer0 fest. Standardeinstellung auf 1024, was zu F_CPU=16000000 passt. Für kleinere CPU-Frequenzen muss evtl ein kleinerer PRESCALE gewählt werden; das geht noch nicht automatisch.
+
 
  |-
 
  |-
  |<code>F_CPU</code>
+
  |<tt>F_CPU</tt>
 
  |
 
  |
 
  |
 
  |
Zeile 92: Zeile 111:
 
  |}
 
  |}
  
===Seiteneffekte===
+
=Seiteneffekte=
  
'''SFRs'''
+
==SFRs==
  
 
Der Code verwendet folgende SFRs und ändert deren Inhalt in den ISRs:
 
Der Code verwendet folgende SFRs und ändert deren Inhalt in den ISRs:
Zeile 102: Zeile 121:
 
: '''<code>TIMSK</code>''': Timer Interrupt Mask Reg
 
: '''<code>TIMSK</code>''': Timer Interrupt Mask Reg
  
Falls eines dieser SFRs veränder wird, nachdem RC5-Empfang aktiviert wurde, ''muss'' diese Änderung atomar erfolgen!
+
{{FarbigerRahmen|
 +
Falls eines dieser SFRs verändert wird, nachdem RC5-Empfang aktiviert wurde, ''muss'' diese Änderung atomar erfolgen!
  
 
<pre>
 
<pre>
Zeile 117: Zeile 137:
 
   ...
 
   ...
 
</pre>
 
</pre>
 +
}}
  
'''Prescaler'''
+
==Prescaler==
  
 
Timer0 verwendet den Prescaler. Ein Prescaler-Reset sollte aufgrund der langsamen Übertragung bei RC5 unkritisch sein.
 
Timer0 verwendet den Prescaler. Ein Prescaler-Reset sollte aufgrund der langsamen Übertragung bei RC5 unkritisch sein.
  
===Code===
+
=Code=
  
 
{| {{Blauetabelle}}
 
{| {{Blauetabelle}}
  |'''ANSI-C'''
+
  !{{Hintergrund1}}| ANSI-C
 
  |Nein (C++ Kommentare, anonymous struct)
 
  |Nein (C++ Kommentare, anonymous struct)
 
  |-
 
  |-
  |'''Dateien'''
+
  !{{Hintergrund1}}| Compiler
  | <code>rc5.h</code>, <code>rc5.c</code>
+
  |avr-gcc 3.4.1. Siehe auch [[avr-gcc#Inkompatibilität|Inkompatibilitäten von avr-gcc]]
 
  |-
 
  |-
  |'''getestet für'''
+
  !{{Hintergrund1}}|Dateien
  | ATMega8-16 @ 16MHz, Vcc = 5V
+
  | <tt>rc5.h</tt>, <tt>rc5.c</tt>
 
  |-
 
  |-
  |'''Portierung'''
+
  !{{Hintergrund1}}|getestet für
  | ATMegaXX: sollte ohne Anpassung laufen<br>ATTiny, Classic: Anpassungen erforderlich
+
  | ATmega8-16 @ 16MHz, [[VCC]] = 5V
 
  |-
 
  |-
  |'''Comment-Style'''
+
  !{{Hintergrund1}}|Portierung
  | &#150;
+
| ATmegaXX: sollte ohne Anpassung laufen<br>ATtiny, Classic: Anpassungen erforderlich
 +
|-
 +
!{{Hintergrund1}}|Comment-Style
 +
  | &mdash;
 
  |}
 
  |}
  
====rc5.c====
+
==rc5.c==
 +
#include <avr/io.h>
 +
#include <avr/interrupt.h>
 +
 +
{{ccomment|Für alte avr-gcc Versionen}}
 +
#ifndef SIGNAL
 +
#include <avr/signal.h>
 +
#endif {{ccomment|SIGNAL}}
 +
 +
#include "rc5.h"
 +
 +
#ifndef RC5_INT
 +
#define RC5_INT      RC5_INT0
 +
#endif  {{comment|RC5_INT}}
 +
 
 +
#ifndef RC5_PRESCALE
 +
#define RC5_PRESCALE 1024
 +
#endif  {{comment|RC5_PRESCALE}}
 +
 +
{{comment|********************************************************************************}}
 +
 +
rc5_t rc5;
 +
 +
{{comment|********************************************************************************}}
 +
 +
#ifndef F_CPU
 +
#error Please define F_CPU
 +
#endif {{comment|!F_CPU}}
 +
 +
{{comment|µs for a whole bit of RC5 (first & second part)}}
 +
#define RC5_BIT_US  (64*27)
 +
 +
#define RC5_TICKS \
 +
        ((uint8_t) ((uint32_t) (F_CPU / 1000 * RC5_BIT_US / 1000 / RC5_PRESCALE)))
 +
       
 +
#define RC5_DELTA \
 +
        (RC5_TICKS / 6)
 +
       
 +
typedef union
 +
{
 +
        uint16_t w;
 +
        uint8_t  b[2];
 +
} code_t;
 +
 +
static code_t code;
 +
static uint8_t rc5_addr;
 +
 +
{{comment|Number of Bits received so far}}
 +
{{comment|Number of Interrupts occured so far}}
 +
static uint8_t nbits;
 +
static uint8_t nint;
 +
 +
{{comment|********************************************************************************}}
 +
       
 +
void rc5_init (uint8_t addr)
 +
{
 +
        nint  = 0;
 +
        nbits = 0;
 +
        rc5.flip = -1;
 +
       
 +
        rc5_addr = addr;
 +
       
 +
#if (RC5_PRESCALE==1024)
 +
        TCCR0 = (1 << CS02) | (1 << CS00);
 +
#elif  (RC5_PRESCALE==256)
 +
        TCCR0 = (1 << CS02);
 +
#elif  (RC5_PRESCALE==64)
 +
        TCCR0 = (1 << CS01) | (1 << CS00);
 +
#else
 +
#error This RC5_PRESCALE is not supported
 +
#endif {{comment|RC5_PRESCALE}}
 +
       
 +
        {{comment|INTx on falling edge}}
 +
        {{comment|clear pending INTx}}
 +
        {{comment|enable INTx interrupt}}
 +
#if (RC5_INT == RC5_INT0)             
 +
        MCUCR = (MCUCR | (1 << ISC01)) & ~ (1 << ISC00);
 +
        GIFR = (1 << INTF0);
 +
        GICR |= (1 << INT0);
 +
#elif (RC5_INT == RC5_INT1)           
 +
        MCUCR = (MCUCR | (1 << ISC11)) & ~ (1 << ISC10);
 +
        GIFR = (1 << INTF1);
 +
        GICR |= (1 << INT1);
 +
#else
 +
#error please define RC5_INT
 +
#endif {{comment|RC5_INT}}
 +
}
 +
 +
{{comment|********************************************************************************}}
 +
 +
SIGNAL (SIG_OVERFLOW0)
 +
{
 +
        TIMSK &= ~(1 << TOIE0);
 +
       
 +
        uint8_t _nbits = nbits;
 +
        code_t _code = code;
 +
       
 +
        if (26 == _nbits)
 +
        {
 +
                _nbits++;
 +
                _code.w <<= 1;
 +
        }
 +
       
 +
        if (27 == _nbits
 +
                && _code.b[1] >= 0x30 /* AGC == 3 */
 +
                && 0 > rc5.flip)
 +
        {
 +
                uint8_t _rc5_code;
 +
                uint8_t _rc5_addr;
 +
                {{comment|we do the bit manipulation stuff by hand, because of code size}}
 +
                _rc5_code = _code.b[0] & 0x3f; {{comment|0b00111111 : #0..#5}}
 +
                _code.w <<= 2;
 +
                _rc5_addr = _code.b[1] & 0x1f; {{comment|0b00011111 : #6..#10}}
 +
               
 +
                if (rc5_addr & 0x80
 +
                        || rc5_addr == _rc5_addr)
 +
                {
 +
                        rc5.code = _rc5_code;
 +
                        rc5.addr = _rc5_addr;
 +
                        signed char flip = 0;
 +
                        if (_code.b[1] & 0x20) {{comment|0b00100000 : #11}}
 +
                                flip = 1;
 +
                        rc5.flip = flip;
 +
                }
 +
        }
 +
       
 +
        nint = 0;
 +
        nbits = 0;
 +
       
 +
        {{comment|INTx on falling edge}}
 +
        {{comment|clear pending INTx}}
 +
        {{comment|enable INTx interrupt}}
 +
#if (RC5_INT == RC5_INT0)             
 +
        MCUCR = (MCUCR | (1 << ISC01)) & ~ (1 << ISC00);
 +
        GIFR = (1 << INTF0);
 +
        GICR |= (1 << INT0);
 +
#elif (RC5_INT == RC5_INT1)           
 +
        MCUCR = (MCUCR | (1 << ISC11)) & ~ (1 << ISC10);
 +
        GIFR = (1 << INTF1);
 +
        GICR |= (1 << INT1);
 +
#endif
 +
}
 +
 +
{{comment|********************************************************************************}}
 +
 +
#if (RC5_INT == RC5_INT0)             
 +
SIGNAL (SIG_INTERRUPT0)
 +
#elif (RC5_INT == RC5_INT1)           
 +
SIGNAL (SIG_INTERRUPT1)
 +
#endif {{comment|RC5_INT}}
 +
{
 +
        code_t _code = code;
 +
        uint8_t _nint = nint;
 +
       
 +
        uint8_t tcnt0 = TCNT0;
 +
        TCNT0 = 0;
 +
       
 +
        if (0 == _nint)
 +
        {
 +
                {{comment|INTx on both edges}}
 +
#if (RC5_INT == RC5_INT0)             
 +
                MCUCR = (MCUCR | (1 << ISC00)) & ~ (1 << ISC01);
 +
#elif (RC5_INT == RC5_INT1)           
 +
                MCUCR = (MCUCR | (1 << ISC10)) & ~ (1 << ISC11);
 +
#endif {{comment|RC5_INT}}
 +
       
 +
                TIFR = (1 << TOV0);
 +
                TIMSK |= (1 << TOIE0);
 +
                _code.w = 0;
 +
        }
 +
        else
 +
        {
 +
                {{comment|Number of bits of the just elapsed period}}
 +
                uint8_t n = 1;
 +
         
 +
                {{comment|Bits received so far}}
 +
                uint8_t _nbits = nbits;
 +
       
 +
                {{comment|is TCNT0 close to RC5_TICKS or RC5_TICKS/2 ?}}
 +
                if (tcnt0 > RC5_TICKS + RC5_DELTA)
 +
                        goto invalid;
 +
                else if (tcnt0 < RC5_TICKS/2 - RC5_DELTA)
 +
                        goto invalid;
 +
                else if (tcnt0 > RC5_TICKS - RC5_DELTA)
 +
                        n = 2;
 +
                else if (tcnt0 > RC5_TICKS/2 + RC5_DELTA)
 +
                        goto invalid;
 +
               
 +
                {{comment|store the just received 1 or 2 bits}}
 +
                do
 +
                {
 +
                        _nbits++;
 +
                        if (_nbits & 1)
 +
                        {
 +
                                _code.w <<= 1;
 +
                                _code.b[0] |= _nint & 1;
 +
                        }
 +
                }
 +
                while (--n);
 +
               
 +
                if (0)
 +
                {
 +
                        invalid:
 +
                       
 +
                        {{comment|disable INTx, run into Overflow0}}
 +
#if (RC5_INT == RC5_INT0)             
 +
                        GICR &= ~(1 << INT0);
 +
#elif (RC5_INT == RC5_INT1)           
 +
                        GICR &= ~(1 << INT1);
 +
#endif {{comment|RC5_INT}}
 +
 +
                        _nbits = 0;
 +
                }
 +
               
 +
                nbits = _nbits;
 +
        }
 +
 +
        code = _code;
 +
        nint = 1+_nint;
 +
}
  
<pre>
+
==rc5.h==
#include <avr/io.h>
+
#ifndef _RC5_H_
#include <avr/signal.h>
+
#define _RC5_H_
 +
 +
#include <inttypes.h>
 +
 +
#define RC5_INT0 0
 +
#define RC5_INT1 1
 +
 +
#define RC5_ALL 0xff
 +
 +
typedef struct
 +
{
 +
uint8_t code;
 +
uint8_t addr;
 +
volatile signed char flip;
 +
} rc5_t;
 +
 +
extern rc5_t rc5;
 +
extern void rc5_init (uint8_t addr);
 +
 +
#endif {{comment|_RC5_H_}}
  
#include "rc5.h"
+
=Beispiele=
  
#ifndef RC5_INT
+
==Initialisierung==
#define RC5_INT      RC5_INT0
+
#endif  // RC5_INT
+
  
#ifndef RC5_PRESCALE
+
#include <avr/io.h>
#define RC5_PRESCALE 1024
+
#include <avr/interrupt.h>
#endif // RC5_PRESCALE
+
 +
#include "rc5.h"
 +
   
 +
...
 +
{{comment|der ensprechende INT-Port muss INPUT sein}}
 +
{{comment|RC5 initialisieren, alle Adressen zulassen}}
 +
rc5_init (RC5_ALL);
 +
 +
{{comment|Interrupts zulassen}}
 +
sei();
 +
...
  
//////////////////////////////////////////////////////////////////////////////
+
==Anwendung==
  
rc5_t rc5;
+
#include <avr/io.h>
 +
#include <avr/interrupt.h>
 +
 +
#include "rc5.h"
 +
 +
    ...
 +
    {{comment|Gibt's was Neues?}}
 +
    if (-1 == rc5.flip)
 +
    {
 +
      {{comment|Nein, dann mach irgendwas (oder nix)}}
 +
    }
 +
    else
 +
    {
 +
      {{comment|Ja, dann rc5.code merken und evtl. rc5.addr}}
 +
      {{comment|falls man die braucht und nicht sowieso schon kennt}}
 +
      uint8_t code = rc5.code;
 +
      uint8_t addr = rc5.addr;
 +
      {{comment|und auf naechstes Zeichen warten}}
 +
      rc5.flip = -1;
 +
     
 +
      {{comment|code (evtl. addr) auswerten}}
 +
    }
 +
    ...
  
//////////////////////////////////////////////////////////////////////////////
 
  
#ifndef F_CPU
 
#error Please define F_CPU
 
#endif // !F_CPU
 
  
// µs for a whole bit of RC5 (first & second part)
+
=Siehe auch=
#define RC5_BIT_US  (64*27)
+
* [[RC5-Code]]
 +
* [[avr-gcc]]
  
#define RC5_TICKS \
+
=WebLinks=
((uint8_t) ((uint32_t) (F_CPU / 1000 * RC5_BIT_US / 1000 / RC5_PRESCALE)))
+
* [http://www.atmel.com/dyn/resources/prod_documents/DOC1473.PDF AVR410 (Application Note): ''RC5 IR Remote Control Receiver'', pdf (en)]
+
#define RC5_DELTA \
+
(RC5_TICKS / 6)
+
+
typedef union
+
{
+
uint16_t w;
+
uint8_t b[2];
+
+
struct
+
{
+
unsigned code:6;
+
unsigned addr:5;
+
unsigned flip:1;
+
unsigned agc:4;
+
} __attribute__ ((packed));
+
+
} code_t;
+
  
static code_t code;
+
* [http://www.gjlay.de/pub/c-code/rc5.html Ähnlich aufgebauter RC5-Decoder(AT90S2313, ATtiny2313, ATmega8/16/32/48/88/168)]
static uint8_t rc5_addr;
+
  
// Number of Bits received so far
+
=Autor=
// Number of Interrupts occured so far;
+
static uint8_t nbits;
+
static uint8_t nint;
+
  
//////////////////////////////////////////////////////////////////////////////
+
--[[Benutzer:SprinterSB|SprinterSB]] 18:17, 7. Dez 2005 (CET)
+
void
+
rc5_init (uint8_t addr)
+
{
+
nint = 0;
+
nbits = 0;
+
rc5.flip = -1;
+
+
rc5_addr = addr;
+
+
#if (RC5_PRESCALE==1024)
+
TCCR0 = (1 << CS02) | (1 << CS00);
+
#elif (RC5_PRESCALE==256)
+
TCCR0 = (1 << CS02);
+
#elif (RC5_PRESCALE==64)
+
TCCR0 = (1 << CS01) | (1 << CS00);
+
#else
+
#error This RC5_PRESCALE is not supported
+
#endif // RC5_PRESCALE
+
+
// INTx on falling edge
+
// clear pending INTx
+
// enable INTx interrupt
+
#if (RC5_INT == RC5_INT0)
+
MCUCR |=  (1 << ISC01);
+
MCUCR &= ~ (1 << ISC00);
+
GIFR = (1 << INTF0);
+
GICR |= (1 << INT0);
+
#elif (RC5_INT == RC5_INT1)
+
MCUCR |=  (1 << ISC11);
+
MCUCR &= ~ (1 << ISC10);
+
GIFR = (1 << INTF1);
+
GICR |= (1 << INT1);
+
#else
+
#error please define RC5_INT
+
#endif // RC5_INT
+
}
+
  
//////////////////////////////////////////////////////////////////////////////
 
 
SIGNAL (SIG_OVERFLOW0)
 
{
 
TIMSK &= ~(1 << TOIE0);
 
 
uint8_t _nbits = nbits;
 
code_t _code = code;
 
 
if (26 == _nbits)
 
{
 
_nbits++;
 
_code.w <<= 1;
 
}
 
 
if (27 == _nbits
 
&& 3 == _code.agc
 
&& 0 > rc5.flip)
 
{
 
uint8_t _rc5_code;
 
uint8_t _rc5_addr;
 
// we do the bit manipulation stuff by hand, because of code size
 
_rc5_code = _code.b[0] & 0x3f; // 0b00111111 : #0..#5
 
_code.w <<= 2;
 
_rc5_addr = _code.b[1] & 0x1f; // 0b00011111 : #6..#10
 
 
if (rc5_addr & 0x80
 
|| rc5_addr == _rc5_addr)
 
{
 
rc5.code = _rc5_code;
 
rc5.addr = _rc5_addr;
 
char flip = 0;
 
if (_code.b[1] & 0x20) // 0b00100000 : #11
 
flip = 1;
 
rc5.flip = flip;
 
}
 
}
 
 
nint = 0;
 
nbits = 0;
 
 
// INTx on falling edge
 
// clear pending INTx
 
// enable INTx interrupt
 
#if (RC5_INT == RC5_INT0)
 
MCUCR |=  (1 << ISC01);
 
MCUCR &= ~ (1 << ISC00);
 
GIFR = (1 << INTF0);
 
GICR |= (1 << INT0);
 
#elif (RC5_INT == RC5_INT1)
 
MCUCR |=  (1 << ISC11);
 
MCUCR &= ~ (1 << ISC10);
 
GIFR = (1 << INTF1);
 
GICR |= (1 << INT1);
 
#endif
 
}
 
 
//////////////////////////////////////////////////////////////////////////////
 
 
#if (RC5_INT == RC5_INT0)
 
SIGNAL (SIG_INTERRUPT0)
 
#elif (RC5_INT == RC5_INT1)
 
SIGNAL (SIG_INTERRUPT1)
 
#endif // RC5_INT
 
{
 
code_t _code = code;
 
uint8_t _nint = nint;
 
 
if (0 == _nint)
 
{
 
// INTx on both edges
 
// clear pending INTx
 
#if (RC5_INT == RC5_INT0)
 
MCUCR &= ~ (1 << ISC01);
 
MCUCR |=  (1 << ISC00);
 
GIFR = (1 << INTF0);
 
#elif (RC5_INT == RC5_INT1)
 
MCUCR &= ~ (1 << ISC11);
 
MCUCR |=  (1 << ISC10);
 
GIFR = (1 << INTF1);
 
#endif // RC5_INT
 
 
TCNT0 = 0;
 
TIFR = (1 << TOV0);
 
TIMSK |= (1 << TOIE0);
 
_code.w = 0;
 
}
 
else
 
{
 
uint8_t tcnt0 = TCNT0;
 
 
TCNT0 = 0;
 
 
// Number of bits of the just elapsed period;
 
uint8_t n = 1;
 
// Bits received so far
 
uint8_t _nbits = nbits;
 
 
// is TCNT0 close to RC5_TICKS or RC5_TICKS/2 ?
 
if (tcnt0 > RC5_TICKS + RC5_DELTA)
 
goto invalid;
 
else if (tcnt0 < RC5_TICKS/2 - RC5_DELTA)
 
goto invalid;
 
else if (tcnt0 > RC5_TICKS - RC5_DELTA)
 
n = 2;
 
else if (tcnt0 > RC5_TICKS/2 + RC5_DELTA)
 
goto invalid;
 
 
// store the just received 1 or 2 bits
 
do
 
{
 
_nbits++;
 
if (_nbits & 1)
 
{
 
_code.w <<= 1;
 
_code.b[0] |= _nint & 1;
 
}
 
}
 
while (--n);
 
 
if (0)
 
{
 
invalid:
 
 
// disable INTx, run into Overflow0
 
#if (RC5_INT == RC5_INT0)
 
GICR &= ~(1 << INT0);
 
#elif (RC5_INT == RC5_INT1)
 
GICR &= ~(1 << INT1);
 
#endif // RC5_INT
 
 
_nbits = 0;
 
}
 
 
nbits = _nbits;
 
}
 
 
code = _code;
 
nint = 1+_nint;
 
}
 
</pre>
 
 
====rc5.h====
 
<pre>
 
#ifndef _RC5_H_
 
#define _RC5_H_
 
 
#include <inttypes.h>
 
 
#define RC5_INT0 0
 
#define RC5_INT1 1
 
 
#define RC5_ALL 0xff
 
 
typedef struct
 
{
 
uint8_t code;
 
uint8_t addr;
 
volatile char flip;
 
} rc5_t;
 
 
extern rc5_t rc5;
 
extern void rc5_init (uint8_t addr);
 
 
#endif /* _RC5_H_ */
 
</pre>
 
 
====Beispiele====
 
 
'''<code>Beispiel: Anwendung</code>'''
 
<pre>
 
#include <avr/io.h>
 
#include <avr/interrupt.h>
 
 
#include "rc5.h"
 
 
...
 
// Code atomar machen
 
uint8_t sreg = SREG;
 
cli();
 
// Gibt's was Neues?
 
if (-1 == rc5.flip)
 
{
 
// Nein, dann zurück
 
SREG = sreg;
 
return;
 
}
 
// Ja, dann code merken
 
uint8_t code = rc5.code;
 
// und auf nächstes Zeichen warten
 
rc5.flip = -1;
 
SREG = sreg;
 
...
 
</pre>
 
 
'''<code>Beispiel: Initialisierung</code>'''
 
<pre>
 
#include <avr/io.h>
 
#include <avr/interrupt.h>
 
 
#include "rc5.h"
 
 
...
 
// RC5 initialisieren, alle Adressen zulassen
 
rc5_init (RC5_ALL);
 
 
// Interrupts zulassen
 
sei();
 
...
 
</pre>
 
 
==WebLinks==
 
* [http://www.atmel.com/dyn/resources/prod_documents/DOC1473.PDF AVR410 (Application Note): ''RC5 IR Remote Control Receiver'', pdf (en)]
 
  
 +
[[Kategorie:Kommunikation]]
 
[[Kategorie:Software]]
 
[[Kategorie:Software]]
 +
[[Kategorie:Praxis]]
 +
[[Kategorie:Quellcode C]]

Aktuelle Version vom 7. Oktober 2007, 09:16 Uhr

Dieser Code implementiert einen Interrupt-getriebenen RC5-Empfänger.

Auf eine Flanke an einem externen INT hin werden die nachfolgenden Pulslängen gemessen und in einer Struktur bereitgestellt, falls es sich um RC5-Code handelt und die Empfängeradresse übereinstimmt.

Bitte beachte auch die Hinweise zu Inkompatibilitäten von avr-gcc!

Abgrenzung

Nicht alle Fernbedienungen halten sich genau an die RC5-Spezifikation und haben oft einen mehr oder weniger starken Jitter auf dem Signal. In konstanten Zeitabständen auf den Port zu schauen und anhand des gelesenen Wertes das RC5-Signal aufzubauen, funktioniert daher nicht zuverlässig bei allen Fernbedienungen.

Der Ansatz, den diese Implementierung verfolgt, ist aufwändiger und ergibt ein längeres Programm, hat aber dafür nicht den beschriebenen Nachteil.

Resourcen

Resource Verbrauch (mit -Os)
I/O Timer0, 1 Pin für extern INT
Interrupts Timer0 Overflow, 1 externer IRQ
Flash ~ 0x170 (370 Bytes)
SRAM statisch: 8
Stack: 11
Laufzeit,
Erhöhung der IRQ-Latenz
 ?, aber statisch abschätzbar
externe Hardware IR-Empfänger wie TSOP17xx, TSOP18xx, SFH 506-xx o.ä.

Schaltplan

Das ist ein minimaler Anschlussplan für einen TSOP17xx. Um einen IR-Empfänger zu entstören und in verrauschter Umgebung einzusetzen, sei auf das jeweilige Datenblatt verwiesen.

Anschluss TSOP17xx an AVR, R1 ca 10kΩ
IR-Empfänger vom Typ TSOP17xx an AVR
R1 ca 10 kΩ

Für RC5 empfiehlt sich die 36kHz-Variante, also z.B. ein TSOP1736.

Weitere IR-Empfänger-ICs sind SFH 506-xx

Funktionsweise

Diese RC5-Software braucht eine Zeitbasis, für welche Timer0 verwendet wird. Timer0 wird deshalb verwendet, weil er bei vielen AVRs der "schwächste" Timer ist, also der Timer, der am wenigsten Funktionalität bietet. So fehlt ihm bei vielen AVR-Modellen ein OutputCompare-Funktion, und er kann keine PWM erzeugen. Seine Funktionen reichen für einen RC5-Empfänger aber aus.

Die am externen Interrupt-Port (der beim Compilieren durch das Makro RC5_INT ausgewählt werden kann) gemessenen Zeiten zwischen eintreffenden Flanken, d.h. Wechseln zwischen LOW und HIGH, werden ausgewertet und in Bits umgewandelt. Falls die Zeiten nicht dem RC5-Standard entsprechen, werden die Daten verworfen. Wurde ein kompletter RC5-Frame (also Adresse, Kommand, Flip-Bit, etc) empfangen und stimmt die übermittelte Adresse mit der Adresse überein, die bei der Initialisierung des Empfängers mit rc5_init angegeben wurde, dann werden die empfangenen Daten in der globalen Struktur rc5 zur weiteren Auswertung gespeichert.

Von Timer0 wird der Overflow-Interrupt genutzt, um ungültigen Code zu erkennen und den Empfänger bei ungültigem Code wieder in einen definierten Zustand zu versetzten. Der externe Interrupt wertet die Zeiten aus, speichert die empfangenen Bits und baut so den Inhalt der rc5-Struktur auf.

Der Anwender braucht sich nicht um diese Interna zu kümmern. Nach Aufruf der Initialisierung läuft der RC5-Empfang "nebenher".

In der rc5-Struktur können die empfangenen Daten abgeholt werden, und über ihre .flip-Komponente wird der Empfang gesteuert und mitgeteilt, ob neue Daten angekommen sind.

Interface

rc5.h
#define RC5_INT0 0
#define RC5_INT1 1

#define RC5_ALL 0xff

typedef struct
{
        uint8_t code;
        uint8_t addr;
        volatile signed char flip;
} rc5_t;

extern rc5_t rc5;
extern void rc5_init (uint8_t addr);
void rc5_init (uint8_t addr)
Initialisiert die Hardware für RC5-Empfang. Akzeptiert wird Code, der an Adresse addr geschickt wird. Falls addr = RC5_ALL bzw Bit 7 von addr gesetzt ist, werden alle Adressen akzeptiert.

Der beteiligte INT-Port wird nicht auf IN geschaltet und das I-Flag in SREG (Global Interrupt Enable/Disable-Flag) wird nicht verändert.

extern rc5_t rc5
In der Struktur rc5 wird der empfangene RC5-Code geliefert. Über dieses Objekt wird zudem der RC5-Empfang gesteuert. Wird ein Code mit der gewünschten Adresse empfangen und ist rc5.flip = -1, dann wird der Code gespeichert und rc5.flip gesetzt wie es empfangen wurde.
Danach wird der Empfänger solange inaktiv, bis der Anwender wieder rc5.flip auf -1 setzt.
rc5.code
der empfangene RC5-Code, falls rc5.flip != -1
rc5.addr
die Adresse, an die gesendet wurde, falls rc5.flip != -1
rc5.flip
das Flip-Bit
rc5.flip = 0
Code empfangen, RC5-Empfang inaktiv
rc5.flip = 1
dito
rc5.flip = -1
RC5-Empfang aktiv, wartet auf nächste Übertragung
Define default Werte Beschreibung
RC5_INT RC5_INT0 RC5_INT0, RC5_INT1 Über dieses Define wird eingestellt, an welchem Port auf RC5-Signale gelauscht wird. Code wird generiert für INT0 resp. INT1, zB gcc-Aufruf mit -DRC5_INT=RC5_INT1 erzeugt Code für INT1.
RC5_PRESCALE 1024 64, 256, 1024 Legt den Prescaler für Timer0 fest. Standardeinstellung auf 1024, was zu F_CPU=16000000 passt. Für kleinere CPU-Frequenzen muss evtl. ein kleinerer Prescaler gewählt werden; das geht noch nicht automatisch.
F_CPU Gibt die CPU-Frequenz in Hz an

Seiteneffekte

SFRs

Der Code verwendet folgende SFRs und ändert deren Inhalt in den ISRs:

MCUCR: MCU Control Reg
GICR: Global Interrupt Control Reg
TCNT0: Timer0 Counter Reg
TIMSK: Timer Interrupt Mask Reg

Falls eines dieser SFRs verändert wird, nachdem RC5-Empfang aktiviert wurde, muss diese Änderung atomar erfolgen!

#include <avr/io.h>
#include <avr/interrupt.h>

   ...
   {
      sreg = SREG;
      cli();     
      TIMSK |= ...
      SREG = sreg;
   }
   ...

Prescaler

Timer0 verwendet den Prescaler. Ein Prescaler-Reset sollte aufgrund der langsamen Übertragung bei RC5 unkritisch sein.

Code

ANSI-C Nein (C++ Kommentare, anonymous struct)
Compiler avr-gcc 3.4.1. Siehe auch Inkompatibilitäten von avr-gcc
Dateien rc5.h, rc5.c
getestet für ATmega8-16 @ 16MHz, VCC = 5V
Portierung ATmegaXX: sollte ohne Anpassung laufen
ATtiny, Classic: Anpassungen erforderlich
Comment-Style

rc5.c

#include <avr/io.h>
#include <avr/interrupt.h>

// Für alte avr-gcc Versionen
#ifndef SIGNAL
#include <avr/signal.h>
#endif // SIGNAL

#include "rc5.h"

#ifndef RC5_INT
#define RC5_INT      RC5_INT0
#endif  /* RC5_INT */
  
#ifndef RC5_PRESCALE
#define RC5_PRESCALE 1024
#endif  /* RC5_PRESCALE */

/* ******************************************************************************** */

rc5_t rc5;

/* ******************************************************************************** */

#ifndef F_CPU
#error Please define F_CPU
#endif /* !F_CPU */

/* µs for a whole bit of RC5 (first & second part) */
#define RC5_BIT_US   (64*27)

#define RC5_TICKS \
        ((uint8_t) ((uint32_t) (F_CPU / 1000 * RC5_BIT_US / 1000 / RC5_PRESCALE)))
        
#define RC5_DELTA \
        (RC5_TICKS / 6)
        
typedef union 
{
        uint16_t w;
        uint8_t  b[2];
} code_t;

static code_t code;
static uint8_t rc5_addr;

/* Number of Bits received so far */
/* Number of Interrupts occured so far */
static uint8_t nbits;
static uint8_t nint;

/* ******************************************************************************** */
        
void rc5_init (uint8_t addr)
{
        nint  = 0;
        nbits = 0;
        rc5.flip = -1;
        
        rc5_addr = addr;
        
#if (RC5_PRESCALE==1024)
        TCCR0 = (1 << CS02) | (1 << CS00);
#elif   (RC5_PRESCALE==256)
        TCCR0 = (1 << CS02);
#elif   (RC5_PRESCALE==64)
        TCCR0 = (1 << CS01) | (1 << CS00);
#else
#error This RC5_PRESCALE is not supported
#endif /* RC5_PRESCALE */
        
        /* INTx on falling edge */
        /* clear pending INTx */
        /* enable INTx interrupt */
#if (RC5_INT == RC5_INT0)               
        MCUCR = (MCUCR | (1 << ISC01)) & ~ (1 << ISC00);
        GIFR = (1 << INTF0);
        GICR |= (1 << INT0);
#elif (RC5_INT == RC5_INT1)             
        MCUCR = (MCUCR | (1 << ISC11)) & ~ (1 << ISC10);
        GIFR = (1 << INTF1);
        GICR |= (1 << INT1);
#else
#error please define RC5_INT
#endif /* RC5_INT */
}

/* ******************************************************************************** */

SIGNAL (SIG_OVERFLOW0)
{
        TIMSK &= ~(1 << TOIE0);
        
        uint8_t _nbits = nbits;
        code_t _code = code;
        
        if (26 == _nbits)
        {
                _nbits++;
                _code.w <<= 1;
        }
        
        if (27 == _nbits 
                && _code.b[1] >= 0x30 /* AGC == 3 */
                && 0 > rc5.flip)
        {
                uint8_t _rc5_code;
                uint8_t _rc5_addr;
                /* we do the bit manipulation stuff by hand, because of code size */
                _rc5_code = _code.b[0] & 0x3f; /* 0b00111111 : #0..#5 */
                _code.w <<= 2;
                _rc5_addr = _code.b[1] & 0x1f; /* 0b00011111 : #6..#10 */
                
                if (rc5_addr & 0x80
                        || rc5_addr == _rc5_addr)
                {
                        rc5.code = _rc5_code;
                        rc5.addr = _rc5_addr;
                        signed char flip = 0;
                        if (_code.b[1] & 0x20) /* 0b00100000 : #11 */
                                flip = 1;
                        rc5.flip = flip;
                }
        }
        
        nint = 0;
        nbits = 0;
        
        /* INTx on falling edge */
        /* clear pending INTx */
        /* enable INTx interrupt */
#if (RC5_INT == RC5_INT0)               
        MCUCR = (MCUCR | (1 << ISC01)) & ~ (1 << ISC00);
        GIFR = (1 << INTF0);
        GICR |= (1 << INT0);
#elif (RC5_INT == RC5_INT1)             
        MCUCR = (MCUCR | (1 << ISC11)) & ~ (1 << ISC10);
        GIFR = (1 << INTF1);
        GICR |= (1 << INT1);
#endif
}

/* ******************************************************************************** */

#if (RC5_INT == RC5_INT0)               
SIGNAL (SIG_INTERRUPT0)
#elif (RC5_INT == RC5_INT1)             
SIGNAL (SIG_INTERRUPT1)
#endif /* RC5_INT */
{
        code_t _code = code;
        uint8_t _nint = nint;
        
        uint8_t tcnt0 = TCNT0;
        TCNT0 = 0;
        
        if (0 == _nint)
        {
                /* INTx on both edges */
#if (RC5_INT == RC5_INT0)               
                MCUCR = (MCUCR | (1 << ISC00)) & ~ (1 << ISC01);
#elif (RC5_INT == RC5_INT1)             
                MCUCR = (MCUCR | (1 << ISC10)) & ~ (1 << ISC11);
#endif /* RC5_INT */
        
                TIFR = (1 << TOV0);
                TIMSK |= (1 << TOIE0);
                _code.w = 0;
        }
        else
        {
                /* Number of bits of the just elapsed period */
                uint8_t n = 1;
         
                /* Bits received so far */
                uint8_t _nbits = nbits;
        
                /* is TCNT0 close to RC5_TICKS or RC5_TICKS/2 ? */
                if (tcnt0 > RC5_TICKS + RC5_DELTA)
                        goto invalid;
                else if (tcnt0 < RC5_TICKS/2 - RC5_DELTA)
                        goto invalid;
                else if (tcnt0 > RC5_TICKS - RC5_DELTA)
                        n = 2;
                else if (tcnt0 > RC5_TICKS/2 + RC5_DELTA)
                        goto invalid;
                
                /* store the just received 1 or 2 bits */
                do
                {
                        _nbits++;
                        if (_nbits & 1)
                        {
                                _code.w <<= 1;
                                _code.b[0] |= _nint & 1;
                        }
                } 
                while (--n);
                
                if (0)
                {
                        invalid:
                        
                        /* disable INTx, run into Overflow0 */
#if (RC5_INT == RC5_INT0)               
                        GICR &= ~(1 << INT0);
#elif (RC5_INT == RC5_INT1)             
                        GICR &= ~(1 << INT1);
#endif /* RC5_INT */

                        _nbits = 0;
                }
                
                nbits = _nbits;
        }

        code = _code;
        nint = 1+_nint;
}

rc5.h

#ifndef _RC5_H_
#define _RC5_H_

#include <inttypes.h>

#define RC5_INT0 0
#define RC5_INT1 1

#define RC5_ALL 0xff

typedef struct
{
	uint8_t code;
	uint8_t addr;
	volatile signed char flip;
} rc5_t;

extern rc5_t rc5;
extern void rc5_init (uint8_t addr);

#endif /* _RC5_H_ */

Beispiele

Initialisierung

#include <avr/io.h>
#include <avr/interrupt.h>

#include "rc5.h"

	...
	/* der ensprechende INT-Port muss INPUT sein */
	/* RC5 initialisieren, alle Adressen zulassen */
	rc5_init (RC5_ALL);

	/* Interrupts zulassen */
	sei();
	...

Anwendung

#include <avr/io.h>
#include <avr/interrupt.h>

#include "rc5.h"

   ...
   /* Gibt's was Neues? */
   if (-1 == rc5.flip)
   {
      /* Nein, dann mach irgendwas (oder nix) */
   }
   else
   {
      /* Ja, dann rc5.code merken und evtl. rc5.addr */
      /* falls man die braucht und nicht sowieso schon kennt */
      uint8_t code = rc5.code;
      uint8_t addr = rc5.addr;
      /* und auf naechstes Zeichen warten */
      rc5.flip = -1;
      
      /* code (evtl. addr) auswerten */
   }
   ...


Siehe auch

WebLinks

Autor

--SprinterSB 18:17, 7. Dez 2005 (CET)


LiFePO4 Speicher Test