你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32H7系列其二

[复制链接]
STMCU小助手 发布时间:2021-12-18 17:43
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
  1. #include <stdio.h># `: T  z5 Y$ n' r* ]# m6 A9 Z& P
  2. struct __FILE
    1 i7 ]  u* @9 D5 @: U( F
  3. {3 l( R$ D6 Y1 v) v0 G& O3 Y
  4.   int handle;* `0 i0 ]) Q+ ]
  5.   /* Whatever you require here. If the only file you are using is */
    ) o. v7 _! X; L1 J' r) Z5 r0 `, @1 i
  6.   /* standard output using printf() for debugging, no file handling */% f' z4 `6 Q: t) C9 d* ~8 y/ c, O* Z! D
  7.   /* is required. */* Y& R6 C) B! |: L
  8. };6 o" K; x7 y+ ]: L
  9. /* FILE is typedef’d in stdio.h. */( p8 F' @' U7 V8 g* z
  10. FILE __stdout;5 k: _& v5 g7 K7 }7 }/ H4 {0 w  L
  11. int fputc(int ch, FILE *f)
    7 Z! y2 m- T/ `) Y  U' |( ~+ U
  12. {( u* O1 ^: P/ y& @# \7 v
  13.   /* Your implementation of fputc(). */
    ; P2 {% A/ R6 V1 s- s+ A$ e) X  U
  14.   return ch;3 p. e  d  a: ^( z1 G
  15. }$ Q# J# k5 i) n* Z7 b& c
  16. int ferror(FILE *f)
    6 P) Q. H* Z+ m2 y7 x$ g* ^
  17. {
    ( G! r4 `/ w5 q
  18.   /* Your implementation of ferror(). */
    ; D3 `( p4 V% y% Q
  19.   return 0;+ B) h+ {9 q  j
  20. }
复制代码

; 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$ ~
  1. #include <stdio.h>. f1 z  c" B# Q& z( h& J
  2. struct __FILE
    ( A3 X5 w, t6 i
  3. {
    0 L& T6 h3 D* F6 |. D/ x
  4.   int handle;+ m9 t4 R0 T( k$ t+ y
  5.   /* Whatever you require here. If the only file you are using is */4 y1 W1 g! R; S' F1 w, p# ?; \! H
  6.   /* standard output using printf() for debugging, no file handling */) w* ]1 U' M9 K: @) ^
  7.   /* is required. */$ z1 T; _7 e6 w9 K+ w# I& i3 y
  8. };
    + o" T. m( C7 P) K$ Z0 u6 d5 y, X
  9. /* FILE is typedef’d in stdio.h. */
    ) F' y/ Q$ r2 U+ E7 k
  10. FILE __stdout;8 M  E3 L& t, A4 E5 J* V7 [
  11. int fputc(int ch, FILE *f) # x1 ^3 I# Q' a6 ~
  12. {, I& Y! r8 D( ?( q4 u0 s& B
  13.   /* Your implementation of fputc(). */0 Y$ L$ _1 e+ X; v0 R
  14.   HAL_UART_Transmit( &huart3, ( uint8_t* )&ch, 1, 0xFFFF );2 ]; w" d+ E9 Z. z  J) U$ I5 f
  15.   return ch;
      B, T4 X8 h' m7 W2 T4 O
  16. }  z! I1 _& X- f, f4 C) y
  17. int ferror(FILE *f)) F8 L+ J: X% f, R
  18. {
    . z* P1 B; r8 R4 a6 Q  X
  19.   /* Your implementation of ferror(). */
    : M) q4 D8 ^, Q# G, X* \5 i
  20.   HAL_UART_Transmit( &huart3, ( uint8_t* )"Printf Error\n", 13, 0xFFFF );// 可选
      j8 p2 K/ q- }1 a
  21.   return 0;
    ( m& ~1 g( E+ `& k/ _. E" F5 U' V& R+ P
  22. }
复制代码

! [) u- L6 D1 |) p5 \写个简单的程序试一试:
6 z: A/ W' Y5 N; H# M
% f+ U: W4 A8 `+ X: i) S' l
  1. int main(void)0 p4 }1 C2 y- _6 ~* A; R& {* O+ B9 G
  2. {
    9 y/ t2 T! f* e# ^
  3.     MPU_Config();
    % N; b. o$ y8 `3 r- v% J$ x; g
  4.     SCB_EnableICache();2 M* O. P, C2 @6 {+ s+ {& K  n
  5.     SCB_EnableDCache();$ Q) S& G7 ~6 |! L5 q/ G
  6.     HAL_Init();$ |8 z3 }8 M* G& l
  7.     SystemClock_Config();8 q8 L/ f  l% W
  8.     MX_GPIO_Init();. r$ x% c8 l/ E3 u  }2 z/ X9 i
  9.     MX_ETH_Init();; ^' h) i1 G4 r/ M3 \. s+ @
  10.     MX_USART3_UART_Init();; L' x1 v, l' w* B
  11.     /* USER CODE BEGIN 2 */
    3 v3 f  W3 s  N) Q! M2 x% ?' g
  12.         double d = 1.234;
    $ Q" a, o) m/ }1 ]
  13.         int i = 60;
    $ E9 Q# P! M* F
  14.         char str[] = "Do not be lazy.\n";
    $ u0 t; ]; q# |# S
  15.         printf("Hello World\n");
    5 [6 c% G5 r; X2 @& ~6 n9 \+ J' P
  16.         printf("d = %lf\ni = %d\n", d, i);
    ! b+ J4 f+ n! B$ z% X1 |2 u6 W
  17.         printf("this is a string : %s", str);
    ' U, A* Y" h1 |* j% a5 d

  18. . a( Q8 J( B& D( L- F
  19.     while (1){}
    4 F" o0 G& o. n" ~# s6 u
  20. }
复制代码
1 Z/ L" ]2 ^0 L) z) ~9 l
输出结果:0 t# {. S3 i& q$ H1 `& R9 p
20190313212812741.png
% 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
赞 收藏 评论0 发布时间:2021-12-18 17:43

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版