printf重定向介绍/ F+ r$ U/ A) P8 M
在学C语言的时候,会经常用标准库<stdio.h>中printf(), scanf()这两个函数, 来实现数据的输入与输出. 格式化输入输出的功能还是挺强大的, 那已经有了现成的轮子, 就要寻思一下如何进一步在单片机上使用它.
' D/ c, s X; H1 l6 a5 x下面是ARM Compiler6文档中对printf的介绍:: l3 b; t" l3 u% L0 y5 c
) ]1 g2 g' Y, G8 n0 N2 _) W
The printf family consists of _printf(), printf(), _fprintf(), fprintf(), vprintf(), and vfprintf().2 X$ \2 \4 V. [1 l: \. ?" n
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.+ f. {8 J/ V% C. P
The standard output functions of the form _printf(…) are equivalent to:
) z7 s. H: t- |9 I6 f% d9 R! Ofprintf(& __stdout, …)where __stdout has type __FILE.
6 S$ r6 j( `3 E* S _' L* J8 J6 U* U3 g) n$ E+ [0 _: \8 |- R
大致是说printf家族有这么些函数<_printf(), printf(), _fprintf(), fprintf(), vprintf(), and vfprintf()>, 这些函数都隐式的使用__FILE<文件流>, 并且只依靠fputc(), ferror()这两个函数.6 m+ i# j& e* [ K6 k* Z
\/ u" F' @9 ~
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.
4 d8 {2 s& h8 G3 [7 M3 e u Z7 \8 r1 z
重新定义__FILE, fputc(), ferror(), __stdout, 就可以使用printf()家族的各种函数了.
! \9 j6 A5 m6 K% L5 x( V- d: e5 m* u# y! c
STM32中printf重定向
2 h% J$ H8 _# P# ]1 `+ `下面是官方给出的重映射模板:
- F4 w' G4 j/ }% g# _<遇到不会的先看看文档往往能得到最直接的答案>
1 p. ^" n* |3 p$ a' W2 H0 _. Z7 T
- #include <stdio.h># `: T z5 Y$ n' r* ]# m6 A9 Z& P
- struct __FILE
1 i7 ] u* @9 D5 @: U( F - {3 l( R$ D6 Y1 v) v0 G& O3 Y
- int handle;* `0 i0 ]) Q+ ]
- /* Whatever you require here. If the only file you are using is */
) o. v7 _! X; L1 J' r) Z5 r0 `, @1 i - /* standard output using printf() for debugging, no file handling */% f' z4 `6 Q: t) C9 d* ~8 y/ c, O* Z! D
- /* is required. */* Y& R6 C) B! |: L
- };6 o" K; x7 y+ ]: L
- /* FILE is typedef’d in stdio.h. */( p8 F' @' U7 V8 g* z
- FILE __stdout;5 k: _& v5 g7 K7 }7 }/ H4 {0 w L
- int fputc(int ch, FILE *f)
7 Z! y2 m- T/ `) Y U' |( ~+ U - {( u* O1 ^: P/ y& @# \7 v
- /* Your implementation of fputc(). */
; P2 {% A/ R6 V1 s- s+ A$ e) X U - return ch;3 p. e d a: ^( z1 G
- }$ Q# J# k5 i) n* Z7 b& c
- int ferror(FILE *f)
6 P) Q. H* Z+ m2 y7 x$ g* ^ - {
( G! r4 `/ w5 q - /* Your implementation of ferror(). */
; D3 `( p4 V% y% Q - return 0;+ B) h+ {9 q j
- }
复制代码
; q# w- s1 j4 Z. D6 O要将printf()重定向到STM32中的串口, 只需要重新实现 fputc() 函数即可, 在fputc()中通过串口发送一个char. 在上一次的工程上进行修改, 将printf()重定向到串口3.
4 S* S1 ]: |. Q. O0 d( ]( u; T: F* ~) Z2 U/ V# w$ ~
- #include <stdio.h>. f1 z c" B# Q& z( h& J
- struct __FILE
( A3 X5 w, t6 i - {
0 L& T6 h3 D* F6 |. D/ x - int handle;+ m9 t4 R0 T( k$ t+ y
- /* Whatever you require here. If the only file you are using is */4 y1 W1 g! R; S' F1 w, p# ?; \! H
- /* standard output using printf() for debugging, no file handling */) w* ]1 U' M9 K: @) ^
- /* is required. */$ z1 T; _7 e6 w9 K+ w# I& i3 y
- };
+ o" T. m( C7 P) K$ Z0 u6 d5 y, X - /* FILE is typedef’d in stdio.h. */
) F' y/ Q$ r2 U+ E7 k - FILE __stdout;8 M E3 L& t, A4 E5 J* V7 [
- int fputc(int ch, FILE *f) # x1 ^3 I# Q' a6 ~
- {, I& Y! r8 D( ?( q4 u0 s& B
- /* Your implementation of fputc(). */0 Y$ L$ _1 e+ X; v0 R
- HAL_UART_Transmit( &huart3, ( uint8_t* )&ch, 1, 0xFFFF );2 ]; w" d+ E9 Z. z J) U$ I5 f
- return ch;
B, T4 X8 h' m7 W2 T4 O - } z! I1 _& X- f, f4 C) y
- int ferror(FILE *f)) F8 L+ J: X% f, R
- {
. z* P1 B; r8 R4 a6 Q X - /* Your implementation of ferror(). */
: M) q4 D8 ^, Q# G, X* \5 i - HAL_UART_Transmit( &huart3, ( uint8_t* )"Printf Error\n", 13, 0xFFFF );// 可选
j8 p2 K/ q- }1 a - return 0;
( m& ~1 g( E+ `& k/ _. E" F5 U' V& R+ P - }
复制代码
! [) u- L6 D1 |) p5 \写个简单的程序试一试:
6 z: A/ W' Y5 N; H# M
% f+ U: W4 A8 `+ X: i) S' l- int main(void)0 p4 }1 C2 y- _6 ~* A; R& {* O+ B9 G
- {
9 y/ t2 T! f* e# ^ - MPU_Config();
% N; b. o$ y8 `3 r- v% J$ x; g - SCB_EnableICache();2 M* O. P, C2 @6 {+ s+ {& K n
- SCB_EnableDCache();$ Q) S& G7 ~6 |! L5 q/ G
- HAL_Init();$ |8 z3 }8 M* G& l
- SystemClock_Config();8 q8 L/ f l% W
- MX_GPIO_Init();. r$ x% c8 l/ E3 u }2 z/ X9 i
- MX_ETH_Init();; ^' h) i1 G4 r/ M3 \. s+ @
- MX_USART3_UART_Init();; L' x1 v, l' w* B
- /* USER CODE BEGIN 2 */
3 v3 f W3 s N) Q! M2 x% ?' g - double d = 1.234;
$ Q" a, o) m/ }1 ] - int i = 60;
$ E9 Q# P! M* F - char str[] = "Do not be lazy.\n";
$ u0 t; ]; q# |# S - printf("Hello World\n");
5 [6 c% G5 r; X2 @& ~6 n9 \+ J' P - printf("d = %lf\ni = %d\n", d, i);
! b+ J4 f+ n! B$ z% X1 |2 u6 W - printf("this is a string : %s", str);
' U, A* Y" h1 |* j% a5 d
. a( Q8 J( B& D( L- F- while (1){}
4 F" o0 G& o. n" ~# s6 u - }
复制代码 1 Z/ L" ]2 ^0 L) z) ~9 l
输出结果:0 t# {. S3 i& q$ H1 `& R9 p
% v9 d# L2 N* p8 \0 Q2 s9 V9 g$ X& i
1 {6 R0 }) K" g0 o- t) c
可以开始愉快的使用printf()了.
4 f# f! T1 @% ?) I+ A0 c9 t' d: [8 o' q& u
0 i0 V& Z% E7 u6 V9 \; {! H$ t$ u6 s1 R7 l* J7 f6 U( F; r
|