Forum: Compiler & IDEs Problem Strings über USART zu senden


von Klaus (Gast)


Lesenswert?

Hallo,

ich glaube ich habe ein kleines c-Problem. Ich versuche einen String 
über USART1 vom Mega128 auszugeben. Ich habe zwei Prozeduren. Eine, um 
Zeichen zu senden, eine Andere um Strings zu senden.
Kurz gesagt: Die Prozedur usart1_sendByte() funktioniert, 
usart1_sendString() funktioniert nicht. Ich erhalte im Hyperterminal nur 
Leerzeichen.

Kann mir jemand einen Tip geben woran das liegen könnte?

Ich rufe die Prozeduren im hauptprogramm so auf:

usart1_sendByte('X');  <--- funktioniert
usart1_sendString("Willkommen"); <--- funktioniert nicht

Hier die beiden Prozeduren:

void usart1_sendByte(unsigned char data){
  //Warte bis Transmit Buffer leer ist
  while ( !( UCSR1A & (1<<UDRE1) ) );

  //Data in den Buffer schreiben (startet die Übertragung)
  UDR1 = data;
}

void usart1_sendString(unsigned char* data){
  //Alle zeichen nacheinander ausgeben
  while (*data++){
    //Warte bis Transmit Buffer leer ist
    while ( !( UCSR1A & (1<<UDRE1) ) );

    //Data in den Buffer schreiben (startet die Übertragung)
    UDR1 = *data;
  }
}

von Oryx (Gast)


Lesenswert?

Hallo Klaus,

ich hasse Konstruktionen wie
while (*data++){

weil ich mir die Reihenfolge der Abarbeitung einfach nicht merken kann.

teste doch mal
while (*data)
{
  //Warte bis Transmit Buffer leer ist
  while ( !( UCSR1A & (1<<UDRE1) ) );

  //Data in den Buffer schreiben (startet die Übertragung)
  UDR1 = *data;
  data++;
}

Wenn das läuft, kanst Du immer noch den vermeindlich kürzeren Code 
testen.

Oryx

von Klaus (Gast)


Lesenswert?

Hallo Oryx,

ich habe das schon längst getestet, auch die Variante mit Zähler und 
data[i]...

Aber ich habe es eben nochmal getestet. Ich habe deinen Vorschlag 
genommen und im Hauptprogramm folgendes geschrieben:

usart1_sendByte('K');
usart1_sendString("Willkommen");
usart1_sendByte('D');

Ich benutze UARTMonitor, um zu sehen was am PC ankommt:

4b ff ff ff ff ff ff ff ff ff ff ff ff 44

(K und D kommen fehlerfrei an!)

mich wundert es warum ich 12 Mal "ff" erhalte....

Wenn ich anstatt UDR1 = *data einfach mal UDR1='X' schreibe, dann 
erhalte ich 12 Mal "X". Das heisst prinziepiell funktioniert es, aber 
eventuell ist was mit "data" nicht in Ordnung. Vielleicht steht das 
"Willkommen" nicht im Speicher?

Für weitere Hinweise und Tips wäre ich dankbar.

Gruß,
 Klaus

von Klaus (Gast)


Lesenswert?

Jetzt wirds peinlich :-)

Ich habe den Fehler gefunden. nachdem ich im vorherigen Posting 
geschrieben habe, daß "Willkommen" evtl. nicht im Speicher steht, habe 
ich mal mein Makefile untersucht:

$(OBJCOPY) -j .text -j .datam -O ihex $(PRG) $(PRG)_flash.hex

Da stand ".datam" anstatt ".data". Daran hat es gelegen und jetzt geht 
es auch wie es soll.

Man, man. Wenn das so weiter geht, darf ich mich hier gar nicht mehr 
hertrauen ;-)

Danke nochmal für die Hilfe.

Gruß,
 Klaus

von Joerg Wunsch (Gast)


Lesenswert?

Nun, Dein erster Code hat einen kleinen Schönheitsfehler:

while (*data++)
{
   ... = *data;
}

Du inkrementierst den Pointer zu früh.  Du willst eher

while (*data)
{
   ... = *data++;
}

schreiben oder auch

while ((c = *data++))
{
   ... = c;
}

Für Dein 0xff-Problem: ich tippe darauf, daß Du Deinen m128
irgendwie über das COFF-File und AVR-Studio programmierst,
ja?  Don't do this.  Nimm lieber avrdude dafür.

Details zum Problem findest Du im README zum Betatest meines
avr-coff-patches, unter ``known issues'', ziemlich am Ende:

http://www.sax.de/~joerg/README.coff-avr-patch

von Joerg Wunsch (Gast)


Lesenswert?

Haben sich unsere Postings gekreuzt.  Klar, Du hast damit
ungewollt das Verhalten von AVR Studio simuliert. ;-)  Genau
dasselbe passiert nämlich dort auch (die Initialisierungswerte
von .data werden nicht in den ROM geladen).

von Klaus (Gast)


Lesenswert?

Hallo Joerg,

auch dir danke für deine Antwort. Du hattest Recht.
Das while(*data++) war falsch. Dadurch wurde das erste Zeichen 
weggelassen, aber dieser Fehler war schnell behoben :-)

Zum programmieren benutze ich übrigens schon avrdude. Nur, um die fuses 
zu setzen habe ich stk500.exe benutzt (bei avrdude kann man die nicht in 
der Kommandozeile übergeben, wenn ich das richtig verstanden habe)...

So, jetzt muß ich nur noch herausfinden warum Umlaute nicht richtig 
übertragen werden, dann habe ich es geschafft. Any ideas? (8 Bit-Modus 
ist an: UCSR1C = (3<<UCSZ10); )

Gruß,
 Klaus

von Christian Schifferle (Gast)


Lesenswert?

Hallo an alle

Ebenfalls eine elegante Lösung wäre:

for ( ;*data; data++) {
   while ( !( UCSR1A & (1<<UDRE1) ) );
   UDR1 = *data;
}

wobei ich persönlich direkte Zuweisungen an die Register scheusslich 
finde und selber auch vermeide.

Gruss
Christian

von Joerg Wunsch (Gast)


Lesenswert?

Bei avrdude kann man die Fusebits derzeit nur als Hex in der
Kommandozeile übergeben.  Symbolische Fusebits habe ich mir
gedanklich mal vorgenommen, wenn ich mal vieeel Zeit habe. ;-)
(Vielleicht macht's ja jemand anders vor mir.)

Wie kommen Deine Umlaute denn an?  Gleicher Zeichensatz auf
beiden Seiten?  Was ist, wenn Du sie im C-Programm mal in
hex codierst, '\xdf' wäre beispielsweise ein ß.

von Klaus (Gast)


Lesenswert?

Hi Joerg,

danke für deine Antwort.

kannst du mal an einem Beispiel zeigen, wie man die Fuses und Lockbits 
per Kommandozeile übergibt? Die Anleitung von Avrdude ist was das 
betrifft ziemlich lückenhaft. ich habe da nur ein Beispiel gefunden, wie 
man das im Terminalmodus macht.


Ich habe mal einen Test wegen den Umlauten gemacht:
1. usart1_sendByte(129);      -> kommt korrekt als ü an
2. usart1_sendByte('ü');      -> kommt als 0xfc an
3. usart1_sendByte('\129');   -> kommt als 0x39 an

Wieso kommen 2+3 falsch an?

Als Empfänger benutze ich Hyperterminal. habe schon Ansi, VT100 etc. 
eingestellt...kein Erfolg.

Gruß,
 Klaus

von Joerg Wunsch (Gast)


Lesenswert?

Aus der man page von avrdude:

           -f format
                   This option specifies the file format for the input 
or out-
                   put files to be processed.  Format can be one of:
...
                   m    immediate; actual byte values specified on the 
command
                        line, seperated by commas or spaces.  This is 
good for
                        programming fuse bytes without having to create 
a sin-
                        gle-byte file or enter terminal mode.

D. h. sowas wie

avrdude ... -f m -m lf -i 0x23

Eine Alternative ist

avrdude ... -m lf -I 0x23

(-I ist die Vereinigung von -i ... mit -f m)

Deine Umlautprobleme sind nur Verständnisprobleme und
Mismatch zwischen Zeichensätzen. ;-)

Zeichen 129 mag ein ü in der steinalten IBM Codepage 437 sein,
aber die nimmt praktisch keiner mehr.  Auch Windows ist seit
langem zu ISO 8859-1 (dort ,,ANSI'' genannt) gewechselt und
danach zu Unicode (für 16-bit Zeichensätze).  Dort ist ein ü
halt ein \xfc.

\129 ist oktal 129, also völlig korrekt \x39.

Wahrscheinlich mußt Du Dir was anderes als das blöde Hyperterminal
leisten.  Keine Ahnung, hab' kein Windows.  Unter Unix nehme
ich cu als ,,Terminal-Emulator'', das muß aber nicht wirklich
ein Terminal emulieren, sondern es bedient lediglich die
seriöse Schnittstelle -- es läuft ja schon selbst in einem
Terminal.  In diesem sind dann folglich die Zeichensätze, die
ich beim Editieren nehme und die zum Anzeigen der Daten die
gleichen.

von Klaus (Gast)


Lesenswert?

Hallo Joerg,

danke für deine Antwort.
Das mit den Umlauten ist mir aber noch nicht ganz klar.

Wenn ich vom Mega128 aus folgendes an meinen Pc sende

usart1_sendByte(129);

dann kommt das korrekt als ü an.
Wieso kommt das korrekt an? Wieso sehe ich im Hyperterminal unter 
Windows und auch unter anderen Programmen, wie zb UARTMonitor etc. das 
es ein "ü" ist (obwohl es ne Steinalte IBM Codepage 437 ist)?

Wenn ich aber vom Mega128 aus das versende:

usart1_sendByte('ü');

Dann empfange ich auf dem Windows Rechner 0xfc. Hyperterminal zeigt mir 
das aber nicht als "ü" an, sondern als ^3 (hochgestellte drei), obwohl 
das jetzt "Windows-kompatibel" sein soll?

Für mich ist hier eindeutig der avr-gcc "schuld", weil er aus 'ü' nicht 
eine 129 (dezimal) macht, sondern 0xfc.

Langer rede kurzer Sinn. Wie kann ich dem avr-gcc beibringen, daß er 
Strings wie "Menü" auch korrekt verschickt? Kann ich die verwendete 
Codepage irgendwo ändern?

Habe nur ich dieses Umlaut-Problem? ;-) Andere arbeiten doch auch unter 
Windows und dem Hyperterminal.

Gruß,
 Klaus

von Joerg Wunsch (Gast)


Lesenswert?

Offenbar benutzt Hyperterminal die CP437, der Rest von Windows
aber (insbesondere der Editor, mit dem Du das Zeichen in das
C-Programm eingibst) ISO 8859-1.  Dein Hyperterminal findet das
dann abartig, wenn das Zeichen gesendet wird.

Der avr-gcc baut exakt das in den Code ein, was Du ihm eingibst,
und der AVR gibt genau das über die UART aus.  Wenn Du in der
Eingabe (Editor) und Ausgabe (Hyperterminal) beides unterschiedlich
interpretierst, ist das ganz offenbar Deine Schuld. ;-)

von Klaus (Gast)


Lesenswert?

Ich dachte mir schon, daß ich irgendwie Schuld daran habe ;-)

Najut, dann muß ich mal kucken, wie ich dieses Problem löse (evtl. mit 
ein paar #defines für die Umlaute...)

Nette Seite: http://www.gymel.com/charsets/

Vielleicht finde ich ja im Netz einen "Codepage converter" :-)

Danke für deine Hilfe!

Gruß,
 Klaus

von Joerg Wunsch (Gast)


Lesenswert?

Der Codepage-Konverter heißt `recode' (GNU recode).

Ah ja, Eingabe von "gnu recode" bei Gugel bringt ihn sofort als
ersten Treffer...

% echo 'äöüÄÖÜß' | recode latin1..ibm437 | hd
00000000  84 94 81 8e 99 9a e1 0d  0a                       |......á..|
00000009

von Joerg Wunsch (Gast)


Lesenswert?

Achso, damit weißt Du natürlich nicht die ISO 8859-1 Werte:

% echo 'äöüÄÖÜß' | hd
00000000  e4 f6 fc c4 d6 dc df 0a                           |äöüÄÖÜß.|
00000008

Jetzt hast Du beides.  Wie Du siehst, impliziert recode bei
Angabe von ibm437 auch, daß dort \r\n als Zeilentrenner benutzt
wird.

von Klaus (Gast)


Lesenswert?

Nochmal vielen Dank für deine Antowrt.

Hab "recode" und "hd" sogar für meinen Windows-Rechner gefunden!

Gruß,
 Klaus

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.