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

【经验分享】STM32H7系列其二

[复制链接]
STMCU小助手 发布时间:2021-12-18 17:43
printf重定向介绍
% E- P3 l9 D, b1 F在学C语言的时候,会经常用标准库<stdio.h>中printf(), scanf()这两个函数, 来实现数据的输入与输出. 格式化输入输出的功能还是挺强大的, 那已经有了现成的轮子, 就要寻思一下如何进一步在单片机上使用它.
. ^% C% Q- i( X下面是ARM Compiler6文档中对printf的介绍:
  H' |- V1 [) a; G  c7 H2 Q# r. r' u( Y! y* T* `; M
The printf family consists of _printf(), printf(), _fprintf(), fprintf(), vprintf(), and vfprintf().0 X2 d* F* ^( |1 u& 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.* G( G: [: _4 R
The standard output functions of the form _printf(…) are equivalent to:
$ l) [& x1 M- K' qfprintf(& __stdout, …)where __stdout has type __FILE.' s8 V7 D: ^& ~8 P+ {# y" r0 \
- y! S1 w0 Y+ E
大致是说printf家族有这么些函数<_printf(), printf(), _fprintf(), fprintf(), vprintf(), and vfprintf()>, 这些函数都隐式的使用__FILE<文件流>, 并且只依靠fputc(), ferror()这两个函数.8 z4 z: A3 @/ _8 L
1 u& q; {/ ~2 u) e% E* J
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.' I: u7 `8 g+ K% W" T) d

; @# i! e* P/ m7 {3 w' M3 W+ @" v重新定义__FILE, fputc(), ferror(), __stdout, 就可以使用printf()家族的各种函数了.6 Z/ Z) ^/ C+ o" z' e
3 X* G, {( X9 n: n4 l5 `
STM32中printf重定向
8 s, b6 D5 M' Z% X/ x, g+ r2 z
下面是官方给出的重映射模板:
. M; Z" e) a0 v# ~( {3 ^<遇到不会的先看看文档往往能得到最直接的答案>
  D1 A; H% _, {. G7 ?2 N0 o% J" y% q7 }6 I" E9 M0 B+ j
  1. #include <stdio.h>
    ( F$ N2 }4 J7 x: w" N
  2. struct __FILE
    " g- G4 w/ p+ q5 s, a  e9 m  f
  3. {
    ! |' n9 M4 O( T& ]; f' u; ^8 p
  4.   int handle;$ d: C# H. ^- E3 i0 J# ^8 d2 z6 ^/ e) q
  5.   /* Whatever you require here. If the only file you are using is */6 c$ L( i6 ~' v7 a
  6.   /* standard output using printf() for debugging, no file handling */1 q5 s5 }0 s. P
  7.   /* is required. */$ z: }- S1 R% ]$ S
  8. };& [7 V. d  ?3 j/ Z" Q9 t1 {
  9. /* FILE is typedef’d in stdio.h. */
    2 k' i8 n1 V7 ?8 D7 R9 f% T2 E
  10. FILE __stdout;7 ?' b& f: u* ~: f0 |: P4 A
  11. int fputc(int ch, FILE *f)
    " L9 W9 ^# p' d) ^4 T6 q/ w6 R: G0 B
  12. {7 n9 B3 r# S# V9 t* Z) [' M
  13.   /* Your implementation of fputc(). */( |0 S5 Y( }2 _8 C2 s, q
  14.   return ch;! s9 m2 w) w9 k4 i0 w0 W8 p7 j6 t  `
  15. }! o3 m& J/ \7 f4 F/ T
  16. int ferror(FILE *f)
    ; H+ I3 w* s, M6 J% B
  17. {
    ) k" F: [2 x/ v5 c+ J; n/ F7 i6 S
  18.   /* Your implementation of ferror(). */
    ! J1 Q" P$ m7 K5 x; @- x
  19.   return 0;9 I7 L8 [2 w& A, E4 B' L2 s
  20. }
复制代码

5 X1 I- }0 _0 i1 _8 |( r要将printf()重定向到STM32中的串口, 只需要重新实现 fputc() 函数即可, 在fputc()中通过串口发送一个char. 在上一次的工程上进行修改, 将printf()重定向到串口3.$ g2 a6 q: }2 g
' B# H/ w5 M) D* X8 d
  1. #include <stdio.h>
    5 Z: g6 [. i; @7 B* p
  2. struct __FILE
    " ^2 H8 T, r4 N# s- q
  3. {$ e; J' z% ~. [8 |: E+ o& F: E' K
  4.   int handle;
    6 U, s' M8 A7 R
  5.   /* Whatever you require here. If the only file you are using is */8 W  |/ v2 b4 \% B. E$ F# m
  6.   /* standard output using printf() for debugging, no file handling */4 ^4 q* f$ h# t' i" `
  7.   /* is required. */
    % C1 y, W: {+ e
  8. };
    " L1 f  m; g$ m+ e% q3 M/ h/ B
  9. /* FILE is typedef’d in stdio.h. */5 `3 y8 w1 g- g" n  X! x
  10. FILE __stdout;
    " i7 f1 I6 J$ b/ Q& d
  11. int fputc(int ch, FILE *f) ) ?3 u- ^  t3 s
  12. {" P& _6 i5 @9 m6 ^
  13.   /* Your implementation of fputc(). */
    , f# C3 C& L+ Y: {' q/ |
  14.   HAL_UART_Transmit( &huart3, ( uint8_t* )&ch, 1, 0xFFFF );, L2 q  Y0 C- f! J& v8 R  J
  15.   return ch;8 m- A1 Z0 N- i0 K5 P5 x& U
  16. }! I4 @( j+ `4 w. Q
  17. int ferror(FILE *f)
    5 g* i2 Y; [9 J9 J) X
  18. {0 M! L3 A) |  c5 E& ~+ Y2 a
  19.   /* Your implementation of ferror(). */
    1 J! C5 ^! }" j2 O" |0 d1 s6 Q
  20.   HAL_UART_Transmit( &huart3, ( uint8_t* )"Printf Error\n", 13, 0xFFFF );// 可选% E2 p& W! r$ x# _8 F
  21.   return 0;
    / H' r* k9 a4 _3 f
  22. }
复制代码
; _; Y& A+ G3 w1 [+ u
写个简单的程序试一试:. E/ U, X/ ]$ ~6 |. p  N1 |
. r  k+ P* v/ O( p
  1. int main(void)
    1 ~1 z0 u6 h  q# n% }# F0 T, \, X: c
  2. {
    ) }: }8 l" `% B/ U  a8 J# K' [
  3.     MPU_Config();
    4 P" I/ @- a; I  E4 O+ N
  4.     SCB_EnableICache();0 ^( F2 [) D7 j$ P) j: U2 r
  5.     SCB_EnableDCache();
    4 X6 C: l2 q5 \1 r1 j3 W
  6.     HAL_Init();
      e- d& y+ O6 F9 j# V
  7.     SystemClock_Config();
    6 q6 i) D3 o6 u5 G- `: l7 J
  8.     MX_GPIO_Init();9 t$ A8 A4 w5 v$ K2 F7 a) m
  9.     MX_ETH_Init();
    . @" G6 R  ^/ P; V) {
  10.     MX_USART3_UART_Init();
    ' @# i2 ?. n+ r" l6 F( f: i# l4 C" F
  11.     /* USER CODE BEGIN 2 */- I; N+ r! P; C
  12.         double d = 1.234;
    $ g' E+ e/ l6 h: d
  13.         int i = 60;
    , r1 M1 H- [, P" h: o: i& `, z
  14.         char str[] = "Do not be lazy.\n";# K8 O1 {4 z3 M- ]
  15.         printf("Hello World\n");
    / Y' n" X% i5 g7 M& v: I
  16.         printf("d = %lf\ni = %d\n", d, i);
    / {% A( A/ v: b# j; l9 c& X
  17.         printf("this is a string : %s", str);
    # k2 f7 _7 D( e" H* H0 k

  18. * c% I8 C1 J# {! F- T# r
  19.     while (1){}% Y2 _$ W2 R1 x/ [0 z
  20. }
复制代码

( o- R9 l" Z0 I/ m输出结果:
+ z, `5 v$ c* V+ f7 B- G" N( S
20190313212812741.png

, @& d) [/ I/ S7 [
8 Z, V0 K: D4 J, L. @; g! R7 ]可以开始愉快的使用printf()了.; h& F" }% a# m: W& a
8 S. y0 L, ^. E9 I9 r6 U6 e
+ Y) N: g( L1 F- B+ \

. S. s* |: `3 U( H/ P6 v8 z# T$ f
赞 收藏 评论0 发布时间:2021-12-18 17:43

举报

0个回答

所属标签

相似技术帖

官网相关资源

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