axel88
11.11.2011, 14:04
Hallo,
ich versuche seit ein paar Tagen den http://www.rn-wissen.de/index.php/RC5-Decoder_f%C3%BCr_ATMega code für den Atiny13 anzupassen. Leider noch mit wenig erfolg. Hier erstmal der Code:
/*
* IR_relay.c
*
* Created: 07.11.2011 09:25:53
* Author: Axel
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include "lib/rc5.h"
int main(void)
{
DDRB=0b00000001;
rc5_init(RC5_ALL);
sei();
while(1)
{
if (-1 == rc5.flip)
{
}
else
{
uint8_t code = rc5.code;
uint8_t addr = rc5.addr;
rc5.flip = -1;
PORTB++;
}
}
}
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 1160000
// Für alte avr-gcc Versionen
#ifndef SIGNAL
#include <avr/signal.h>
#endif // SIGNAL
#include "rc5.h"
#ifndef RC5_PRESCALE
#define RC5_PRESCALE 256
#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)
TCCR0B = (1 << CS02) | (1 << CS00);
#elif (RC5_PRESCALE==256)
TCCR0B = (1 << CS02);
#elif (RC5_PRESCALE==64)
TCCR0B = (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 */
MCUCR = (MCUCR | (1 << ISC01)) & ~ (1 << ISC00);
GIFR |= (1 << INTF0);
GIMSK |= (1 << INT0);
}
/* ************************************************** ****************************** */
ISR (TIM0_OVF_vect)
{
TIMSK0 &= ~(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 */
MCUCR = (MCUCR | (1 << ISC01)) & ~ (1 << ISC00);
GIFR |= (1 << INTF0);
GIMSK |= (1 << INT0);
}
/* ************************************************** ****************************** */
ISR (INT0_vect)
{
code_t _code = code;
uint8_t _nint = nint;
uint8_t tcnt0 = TCNT0;
TCNT0 = 0;
if (0 == _nint)
{
/* INT0 on both edges */
MCUCR = (MCUCR | (1 << ISC00)) & ~ (1 << ISC01);
TIFR0 = (1 << TOV0);
TIMSK0 |= (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 */
GIMSK &= ~(1 << INT0);
_nbits = 0;
}
nbits = _nbits;
}
code = _code;
nint = 1+_nint;
}
#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_ */
Was bisher klappt ist:
1) ein RC5 Signal mit dem Oszi am pin 6 des Atiny zu beobachten
2) die Interruptroutine INT0 per Fernbedienung auszulösen
3) teilweise wird auch der Timerinterrupt aufgerufen, d.h. wenn ich im Timerinterupt PORTB++; ausführen lasse, wird es einmal getogglet, danach reagiert es nicht mehr auf die Fernbedienung.
Meine Anpassung bestand eigentlich nur darin die Option für INT1 herauszulöschen, und diverse Register zur Interruptkonfiguration auf den Atiny13 anzupassen. Leider habe ich keinen überblick wie die Routine genau funktionieren soll und weiß nicht so recht weiter.
Gruß Axel
ich versuche seit ein paar Tagen den http://www.rn-wissen.de/index.php/RC5-Decoder_f%C3%BCr_ATMega code für den Atiny13 anzupassen. Leider noch mit wenig erfolg. Hier erstmal der Code:
/*
* IR_relay.c
*
* Created: 07.11.2011 09:25:53
* Author: Axel
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include "lib/rc5.h"
int main(void)
{
DDRB=0b00000001;
rc5_init(RC5_ALL);
sei();
while(1)
{
if (-1 == rc5.flip)
{
}
else
{
uint8_t code = rc5.code;
uint8_t addr = rc5.addr;
rc5.flip = -1;
PORTB++;
}
}
}
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 1160000
// Für alte avr-gcc Versionen
#ifndef SIGNAL
#include <avr/signal.h>
#endif // SIGNAL
#include "rc5.h"
#ifndef RC5_PRESCALE
#define RC5_PRESCALE 256
#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)
TCCR0B = (1 << CS02) | (1 << CS00);
#elif (RC5_PRESCALE==256)
TCCR0B = (1 << CS02);
#elif (RC5_PRESCALE==64)
TCCR0B = (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 */
MCUCR = (MCUCR | (1 << ISC01)) & ~ (1 << ISC00);
GIFR |= (1 << INTF0);
GIMSK |= (1 << INT0);
}
/* ************************************************** ****************************** */
ISR (TIM0_OVF_vect)
{
TIMSK0 &= ~(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 */
MCUCR = (MCUCR | (1 << ISC01)) & ~ (1 << ISC00);
GIFR |= (1 << INTF0);
GIMSK |= (1 << INT0);
}
/* ************************************************** ****************************** */
ISR (INT0_vect)
{
code_t _code = code;
uint8_t _nint = nint;
uint8_t tcnt0 = TCNT0;
TCNT0 = 0;
if (0 == _nint)
{
/* INT0 on both edges */
MCUCR = (MCUCR | (1 << ISC00)) & ~ (1 << ISC01);
TIFR0 = (1 << TOV0);
TIMSK0 |= (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 */
GIMSK &= ~(1 << INT0);
_nbits = 0;
}
nbits = _nbits;
}
code = _code;
nint = 1+_nint;
}
#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_ */
Was bisher klappt ist:
1) ein RC5 Signal mit dem Oszi am pin 6 des Atiny zu beobachten
2) die Interruptroutine INT0 per Fernbedienung auszulösen
3) teilweise wird auch der Timerinterrupt aufgerufen, d.h. wenn ich im Timerinterupt PORTB++; ausführen lasse, wird es einmal getogglet, danach reagiert es nicht mehr auf die Fernbedienung.
Meine Anpassung bestand eigentlich nur darin die Option für INT1 herauszulöschen, und diverse Register zur Interruptkonfiguration auf den Atiny13 anzupassen. Leider habe ich keinen überblick wie die Routine genau funktionieren soll und weiß nicht so recht weiter.
Gruß Axel