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

【经验分享】STM32H7系列其二

[复制链接]
STMCU小助手 发布时间:2021-12-18 17:43
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
  1. #include <stdio.h>
    0 ]3 ^, C$ {6 p  j& u( \$ U
  2. struct __FILE
    . n7 c+ N& O# N' i' _( ?# I6 R; v
  3. {" T+ \8 J2 G+ {" ]/ C' }$ j
  4.   int handle;/ V( l4 `; M) K& r/ s
  5.   /* Whatever you require here. If the only file you are using is */
    & Z- O2 K' i/ w1 ]; |
  6.   /* standard output using printf() for debugging, no file handling */* o; \9 c4 j! O
  7.   /* is required. */
    8 b6 m# ~% @, I, c5 }6 D
  8. };& f" r, T& ~! b! H( `7 c4 o
  9. /* FILE is typedef’d in stdio.h. */$ j- |# X. W+ j
  10. FILE __stdout;
    , j& S3 T, g+ T" I6 D+ _* Q
  11. int fputc(int ch, FILE *f)
    3 I( U8 h7 ]& k+ D# U
  12. {+ o& p) ?3 J4 L' B+ U
  13.   /* Your implementation of fputc(). */) }" a5 B8 q- Y: t. g- Q9 s
  14.   return ch;
    0 z- m* @* A% J* x
  15. }0 L7 L* j- \( s) S8 Y' V# R& z
  16. int ferror(FILE *f)$ s  H, w: `; R  F, K- D+ J  N4 U+ Y
  17. {, T! \0 C7 N$ Q8 v" \4 O  D6 ~2 X
  18.   /* Your implementation of ferror(). */1 c. N1 s* X5 p3 y  q  }1 r8 a
  19.   return 0;; E) R/ G; ]* ~
  20. }
复制代码

+ 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
  1. #include <stdio.h>; O$ ?* |" ^; t- z3 E0 B
  2. struct __FILE) f6 I  F1 v% R
  3. {) I) l6 x8 D# f" o
  4.   int handle;
    * v, ?4 F9 }" @% `- _
  5.   /* Whatever you require here. If the only file you are using is */+ r  y; @7 v3 F( K, n: E
  6.   /* standard output using printf() for debugging, no file handling */
    8 `5 Z8 E2 J2 a5 I1 R
  7.   /* is required. */
    5 ~0 `* e6 z& |: D) ^4 u9 s
  8. };
    ( Z/ }6 \0 X) n, j( R. p, |; J: g
  9. /* FILE is typedef’d in stdio.h. */
    : S7 a. I) h9 V9 a, m, Y4 i
  10. FILE __stdout;
    7 i; K1 [& S% e, r8 h# O
  11. int fputc(int ch, FILE *f) 0 E' o) `, E, q) ^
  12. {; {2 m' d" x* @0 I# J
  13.   /* Your implementation of fputc(). */) a  S: [4 u# E, i5 i5 z
  14.   HAL_UART_Transmit( &huart3, ( uint8_t* )&ch, 1, 0xFFFF );
    ( l1 r' Q& ]( x- M- C/ \
  15.   return ch;
    ( p3 [0 Y, Y; |0 m! ]6 ?$ ]5 l
  16. }# E- U% P: S7 @8 d2 k
  17. int ferror(FILE *f)# y- i) ]1 i* v! {
  18. {. R+ d7 a4 p1 c% \3 c7 w4 r. y# j
  19.   /* Your implementation of ferror(). */1 L. q4 v& l5 b
  20.   HAL_UART_Transmit( &huart3, ( uint8_t* )"Printf Error\n", 13, 0xFFFF );// 可选9 \2 B$ x# G; w
  21.   return 0;
    ! x4 v  \3 [3 j9 x1 `# r+ q
  22. }
复制代码

9 K# P9 `& T2 j+ [7 r+ x/ s1 z写个简单的程序试一试:
2 q6 H  }; b' r: E" Q2 V2 n; t2 O( N3 s6 [, c
  1. int main(void)
    0 A4 O4 h* t8 ~' k! Z/ J8 w
  2. {
    * `. V! b9 z* \2 }& c  Q( W5 ?
  3.     MPU_Config();
    : `5 W% Y/ B' k
  4.     SCB_EnableICache();( a0 @5 w. a$ i" V7 E% M7 }
  5.     SCB_EnableDCache();
    9 n; d" Q# \% L1 A) u  x6 z" u
  6.     HAL_Init();
    . E* A- i/ j! H8 v9 D2 k/ z" [
  7.     SystemClock_Config();- Y5 x5 L& c% F& ]" @( ~) f9 Q
  8.     MX_GPIO_Init();
    0 S( P1 P) U/ I
  9.     MX_ETH_Init();
    ) W# f+ h* l3 X. A( m# S% q
  10.     MX_USART3_UART_Init();
    $ r. @0 r, p0 f: R
  11.     /* USER CODE BEGIN 2 */5 F. U: _9 c, L4 v) R! w
  12.         double d = 1.234;# O- S  y, ^5 P, z8 R9 h
  13.         int i = 60;3 I, W" p( O# ~7 j# Q2 Q" h
  14.         char str[] = "Do not be lazy.\n";  ]6 L0 l* ~3 B2 Z8 _: e; S
  15.         printf("Hello World\n");  I& c6 Q7 O! I- C; |, C# p) X
  16.         printf("d = %lf\ni = %d\n", d, i);+ l2 t% D9 D7 O' A
  17.         printf("this is a string : %s", str);
    4 [) A) V3 Z5 y/ a! x0 k$ A1 I
  18. . H2 ^# _' i2 R3 |
  19.     while (1){}: `1 J% {2 U. J0 l- C) Z+ B
  20. }
复制代码

$ i4 k  [0 j5 w6 c4 ^0 }( z输出结果:
( b1 A! v9 u- L- n: g
20190313212812741.png
( 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
收藏 评论0 发布时间:2021-12-18 17:43

举报

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