Forum: Mikrocontroller und Digitale Elektronik Zeichen fehlerhaft über RS232 an/von ATmega16


von Tom (Gast)


Lesenswert?

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

von Björn W. (bwieck)


Lesenswert?

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

von Tom (Gast)


Lesenswert?

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

von Johannes M. (johnny-m)


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

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.

von Michael Wilhelm (Gast)


Lesenswert?

externer Quarz oder interner RC-Oszillator?

MW

von Björn W. (bwieck)


Lesenswert?

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

von Tom (Gast)


Lesenswert?

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

von Michael Wilhelm (Gast)


Lesenswert?

Der interne Oszillator ist sehr Temperatur- und 
Betriebsspannungsabhängig. Externer Baudratenquarz wird dein Problem 
lösen.

MW

von Björn W. (bwieck)


Lesenswert?

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...

von Johannes M. (johnny-m)


Lesenswert?

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.

von Tom (Gast)


Lesenswert?

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

von Johannes M. (johnny-m)


Lesenswert?

> 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?

von Tom (Gast)


Lesenswert?

@Johannes M.

Das sollt natürlich keine Provokation darstellen. Dies wurde mir 
empfohlen, um das Programm für andere Compiler lesbar zu machen....

von Johannes M. (johnny-m)


Lesenswert?

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%...

von Johannes M. (johnny-m)


Lesenswert?

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.

von mik (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Andreas K. (a-k)


Lesenswert?

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.

von Björn W. (bwieck)


Lesenswert?

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

von Johannes M. (johnny-m)


Lesenswert?

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.

von Björn W. (bwieck)


Lesenswert?

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
Noch kein Account? Hier anmelden.