Forum: Mikrocontroller und Digitale Elektronik Code: Timerproblem bei rc5-receiver


von Michael N. (garril)


Lesenswert?

Hallo,
ich möchte einen Fernbedienungssignal-Empfänger für das RC5 Protokoll 
bauen.

Da ich selbst üben möchte und das ganze auch selbst verstehen möchte, 
hab ich den Code also selbst entworfen.
Allerdings läuft das mit meinem Timer noch nicht so rund.
Mein Gedanke:
Eingang liegt normal auf High. Wenn dann ein Signal kommt geht er je 
nach Signal ein paar mal auf Low.
Wenn das letzte Bit eine 1 war warte ich auf eine steigende Flanke und 
wenn das letzte erkannte Bit eine 0 war auf eine sinkende.
Anhand der Zeit bis die nächste Flanke erkannt wird kann ich so 
berechnen ob dieses Bit wiederrum eine 0 oder 1 ist.

Aktuell sind die ersten beiden Startbit einfach mal fest auf 1 
programmiert. Das Toggle-Bit müsste sich ja bei jedem Tastendruck 
ändern, deshalb wollte ich mit dem mal beginnen.
Leider macht das Ding was es will... Manchmal geht der Ausgang auf high 
und manchmal auf low...
Anschienend passt etwas mit meiner Zeitberechnung nicht.
Per
if (rc5_position==2) {
if (rc5_timer>=8) {LED an} else {LED aus}
}
lasse ich mir erstmal das Toggle-Bit anzeigen.
Die 8 kommt daher, dass der rc5_timer dann ca. 2,2ms gezählt hat und das 
eine 1 von einer 0 unterscheiden müsste.

Hier mein Code:
1
#define F_CPU 7372000L                  // Systemtakt in Hz
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include <util/delay.h>
5
6
#define an(port,b) (port) |= (1<<(b))
7
#define aus(port,b) (port) &= ~(1<<(b))
8
9
volatile uint8_t rc5_adr=0;
10
volatile uint8_t rc5_cmd=0;
11
volatile uint8_t rc5_position=0;
12
volatile uint8_t rc5_timer=0; //Zeit seit letzter erkannten Flanke
13
volatile uint8_t rc5_lastbit=1; //zuletzt erkanntes Bit
14
volatile uint8_t rc5_bit0=0;
15
volatile uint8_t rc5_bit1=0;
16
volatile uint8_t rc5_bit2=1;
17
18
void wait_for_high() {
19
  MCUCR |= (1 << ISC01) | (1 << ISC00); //Interrupt bei steigender Flanke
20
}
21
void wait_for_low() {
22
  MCUCR |= (1 << ISC01);
23
  MCUCR &= ~(1 << ISC00); //Interrupt bei fallender Flanke
24
}
25
26
ISR(_VECTOR(1))
27
{
28
  if (rc5_position==0) {  
29
    rc5_bit0=1;
30
    rc5_lastbit=1;
31
    rc5_timer=0;
32
  }
33
  if (rc5_position==1) {
34
    rc5_bit1=1;
35
    rc5_lastbit=1;
36
    rc5_timer=0;
37
  }
38
  if (rc5_position==2) {
39
    if (rc5_timer>=8) { //<<<<<<HIER LIEGT DAS PROBLEM
40
      rc5_bit2=1;
41
      rc5_lastbit=1;
42
    }
43
    else {
44
      rc5_bit2=0;
45
      rc5_lastbit=0;
46
    }
47
    rc5_timer=0;
48
  }
49
50
  if (rc5_position>=5) { //eigentlich bis 13te Flanke zählen, DEBUG
51
    rc5_position=0;
52
    cli(); //Interrupts abschalten und abwarten bis Übertragung sicherlich zu Ende ist
53
    _delay_ms(50);
54
    wait_for_low();
55
    sei(); //Interrupts wieder an
56
  }
57
  else {
58
    rc5_position++;
59
    if (rc5_lastbit==1) {
60
      wait_for_high();
61
    }
62
    else {
63
      wait_for_low();
64
    }
65
  }
66
  
67
}
68
ISR (TIMER0_OVF_vect) {
69
  rc5_timer++;
70
  if (rc5_timer==255) {
71
    rc5_timer=0;
72
  }
73
  an(PORTD,PD1); //DEBUG: PD1 high -> ISR wird angesprungen
74
}
75
int main(void) {
76
  
77
  DDRD  = 0xFB; /* PD2 als Eingang, Rest Ausgang: 11111011 */
78
  PORTD = 0x00; /* Interner Pull-Up an PD2 deaktivieren, Ausgänge low */
79
  wait_for_low();
80
  GICR |= (1 << INT0); //Interrupt aktivieren
81
  TCCR0 = (1<<CS01); //Start Timer, Prescaler 8 -> Overflow alle 0,277ms
82
  TIMSK |= (1<<TOIE0); // Overflow Interrupt erlauben
83
  sei();
84
85
  while (1) {
86
    /*if (!( PIND & (1<<PIND2) )) {
87
      an(PORTD,PD0);
88
      _delay_ms(100);
89
      aus(PORTD,PD0);
90
    }*/
91
    if (rc5_bit2==1) {
92
      an(PORTD,PD0);
93
    }
94
    else {
95
      aus(PORTD,PD0);
96
    }
97
  }
98
}

Vielleicht hat jemand von euch ja schonmal sowas gecodet und kann mir 
dabei helfen.

Vielen Dank.

mfg
Michael

von Michael N. (garril)


Lesenswert?

Also der Prescaler war zu hoch. Hab jetzt das ganze ohne Prescaler 
probiert.
Die 8 hat auch nicht so ganz gestimmt.
Ohne Prescaler kommt man bei der if-Abfrage mit >38 ganz gut hin. 
Allerdings ist das wohl total ungeau. Klappt nicht immer und sobald ich 
das auf 37 oder 39 stelle ist die LED entweder immer an oder immer aus.

Verfolge ich vielleicht einen ganz falschen Ansatz?

von olibert (Gast)


Lesenswert?

Michael, vielleicht kann ich dir indirekt weiterhelfen. Ich habe letzte 
Woche eine aehnliche Schaltung aufgebaut und mich an Frank Links 
RC5-Motorpotisteuerung orientiert..

http://www.elektor.de/jahrgang/2008/november/einstellen-mit-niveau.710381.lynkx

..und einige Anpassungen an der Software (RC5-Codes auch auf UART) und 
HW (Motoransteuerung ueber L203 statt parallelschalten der 
Atmega8-Ausgaenge).

Franks RC5-Auswertung funktioniert einwandfrei und die Software ist ein 
freier Download unter obigen Link. Vielleicht kann dir Franks Quellcode 
ein
paar Tips geben, wie andere das Problem geloest haben.

von Michael N. (garril)


Lesenswert?

Da wurde wohl auch der Code von Peter Dannegger benutzt. Ich habe ihn 
jetzt mal auf mich angepasst. Funktioniert allerdings noch nicht...

Hab ein ext. Quarz dran und an PB0-7 je eine LED.
IR-Empfänger hängt an PD7
main.h
1
#define F_CPU 7372000L
2
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <avr/signal.h>
6
#include <util/delay.h>
7
#include <stdlib.h>
8
9
10
#define uchar unsigned char
11
#define uint unsigned int
12
13
#define  xRC5_IN    PIND
14
#define  xRC5    PD7      // IR input low active
15
16
#define  XTAL    7.372e6
17
//#define  XTAL    11.0592e6 <<Original
18
//#define  XTAL    7.3728e6
19
//#define XTAL    5e6
20
21
#define  BAUD  19200
22
#define bauddivider (uint)(XTAL / BAUD / 16 - 0.5)
23
24
25
extern uint  rc5_data;        // store result

und die rc5-receiver.c:
1
#include "main.h"
2
#define an(port,b) (port) |= (1<<(b))
3
#define aus(port,b) (port) &= ~(1<<(b))
4
5
#define RC5TIME   1.778e-3    // 1.778msec
6
#define PULSE_MIN  (uchar)(XTAL / 512 * RC5TIME * 0.4 + 0.5)
7
#define PULSE_1_2  (uchar)(XTAL / 512 * RC5TIME * 0.8 + 0.5)
8
#define PULSE_MAX  (uchar)(XTAL / 512 * RC5TIME * 1.2 + 0.5)
9
10
11
uchar  rc5_bit;        // bit value
12
uchar  rc5_time;        // count bit time
13
uint  rc5_tmp;        // shift bits in
14
uint  rc5_data;        // store result
15
16
17
SIGNAL (SIG_OVERFLOW0)
18
{
19
  uint tmp = rc5_tmp;        // for faster access
20
21
  TCNT0 = -2;          // 2 * 256 = 512 cycle
22
23
  if( ++rc5_time > PULSE_MAX ){      // count pulse time
24
    if( !(tmp & 0x4000) && tmp & 0x2000 )  // only if 14 bits received
25
      rc5_data = tmp;
26
    tmp = 0;
27
  }
28
29
  if( (rc5_bit ^ xRC5_IN) & 1<<xRC5 ){    // change detect
30
    rc5_bit = ~rc5_bit;        // 0x00 -> 0xFF -> 0x00
31
32
    if( rc5_time < PULSE_MIN )      // to short
33
      tmp = 0;
34
35
    if( !tmp || rc5_time > PULSE_1_2 ){    // start or long pulse time
36
      if( !(tmp & 0x4000) )      // not to many bits
37
        tmp <<= 1;        // shift
38
      if( !(rc5_bit & 1<<xRC5) )    // inverted bit
39
        tmp |= 1;        // insert new bit
40
      rc5_time = 0;        // count next pulse time
41
    }
42
  }
43
44
  rc5_tmp = tmp;
45
}
46
47
48
void putchar( char c )
49
{
50
  while( (UCSRA & 1<<UDRE) == 0 );
51
  UDR = c;
52
}
53
54
55
void puts( char *s )
56
{
57
  while( *s )
58
    putchar( *s++ );
59
}
60
61
62
int main( void )
63
{
64
  DDRB = 0xFF; //Port B als Ausgang
65
  DDRD = 0x7F; //PD7 Eingang
66
  uint i;
67
  char s[30];
68
69
  TCCR0 = 1<<CS02;      //divide by 256
70
  TIMSK = 1<<TOIE0;      //enable timer interrupt
71
72
  UBRRL = bauddivider;      //set baud rate
73
  UBRRH = bauddivider >> 8;
74
  UCSRA = 0;        //no U2X, MPCM
75
  UCSRC = 1<<URSEL^1<<UCSZ1^1<<UCSZ0;  //8 Bit
76
  UCSRB = 1<<RXEN^1<<TXEN;    //enable RX, TX
77
78
  sei();
79
  puts( "RC5-Dekoder:\n\r" );
80
  for(;;){        // main loop
81
    cli();
82
    i = rc5_data;      // read two bytes from interrupt !
83
    rc5_data = 0;
84
    sei();
85
    if( i ){
86
      DDRB = i;        // LED output
87
      putchar(( i >> 11 & 1) + '0');  // Toggle Bit
88
      putchar(' ');
89
      itoa( i >> 6 & 0x1F, s, 10);  // Device address
90
      puts( s );
91
      putchar(' ');
92
      itoa((i & 0x3F) | (~i >> 7 & 0x40), s, 10); // Key Code
93
      puts( s );
94
      puts( "\n\r" );
95
    }
96
  }
97
}

Weiß nicht wo der Hund begraben ist...
Wo sollte ich mit der Fehlersuche ansetzen?
LEDs bleiben einfach dunkel
Die includes habe ich etwas angepasst, da der code noch recht alt war.

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.