Forum: Mikrocontroller und Digitale Elektronik fprintf ohne stdio?


von Bauform B. (bauformb)


Lesenswert?

Servus!

mal angenommen, man meint -ffreestanding ernst, es gibt keine libc und 
selbst "Simply the best printf around the net"¹ ist noch zu fett. Ein 
kleines printf(), z.B. aus einem alten ChibiOS, gönnt man sich trotzdem.

So ein printf() kann seine Ausgabe ungepuffert über ein extrem einfaches 
putchar() machen. Für ein UART reichen 2 Zeilen. Für ein LCD mit HD44780 
braucht es kaum mehr. Alles trivial, solange es nur UART oder LCD 
gibt.

Damit man so ein printf() für UART und LCD nutzen kann, baut man 
einfach ein putchar(), das seinerseits über einen Pointer entweder 
uart_put() oder lcd_put() aufruft. Im Unterschied zu fprintf() und 
fputc() muss man nicht überall den FILE Pointer mitgeben. Stattdessen 
braucht man eine Funktion, mit der man zwischen den Ausgabekanälen 
umschalten kann. Also ungefähr etwas wie freopen() für stdout, nur 
einfacher, weil es kein close() und open() gibt (geben soll).

Natürlich nimmt man für größere uC stdio, aber für kleinere scheint mir 
diese Lösung geradezu elegant zu sein (mal abgesehen von einem besseren 
Namen statt reopen). Andererseits finde ich praktisch nur Beiträge, die 
entweder mit "nimm stdio" oder mit sprintf() enden. Wo ist der Fehler?
1
// putchar.h
2
typedef int putchar_ptr (int);
3
int putchar (int c);
4
int uart2_put (int c);
5
int lcd_put (int c);
6
7
// putchar.c
8
static putchar_ptr  *do_putchar = uart2_put;
9
10
void
11
reopen (putchar_ptr *fun)
12
{
13
   do_putchar = fun;
14
   return;
15
}
16
17
int
18
putchar (int c)
19
{
20
   assert (do_putchar != NULL);
21
   if (c == '\n' && no_nlcr == 0) {
22
      do_putchar ('\r');
23
   }
24
   return do_putchar (c);
25
}
1) https://github.com/mpaland/printf

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?


von Bauform B. (bauformb)


Lesenswert?

Ja, danke, aber? Das ist doch auch eine Standard-libc, also eine Lösung 
mit FILE *; genau das wollte ich doch vermeiden.

von foobar (Gast)


Lesenswert?

> also eine Lösung mit FILE *; genau das wollte ich doch vermeiden.

Hast du dir das Beispiel mal angeschaut?
1
static int
2
myputchar(char c, FILE *stream)
3
{
4
  if (c == '\n')
5
    do_putchar('\r');
6
  do_putchar(c);
7
  return 0;
8
}
9
10
static FILE uart = FDEV_SETUP_STREAM(myputchar, NULL, _FDEV_SETUP_WRITE);
11
12
int
13
main(void)
14
{
15
  ... init ...
16
  stdout = &uart;  // dein reopen
17
  printf("Hello, world!\n");
18
19
  return 0;
20
}

Im avr-libc ist das FILE-Handling extrem mager - ein FILE ist nur ein 
paar Bytes größer als dein vergleichbarer putchar_ptr.

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.