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

【经验分享】STM103单片机串口输出函数printf重映射

[复制链接]
STMCU小助手 发布时间:2022-3-22 13:00
在调试程序的时候经常需要使用printf’函数来打印相关调试信息,在STM103单片机中printf函数默认只能在串口1使用,有时候串口1被占用了,想要输出调试信息时会比较麻烦。现在就总结一下如何在其他串口上使用printf函数。这里使用正点原子的例程来做说明。
( G) x4 P3 f4 I5 ?默认串口1初始化代码如下5 _, k/ Q* m4 W/ Q
+ H/ B: |  ^% @/ c9 ^4 Q
  1. #if 1
    # G) D! M, v9 @! `# \
  2. #pragma import(__use_no_semihosting)
    $ ~7 d# O, ~/ i' x. a7 }9 T+ x; L+ F
  3. //标准库需要的支持函数6 V+ n) i7 o! I
  4. struct __FILE
    1 J. P" l" Q7 j$ M. b. i6 K$ L  `8 r
  5. {* T8 y% b( ?# g+ H
  6.     int handle;
    ) X! `. h) g" O0 u' R
  7. };
    1 H) j; ?2 C! ]% [( s
  8. FILE __stdout;
    0 }1 k+ E& Y8 K  a& z3 r
  9. //定义_sys_exit()以避免使用半主机模式
    * q* A9 p8 ^2 X. B' O3 Z
  10. _sys_exit(int x)
    4 Q+ E! s& m- C5 H' h
  11. {- w- m( P) T- B4 b
  12.     x = x;6 a1 R+ {$ t3 h# `2 h4 [/ D8 A4 B
  13. }7 c  q1 y8 K( v0 `; M" @- r$ k) r
  14. //重定义fputc函数
    $ e* L2 V3 W1 O* [& a( }2 [  K
  15. int fputc(int ch, FILE *f)2 }. I  n$ P6 u! {( s
  16. {
    & b' A+ w- K: `* r* O4 n2 S4 n
  17.     while((USART1->SR & 0X40) == 0); //循环发送,直到发送完毕+ C8 J; ?- w5 i% ~8 C1 i9 S2 h+ o
  18.     USART1->DR = (u8) ch;
    3 `5 l/ p4 R- B6 p% k
  19.     return ch;! m  U- @5 \% B6 y# W! [
  20. }: \3 P4 x' ?* U! \6 ~/ J/ Q
  21. #endif
    $ D, ?9 |) ~" @( |9 v. ^/ x
  22. * m" }$ }4 r; s" Z( Y$ I7 k6 ~
  23. void uart_init(u32 bound) {
    7 P2 L* X3 |' _
  24.     //GPIO端口设置  t1 O4 f. R$ s4 M4 s
  25.     GPIO_InitTypeDef GPIO_InitStructure;) }( B. d# R7 m/ m; `; C
  26.     USART_InitTypeDef USART_InitStructure;0 w9 c: y  f+ }% S, f0 P
  27.     NVIC_InitTypeDef NVIC_InitStructure;7 r& x5 ~4 t/ y( k' J

  28. ) I) w( g2 P7 q
  29.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);        //使能USART1,GPIOA时钟
      Y2 T1 }) W7 }; }) k

  30. 0 \( m$ _! V- y4 N3 d, _
  31.     //USART1_TX   GPIOA.9
    , n5 n5 W' ^7 h; U" `
  32.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9' Q3 H" x) o( Y+ f$ ?
  33.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;) p% Y0 M4 }) ^5 Y* s9 @* R) N
  34.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        //复用推挽输出
    ! \( \$ K$ H1 N5 i: a* o
  35.     GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9& _  k! D: k4 @$ Q

  36. & s# i! p. B# a  S1 g% S
  37.     //USART1_RX          GPIOA.10初始化2 U2 G& z3 o6 \4 M, m1 [4 H) C0 D
  38.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10$ ]. l8 |+ x7 I5 Y
  39.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入0 r* n- Y+ V0 }5 |1 g* P5 z
  40.     GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
    ( j1 f( P/ P: D9 g! a
  41. 2 O1 X3 U% p4 n1 j% F# e
  42.     //Usart1 NVIC 配置
    ; I& C% w+ @, a" Q7 g0 u# L, r
  43.     NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    7 j" E$ S! g6 L
  44.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3 ; //抢占优先级3
    0 W6 l( Y, w; y9 h. r
  45.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;                //子优先级3) Z# g" L! g" e) {
  46.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //IRQ通道使能( h. Z  g1 x) G8 @# S+ M* D; j5 _4 K
  47.     NVIC_Init(&NVIC_InitStructure);        //根据指定的参数初始化VIC寄存器8 b8 g1 g2 p9 m: {) M

  48. 9 y4 w1 ?# p/ ?# h
  49.     //USART 初始化设置7 I& K9 p: Y1 {) j; E! e  g) V

  50. 9 n* S& @1 {6 }3 K; r3 m, |) j
  51.     USART_InitStructure.USART_BaudRate = bound;//串口波特率* K/ M2 A( ?$ E: O3 g) E* g/ J
  52.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
    - A& m/ ^3 |; G1 I* j
  53.     USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
    0 l1 j5 V. [. x5 m/ s, D3 v# g2 h
  54.     USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位% N% v& e; S# a  S1 J0 b" w3 _
  55.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制9 F2 T: [5 `% P2 t4 }. A
  56.     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;        //收发模式
    : z5 D' g% w) L0 I
  57. " n0 q* O* ~$ d& S
  58.     USART_Init(USART1, &USART_InitStructure); //初始化串口1
    4 _3 E- l( Q& Y' c( a5 ?. @
  59.     USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
    3 Z5 N* R. R; b7 o+ e. T
  60.     USART_Cmd(USART1, ENABLE);                    //使能串口1" F, C9 z) m( y% g; k( J

  61. $ R4 G- K1 i1 _
  62. }
    5 _! }, Q' N* s% {3 B4 N/ I+ v7 Y
复制代码

$ ^, }3 R3 `5 n0 F' O* ]; _1 q. \初始化函数uart_init()上面的部分就是关于printf函数的相关设置,默认情况下printf函数是通过串口1输出数据的。, P% c0 U, p& E$ U" b7 Q  i7 y6 Q% A
假如我们现在要将printf函数重新定义到串口3上,那么就可以将uart_init()上面的一部分代码剪切到串口3初始化函数前面去,同时将fputc()函数中的串口1修改为串口3就行。) [6 t% _4 i4 L0 [
重新修改后的代码如下:) X5 ^* a' f6 H8 s( ]9 ^, e, Q
串口1初始化代码( y. ?. D4 d. F+ V0 ~
- h0 R. B* V0 }* m9 L; y

  1. - [& W/ b* W* F0 F% m" I$ j
  2. void uart_init(u32 bound) {
    7 {$ a% b1 I6 |' y  g4 `( b3 }1 m8 [
  3.     //GPIO端口设置) r9 ~$ ~3 o/ S! [% B/ c# T
  4.     GPIO_InitTypeDef GPIO_InitStructure;
    % R6 A9 T* B: F
  5.     USART_InitTypeDef USART_InitStructure;
    ) d  i( W- c  K$ B$ d  F; w" U
  6.     NVIC_InitTypeDef NVIC_InitStructure;: \6 g/ M8 ?2 E4 W; d6 {

  7. 8 F: r. ?# Y% [$ r) M% D6 d! }
  8.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);        //使能USART1,GPIOA时钟3 a& `* `) h+ j( i0 I

  9. ( C" x5 r. i2 N& H& z! S& n6 M
  10.     //USART1_TX   GPIOA.9% X9 l  \$ N5 e! H8 ^' Y, h0 ^
  11.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.95 }- P$ o" ?" n4 S; [& [: o' Y
  12.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    * r1 u5 A% y6 |" j0 a; w+ Q! a- A
  13.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        //复用推挽输出
    8 n( y( L$ ^. t
  14.     GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
    % O  R; R4 J$ ], v4 q% N

  15. , _' h9 t3 d! b9 b$ L
  16.     //USART1_RX          GPIOA.10初始化' L( \- r; y- v( Q' J1 u
  17.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA109 ?) v; W( ]0 m& N' H
  18.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入% W: g( X4 F  s: \3 `5 H# S7 |
  19.     GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10! o  N. p* v" d2 L1 }: e+ K
  20. 4 S; p3 {) b) q2 {0 M7 P: [
  21.     //Usart1 NVIC 配置% J$ s& w; k; g- m- o
  22.     NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    7 P: ?- r; `5 T9 o9 z$ c
  23.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3 ; //抢占优先级3
    4 K" ~. l8 ^1 w+ n4 c6 p  ?
  24.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;                //子优先级3' G) p1 W% Y1 F, m' c1 l
  25.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //IRQ通道使能3 J9 k4 _) T- b- ]4 J1 P  s! n
  26.     NVIC_Init(&NVIC_InitStructure);        //根据指定的参数初始化VIC寄存器9 ]! a5 Y! L0 L5 x* E6 T7 Y0 P, }  N+ C
  27. , {6 N% y9 J4 B" Z5 S! U! Z" C
  28.     //USART 初始化设置/ t, O! ~" v6 d8 L" y4 Z$ }

  29. ; n' u1 b  C  q# Y8 j/ B  C
  30.     USART_InitStructure.USART_BaudRate = bound;//串口波特率
      ?: B* ]6 d0 X
  31.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
    # `0 @) b+ Q* w; p8 a$ e
  32.     USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位/ u# h# j6 j4 m/ m0 K8 v, z* i
  33.     USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
    9 f% J0 b( X/ P6 P
  34.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
    ; t9 X( [: u: y0 `+ ~
  35.     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;        //收发模式* d6 t  ^. F4 O) B2 ~

  36. 7 ]2 F, p) `1 b
  37.     USART_Init(USART1, &USART_InitStructure); //初始化串口10 a% w; I/ @$ o) h+ `
  38.     USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断/ h* ^+ L4 P' z. S! p' z
  39.     USART_Cmd(USART1, ENABLE);                    //使能串口1/ k' @$ `  E1 T0 p. }
  40. " u! s' R! q* u
  41. }; x& ?2 ^; F3 Y; u# B$ k
复制代码

; M8 B8 K. m3 R- m4 t1 Y0 ]串口3初始化代码, e& u& ^  v2 U9 a$ I

0 C) `1 \7 P( I. [
  1. #if 1/ ?; m# c% j+ W3 D" ~, a0 h7 E
  2. #pragma import(__use_no_semihosting)
    + E% @7 [$ S* n# ^$ I
  3. //标准库需要的支持函数
    4 @5 `  g9 C' e  z) q/ w
  4. struct __FILE
    . ?: G3 B/ [! v  v3 N1 a
  5. {' q3 @$ _# Z) g* R" D4 F# n1 z, `
  6.     int handle;
    0 b/ c3 u7 X" r, r9 D, }' {4 c
  7. ; q- c; a) H% s; m  e( k* j
  8. };- V' e0 x/ b/ \0 x2 x0 Y8 \
  9. ! D- n: R8 [: {2 c' Y$ I4 a
  10. FILE __stdout;$ o% S: |+ C. ~7 ]6 A+ m, `* U3 y
  11. //定义_sys_exit()以避免使用半主机模式2 {: B9 }: a0 ?( G0 I( @- A9 A
  12. _sys_exit(int x)
    , _/ C2 [' j6 j6 W( Q5 i
  13. {
    0 h/ o  u+ F+ E1 n
  14.     x = x;
    2 Z& y) L1 ]- f+ O3 M1 M9 L% {# h; s* o
  15. }
    / W- m# g6 J9 R8 Q. Z
  16. //重定义fputc函数7 {3 M, m* t8 I- j
  17. int fputc(int ch, FILE *f)( |3 @* m3 z8 M. V# F9 R; z
  18. {) u/ t9 Q4 c1 i/ A
  19.     while((USART3->SR & 0X40) == 0); //循环发送,直到发送完毕
    ; n& |% U; R' x
  20.     USART3->DR = (u8) ch;
    : a. x+ B% b0 C2 ^& `
  21.     return ch;; u3 T2 W1 I/ Q# c2 i2 ~
  22. }
    ' D3 P' A) T7 [/ T, h' Q
  23. #endif
    - V! Y/ |+ Z, [8 x$ y  S& `3 X
  24. " A7 e/ G9 q2 X2 x( a8 y
  25. * H8 p# I" d  b$ F% [6 H7 u8 U

  26. 8 r) C* k0 X- @  @

  27. 0 {% d4 h7 v6 J+ X+ z
  28. void  uart3_init(u16 baud)
    6 g& G/ }+ E7 y# Q  D
  29. {
    4 b# {0 m+ \. U( z1 g
  30.     GPIO_InitTypeDef GPIO_InitStructure;
    - Z0 ~0 b$ j+ z
  31.     USART_InitTypeDef USART_InitStructure;# |+ x7 a2 v+ \6 C: C+ x: H
  32.     NVIC_InitTypeDef  NVIC_InitStructure;* N5 R  o' |* h$ @* z2 n# A4 {
  33. , Z$ r# g0 t0 c0 S. o1 {& A
  34.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    ( o; g. b% d5 D0 l7 M, c. B
  35.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);  q: u$ s' m/ ^2 S) P

  36. 1 j7 _0 j% q0 ~4 t2 R2 z1 m# d: K
  37.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;# n) ?9 h9 k% Y' W* @) F
  38.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;4 s% _+ i6 d. J: `/ \; z9 w- e% N
  39.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;4 s0 J( I) H; D7 Z* ]2 H# w6 F7 S
  40.     GPIO_Init(GPIOB, &GPIO_InitStructure);
    9 j# A- Q0 H/ o$ g( Z1 b

  41. 0 n8 p' e3 h+ q
  42.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    , x, v( k6 F0 M1 I
  43.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    5 }/ N: I+ x1 B- z2 u7 h
  44.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    " v$ m4 n1 V, y( g
  45.     GPIO_Init(GPIOB, &GPIO_InitStructure);: F5 x, {! _  C
  46. 0 `4 g3 m* x1 G  ^
  47.     NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
    ; V+ G/ w& P# H; O) e
  48.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
    : y. y* O9 P) P9 N' W7 a4 u
  49.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;
    6 R: b" T* h9 q* P) D( b
  50.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;! N5 a% v; c/ w; d* }; E  a

  51. & s) K6 e/ c' P% m( d
  52.     NVIC_Init(&NVIC_InitStructure);
    : w* L% }4 ?; ?: @& q8 N- d, g
  53. $ X0 n; x0 X3 C4 d
  54.     USART_InitStructure.USART_BaudRate = baud;
    0 t5 A1 O! _# S2 @) u; g0 O
  55.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    + R" [  `( O8 @5 t* {! p1 _5 c
  56.     USART_InitStructure.USART_StopBits = USART_StopBits_1;
    ; N! B: A' x. S5 x# b6 R; }- Y  x
  57.     USART_InitStructure.USART_Parity = USART_Parity_No;
    / W4 l0 f1 \$ e: i
  58.     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
      t1 \  |9 S: L( F1 \! ^* \& j
  59.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;) c$ ]) m* W3 N' O! r
  60. & [! [* o% Q# {# s' E
  61.     USART_Init(USART3, &USART_InitStructure);4 G% e) j# M9 C0 f% a
  62. % c  C6 u2 }: f& g$ Z) [' U4 X
  63.     USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);2 ~( M# G3 W5 A( O; w$ l
  64.     USART_Cmd(USART3, ENABLE);4 j, {3 ?- x, k/ S
  65.   {) i; }0 }; {/ @6 G- Y: ~4 c5 d
  66. }- \0 z/ \' i5 h
复制代码

# Z; t8 a/ q: E- G; e' e9 t2 W修改后再使用printf函数时,就可以通过串口3输出了。8 r. b9 J0 x/ ~+ J7 R
关于printf函数的设置核心代码如下:
: u/ p- e1 I% J! K8 W0 M$ f
) Y; E' N2 o! u
  1. #pragma import(__use_no_semihosting). Q* n! O" e  D, P" ~) B+ ]+ O
  2. //标准库需要的支持函数; \; i+ f) F9 V% u. c6 y" g' Y
  3. struct __FILE
    : [  s4 j' }( W. H# ~
  4. {  W3 l$ S$ n9 P, D; ~; U
  5.     int handle;3 F+ F3 P: ?' s: Y7 s* d
  6. " e/ ?7 p( j4 w
  7. };8 D: g) m) I6 F$ G! d/ B

  8. - F1 i2 D% w1 [" O% w/ T7 E
  9. FILE __stdout;
    - f& D, X5 B( l: r7 ?+ F8 }
  10. //定义_sys_exit()以避免使用半主机模式
    4 Q+ F2 Y4 p2 E
  11. _sys_exit(int x)
    + }# P! g/ e/ C2 n8 p+ F; Q* Z
  12. {
    3 w: L* S. H! L( w
  13.     x = x;6 Z: K6 \. r* j2 e6 A; H
  14. }
    4 y  |/ S! ]6 a* C, }' e6 s  Y
  15. //重定义fputc函数, a5 [1 `% j. y& f4 m; p+ a* M
  16. int fputc(int ch, FILE *f)  _3 v) e/ h. c# Q2 P, [
  17. {
    9 F. C% Q: n5 G  x7 y$ [8 q
  18.     while((USART3->SR & 0X40) == 0); //循环发送,直到发送完毕
    2 |, H7 x1 \2 `9 n- ?' ?! U0 C: c* l
  19.     USART3->DR = (u8) ch;
    $ T$ ~7 P% Y/ B4 p" X8 g
  20.     return ch;  K( I- C  I. G) [! u4 C- x
  21. }
    " x. x1 Z" T  N6 C9 o
复制代码
: h& u  o8 s% g6 |& I  i, z; h
通过上面几个函数可以看出,要重新定义printf函数的输出串口时,只需要修改fputc()函数中关于串口的定义就行。' K/ A3 H0 ^( B; w9 @

" C/ t  t% x/ M$ s, ~
, F$ {! _6 N* D7 T4 d2 f, Z" }7 J7 K
收藏 评论0 发布时间:2022-3-22 13:00

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版