Forum: Mikrocontroller und Digitale Elektronik STM32 scanf/printf verschluckt erste gesendete Ziffer


von Ratlos (Gast)


Lesenswert?

Hi,

ich bin gerade dabei einen USART von meinem STM32 als 
Debug-Schnittstelle in Betrieb zu nehmen. Kann eigentlich keine große 
Sache sein, aber irgendwie stehe ich auf dem Schlauch und weiß nicht 
mehr weiter. Die printf-Ausgaben laufen auch schon wunderbar, nur 
scheint es noch Probleme mit dem Einlesen bzw. mit der anschließenden 
Ausgabe zu geben. Ich gebe nach einer printf-Anweisung testweise eine 
Zahl mit Hyperterminal oder Putty ein (scanf Aufruf) und speicher diese 
in einer Variablen. Der Inhalt wird wieder mittels printf ausgegeben. 
Jedoch wird dabei die erste eingegebene Ziffer verschluckt. Beim 
Debuggen habe ich festgestellt, dass die Variable die erste Ziffer nicht 
enthält. Von fputc wird die Ziffer jedoch empfangen!
1
int fgetc(FILE *f)
2
{
3
  while(!(USART2->SR & USART_FLAG_RXNE));
4
  return((int)(USART2->DR & 0x01FF)); 
5
}
6
7
int fputc(int iChar, FILE *f)
8
{
9
  while(!(USART2->SR & USART_FLAG_RXNE));
10
  return((int)(USART2->DR & 0x01FF));
11
}
12
13
{
14
  int iNumb = 0;
15
16
  scanf("%d", &iNumb);
17
  printf("Zahl %d \r\n", iNumb);
18
}

von (prx) A. K. (prx)


Lesenswert?

fputc sieht fgetc erstaunlich ähnlich.

von Ratlos (Gast)


Lesenswert?

Achso ich nutze die IAR Workbench (Kickstart) mit der eingebauten CMSIS 
und der STM32 Std. Library 3.5

von Ratlos (Gast)


Lesenswert?

Ups ;)
1
int fputc(int iChar)
2
{
3
  while(!(USART2->SR & USART_FLAG_TXE));
4
  USART2->DR = (iChar & 0x01FF);
5
  return iChar
6
}

von Ratlos (Gast)


Lesenswert?

Wenn ich die interne Ausgabe im IAR über ST-Link SWO/ITM nutze funzts 
ohne Probleme, also muss es was mit meinen Funktionen zu tun haben...

von Arne (Gast)


Lesenswert?

Du nutzt das IAR interne Terminal I/O? Vorsicht, das hält dir 
streckenweise den µC an und zerwürfelt das Timing kolossal. Wir nehmen 
es nicht mehr, weil das Voodoo Zeugs Seiteneffekte produziert, die man 
erstmal nicht mit dem Terminal I/O in Verbindung bringt.

von Ratlos (Gast)


Lesenswert?

Ich habe es einfach mal testweise aktiviert, mir war das ganze auch 
nicht geheuer. Trotzdem bleibt das Problem, dass meine Funktionen 
irgendwie eine Ziffer verschlucken. Beispiel:

Eingabe: "Geben Sie eine Zahl ein: " 1234
Ausgabe: "Zahl: 234" <- tja wo ist die 1 ? fgetc hat sie erhalten.

Ich werde nochmal nach Arnes Hinweise die ganzen ITM Sachen 
deaktivieren...

von Arne (Gast)


Lesenswert?

Bist Du Dir sicher, dass DEINE fputc() aufgerufen wird und nicht 
irgendeine aus einer IAR Lib? Setz mal einen Breakpoint auf das Befüllen 
des USART2->DR und schließe ein Terminalprg an. Wenn Du dann eine Zeile 
drüberstepst muss das Zeichen im Terminalprg. angekommen sein.
BTW: nutzt Du USB<->RS232 Wandler am PC?

von Ratlos (Gast)


Lesenswert?

Hmm, also reingesprungen wird auf jeden Fall in beide Funktionen (fputc, 
fgetc). Beim Weitersteppen kann ich bei meiner fputc auch sehen, dass 
sich das DR ändert (mit der entsprechenden Ziffer befüllt), so konnte 
ich auch feststellen, dass alle im Terminal eingegeben Zeichen wirklich 
empfangen werden (zumindest von fgetc). Bei der fputc kann ich jedoch 
keine Änderung des DR sehen, es bleibt auf 0x00. Trotzdem erscheint im 
Terminalprogramm (putty) das entsprechende Zeichen (wird auch richtig 
übergeben). Das hört sich komisch an. Es ist aber auf jeden Fall so, 
dass die erste Ziffer gar nicht in meiner Variablen ankommt, da habe ich 
auch schon nachgeschaut.

Nutze ein Olimex STM32-P103 (ti max3232c ist auf dem Board) ohne 
USB-RS232 Wandler, der PC hat einen COM-Port (und der hängt an einem 
Q57 Express Chipset LPC Interface Controller - 3B0A).

von ttl (Gast)


Lesenswert?

eine blockierend Funktion zum Debuggen? Das ist nicht dein Ernst! Da 
steht das Programm bis sich die Bytes durch den UART gequetscht haben.

von Ratlos (Gast)


Lesenswert?

Und wie würdest du dann machen, also ich komme so nicht weiter...

von Arne (Gast)


Lesenswert?

Dass beim Senden 0 im TransmitRegister steht ist klar - der UART schiebt 
es gleich ins Schieberegister.
> Trotzdem erscheint im Terminalprogramm (putty) das entsprechende Zeichen
> (wird auch richtig übergeben). Das hört sich komisch an. Es ist aber auf
> jeden Fall so, dass die erste Ziffer gar nicht in meiner Variablen
> ankommt, da habe ich auch schon nachgeschaut.
Ähhh... wie jetzt? Kommt alles an oder doch nicht? Welche Variable 
(iChar)?

Du nimmst Teile aus einer Lib (printf), die dann sukzessive Dein fputc() 
aufruft?
Oder andersrum: Du hast Teile drin, die Du nicht kontrollieren kannst.
Warum schreibst Du nicht erstmal den String mit sprintf/snprintf in 
einen Puffer und haust den dann byteweise mit fputc() raus?

von Ratlos (Gast)


Lesenswert?

So, dass das DR beim Senden 0 ist, ist mir dann auch gekommen.
Ich nutze in meiner main() die printf. Diese ruft dann meine überladene 
fputc auf und schreibt dann auf den USART. Wenn ich eine Abfrage mit 
scanf mache erhält meine fgetc zwar alle eingegeben Zeichen, leitet 
diese wohl aber nicht richtig/vollständig an scanf weiter. Die erste 
eingegeben Ziffer einer Zahl wird nicht der Variablen (iNumb) 
gespeichert:

int iNumb=0;
scanf("%d", &iNumb);   // Bspw. Eingabe von 1234
printf("Zahl %d \r\n", iNumb); // Ausgabe nur noch 234

Die Lösung mit sprintf/snprintf hört sich auch interessant werde ich 
jetzt mal ausprobieren. Thx

von Ratlos (Gast)


Lesenswert?

Also es scheint so als ob ich ein Problem mit scanf habe. Mit meiner 
eigenen Funktion zur Ein- und Ausgabe funktioniert es offenbar. Ich kann 
auch einen empfangenen String mit printf wieder rausschicken ohne 
verlorene Zeichen. Wäre trotzdem interessant woran das liegen könnte... 
Etwas praktikabler wäre es auch noch mit scanf.

von Arne (Gast)


Lesenswert?

> Also es scheint so als ob ich ein Problem mit scanf habe.
Bytes in Puffer empfangen.
Wenn fertig, dann mit sscanf() parsen.
Das sind GRUNDLAGEN! Nur mal so am Rande!

von Ratlos (Gast)


Lesenswert?

Arne schrieb:
> Bytes in Puffer empfangen.
> Wenn fertig, dann mit sscanf() parsen.
> Das sind GRUNDLAGEN! Nur mal so am Rande!

Und diese Geschichte mit sscanf wollte ich mir ersparen. Ich wollte eher 
das Problem lösen (warum mir ein Zeichen verloren geht), anstelle einen 
zusätzlichen Workaround zu basteln.

von Ratlos (Gast)


Lesenswert?

So ich denke ich habe eine Lösung für das Problem gefunden. Die IAR 
Workbench 6.21 kann zwei Versionen der C-Libs nutzen (CLib und DLib). Je 
nachdem welche Version man einsetzt müssen unterschiedliche Routinen 
überschrieben werden! Habe online zu den Libs das hier gefunden:

● The IAR DLIB Library, which supports ISO/ANSI C and C++. This library 
also supports floating-point numbers in IEEE 754 format and it can be 
configured to include different levels of support for locale, file 
descriptors, multibytes, et cetera.
● The IAR CLIB Library is a light-weight library, which is not fully 
compliant with ISO/ANSI C. Neither does it fully support floating-point 
numbers in IEEE 754 format or does it support Embedded C++. (This 
library is used by default).

Quelle: 
http://supp.iar.com/FilesPublic/UPDINFO/004350/EWM32C_CompilerReferenceAddendum.pdf

Leider findet man in der Workbench selber und in den dort enthaltenen 
Dokumenten kaum Infos über DLib/Clib deshalb dieses etwas ältere pdf.

Und nun zum interessanten Teil:
Migration from CLIB to DLIB
There are some considerations to have in mind if you want to migrate 
from the CLIB
library, the legacy C library, to the modern DLIB C/C++ library:
● The CLIB exp10() function defined in iccext.h is not available in 
DLIB.
● The DLIB library uses the low-level I/O routines __write and __read 
instead of putchar and getchar.
● If the heap size in your old compiler version using CLIB was defined 
in a file named heap.c, you must now set the heap size either in the 
extended linker command file (*.xcl) or in the Embedded Workbench to use 
the DLIB library.

Da ich die DLib nutze (eine Wechselmöglichkeit zu CLib konnte ich 
übrigens nicht finden), muss ich __write und __read überschreiben. Dort 
habe ich nun meine USART-Routinen eingefügt und es funktioniert ohne 
Probleme.

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.