printf重定向介绍
/ l. }' R2 ^1 p! `4 ]3 N5 u在学C语言的时候,会经常用标准库<stdio.h>中printf(), scanf()这两个函数, 来实现数据的输入与输出. 格式化输入输出的功能还是挺强大的, 那已经有了现成的轮子, 就要寻思一下如何进一步在单片机上使用它.
+ v% f+ Z6 R/ Z下面是ARM Compiler6文档中对printf的介绍:
: z, X% W# \* O. p6 G: ^: E+ I. r) [9 _" _$ ~
The printf family consists of _printf(), printf(), _fprintf(), fprintf(), vprintf(), and vfprintf().4 ^4 ^) z2 Y; a% v4 N' w* a
All these functions use __FILE opaquely and depend only on the functions fputc() and ferror(). The functions _printf() and _fprintf() are identical to printf() and fprintf() except that they cannot format floating-point values.' r9 C$ ^+ E8 e9 T
The standard output functions of the form _printf(…) are equivalent to:/ a$ Q2 p$ _( V+ _9 w# t
fprintf(& __stdout, …)where __stdout has type __FILE.
( m W4 {4 _3 _% g! P; y+ c z
% h2 o' r" Y& k0 r大致是说printf家族有这么些函数<_printf(), printf(), _fprintf(), fprintf(), vprintf(), and vfprintf()>, 这些函数都隐式的使用__FILE<文件流>, 并且只依靠fputc(), ferror()这两个函数.2 z% P1 e1 N" w# x
f7 i# H) P+ F$ A7 Y
If you define your own version of __FILE, your own fputc() and ferror() functions, and the __stdout object, you can use all of the printf() family, fwrite(), fputs(), puts() and the C++ object std::cout unchanged from the library.1 _: |- y6 W w, L5 g7 G5 W
9 V" R6 p( K, K# e) C! U
重新定义__FILE, fputc(), ferror(), __stdout, 就可以使用printf()家族的各种函数了.3 g9 ^2 H f5 {6 i) ~/ r2 `! [1 E
% q- I' O, c* Q- |. y
STM32中printf重定向' b; `( P% o) r: r" L0 [
下面是官方给出的重映射模板:
4 {. R" m* x7 y) \" F9 Y/ a# Y<遇到不会的先看看文档往往能得到最直接的答案>
. ?" E8 I. M2 o, }0 m% v/ W8 |: S$ J# X7 c1 @6 X. _3 p0 p
- #include <stdio.h>
" k* A0 _2 R; x# r( a - struct __FILE6 x1 J2 @+ y% p
- {
" `" }2 c- Z- A4 T# f$ f- e+ l - int handle;$ c5 w' C: [1 ^" M2 q
- /* Whatever you require here. If the only file you are using is */
; R& j: H, d/ z5 T! c6 A! Y: N. n - /* standard output using printf() for debugging, no file handling */0 h; o1 e* B( j& |
- /* is required. */6 |6 Y8 O6 Q7 {: U- S
- };3 d4 { S' I& U9 C
- /* FILE is typedef’d in stdio.h. */5 J2 b- k ~ }
- FILE __stdout;% w# t1 |' Z! W7 d4 u8 k2 v! b
- int fputc(int ch, FILE *f)
0 N. r# [* _: I- G; E - {
8 B: x; i" w0 R - /* Your implementation of fputc(). */2 q1 I9 V( ~4 E/ @/ d$ Q
- return ch;4 |$ @) \* }9 k# q2 ^! V5 a
- } \3 c5 \/ s8 Z7 Y1 N/ E7 |
- int ferror(FILE *f)" t$ Y% `- Q. w+ W0 z# o
- {
. J" D+ \9 n& ~% O) K- e - /* Your implementation of ferror(). */1 n1 D( |' K0 y/ h7 u& A
- return 0;' e# N7 c: I- d, L+ |
- }
复制代码
X- ~7 r3 E" Z$ U N v要将printf()重定向到STM32中的串口, 只需要重新实现 fputc() 函数即可, 在fputc()中通过串口发送一个char. 在上一次的工程上进行修改, 将printf()重定向到串口3.* P* c. @ q2 ~) j; a- g
9 D& L0 L( X X0 ?; e0 o& r# A
- #include <stdio.h>
5 @9 A9 {+ |% m7 V/ i \4 O1 ]8 y: G - struct __FILE; ^& t# o7 I1 B' T) G( i
- {
3 L" M! y; A! s) W @' l - int handle;# C6 R! e2 E, n
- /* Whatever you require here. If the only file you are using is */0 H/ `/ p' p# z8 K; r- g2 m( {1 \
- /* standard output using printf() for debugging, no file handling */0 d5 {' r6 ~& L8 K9 t* U
- /* is required. */4 s2 v! l. K" R6 i3 n
- };7 S% ^* m+ l% T
- /* FILE is typedef’d in stdio.h. */
1 r6 v3 d- ^9 y- X1 H3 B - FILE __stdout;1 R7 V+ Y9 o2 S4 ]
- int fputc(int ch, FILE *f) : ], G( W$ x% Q
- {
4 ]! H; x/ l0 U, l$ t3 K' E - /* Your implementation of fputc(). */" \- ~* b: p; s
- HAL_UART_Transmit( &huart3, ( uint8_t* )&ch, 1, 0xFFFF );6 w. R% G& U5 n7 h* d! V2 U2 b
- return ch;" f7 N- d. q: l8 Y2 B; U
- }
2 v0 f& Z" q | B - int ferror(FILE *f)) ^- v% e% y7 E r- Q0 R7 m
- {
7 x3 Q- m ]8 R4 S9 b - /* Your implementation of ferror(). */
: @4 ]! d3 M( y+ L4 @+ I/ e' u - HAL_UART_Transmit( &huart3, ( uint8_t* )"Printf Error\n", 13, 0xFFFF );// 可选
# ]1 ]% u) N! g; ~ - return 0;4 [$ f( _! ^! Y9 W2 Y$ [
- }
复制代码 5 i2 j- @4 |$ R( o8 j, Z6 p
写个简单的程序试一试:& B& W$ ?3 Q4 u' c0 |& k+ j) K
0 f6 r( I5 r' t6 q- int main(void)
$ G. e |* E" U - {
5 X, I" M" z R. r H9 c% o - MPU_Config();3 Y% q) g8 z* `% A) {
- SCB_EnableICache();
" T& p7 z$ u* ^' k) v7 c - SCB_EnableDCache();
- [: a* P' B+ _8 \" i4 g! m# x( k - HAL_Init();
`8 I/ S. Q! j7 E( H6 @0 d: ~ - SystemClock_Config();' Q0 ?6 u7 d5 E- J( M$ Y
- MX_GPIO_Init();* q6 S- n* A; l. i, W8 Q8 Y
- MX_ETH_Init();
$ \0 j, `6 i! y; h, R8 P1 S - MX_USART3_UART_Init();& P$ h$ `: v6 K
- /* USER CODE BEGIN 2 */
& k0 O) V8 T Q& B8 E - double d = 1.234;
6 A c9 b5 A5 ]9 R+ w - int i = 60;
; }' I2 L& k6 [* _ - char str[] = "Do not be lazy.\n";
C3 ?" a9 I4 ?' x' `8 ~! U' [" B - printf("Hello World\n");
3 w0 k) L1 z, g" R. A+ a - printf("d = %lf\ni = %d\n", d, i);$ I, _( O+ r2 d
- printf("this is a string : %s", str);
0 U: i" n' B) V, {% W7 W& B
8 z2 A" ~! v! g9 b1 m+ y: D- while (1){}' g+ O: i6 l3 B% ~
- }
复制代码 1 E' q- `- b+ b- t
输出结果:: f1 e c& T- h' Z- w/ L# X, q
5 |* u4 b- |+ w9 B/ o8 } y; }. }" } p' c6 [( s; o% ?
可以开始愉快的使用printf()了.
& w/ ~$ ?1 r, O/ N. x- i7 k
( K4 N1 I1 B6 m4 K4 r$ _" W! _- `* [- t. [8 \' \' i
8 s4 b! V# M, u( _ |