printf重定向介绍& _3 P7 O( J, F- l3 u# f
在学C语言的时候,会经常用标准库<stdio.h>中printf(), scanf()这两个函数, 来实现数据的输入与输出. 格式化输入输出的功能还是挺强大的, 那已经有了现成的轮子, 就要寻思一下如何进一步在单片机上使用它.
* }: _4 T: ]: w! W/ ~ K$ Y下面是ARM Compiler6文档中对printf的介绍:! ~0 q( b4 W% Y4 ~( k* d
7 C% ]- Z& F8 B) q, b% F) i
The printf family consists of _printf(), printf(), _fprintf(), fprintf(), vprintf(), and vfprintf().
" m- i+ Z" M3 i" U( ^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.
1 D4 {! N N I! y7 \: VThe standard output functions of the form _printf(…) are equivalent to:
. z, T5 y( R! N4 Z+ Ifprintf(& __stdout, …)where __stdout has type __FILE.$ c% n+ {( p" a& s
6 h" r* C. g$ J6 h$ t) @大致是说printf家族有这么些函数<_printf(), printf(), _fprintf(), fprintf(), vprintf(), and vfprintf()>, 这些函数都隐式的使用__FILE<文件流>, 并且只依靠fputc(), ferror()这两个函数.' P. `" y- z3 L& j* L
! _* ^2 \* Z8 y6 k7 W. n" cIf 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.2 I( w# t8 ^$ P' _: |; x7 Q
l% q; |$ T! ]5 p重新定义__FILE, fputc(), ferror(), __stdout, 就可以使用printf()家族的各种函数了.
: z( f4 e! ~7 a' b5 E3 E% s v- s* \, N. k) K9 J' i0 m
STM32中printf重定向
p5 z1 i1 v8 u; v$ ?5 T下面是官方给出的重映射模板:! T( g' s f5 K R
<遇到不会的先看看文档往往能得到最直接的答案>5 M$ g9 u9 |" v9 d; ^" `$ H
0 [1 c5 [9 X2 X0 U2 c' e: E) W- #include <stdio.h>
0 ]3 ^, C$ {6 p j& u( \$ U - struct __FILE
. n7 c+ N& O# N' i' _( ?# I6 R; v - {" T+ \8 J2 G+ {" ]/ C' }$ j
- int handle;/ V( l4 `; M) K& r/ s
- /* Whatever you require here. If the only file you are using is */
& Z- O2 K' i/ w1 ]; | - /* standard output using printf() for debugging, no file handling */* o; \9 c4 j! O
- /* is required. */
8 b6 m# ~% @, I, c5 }6 D - };& f" r, T& ~! b! H( `7 c4 o
- /* FILE is typedef’d in stdio.h. */$ j- |# X. W+ j
- FILE __stdout;
, j& S3 T, g+ T" I6 D+ _* Q - int fputc(int ch, FILE *f)
3 I( U8 h7 ]& k+ D# U - {+ o& p) ?3 J4 L' B+ U
- /* Your implementation of fputc(). */) }" a5 B8 q- Y: t. g- Q9 s
- return ch;
0 z- m* @* A% J* x - }0 L7 L* j- \( s) S8 Y' V# R& z
- int ferror(FILE *f)$ s H, w: `; R F, K- D+ J N4 U+ Y
- {, T! \0 C7 N$ Q8 v" \4 O D6 ~2 X
- /* Your implementation of ferror(). */1 c. N1 s* X5 p3 y q }1 r8 a
- return 0;; E) R/ G; ]* ~
- }
复制代码
+ e0 y5 Y; G! f- c/ f- \要将printf()重定向到STM32中的串口, 只需要重新实现 fputc() 函数即可, 在fputc()中通过串口发送一个char. 在上一次的工程上进行修改, 将printf()重定向到串口3.0 B; A2 O* X1 \! r8 B# y
. i% Q( ~! Q) U* W- #include <stdio.h>; O$ ?* |" ^; t- z3 E0 B
- struct __FILE) f6 I F1 v% R
- {) I) l6 x8 D# f" o
- int handle;
* v, ?4 F9 }" @% `- _ - /* Whatever you require here. If the only file you are using is */+ r y; @7 v3 F( K, n: E
- /* standard output using printf() for debugging, no file handling */
8 `5 Z8 E2 J2 a5 I1 R - /* is required. */
5 ~0 `* e6 z& |: D) ^4 u9 s - };
( Z/ }6 \0 X) n, j( R. p, |; J: g - /* FILE is typedef’d in stdio.h. */
: S7 a. I) h9 V9 a, m, Y4 i - FILE __stdout;
7 i; K1 [& S% e, r8 h# O - int fputc(int ch, FILE *f) 0 E' o) `, E, q) ^
- {; {2 m' d" x* @0 I# J
- /* Your implementation of fputc(). */) a S: [4 u# E, i5 i5 z
- HAL_UART_Transmit( &huart3, ( uint8_t* )&ch, 1, 0xFFFF );
( l1 r' Q& ]( x- M- C/ \ - return ch;
( p3 [0 Y, Y; |0 m! ]6 ?$ ]5 l - }# E- U% P: S7 @8 d2 k
- int ferror(FILE *f)# y- i) ]1 i* v! {
- {. R+ d7 a4 p1 c% \3 c7 w4 r. y# j
- /* Your implementation of ferror(). */1 L. q4 v& l5 b
- HAL_UART_Transmit( &huart3, ( uint8_t* )"Printf Error\n", 13, 0xFFFF );// 可选9 \2 B$ x# G; w
- return 0;
! x4 v \3 [3 j9 x1 `# r+ q - }
复制代码
9 K# P9 `& T2 j+ [7 r+ x/ s1 z写个简单的程序试一试:
2 q6 H }; b' r: E" Q2 V2 n; t2 O( N3 s6 [, c
- int main(void)
0 A4 O4 h* t8 ~' k! Z/ J8 w - {
* `. V! b9 z* \2 }& c Q( W5 ? - MPU_Config();
: `5 W% Y/ B' k - SCB_EnableICache();( a0 @5 w. a$ i" V7 E% M7 }
- SCB_EnableDCache();
9 n; d" Q# \% L1 A) u x6 z" u - HAL_Init();
. E* A- i/ j! H8 v9 D2 k/ z" [ - SystemClock_Config();- Y5 x5 L& c% F& ]" @( ~) f9 Q
- MX_GPIO_Init();
0 S( P1 P) U/ I - MX_ETH_Init();
) W# f+ h* l3 X. A( m# S% q - MX_USART3_UART_Init();
$ r. @0 r, p0 f: R - /* USER CODE BEGIN 2 */5 F. U: _9 c, L4 v) R! w
- double d = 1.234;# O- S y, ^5 P, z8 R9 h
- int i = 60;3 I, W" p( O# ~7 j# Q2 Q" h
- char str[] = "Do not be lazy.\n"; ]6 L0 l* ~3 B2 Z8 _: e; S
- printf("Hello World\n"); I& c6 Q7 O! I- C; |, C# p) X
- printf("d = %lf\ni = %d\n", d, i);+ l2 t% D9 D7 O' A
- printf("this is a string : %s", str);
4 [) A) V3 Z5 y/ a! x0 k$ A1 I - . H2 ^# _' i2 R3 |
- while (1){}: `1 J% {2 U. J0 l- C) Z+ B
- }
复制代码
$ i4 k [0 j5 w6 c4 ^0 }( z输出结果:
( b1 A! v9 u- L- n: g( C: v& ] R+ q+ F% y7 o- r2 m" Z
+ x& q r' x8 ? {$ E0 H0 b8 k5 Y, o' [可以开始愉快的使用printf()了.
: I+ B- X/ y6 P- j# G& {
( C/ K$ ^2 G3 k3 x& D5 w/ q3 L( q8 |. p% K. q
4 j- R& w* |9 J* O& ~7 n |