Forum: Mikrocontroller und Digitale Elektronik USART mit Attiny2313


von Valentin S. (jonava)


Lesenswert?

Hallo Zusammen, ich habe folgendes Problem:

Ich möche den RC5 Code mit einem Attiny2313 decodeieren. Dazu habe ich 
aus dem Forum den Code von Peter Dannegger genommen und an den 
Attiny2313 angepsst. Leider bekomme ich keine Ausgaben an der seriellen 
Schnittstelle.
Ich verwende ein STK500 und habe einen externen 4MHz Quarz 
angeschlossen.

Hier meine Code:

Main.c:

/*********************************************************************** 
*/
/* 
*/
/*                      RC5 Remote Receiver 
*/
/* 
*/
/*              Author: Peter Dannegger 
*/
/*                      danni@specs.de 
*/
/* 
*/
/*********************************************************************** 
*/
#include "main.h"
#include <avr/io.h>

#ifndef F_CPU
#define F_CPU 4000000UL
#endif

#include<util/delay.h>
#include<stdint.h>
#include<avr/interrupt.h>
#include<stdlib.h>

void putchar( char c )
{
  while ( !(UCSRA & (1<<UDRE)) )
  UDR = c;
}


void puts( char *s )
{
  while( *s )
    putchar( *s++ );
}


int main( void )
{


  DDRD |= (1<<PD6) ; // PD6 Ausgang
  PORTD |= (1<<PD6); // DEBUG-LED LED1 an

  unsigned int i;
  char s[30];

  TCCR0B = 1<<CS02;      //divide by 256
  TIMSK = 1<<TOIE0;      //enable timer interrupt

//  UBRRL = 12;      //set baud rate
//  UBRRH = 0x00;


   UBRRL = (bauddivider);      //set baud rate
  UBRRH = (bauddivider >> 8);

  UCSRA = 0;        //no U2X, MPCM
  UCSRC = 1<<UMSEL^1<<UCSZ1^1<<UCSZ0;  //8 Bit
  UCSRB = (1<<TXEN) | (1<<RXCIE);


  sei();
  puts( "RC5-Dekoder:\n\r" );
  for(;;){        // main loop
    cli();
    i = rc5_data;      // read two bytes from interrupt !
    rc5_data = 0;
    sei();
    if( i ){
      //DDRB = i;        // LED output
      putchar(( i >> 11 & 1) + '0');  // Toggle Bit
      putchar(' ');
      itoa( i >> 6 & 0x1F, s, 10);  // Device address
      puts( s );
      putchar(' ');
      itoa((i & 0x3F) | (~i >> 7 & 0x40), s, 10); // Key Code
      puts( s );
      puts( "\n\r" );
    }
  }
}

main.h:

/*********************************************************************** 
*/
/* 
*/
/*                      RC5 Remote Receiver 
*/
/* 
*/
/*              Author: Peter Dannegger 
*/
/*                      danni@specs.de 
*/
/* 
*/
/*********************************************************************** 
*/
#include <avr/io.h>
#include <avr/interrupt.h>
//#include <avr/signal.h>
#include <avr/include/stdlib.h>
#ifndef F_CPU
#define F_CPU 4000000UL
#endif


#define uchar unsigned char
#define uint unsigned int

#define  xRC5_IN    PIND
#define  xRC5    PD2      // IR input low active

//#define XTAL F_CPU
//#define  XTAL    11.0592e6
#define  XTAL    4000000UL
//#define XTAL    5e6

#define  BAUD  19200
#define bauddivider (uint)((XTAL/(16UL * BAUD)-1))


extern  uint  rc5_data;        // store result

rc5.c:
/*********************************************************************** 
*/
/* 
*/
/*                      RC5 Remote Receiver 
*/
/* 
*/
/*              Author: Peter Dannegger 
*/
/*                      danni@specs.de 
*/
/* 
*/
/*********************************************************************** 
*/
#include "main.h"
#include <avr/io.h>
#include <avr/include/stdlib.h>
#include <avr/delay.h>

#define RC5TIME   1.778e-3    // 1.778msec
#define PULSE_MIN  (uchar)(XTAL / 512  RC5TIME  0.4 + 0.5)
#define PULSE_1_2  (uchar)(XTAL / 512  RC5TIME  0.8 + 0.5)
#define PULSE_MAX  (uchar)(XTAL / 512  RC5TIME  1.2 + 0.5)


uchar  rc5_bit;        // bit value
uchar  rc5_time;        // count bit time
uint  rc5_tmp;        // shift bits in
uint  rc5_data;        // store result


SIGNAL (SIG_OVERFLOW0)
{
  uint tmp = rc5_tmp;        // for faster access

  TCNT0 = -2;          // 2 * 256 = 512 cycle

  if( ++rc5_time > PULSE_MAX ){      // count pulse time
    if( !(tmp & 0x4000) && tmp & 0x2000 )  // only if 14 bits received
      rc5_data = tmp;
    tmp = 0;
  }

  if( (rc5_bit ^ xRC5_IN) & 1<<xRC5 ){    // change detect
    rc5_bit = ~rc5_bit;        // 0x00 -> 0xFF -> 0x00

    if( rc5_time < PULSE_MIN )      // to short
      tmp = 0;

    if( !tmp || rc5_time > PULSE_1_2 ){    // start or long pulse time

  //eingefügt
  #if 1
      /*
        Anschluss PD6----###--->|---- GND
      */
      DDRD |= (1<<PD6);   // PD6 auf Ausgang
     // _delay_ms(500);
    PORTD ^= (1<<PD6);  // LED1 an PD6 togglen
  #endif

    if( !(tmp & 0x4000) )      // not to many bits
        tmp <<= 1;        // shift
      if( !(rc5_bit & 1<<xRC5) )    // inverted bit
        tmp |= 1;        // insert new bit
      rc5_time = 0;        // count next pulse time
    }
  }

  rc5_tmp = tmp;
}


Kann mir jemand sagen, was ich falsch mache?

Vielen Dank im Voraus.

Gruß
Jonanova

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Kann es sein, dass du nicht den Originalcode von Peter genommen hast, 
sondern Teile der Attiny2313-Anpassung für das [[Pollin 
Funk-AVR-Evaluationsboard]]. Ich meine in main() und in der SIGNAL 
(SIG_OVERFLOW0) hardwarespezifische Anweisungen dafür zu erkennen.

Funktioniert dein UART ohne den RC5 Teil überhaupt? Das wäre ein Hinweis 
wo du nach dem Fehler suchen kannst. Ich würde mit dieser Zeile 
anfangen:

  UCSRB = (1<<TXEN) | (1<<RXCIE);

Es ist nämlich übel, wenn man keinen Signalhandler (ISR) für den 
Zeichen-Empfangen-Interrupt hat und diesen Interrupt enabled.

1: 
http://www.mikrocontroller.net/articles/Pollin_Funk-AVR-Evaluationsboard#RC5_Empf.C3.A4nger

von Karl H. (kbuchegg)


Lesenswert?

Sieh dir auch mal diesen Code GENAU an
1
void putchar( char c )
2
{
3
  while ( !(UCSRA & (1<<UDRE)) )
4
  UDR = c;
5
}

und dann überlege (auch mal mit dem Datenblatt abklären, was hier 
eigentlich warum gemacht wird) ob das so stimmen kann.

von Valentin S. (jonava)


Lesenswert?

Hallo Zusammen,

@ Stefan: Ja ich habe auch etwas aus dem Pollin teil genommen und 
angepasst. Ich habe den Code ohne RC5 nicht getestet.

Wie könnte ich das tun ohne den code nicht löschen zu müssen?

@ Karl Heinz

Ich muss sagen, dass ich noch ziemlich am Anfang bin, was 
C-Programmierung betrifft und deswegen nicht weiß was der Code macht.

 while ( !(UCSRA & (1<<UDRE)) )
  UDR = c;
Wenn ich statt UDRE RXC reinschreibe, dann Bekomme ich laufend ein "R",
was aus diesem
          puts( "RC5-Dekoder:\n\r" );

 kommt.

Kann mir jemand sagen, was ich dazu schreiben könnte um die serielle 
Schnittstelle zu testen unabhängig vom RC5??

Vielen Dank im Voraus
Gruß
Jonanova

von Karl H. (kbuchegg)


Lesenswert?

avr-gcc-Tutorial
Abschnitt "UART"

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Du hättest dir auch den Teil UART beim Attiny2313 anschauen sollen. Das 
Bit UMSEL hat der/braucht der nicht. Da weicht die Initialisierung der 
UART von dem AVR ab, den Peter benutzte.

Wenn ich größere Änderungen machen muss und den Restcode nicht verlieren 
möchte, verwende ich eine von diesen Methoden

1) Neues Projekt anlegen und altes Projekt rüberkopieren. Dann nach 
Herzenslust im neuen Projekt löschen oder ändern. Änderungen nach Erfolg 
in das alte Projekt zurückführen.

2) Mit #if 0 .... #endif Codeteile per C-Präprozessor auskommentieren. 
Mit einem zusätzlichen #else kann man einfach zwischen Varianten 
umschalten. Im finalen Code sollten möglicht wenige dieser Reste stehen, 
weil sie die Übersicht nehmen.

von Valentin S. (jonava)


Lesenswert?

ich habe mir jetzt folgendes Projekt angelegt um etwas auf die Serielle 
Schnittstelle zu bekommen, leider funktioniert das auch nicht. Könnt ihr 
mir sagen warum nicht???

#include <avr/io.h>
#ifndef F_CPU
#define F_CPU 4000000UL
#endif
#include<util/delay.h>
#include<stdint.h>
#include<avr/interrupt.h>
#include<stdlib.h>
#define uint unsigned int
#define BAUD 19200
#define bauddivider (uint)(F_CPU  BAUD  16 - 1)


int main ()
{

  UBRRL = (bauddivider & 0x0ff);      //set baud rate
  UBRRH = bauddivider>>8;

  UCSRA = 0;        //no U2X, MPCM
  UCSRC |=  (0 << USBS) | (3 << UCSZ0);


  UCSRB |= (1<<RXEN) | (1<<TXEN) ;//| (1<<RXCIE);    //enable RX, TX


  while (1)
  {
  printf ("hallo");
  }
return 0;
}


Vielen Dank im Voraus!!

Gruß
Jonanova

von Karl H. (kbuchegg)


Lesenswert?

Und was veranlasst dich zu der Vermutung, dass printf seine Ergüsse über 
die serielle Schnittstelle ausgeben wird?
Warum sollte printf nicht auf 'dem LCD' ausgeben. Oder über SPI?

Nochmal: Schau ins Tutorial. Da gibt es einen Abschnitt über UART. Dort 
steht alles drinn, was du wissen musst und dort gibt es auch ein paar 
oft benötigte Routinen. Selbst wenn man die nicht 1:1 benutzen kann 
(weil zb ein paar Register anders heißen), so gibt es doch genügend 
Hinweise, dass man sich die Dinge auf seine Gegebenheiten anpassen kann.

von Valentin S. (jonava)


Lesenswert?

Sorry aber ich steh voll auf dem Schlauch. Ich hab den Code laut dem Tut 
so abgeändert aber es tut sich immer noch nichts.

#include <avr/io.h>
#ifndef F_CPU
#define F_CPU 4000000UL
#endif
#include<util/delay.h>
#include<stdint.h>
#include<avr/interrupt.h>
#include<stdlib.h>
#include <stdio.h>
#define uint unsigned int
#define BAUD 19200
#define bauddivider (uint)(F_CPU  BAUD  16 - 1)

int uart_putc(unsigned char c)
{
    while (!(UCSRA & (1<<UDRE)))  /* warten bis Senden moeglich */
    {
    }

    UDR = c;                      /* sende Zeichen */
    return 0;
}


int main ()
{

  UBRRL = (bauddivider & 0x0ff);      //set baud rate
  UBRRH = bauddivider>>8;

  UCSRA = 0;        //no U2X, MPCM
  UCSRC |=  (0 << USBS) | (3 << UCSZ0);


  UCSRB |= (1<<RXEN) | (1<<TXEN) ;//| (1<<RXCIE);    //enable RX, TX


  while (1)
  {
  uart_putc ("hallo \0");
  }
return 0;
}


Danke für die Geduld.

Gruß
jonanova

von Karl H. (kbuchegg)


Lesenswert?

Was mich immer wieder verblüfft ist, das der Compiler hier

uart_putc ("hallo \0");


keine Warnung gibt, bzw. dass Programmierer diese Warnung ignorieren.

uart_putc gibt ein einzelnes Zeichen (einen einzelnen char) aus.
Du hast aber kein einzelnes Zeichen. Du hast einen String!

http://www.mikrocontroller.net/articles/FAQ#Wie_funktioniert_String-Verarbeitung_in_C.3F

von Stefan B. (stefan) Benutzerseite


Lesenswert?

1
#include <avr/io.h>
2
3
#ifndef F_CPU
4
#define F_CPU 4e6
5
#endif
6
7
// Baudratenfehler bei 19200 Baud und 4 MHz im Datenblatt nachsehen!
8
#define BAUD 19200 
9
#define bauddivider (unsigned int)((F_CPU/(16UL * BAUD)-1))
10
11
void uart_putc(unsigned char c)
12
{
13
    while (!(UCSRA & (1<<UDRE)))  /* warten bis Senden moeglich */
14
    {
15
    }
16
    UDR = c;                      /* sende Zeichen */
17
}
18
19
20
void uart_puts(char * s)
21
{
22
    while (*s)  /* so lange Zeichen vorhanden */
23
    {
24
      uart_putc(*s++);
25
    }
26
}
27
28
29
int main(void)
30
{
31
  UBRRL = (bauddivider & 0x0ff);      //set baud rate
32
  UBRRH = bauddivider>>8;
33
34
  UCSRA = 0;        // no U2X, MPCM
35
  UCSRC = 3<<UCSZ0; // Frame format: 8N1
36
  UCSRB = (1<<RXEN) | (1<<TXEN);
37
38
  while(1)
39
  {
40
    uart_puts("Hallo\r\n");
41
  }
42
  return 0;
43
}

von Valentin S. (jonava)


Lesenswert?

Hallo Stefan,

Vielen Dank für deinen Code.
Leider bekomme ich auch hier keine Anzeige auf dem Terminal.
Woran könnte das liegen?
Ich habe ein STK500 mit einem 4MHZ Quarz. Auf dem Board habe ich PD0 und 
PD1 mit RXD und TXD verkabelt und das Serielle Kabel ist an RS232 Spare 
angeschlossen.

Vielen Dank.

von Valentin S. (jonava)


Lesenswert?

Hallo,
ich nehm alles zurück. Der Code macht genau das was er soll. Ich hatte 
im AVR die HEX-Datei vom RC5 code drin.

sorry.

Jetzt weiß ich dass die USART tut.

Weiß jemand von euch was ich am RC5 anpassen muss damit er das auch 
ausgibt was er da misst?

Vielen Dank im Voraus.

Gruß
Jonanova

von Karl H. (kbuchegg)


Lesenswert?

Was spricht dagegen, die beiden Code-Quellen zu kombinieren?

Du hast ein Projekt mit funktionierenden UART Routinen und du hast 
eines, bei dem sie nicht funktionieren. Also nimmst du die 
funktionierenden und ersetzt die nichtfunktionierenden. Dann passt du 
das Hauptprogramm noch an eventuell veränderte Funktionsnamen an und 
.... siehst nach, was dann die Ausgabe ist.

Alternativ kannst du natürlich auch deinen nichtfunktionierenden 
UART-Code mit dem funktionierenden vergleichen und darauf achten, was du 
beim Abtippen vergessen hast :-)

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Meine optimistische Vermutung: Den RC5 Code baust du jetzt in das 
funktionierende UART Beispiel ein und er wird grundsätzlich 
funktionieren.

Oder du korrigierst die 2 wesentlichen Punkte in deinem ersten Beitrag.

Vorausgesetzt die Hardwareschaltung dahinter ist richtig angeschlossen 
und deine Testfernbedienung schickt auch einen RC5-Code.

Und das Timing passt zu dem 4 MHz Quarz. Peters Original hatte ja 
11.paarzerquetschte MHz, mein Beispiel auf dem Pollinboard hatte 8 MHz 
(ging), du versuchst es jetzt mit 4 MHz...

Die Debug-LED aus meinem Beispiel an PD6 fand ich ganz nützlich, um zu 
sehen, ob der IR-Empfänger was zum µC schaufelt, hast du sowas auch?

von Valentin S. (jonava)


Lesenswert?

Das habe ich soeben gemacht, aber irgendetwas verhindert, dass er zum 
senden kommt.

ich habe den Code in der main.c jetzt so angepasst:

#include "main.h"
#include <avr/io.h>


#include<util/delay.h>
#include<stdint.h>
#include<avr/interrupt.h>
#include<stdlib.h>

#ifndef F_CPU
#define F_CPU 4e6
#endif

// Baudratenfehler bei 19200 Baud und 4 MHz im Datenblatt nachsehen!
#define BAUD 19200
#define bauddivider (unsigned int)((F_CPU/(16UL * BAUD)-1))

void putchar( char c )
{
  while ( !(UCSRA & (1<<UDRE)))
  UDR = c;
}


void puts( char *s )
{
  while( *s )
    putchar( *s++ );
}


int main( void )
{


  DDRD |= (1<<PD6) ; // PD6 Ausgang
  PORTD |= (1<<PD6); // DEBUG-LED LED1 an

  uint i;
  char s[30];

  TCCR0B = 1<<CS02;      //divide by 256
  TIMSK = 1<<TOIE0;      //enable timer interrupt

   UBRRL = (bauddivider & 0x0ff);      //set baud rate
  UBRRH = bauddivider>>8;
  UCSRA = 0;        //no U2X, MPCM
  UCSRC |= (3 << UCSZ0);
  UCSRB |= (1<<RXEN) | (1<<TXEN) ;  //enable RX, TX
puts( "RC5-Dekoder:\n\r" );


  sei();
  puts( "RC5-Dekoder:\n\r" );
  for(;;){        // main loop
    cli();
    i = rc5_data;      // read two bytes from interrupt !
    rc5_data = 0;
    sei();
    if( i ){
      //DDRB = i;        // LED output
      putchar(( i >> 11 & 1) + '0');  // Toggle Bit
      putchar(' ');
      itoa( i >> 6 & 0x1F, s, 10);  // Device address
      puts( s );
      putchar(' ');
      itoa((i & 0x3F) | (~i >> 7 & 0x40), s, 10); // Key Code
      puts( s );
      puts( "\n\r" );
    }
  }
}


leider gibt er mir das nicht aus: puts( "RC5-Dekoder:\n\r" );

Gruß

von Karl H. (kbuchegg)


Lesenswert?

Valentin S. schrieb:
> Das habe ich soeben gemacht, aber irgendetwas verhindert, dass er zum
> senden kommt.
>
> ich habe den Code in der main.c jetzt so angepasst:

Nein, hast du nicht. Da ist immer noch derselbe Fehler

void putchar( char c )
{
  while ( !(UCSRA & (1<<UDRE)))
  UDR = c;
}


Vergleich doch mal mit der uart_putc.
Das ist die korrespondierende Funktion in den funktionierenden Routinen. 
Und noch ein Hinweis: Dem Compiler ist es völlig egal wie du einrückst. 
Das beeinflusst ihn nicht im geringsten, welche Anweisung von der while 
Schleife abhängt und welche nicht.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

> void putchar( char c )
> {
>   while ( !(UCSRA & (1<<UDRE)))
>   UDR = c;
> }

immer noch falsch. Weiter habe ich nicht geschaut.

von Valentin S. (jonava)


Lesenswert?

Ich habe auch die Debug LED dran.
Wenn ich die Fernbedienung drücke, dann flackert die LED. Die LED ist 
ansonsten immer an.

Mit nem Oszi habe ich auch den Ausgang gemessen und die Schaltung vom IR 
Empfänger hatte ich auch schon an nem Atmega 8 laufen.

von Valentin S. (jonava)


Lesenswert?

Sorry,

ihr habt recht.
Jetzt spuckt er auch "RC5-Dekoder:" aus.
Das mit dem Code leider noch nicht.

tut mir leid, dass ich mich so dämlich anstelle.

von Karl H. (kbuchegg)


Lesenswert?

Valentin S. schrieb:

> tut mir leid, dass ich mich so dämlich anstelle.

Bitte versteh auch, dass wir dir zwar gerne Hinweise geben aber nach 
Möglichkeit keinen fix fertign Code. Es sei denn die Funktionalität ist 
so schwer zu beschreiben, dass Code tatsächlich die einfachste Lösung 
ist.

Du hast jetzt hoffentlich gelernt, dass es in C oftmals auf jedes 
einzelne Zeichen im Quelltext ankommt. Alles und jedes hat seine 
Bedeutung. Und die kann extrem wichtig sein.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Ändere in main.h und rc5.c
1
extern volatile uint  rc5_data;        // store result 
2
uint  rc5_data;        // store result

in
1
extern volatile uint  rc5_data;        // store result
2
volatile uint  rc5_data;        // store result

Bei meinem uralten WinAVR beeinflusst das Weglassen des volatile die 
Funktion nicht. Modernere WinAVR sind da aber pingeliger.

von Valentin S. (jonava)


Lesenswert?

Danke soweit,
find ich echt Klasse, dass ihr soviel Geduld mit habt.


ich hab das volatile jetzt hinzugefügt und sihe da es tut. Jetzt spuckt 
er mir ab und zu den Code Raus. Der Code ist auch richtig, aber leider 
macht er das nicht mit jedem Tastendruck.
waran könnte das liegen?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Da kann ich nur raten bzw. würde ich experimentieren.

Und zwar würde ich versuchen die Herabsetzung des Taktes 11,x => 4 MHz 
durch eine Verringerung des Prescalers 256 => 64 "auszugleichen".

Im Prinzip also darauf spekulieren, dass bei deinem langsamer laufenden 
Timer gelegentlich RC5-Kommandosequenzen nicht oder als nicht legal 
empfangen werden und dass sich das bei schneller laufendem Timer 
verbessert.

von Karl H. (kbuchegg)


Lesenswert?

Stefan B. schrieb:
> Da kann ich nur raten bzw. würde ich experimentieren.
>
> Und zwar würde ich versuchen die Herabsetzung des Taktes 11,x => 4 MHz
> durch eine Verringerung des Prescalers 256 => 64 "auszugleichen".

Auch müsste man in der ISR anpassen

  TCNT0 = -2;          // 2 * 256 = 512 cycle

Das wird bei einer Veränderung der Taktfrequenz nicht mehr stimmen.

Der Code muss wirklich schon sehr alt sein. Normalerweise baut PeDa das 
alles so, dass sich eine Änderung der Taktfrequenz nicht auswirkt.

von Valentin S. (jonava)


Lesenswert?

Ich habe den Prescaler auf 64 gesetzt in dem ich das so aus dem 
Datenblatt entnommen habe
TCCR0B |= (1<<CS00) | (1<<CS01);

ist das richtig so?

Leider gibt er den Code gar nicht mehr aus.

Wie müsste ich den Wert bei TCNT0 wählen???

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Ich schrieb ja, dass ich raten/experimentieren würde. Ich möchte 
keinesfalls sbehaupten, dass das das Problem ist.

Peter hat schon Makros für die RC5-Pulslängen im Code, die F_CPU bzw. 
XTAL berücksichtigen!

Ich habe nur nicht genau aufgedröselt, bei ob das bei 4 MHz noch 
funktioniert. Denn es wäre schneller getestet als studiert :)

von Valentin S. (jonava)


Lesenswert?

Ich muss das leider für eine fertige Schaltung anpassen und da habe ich 
leider nur einen 4MHz Quarz zur Verfügung.

Wie könnte ich das testen? Habt ihr da ne Idee für mich?

Ich muss jetzt los werde mich dann morgen nochmal melden.

Vielen Vielen Dank an euch Beide ihr habt mir echt weiter geholfen.

Gruß
jonanova

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Im Original bei 11.0592 MHz wird der Timer mit Prescaler 256 und 
Vorladewert -2 alle 46,3µs aufgerufen. Das sind 512 Zyklen. Die 512 
stecken auch in den Makros für die Pulsdauern

Wenn man bei 4 MHz eine ähnlich hohe Aufruffrequenz haben will, kann man 
den Precaler auf 64 runtersetzen und den Vorladewert -3 benutzen. Das 
ergibt dann 48 µs (64 und -2 ergäbe einen schnelleren Timer mit 32 µs, 
schadet auch nicht).

Man muss dann aber die Makros für die Pulsdauern anpassen, damit die 
Zyklenzahl stimmt und die Pulsdauern richtig gezählt werden. Die 
richtige Zahl ist Prescaler * Betrag(Vorladewert), also bei 64 mit -3 
ist der Wert fürs Makro 192 und bei 64 mit -2 ist der Wert fürs Makro 
128.

von Valentin S. (jonava)


Lesenswert?

Hallo Stefan,

der Tipp war goldrichtig. Vielen Vielen Dank.

Wie kann ich mich dafür bedanken?


Gruß
Jonanova

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Hast du doch schon. Mich freut es, wenn eine Rückmeldung kommt "es 
geht", nachdem man an einem Problem geknabbert hat.

von Valentin S. (jonava)


Lesenswert?

Eine Kurze Frage habe ich noch. Wie kann ich einen Taster realisieren, 
d.h. Ich möchte eine LED (zum testen erstmal) so lange leuchten lassen 
wie ich Taste x gedrückt halte. Ich habe das mit einer while Schleife 
probiert, bin aber gescheitert. Mit meiner jetzigen lösung toggelt er 
das. Hast du eine Idee wie man das Lösen kann?

 for(;;)
  {        // main loop
        cli();
        i = rc5_data;      // read two bytes from interrupt !
        rc5_data = 0;
        sei();

      char v[14];
         uint k  = i;

    if (k)
    {

        //itoa( k, s, 10 );


      if(strcmp(itoa( k, s, 10) , "15376") == 0)
      {
         PORTB &=~(1<<PB4); // PB4 auf Low
         puts("LED PB4 \n\r");
         //PORTB |= (1<<PB4);

      }

      if (strcmp(itoa( k, s, 10) , "13329") == 0)
      {
         PORTB &= ~(1<<PB5); // PB5 auf Low
         puts("LED PB5 \n\r");
         //PORTB |= (1<<PB5);

      }

    PORTB |= ((1<<PB4) | (1<<PB5));
    }

Wenn ich aus der If eine While Schleife mache, dann er da nicht mehr 
raus.

Gruß
Jonanova

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Das ist DIE Gelegenheit dich mit dem Entprellen bekannt zu machen! Peter 
Dannegger hat da kürzlich eine Routine "Entprellen für Anfänger" in der 
Codesammlung veröffentlicht.

Je nach Hardwareschaltung der Taster und kleinen Änderungen im Code kann 
man das Leuchten-bei-Tastendruck einfach und sicher implementieren.

Vielleicht magst du meine Anpassung für Attiny2313 und active high 
(Bedeutung siehe AVR-GCC-Tutorial) geschalteten Taster als Anregung 
nehmen: 
http://www.mikrocontroller.net/articles/Pollin_Funk-AVR-Evaluationsboard#Tasty_Reloaded

von Valentin S. (jonava)


Lesenswert?

Mir ist noch etwas anderes eingefallen:

if(strcmp(itoa( k, s, 10) , "15376") == 0)
      {
         PORTB &=~(1<<PB4); // PB4 auf Low
         //puts("LED PB4 \n\r");
         _delay_ms(100);
         PORTB |= (1<<PB4);



      }
Gibt es da eine ellegantere Lösung?

Gruß
Jonanova

von Karl H. (kbuchegg)


Lesenswert?

Valentin S. schrieb:
> Eine Kurze Frage habe ich noch. Wie kann ich einen Taster realisieren,
> d.h. Ich möchte eine LED (zum testen erstmal) so lange leuchten lassen
> wie ich Taste x gedrückt halte. Ich habe das mit einer while Schleife
> probiert, bin aber gescheitert. Mit meiner jetzigen lösung toggelt er
> das. Hast du eine Idee wie man das Lösen kann?

Wie wäre es. wenn du nach der Auswertung das k, bzw i bzw. rc5_data 
einfach auf 0 setzt? Wenn ich mich recht erinnere, macht das auch der 
PeDa Code. Schon vergessen: fremden Code genau studieren!

(PS: Zuviele Variablen mit derselben Bedeutung verwirren dich nur. Du 
weisst dann nicht mehr welche eigentlich gilt, welche welchen Wert 
enthält etc.


Das hier
      if(strcmp(itoa( k, s, 10) , "15376") == 0)
ist wohl ein Kandidat für den OCCC in der Kategorie: Beste 
Verschleierung der ursprünglichen Absicht.

von Karl H. (kbuchegg)


Lesenswert?

Stefan B. schrieb:
> Das ist DIE Gelegenheit dich mit dem Entprellen bekannt zu machen!

Ich denke mit Taste meint er
'Taste auf der Fernsteuerung, deren Code über IR gesendet wird' und 
nicht die klassische Taste, die an einem Port hängt.

von Karl H. (kbuchegg)


Lesenswert?

Valentin S. schrieb:

> Gibt es da eine ellegantere Lösung?

Sicher.
Du hast doch einen Timer mitlaufen, dessen ISR in bestimmten 
Zeitabständen (die du kennst) aufgerufen wird.
Diese ISR kann gleich auch noch das Zeitmanagement für die LED 
mitmachen.

Wird die ISR zb alle 10ms aufgerufen, dann ist nach dem 100-ten Aufruf 
genau 1 Sekunde vergangen

ISR( ...
{
  cnt++;
  if( cnt == 100 ) {
    cnt = 0;

    xxxx
  }

  ...
}


Der Codeteil xxxx wird dann genau jede 1 Sekunde ausgeführt. Wenn du 
hier deine LED einfach umschaltest, ist sie daher 1 Sekunde an, 1 
Sekunde aus, 1 Sekunde an, 1 Sekunde aus ...


Edit: Oder hab ich dich misverstanden und du willst gar nicht Blinken 
haben?

von Hannes L. (hannes)


Lesenswert?

Vielleicht solltest Du auch hier mal querlesen, das betrifft auch den 
Pollin-IR8-Bausatz in Version 1.2, also mit UART.
Hier für RECS80-Code:
Beitrag "Re: Quellcode für den Pollin Fernsteuer Bausatz"
Und hier für IR60-Code:
Beitrag "Re: Quellcode für den Pollin Fernsteuer Bausatz"

Durch Analyse der Kommentare (den ASM-Code musst Du nichtmal verstehen) 
müsstest Du erkennen können, wie man unterschiedliches Verhalten auf 
Tastendrücke realisieren kann.

Hier gibt es übrigens noch eine (unvollständige) Liste geeigneter, bei 
Pollin billig erhältlicher Fernbedienungen:
Beitrag "Re: Quellcode für den Pollin Fernsteuer Bausatz"

...

von Stefan B. (stefan) Benutzerseite


Lesenswert?

FB-Taste, klar... sorry war im falschen Film. Der Tipp von Hannes ist 
gut. An vorhandenem Code kann man prima lernen.

Bei "Dauerfeuer" auf einer FB-Taste ist zu beachten, dass bei 
Wiederholungen des RC5 Codes die FB ein Bit im Code wechselt. D.h. für 
die gleiche FB-Taste und "Dauerfeuer" bekommst du verschiendene RC5 
Codes anwechselnd.

In deinem Code oben ist es sehr zeitraubend und unnötig, die Vergleiche 
mit Strings zu machen. Das kann man direkt als Zahlenvergleich 
programmieren.

Du willst pro FB-Taste exklusiv eine Aktion haben und die so lange, wie 
die FB-Taste gedrückt wird. D.h. wenn die FB-Taste losgelassen wird, 
soll die Aktion beendet werden. Richtig?

Ich würde es so probieren (switch/case nur um was Neues reinzubringen 
statt des langweiligen if :)
1
#define WARTEZYKLEN  250   // 250 * ca. 2ms = ca. 500ms
2
3
  for(;;)
4
  { 
5
    static uint timeout = 0;
6
    uint neues_kommando;
7
8
    cli();
9
    neues_kommando = rc5_data;      // read two bytes from interrupt !
10
    rc5_data = 0;
11
    sei();
12
13
    // Auswerten
14
    switch( neues_kommando )
15
    { 
16
      case 0: 
17
        // Kein gültiger RC5 Code empfangen
18
        // wenn das WARTEZYKLEN-mal hintereinander passiert
19
        // wurde die Taste wohl losgelassen...
20
        if ( timeout == WARTEZYKLEN )
21
        {
22
          // Alle Kommandos pauschal annulieren
23
          PORTB |= (1<<PB4) | (1<<PB5);
24
          puts("timeout == WARTEZYKLEN\r\n");
25
        } else
26
          timeout += 1;
27
        break;
28
      case 15376:
29
        // Exklusiv betätigte Taste 
30
        // d.h. ältere Kommandos annulieren
31
        PORTB |= 1<<PB5; 
32
        // Kommando ausführen
33
        PORTB &= ~(1<<PB4);
34
        puts("LED PB4\r\n");
35
        timeout = 0;
36
        break;
37
      case 13329:
38
        PORTB |= 1<<PB4; 
39
        PORTB &= ~(1<<PB5);
40
        puts("LED PB5\r\n");
41
        timeout = 0;
42
        break;
43
     default: 
44
        // Sonstiger RC5 Code
45
        // Alle Kommandos pauschal annulieren
46
        PORTB |= (1<<PB4) | (1<<PB5); 
47
        // RC5 Code anzeigen
48
        puts("RC5 = ");
49
        {
50
          char s[6];
51
          utoa(neues_kommando, s, 10);
52
          puts(s);
53
        }
54
        puts("\r\n");
55
        timeout = WARTEZYKLEN + 1;
56
        break;
57
    }
58
  }

Um keinen Blinkeffekt durch den wechselnden Dauerfeuer RC5 Code zu haben 
sollte man das switch oben um die zusätzlichen Codes in den case: Fällen 
erweitern z.B. so (wobei im folgenden Schnippsel die Zahlen willkürlich 
sind):
1
      case 15376:
2
      case 12345:
3
        // Rest wie oben
4
        break;
5
      case 13329:
6
      case 54321:
7
        // Rest wie oben
8
        break;

von Hannes L. (hannes)


Lesenswert?

"Dauerfeuer" gibt es übrigens bei meinem Code parasitär, wenn man im 
Repeat-Mode die Haltezeit kleiner wählt als die Telegramm-Wiederholzeit 
ist, also Werte im einstelligen Bereich einsetzt.

...

von Valentin S. (jonava)


Lesenswert?

Das mit dem Case ist genaial, aber er sendet jetzt permanent daten über 
die USART. Kann ich die Case-Fälle auch so verwenden mit den 
Zahlenwerten oder muss ich die umrechnen? Der wert "15376" ist ja nach 
der itoa funktion gekommen. Ich weiß leider nicht wie ich den RC5 code 
auslesen kann und dann direkt vegleichen.
Was meinst du mit dem zweiten Teil:
case 15376:
      case 12345:
        // Rest wie oben
        break;
      case 13329:
      case 54321:
        // Rest wie oben
        break;

@Hannes: Vielen Dank für die Links ich werde sie mir am Wochenende zu 
Gemüte führen.

Gruß
jonanova

von Karl H. (kbuchegg)


Lesenswert?

Valentin S. schrieb:
> Das mit dem Case ist genaial, aber er sendet jetzt permanent daten über
> die USART. Kann ich die Case-Fälle auch so verwenden mit den
> Zahlenwerten oder muss ich die umrechnen? Der wert "15376" ist ja nach
> der itoa funktion gekommen.

BIst du dir sicher, dass du weißt, was itoa eigentlich macht?

> Ich weiß leider nicht wie ich den RC5 code
> auslesen kann und dann direkt vegleichen.

   if( neues_kommando == 12345 ) {
   }


Hmm. Ich habe keine Erfahrung mit diesen Codes. Daher die Frage an die 
Leute, die das schon benutzt haben:
Gibt es da eigentlich Schema?
Worauf ich hinaus will: Sind in diesem Fall Dezimalzahlen wirklich 
schlau, oder würde sich bei einer Hex-Schreibweise nicht eine 
generelles, leicht zu durchschauendes Schema ergeben?

von Hannes L. (hannes)


Lesenswert?

Ich habe zwar keine Ahnung von C, aber Itoa macht ASCII aus Integer, 
Integer TO Ascii... ;-)

Man gut, dass es Assembler gibt... :-P

...

von Karl H. (kbuchegg)


Lesenswert?

Hannes Lux schrieb:
> Ich habe zwar keine Ahnung von C,

du lernst aber durch mitlesen.
Nicht mehr lange, und ich hab dich bekehrt :-)

von Hannes L. (hannes)


Lesenswert?

Karl heinz Buchegger schrieb:
> Hannes Lux schrieb:
>> Ich habe zwar keine Ahnung von C,
>
> du lernst aber durch mitlesen.

Stimmt. Ich verfüge auch über den K&R und kann norfalls nachlesen.

> Nicht mehr lange, und ich hab dich bekehrt :-)

Das glaube ich nicht. Ich tu mich mein Leben lang mit Sprachen schwer. 
Egal ob Russisch, Englisch, der Einstieg in Basic und 6502- bzw. 
8085-ASM, es war alles sehr sehr mühsam.

Nun bin ich froh dass ich AVR-ASM einigermaßen verstehe und nur noch 
selten ins Befehlsverzeichnis schauen muss und dass ich auch die 
Architektur einigermaßen verstanden (und schätzen gelernt) habe. Da tu 
ich mir mit sechzig Jahren C nicht mehr an, das ist mir einfach zu 
kryptisch. Das bissel, was ich zu basteln habe, bekomme ich mit AVR-ASM 
ganz gut in die Reihe. Da sehe ich was ich mache, die Befehle sind 
absolut eindeutig und unmissverständlich, da habe ich keinen Bock drauf, 
um eine weitere Ecke denken zu müssen, nur um meine Programme dem 
Mainstream gemäß in C zu formulieren. Da ich meist sehr hardwarenah 
programmiere, greift das Argument der angeblichen Portabilität nicht.

Karl-Heinz, Dein Vorhaben (mich zu bekehren) ehrt Dich, aber selbst 
T.S., der ein verdammt guter C-Programmierer ist und gelegentlich auf 'n 
Käffchen bei mir vorbei kommt, schafft es nicht, mich davon zu 
überzeugen.

Beste Grüße,
Hannes

von Stefan B. (stefan) Benutzerseite


Lesenswert?

@ Karl heinz

Bestimmt wäre die Hexdarstellung oder gar die Binärdarstellung 
aussagekräftiger. Es ist ja ein RC5 Telegramm 
(http://www.sbprojects.com/knowledge/ir/rc5.htm) und da stecken die 
Geräteadresse, das Bit für "Dauerfeuer" und das eigentliche Kommando 
drin. Besonders bei der Binärdarstellung sollte man das eine klappernde 
Bit3 schnell sehen.

@ jonanova

> Kann ich die Case-Fälle auch so verwenden mit den
> Zahlenwerten oder muss ich die umrechnen? Der wert "15376" ist ja nach
> der itoa funktion gekommen. Ich weiß leider nicht wie ich den RC5 code
> auslesen kann und dann direkt vegleichen.

Direkt so verwenden! Das Umwandeln der Zahl 12345 in den String "12345" 
mit itoa() und der Vergleich von Strngs mit strcmp() fressen Zeit und 
kostbare RAM-Bytes.

An die RC5-Codes kommst du, wenn du die Tasten der FB mal 
durchprobierst. Da ist die Ausgabe im default-Fall ganz nützlich. Wenn 
die Ausgaben stören, ändere das Programm und kommentiere die störenden 
puts() Zeilen einfach aus - ist ja dein Programm, da kannst du machen 
was du willst.

Beim Anschauen der Ausgaben wirst du merken, dass ein und dieselbe Taste 
verschiedene Werte liefert, wenn die gedrückt und dann losgelassen und 
dann wieder gedrückt wird. Wenn du diese FB-Taste im Programm auswerten 
willst, musst du auf beide Werte reagieren können. Deshalb die doppelten 
case-Fälle...

Aus http://www.sbprojects.com/knowledge/ir/rc5.htm
"The 3rd bit is a toggle bit. This bit is inverted every time a key is 
released and pressed again. This way the receiver can distinguish 
between a key that remains down, or is pressed repeatedly.
...
As long as a key remains down the message will be repeated every 114ms. 
The toggle bit will retain the same logical level during all of these 
repeated messages. It is up to the receiver software to interpret this 
auto repeat feature."

Ich habe das also im vorherigen Beitrag falsch beschrieben. Das Bit 
toggelt nur von Tastendruck zu Tastendruck bei der gleichen Taste. 
Während die Taste gedrückt ist, bleibt es konstant. Man kann so 
erkennen, ob die Taste zwischenzeitlich losgelassen wurde (Bit wechselt) 
oder nicht (Bit wechselt nicht).

Man kann das auch mit je einem case-Fall lösen, wenn man das Toggle-Bit 
ausmaskiert (immer 1 oder immer 0 setzt) und das Ergebnis im switch 
testet. Wie das Ausmaskieren grundsätzlich geht, ist im Artikel 
Bitmanipulation beschrieben.

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.