Hallo Spezialisten, ich hoffe auf Hilfe von Euch bei folgendem Problem: Ich habe ein kleines Programm auf dem ATmega16 über welches die Tasten der Tastatur des angeschlossenen Rechners eingelesen werden und über "Echo" sofort wieder an das Windows Hyperterminal gesendet und angezeigt werden. Nun habe ich das Problem, dass bei vielen Tasten nicht das aufgedruckte Zeichen gesendet/empfangen wird, sondern willkürliche. Jedoch reproduzierbar immer das gleiche. Weiter tritt der Fehler auf, dass ca. jeder zehnter Tastendruck nicht das gewünschte Zeichen liefert. Z. B.: aaaaaaaaajaaaaaaa. Habe ich einen grundsätzlichen Denkfehler im System bzgl. ASCII-Code o. ä.? Gruß Tom
Tom wrote: > Hallo Spezialisten, > Nun habe ich das Problem, dass bei vielen Tasten nicht das aufgedruckte > Zeichen gesendet/empfangen wird, sondern willkürliche. Jedoch > reproduzierbar immer das gleiche. Weiter tritt der Fehler auf, dass ca. > jeder zehnter Tastendruck nicht das gewünschte Zeichen liefert. Z. B.: > aaaaaaaaajaaaaaaa. > > Habe ich einen grundsätzlichen Denkfehler im System bzgl. ASCII-Code o. Welcher Takt? Welche Baudrate? Welche einstellungen in Hyperterm? Welcher Code? so viele Fragen... Grüße Björn
Sorry hatte ich vergessen anzufügen:
Initialisierung von USART stimmt. Das hab ich natürlich
(achthunderdsiebzigmal) überprüft.
>>Welcher Code?
Hier war nur meine Frage, ob ich evtl. den ASCII-Code o. ä. falsch
interpretiert habe.
Danke
Tom wrote: >>>Welcher Code? > Hier war nur meine Frage, ob ich evtl. den ASCII-Code o. ä. falsch > interpretiert habe. Woher sollen wir das bitteschön wissen, ohne Deinen *PROGRAMM*-Code?
Tom wrote: >>>Welcher Code? > Hier war nur meine Frage, ob ich evtl. den ASCII-Code o. ä. falsch > interpretiert habe. Kann keiner wissen, du zeigst ja keinen Code. Aber: Wie ist das zu interpretieren: dass bei vielen Tasten nicht das aufgedruckte Zeichen gesendet/empfangen wird Heist das du legst den Finger auf die Taste und lässt ihn dort. D.h. die Zeichen werden in schneller Folge gesendet. Oder drückst du jedesmal die Taste erneut? Erhöhe mal die Anzahl der Stoppbits auf 2. Dadurch verschaffst du der jeweiligen Gegenstelle etwas mehr Zeit ein Zeichen zu verarbeiten.
Tom wrote: > Sorry hatte ich vergessen anzufügen: > > Initialisierung von USART stimmt. Das hab ich natürlich > (achthunderdsiebzigmal) überprüft. > >>>Welcher Code? > Hier war nur meine Frage, ob ich evtl. den ASCII-Code o. ä. falsch > interpretiert habe. Wenn Du genau das wieder zurückschickst was reinkommt dann gibt es da nichts zu interpretieren. Ich tippe mal auf ungünstigen Takt in verbindung mit der Baudrate.. Grüße Björn
Vielen Dank für die tolle Resonanz. Anbei der Code: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + #include <avr/io.h> //Deklarationen #include <avr/interrupt.h> //für Interrupt #define TAKT 4000000UL //Controllertakt 4MHz #define PRESET 40000UL //Taktteiler für Vorteiler #define BAUD 9600UL //Baudrate //Festlegung unabhängiger Typennamen: typedef unsigned int uint16; typedef signed int sint16; typedef unsigned short uint8; typedef signed short sint8; //Prototypen von Funktionen void initusart (void); void putch (uint8); uint8 getch (void); uint8 getche (void); uint8 kbhit (void); //globale Variablen uint8 got_cha; //Zeichen vom Kontroll-Rechner (MatLab; LabView) SIGNAL(SIG_UART_RECV) //Servicefunktion für Empfängerinterrupt { getche(); PORTB = got_cha; } int main (void) { DDRB=0xff; PORTB = 0; initusart(); UCSRB |= (1<<RXCIE); sei(); putch('>'); while(1) { } return 0; } /* ********** Nachfolgend Funktionen für USART-Kommunikation ********** */ //USART bzw. UART initialisieren void initusart (void) { uint8 x; //lokale Hilfsvariable #ifdef UBRRL //USART-Schnittstelle UBRRL = (TAKT / (16ul * BAUD)) - 1; //Baudrate mit TAKT und BAUD UCSRB |= (1<<TXEN) | (1<<RXEN); //Sender und Empränger ein UCSRC |= (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0) | (1<<USBS) | (1<<UPM1); //async 8bit #else UBRR = (TAKT / (16ul * BAUD)) - 1; //Baudrate UCR |= (1<<TXEN) | (1<<RXEN); //Sender und Empfänger ein #endif x = UDR; //Empfänger leeren } //warten und Zeichen senden void putch (uint8 x) { #ifdef UCSRA //USART while (!(UCSRA & (1<<UDRE))); //warte, solange Sender besetzt #else //UART while (!(USR & (1<<UDRE))); //warte, solange Sender besetzt #endif UDR = x; //Zeichen nach Sender } //warten und Zeichen abholen uint8 getch (void) { #ifdef UCSRA //USART while (!(UCSRA & (1<<RXC))); //warte, bis Zeichen da #else //UART while (!(USR & (1<<RXC))); //warte, bis Zeichen da #endif return UDR; //Zeichen abholen } //warten und Zeichen abholen mit Echo uint8 getche (void) { //Hilfsvariable #ifdef UCSRA //USART while (!(UCSRA & (1<<RXC))); //warte, bis Zeichen da got_cha = UDR; //abholen und speichern while (!(UCSRA & (1<<UDRE))); //warte, solange Sender besetzt #else //UART while (!(UCSRA & (1<<RXC))); //warte, bis Zeichen da got_cha = UDR; //abholen und speichern while (!(UCSRA & (1<<UDRE))); //warte, solange Sender besetzt #endif UDR = got_cha; //Echo senden return got_cha; //Zeichen zurückgeben } //Empfänger testen uint8 kbhit (void) { #ifdef UCSRA //USART if (UCSRA & (1<<RXC)) return UDR; else return 0; #else //UART if (USR & (1<<RXC)) return UDR; else return 0; #endif } ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++ @Michael Wilhelm interner RC (4MHz) @Karl heinz Buchegger bei beiden Versionen. D. h. egal, ob ich die Taste wieder loslasse, oder draufbleibe
Der interne Oszillator ist sehr Temperatur- und Betriebsspannungsabhängig. Externer Baudratenquarz wird dein Problem lösen. MW
Michael Wilhelm wrote: > Der interne Oszillator ist sehr Temperatur- und > Betriebsspannungsabhängig. Externer Baudratenquarz wird dein Problem > lösen. > > MW Mein reden... mit Baudrate 4800 könnte es eventuell gerade so gehen...
Wenn der RxC-Interrupt auftritt, dann wurde bereits ein Zeichen empfangen! Der Aufruf der Funktion getche in der ISR ist völliger Murks. Bitte schau Dir im AVR-GCC-Tutorial die entsprechenden Abschnitte an. Da steht wie's geht.
Heist das, dass ich einen externen Quarz einbaue? Welche einstellungen muss ich dann vornehmen? Bitte entschuldigt die dumme Fragerei, ich bin noch ein wenig unerfahren, was Fuses usw. betrifft. Übrigens: Ich verwende STK500 und AVRStudio 4.13
> typedef unsigned int uint16; > typedef signed int sint16; > typedef unsigned short uint8; > typedef signed short sint8; In der Headerdatei stdint.h sind bereits Typen mit Längenangabe definiert. Warum muss da jeder seinen eigenen Mist definieren?
@Johannes M. Das sollt natürlich keine Provokation darstellen. Dies wurde mir empfohlen, um das Programm für andere Compiler lesbar zu machen....
Björn Wieck wrote: > Mein reden... > > mit Baudrate 4800 könnte es eventuell gerade so gehen... Der Fehler ist relativ und tritt, wenn vorhanden, dann bei jeder Baudrate auf, die sich mit gleichem Grundfehler einstellen lässt. Und bei 4 MHz CPU-Takt ist es wurscht, ob man 9600 oder 4800 Baud nimmt, haben beide 0,2%...
Tom wrote: > Das sollt natürlich keine Provokation darstellen. Dies wurde mir > empfohlen, um das Programm für andere Compiler lesbar zu machen.... Hab ja auch nicht von einer Provokation geredet. Und die stdint.h ist Bestandteil von C und kann deshalb auch von jedem C-Compiler verarbeitet werden.
ich find das so lustig, wie sehr da immer die rede von internem Osci und UART ist. Ich hab in meinen Computer (mal esikalt, mal sehr warm) eine LedMatrix eingebaut, die wird von einem Atmega16 (osci intern 8Mhz) gesteuert, welcher über FTDI-USB mit dem computer redet. Solange die Baudrate nicht höher als 14400 ist, gibt es mit 1 stopbit keine probleme. schon seit monaten. lg mik
Der springende Punkt ist: Das sind deine Erfahrungen. Andere haben andere Erfahrungen. Hängt auch davon ab, welchen AVR du konkret benutzt. Unterschiedlich AVR haben unterschiedliche RC-Oszillatoren implementiert, die unterschiedliche Temperaturabhängigkeiten haben. interner Oszi + UART kann funktionieren, muss aber nicht.
Vorausetzung für den internen Oszillator ist zunächst, dass man den Kalibrierungswert verwendet. Die AVRs haben dafür eine etwas eigenwillige Methode, denn der Oszillator ist von Haus aus unkalibriert und es muss ein auf dem Umweg über den Programmer aus einem speziellen dem Controller selbst nicht zugänglichen Bereich entnommener Kalibrierwert in OSCAL reingeschrieben werden. Ein Zirkus, der bei anderen µC-Familien mit leidlich genauem internem Oszillator nicht erforderlich ist. Die Chancen auf leidlich verwendbare UART stehen dann bedeutend besser. Aber trotzdem sollte man das dann allenfalls für Testzwecke so machen, beispielsweise bei einem Debug-Ausgang. Nicht für produktiv verwendet Schnittstellen.
Karl heinz Buchegger wrote: > > interner Oszi + UART kann funktionieren, muss aber nicht. So wie bei mir. 2 MHz interner OSC: 9600 und drüber geht nicht, kommt nur Müll. 4800 und drunter geht. Für ein paar Debuginformationen ist das noch zu verkraften aber eine ernsthafte Kommunikation würde ich mit dem internen RC nicht machen wollen. Grüße Björn
Björn Wieck wrote: > So wie bei mir. 2 MHz interner OSC: > 9600 und drüber geht nicht, kommt nur Müll. > 4800 und drunter geht. Wundert mich, dass die 9600 auch schon nicht laufen, wenn 2400 und 4800 gehen (sind schließlich alle mit 0,2% Grundabweichung machbar)... Dass die Raten über 9600 Bd allesamt mit 2 MHz nicht gehen, kann man allerdings dem Datenblatt entnehmen.
Johannes M. wrote: > Wundert mich, dass die 9600 auch schon nicht laufen, wenn 2400 und 4800 > gehen (sind schließlich alle mit 0,2% Grundabweichung machbar)... Dass > die Raten über 9600 Bd allesamt mit 2 MHz nicht gehen, kann man > allerdings dem Datenblatt entnehmen. Ist auch nur eine Erfahrung die ich mal gemacht habe. Vielleicht ist ja auch der PC der daranhängt besonders gutmütig oder so. Die Übertragung mit 4800 ist ja auch nicht immer fehlerfrei gewesen aber für Debug hats gelangt. Die meisten meiner µC Anwendungen sind eh zeitunkritisch so das ich oft den internen RC nehme. Aber wie ich schon sagte: RC Oszillator und UART ist Pfui wenns zuverlässig sein soll. Grüße Björn
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.