Datum:
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
Datum:
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_Fun...
Datum:
Sieh dir auch mal diesen Code GENAU an
void putchar( char c ) { while ( !(UCSRA & (1<<UDRE)) ) UDR = c; } |
und dann überlege (auch mal mit dem Datenblatt abklären, was hier eigentlich warum gemacht wird) ob das so stimmen kann.
Datum:
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
Datum:
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.
Datum:
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
Datum:
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.
Datum:
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
Datum:
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_fu...
Datum:
#include <avr/io.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 uart_putc(unsigned char c) { while (!(UCSRA & (1<<UDRE))) /* warten bis Senden moeglich */ { } UDR = c; /* sende Zeichen */ } void uart_puts(char * s) { while (*s) /* so lange Zeichen vorhanden */ { uart_putc(*s++); } } int main(void) { UBRRL = (bauddivider & 0x0ff); //set baud rate UBRRH = bauddivider>>8; UCSRA = 0; // no U2X, MPCM UCSRC = 3<<UCSZ0; // Frame format: 8N1 UCSRB = (1<<RXEN) | (1<<TXEN); while(1) { uart_puts("Hallo\r\n"); } return 0; } |
Datum:
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.
Datum:
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
Datum:
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 :-)
Datum:
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?
Datum:
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ß
Datum:
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.
Datum:
> void putchar( char c ) > { > while ( !(UCSRA & (1<<UDRE))) > UDR = c; > } immer noch falsch. Weiter habe ich nicht geschaut.
Datum:
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.
Datum:
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.
Datum:
Ändere in main.h und rc5.c
extern volatile uint rc5_data; // store result uint rc5_data; // store result |
in
extern volatile uint rc5_data; // store result volatile uint rc5_data; // store result |
Bei meinem uralten WinAVR beeinflusst das Weglassen des volatile die Funktion nicht. Modernere WinAVR sind da aber pingeliger.
Datum:
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?
Datum:
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.
Datum:
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.
Datum:
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???
Datum:
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 :)
Datum:
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
Datum:
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.
Datum:
Hallo Stefan, der Tipp war goldrichtig. Vielen Vielen Dank. Wie kann ich mich dafür bedanken? Gruß Jonanova
Datum:
Hast du doch schon. Mich freut es, wenn eine Rückmeldung kommt "es geht", nachdem man an einem Problem geknabbert hat.
Datum:
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
Datum:
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_Fun...
Datum:
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
Datum:
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.
Datum:
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.
Datum:
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?
Datum:
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" ...
Datum:
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 :)
#define WARTEZYKLEN 250 // 250 * ca. 2ms = ca. 500ms for(;;) { static uint timeout = 0; uint neues_kommando; cli(); neues_kommando = rc5_data; // read two bytes from interrupt ! rc5_data = 0; sei(); // Auswerten switch( neues_kommando ) { case 0: // Kein gültiger RC5 Code empfangen // wenn das WARTEZYKLEN-mal hintereinander passiert // wurde die Taste wohl losgelassen... if ( timeout == WARTEZYKLEN ) { // Alle Kommandos pauschal annulieren PORTB |= (1<<PB4) | (1<<PB5); puts("timeout == WARTEZYKLEN\r\n"); } else timeout += 1; break; case 15376: // Exklusiv betätigte Taste // d.h. ältere Kommandos annulieren PORTB |= 1<<PB5; // Kommando ausführen PORTB &= ~(1<<PB4); puts("LED PB4\r\n"); timeout = 0; break; case 13329: PORTB |= 1<<PB4; PORTB &= ~(1<<PB5); puts("LED PB5\r\n"); timeout = 0; break; default: // Sonstiger RC5 Code // Alle Kommandos pauschal annulieren PORTB |= (1<<PB4) | (1<<PB5); // RC5 Code anzeigen puts("RC5 = "); { char s[6]; utoa(neues_kommando, s, 10); puts(s); } puts("\r\n"); timeout = WARTEZYKLEN + 1; break; } } |
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):
case 15376:
case 12345:
// Rest wie oben
break;
case 13329:
case 54321:
// Rest wie oben
break;
|
Datum:
"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. ...
Datum:
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
Datum:
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?
Datum:
Ich habe zwar keine Ahnung von C, aber Itoa macht ASCII aus Integer, Integer TO Ascii... ;-) Man gut, dass es Assembler gibt... :-P ...
Datum:
Hannes Lux schrieb:
> Ich habe zwar keine Ahnung von C,
du lernst aber durch mitlesen.
Nicht mehr lange, und ich hab dich bekehrt :-)
Datum:
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
Datum:
@ 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.