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

【经验分享】STM32H7系列其二

[复制链接]
STMCU小助手 发布时间:2021-12-18 17:43
printf重定向介绍
& G" U! t( }/ k6 X5 _在学C语言的时候,会经常用标准库<stdio.h>中printf(), scanf()这两个函数, 来实现数据的输入与输出. 格式化输入输出的功能还是挺强大的, 那已经有了现成的轮子, 就要寻思一下如何进一步在单片机上使用它.0 S) U+ j3 q0 b3 W: ?5 s$ E0 m
下面是ARM Compiler6文档中对printf的介绍:
! Y' g) P& h, i( |0 }* y# S3 b$ H" k; H1 i4 S0 Y- C
The printf family consists of _printf(), printf(), _fprintf(), fprintf(), vprintf(), and vfprintf().
9 Z( K! B5 a6 S& ], _% zAll 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.
" S! o  v& S+ e, z5 I  Q5 sThe standard output functions of the form _printf(…) are equivalent to:
4 I& G( F9 M6 l" W  A) H) K% }3 v1 Pfprintf(& __stdout, …)where __stdout has type __FILE." @! Y" ^" g! v) H! I; s

! a: o$ k1 t+ v8 p: S大致是说printf家族有这么些函数<_printf(), printf(), _fprintf(), fprintf(), vprintf(), and vfprintf()>, 这些函数都隐式的使用__FILE<文件流>, 并且只依靠fputc(), ferror()这两个函数.
" S! c% o. J( w  U" `/ H% e% O
% i- Y+ ^( G- kIf 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.
3 ]/ A3 b) p' h5 V5 s/ ?
' @: H. i  u0 i) G9 ^; u重新定义__FILE, fputc(), ferror(), __stdout, 就可以使用printf()家族的各种函数了.
, Z9 D" ]# g9 |2 y: J! [# j" p" Z! J4 z2 Q1 I
STM32中printf重定向
2 F. @' J1 i0 O! e+ B% r0 U! r
下面是官方给出的重映射模板:
; i8 ~* b/ Z% ^" Y9 K<遇到不会的先看看文档往往能得到最直接的答案>
: p2 l5 }+ z7 W4 k. v
- @% h1 K8 @! m5 `6 H# m2 M
  1. #include <stdio.h>
    ( C3 }! C% a  X* `
  2. struct __FILE
    % k# D7 I# _' m( h3 r0 W0 O# n% r
  3. {
    # ^0 H* c" Y& F: @- D7 P9 p; B
  4.   int handle;5 n6 ]" I) E- n# g) X5 n4 b
  5.   /* Whatever you require here. If the only file you are using is */
    1 U: o$ V: _: d1 I' P( c( p
  6.   /* standard output using printf() for debugging, no file handling */
    . O# u( j6 y* K; ~
  7.   /* is required. */; M5 z# W( h. o* r& |6 ^
  8. };- U  q$ f% A- d4 g
  9. /* FILE is typedef’d in stdio.h. */0 `$ {' U9 d) v9 H" h  l" |
  10. FILE __stdout;/ Y, |+ K1 s6 J4 Q2 C/ Q5 b
  11. int fputc(int ch, FILE *f) ( g7 f; C1 J2 K* d( L
  12. {
    ! H# H  w( P# Z$ v! ?7 C4 x% }7 u
  13.   /* Your implementation of fputc(). */
    / v/ z1 L8 A6 b# \" t  [
  14.   return ch;. P' V" R' u/ r' n4 |% i
  15. }
    % `1 _+ o. A* X9 K; ]7 D
  16. int ferror(FILE *f)
    $ J0 O: g% e" \- ?% H( c
  17. {
    - U. g9 T& k: k7 P
  18.   /* Your implementation of ferror(). */
    # [# w: e0 U5 i" c0 G
  19.   return 0;2 H6 J; z' ~) h1 p
  20. }
复制代码

. `, u1 d2 W* n( q" B: @4 a要将printf()重定向到STM32中的串口, 只需要重新实现 fputc() 函数即可, 在fputc()中通过串口发送一个char. 在上一次的工程上进行修改, 将printf()重定向到串口3.
$ I! w. j8 E/ u. O; l
2 ]6 s0 d9 E6 v7 I
  1. #include <stdio.h>
    ) a  s' s% E! v) f% M$ U
  2. struct __FILE7 W6 E& L9 d) t+ I# U0 i
  3. {
    ! W9 Y0 G% v3 k2 S6 a# T
  4.   int handle;
    7 L0 v' O9 _  |  @8 ~# H5 U
  5.   /* Whatever you require here. If the only file you are using is */( [. M- i# Q- j* a+ F; [
  6.   /* standard output using printf() for debugging, no file handling */
    ) x& J& Y' c; C7 ]
  7.   /* is required. */. l' B$ e) S) F& t# s
  8. };, t8 v# |! u- N, j$ Z
  9. /* FILE is typedef’d in stdio.h. */1 [" a8 d- c/ R* I  X5 {
  10. FILE __stdout;
    " P/ _, |7 Q0 z, n4 n
  11. int fputc(int ch, FILE *f)
    - W* T2 ^$ {0 H2 U8 e" D  B
  12. {2 w) b. Z& v7 d4 A* V% i( p. ]
  13.   /* Your implementation of fputc(). */& r0 y6 a0 T: S, x" ]( M# w
  14.   HAL_UART_Transmit( &huart3, ( uint8_t* )&ch, 1, 0xFFFF );
    . X4 v+ C8 }( l4 t6 \4 I& u
  15.   return ch;
    2 Z9 n- L0 D: \- N1 M. y# M( p
  16. }
    2 x, r( v0 V6 i7 Q+ \7 r7 Z7 w
  17. int ferror(FILE *f)
    9 g3 ~3 m  {' K* ?  M! |
  18. {/ T' H0 S3 o3 F/ D& d: Y
  19.   /* Your implementation of ferror(). */( u; d5 Y9 M+ W2 U( B1 s
  20.   HAL_UART_Transmit( &huart3, ( uint8_t* )"Printf Error\n", 13, 0xFFFF );// 可选+ j( U7 Z2 }1 Q% b3 x5 c# B) g& O* e' H
  21.   return 0;
    5 f3 Q" j5 ]$ e, U& p
  22. }
复制代码

( D' k* _; {, ?- Z写个简单的程序试一试:
$ X: S5 @/ c) c" o
1 Z" I: g$ p" [2 q8 _
  1. int main(void)
    ! k4 c; F4 y/ t
  2. {
    9 h2 Q- s" e3 P7 i- K7 u
  3.     MPU_Config();- P6 a  t# p% ]
  4.     SCB_EnableICache();% H5 d' V" ^% s  c; o: {! u' d
  5.     SCB_EnableDCache();
    ! F! |, Y: R9 L5 b
  6.     HAL_Init();
    & o" G* t$ R0 Z. Z: }4 K
  7.     SystemClock_Config();
    0 f1 K) L2 l, ^3 }
  8.     MX_GPIO_Init();( }0 i* G0 v* k% _: F: X2 \6 b0 K& \
  9.     MX_ETH_Init();6 s% N: N. e1 _4 H) c: o- y
  10.     MX_USART3_UART_Init();
    9 L: K/ U  H$ H2 d
  11.     /* USER CODE BEGIN 2 */$ H/ |% e5 T1 A
  12.         double d = 1.234;
    2 i$ r1 V) a5 \+ J0 }* m; [! X
  13.         int i = 60;3 d0 S6 @* H! S3 }
  14.         char str[] = "Do not be lazy.\n";
    + N' }5 `9 I9 m" Y* ~
  15.         printf("Hello World\n");
    ; m) A' P0 o6 v& ^  T
  16.         printf("d = %lf\ni = %d\n", d, i);+ [1 H+ u% T5 E( I! I: w! ?
  17.         printf("this is a string : %s", str);& r" [1 a4 V2 w9 K, ~( o+ N7 r
  18. , Z- c* I- t) _% [4 t9 S/ Q
  19.     while (1){}
    : d/ b4 M% I. W, y) R: G6 l9 e5 b
  20. }
复制代码

, N5 e& O1 _/ ^6 K% }- l输出结果:
( U4 j; o& m  x! C! t' z
20190313212812741.png
" L1 ^0 [1 g1 w( G, h

2 c: }# h- [3 g( d可以开始愉快的使用printf()了.
- @' @7 P' T$ E, H) }8 V9 ]4 r/ K# K7 J8 Y/ ?  A
4 u! i! Q  o# Z7 R

* L! R; m- y$ a/ k+ {6 |6 R
收藏 评论0 发布时间:2021-12-18 17:43

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版