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