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

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

[复制链接]
STMCU小助手 发布时间:2022-3-22 13:00
在调试程序的时候经常需要使用printf’函数来打印相关调试信息,在STM103单片机中printf函数默认只能在串口1使用,有时候串口1被占用了,想要输出调试信息时会比较麻烦。现在就总结一下如何在其他串口上使用printf函数。这里使用正点原子的例程来做说明。* ~( L  ?+ Y$ u- G' j! X
默认串口1初始化代码如下
1 [0 T' W: {3 v2 V
1 V9 N. M2 n5 |; e$ \, q
  1. #if 10 E, Z8 o1 g: ^4 l3 B
  2. #pragma import(__use_no_semihosting)# h3 Q4 @8 B) C5 H# Z( J! _
  3. //标准库需要的支持函数
    $ z) {" C8 i& P: h' e
  4. struct __FILE
    & W0 e5 f" E2 ], N" o8 l, `- O
  5. {$ w9 L" ^4 j, |! Z: I! X6 L
  6.     int handle;
    8 T* M7 \8 W& y" U" w
  7. };8 c+ U7 e' }8 r! z
  8. FILE __stdout;
    9 x9 f; A; A( S4 `0 w2 S# q3 U
  9. //定义_sys_exit()以避免使用半主机模式
    ( n+ u3 C4 R! M9 g: t$ C
  10. _sys_exit(int x)
    1 c/ P" v: \  u) p0 y6 a. M
  11. {
    , x3 H8 p$ E! J2 L6 Z& w
  12.     x = x;1 X/ O5 [- F3 j+ F
  13. }
    + J2 l/ ^- m+ }1 Q4 B5 @* v
  14. //重定义fputc函数
    3 O! k$ H/ O& u7 ^. i4 j" Z
  15. int fputc(int ch, FILE *f)
    . U! M: G1 `2 g6 x
  16. {
    % ~# [1 g- t  b! _3 U2 r9 N
  17.     while((USART1->SR & 0X40) == 0); //循环发送,直到发送完毕. j) p7 j" B) G1 a4 y  M
  18.     USART1->DR = (u8) ch;8 |* }; u, H4 d
  19.     return ch;
    7 f& K3 L% {" ~7 j6 G
  20. }
    : c) t: J# N9 ?/ D; s( J
  21. #endif' e% G* b5 T- d) Y  O

  22. $ \( \% m; p% {( \% p1 I0 S
  23. void uart_init(u32 bound) {
    1 f% I" x- B. q+ I
  24.     //GPIO端口设置
    / _3 P: R" B0 a3 v0 S* @, i
  25.     GPIO_InitTypeDef GPIO_InitStructure;) v: J# T4 l# l) b2 O5 B* L( D
  26.     USART_InitTypeDef USART_InitStructure;
    3 D& ?2 C8 t  g# G2 V. L% U/ h
  27.     NVIC_InitTypeDef NVIC_InitStructure;# N6 q. m) H  K

  28. # K/ a) |+ E* P4 B8 V/ U4 p  f
  29.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);        //使能USART1,GPIOA时钟4 a( r& x) y2 E2 A8 K+ G
  30. 6 y% s9 y: E5 I! x; H$ ~5 ^  j7 u
  31.     //USART1_TX   GPIOA.94 R  G) t& `' a' J
  32.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.96 v: ^* w* Z% j6 v  w
  33.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;1 r0 `( }9 w/ I  f5 O7 Z
  34.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        //复用推挽输出! _" y/ |; }# `  g& u1 {' |+ _9 X
  35.     GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
    + s" m3 m$ Q8 d8 ~# l/ K. Z

  36. 0 Y/ q6 j: M2 N. X9 O- W
  37.     //USART1_RX          GPIOA.10初始化7 [8 h6 ]. m3 ^( c4 b2 T% i6 z; O
  38.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
    ! G3 s+ w2 P1 N% ^
  39.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入- U  I' P  X! w# T4 _
  40.     GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
    3 s4 `: `3 o7 v+ a+ B6 z

  41. * c( {2 Q/ l& ~9 e" a; C" Z9 K
  42.     //Usart1 NVIC 配置
    # L& q' L5 v" d6 k- H5 l
  43.     NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    " l3 t8 P4 ^0 G. U& D
  44.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3 ; //抢占优先级3- o  q6 K/ b+ j! D5 o& [% j
  45.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;                //子优先级34 C! v" `/ S; g2 C* B; x1 o' J
  46.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //IRQ通道使能
    ' w3 N- A+ i7 h/ R
  47.     NVIC_Init(&NVIC_InitStructure);        //根据指定的参数初始化VIC寄存器
    1 T7 [0 l5 E, X+ W1 q& d( q

  48.   E9 _) ?3 t6 ~& W) n1 n
  49.     //USART 初始化设置8 ^- l$ b) D1 f7 L. r+ b9 H% `" b

  50. / `" u. H) M$ i" E" \9 B& u
  51.     USART_InitStructure.USART_BaudRate = bound;//串口波特率$ a5 Z3 _5 m/ M, A: B$ ?5 c
  52.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式' G* H& G! B" l+ m
  53.     USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位' C; ?. F. c, g* d& w! h
  54.     USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
    . E* M$ C8 C6 J
  55.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
    # E4 o! t5 g! L/ L* g
  56.     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;        //收发模式* u' {7 A# _+ R; o4 A
  57. & B" H0 z/ I$ k& w
  58.     USART_Init(USART1, &USART_InitStructure); //初始化串口1
    ' m) |0 o. X! v0 e8 f
  59.     USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
    . z% n. \6 j( w5 l3 G% a
  60.     USART_Cmd(USART1, ENABLE);                    //使能串口12 ]5 x8 R1 `, |9 u# X( U, D
  61. 5 W, x3 j' Q; U
  62. }
    - I) T+ B" k( _; c& a
复制代码

  O$ t. W4 s9 b" R9 @( |" o9 r初始化函数uart_init()上面的部分就是关于printf函数的相关设置,默认情况下printf函数是通过串口1输出数据的。
* r" v# F; Y: u3 S  \, N% u假如我们现在要将printf函数重新定义到串口3上,那么就可以将uart_init()上面的一部分代码剪切到串口3初始化函数前面去,同时将fputc()函数中的串口1修改为串口3就行。0 O& l" O; ~2 T5 ~# O$ R- T
重新修改后的代码如下:4 e3 {3 t) p/ w1 i4 S) _6 M* ]
串口1初始化代码
* R( b% p1 Q, G8 h; R* Y
* K( P* C. r* h8 u% ?9 X
  1. 7 ~/ ]. X& _6 @5 M% ?% h
  2. void uart_init(u32 bound) {) K( c: Y+ U  h  @$ P
  3.     //GPIO端口设置
    & K3 e* c0 H2 [/ i6 s, l, z: z
  4.     GPIO_InitTypeDef GPIO_InitStructure;) T  N' [% J6 q) B
  5.     USART_InitTypeDef USART_InitStructure;- L) _/ U$ p* I2 B5 }6 S/ x
  6.     NVIC_InitTypeDef NVIC_InitStructure;8 j6 D0 a- F+ `
  7. , o1 ~2 C4 m: Z. R9 E- g
  8.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);        //使能USART1,GPIOA时钟& h9 ^% _0 Z3 y3 y( y) z

  9. 6 g2 N" g' [7 }; J6 h4 L; |+ ~
  10.     //USART1_TX   GPIOA.9
      l. H, m( ]% q" G, o; _( M
  11.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9! K5 R! C" I0 k: W4 ~# }- |; W4 r6 N
  12.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;/ G: M  A+ l' D1 K) J
  13.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        //复用推挽输出& ~! Q3 |5 Z% I' D
  14.     GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
    7 t: V6 c+ S) ]* u# R7 N2 W

  15. 8 f+ T8 D; u! n# [3 y: B: g6 n
  16.     //USART1_RX          GPIOA.10初始化
    8 T; l& m- H3 P* Q- ?* ~+ O0 f+ {
  17.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
    0 w8 j7 R; a/ z5 g, Q, ?7 [
  18.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入1 O  \# m1 t, g5 Z1 f: R
  19.     GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10' f+ S4 ?1 ?, f! ~
  20. - A- [7 S8 A1 I; q) ?9 K" v
  21.     //Usart1 NVIC 配置
    ( N# s" v, `7 L5 c$ ~: [
  22.     NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    . _2 _' ]. \+ c& ]1 s
  23.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3 ; //抢占优先级3
    . L- l$ V$ F0 O. T
  24.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;                //子优先级36 G  M3 G1 r5 i8 o, Q  y# P
  25.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //IRQ通道使能
    " J7 p- R$ g/ U, l8 Y9 q
  26.     NVIC_Init(&NVIC_InitStructure);        //根据指定的参数初始化VIC寄存器' [7 W- K2 X; l! @5 E
  27. 7 a8 T4 u, L8 T1 ?6 u2 G
  28.     //USART 初始化设置
    ' E9 L2 I& O1 @8 \( Q( k
  29. 5 E0 x/ ~% ~4 ~! W7 @0 T
  30.     USART_InitStructure.USART_BaudRate = bound;//串口波特率
    , U# P& [3 B6 r- E4 G( Y; c
  31.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式8 {& h1 i9 X: F5 N' |
  32.     USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
    9 s2 d( ]% z+ F: Q5 x' A# u* _
  33.     USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位# M9 b, @) k0 F# M6 j5 M- i) U
  34.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制+ H4 w5 A" w* k8 l/ E4 I/ i8 z
  35.     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;        //收发模式
    ( [3 s- P7 v2 Q* p! V* E

  36. * T8 j( K  [$ u  B3 m6 l
  37.     USART_Init(USART1, &USART_InitStructure); //初始化串口1, i' v/ H$ R8 n' f' O
  38.     USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断9 ]5 r9 J% v9 S1 X- l
  39.     USART_Cmd(USART1, ENABLE);                    //使能串口13 [9 g, o+ Z4 s) N5 u
  40. * b& G9 |: I7 e$ {( D
  41. }2 w/ p! U$ x, [8 ^1 z0 E6 o
复制代码

$ H" o+ [& \) F/ m  h# i串口3初始化代码3 x6 _. K; E! e- Q

: N: s! X3 K0 }* _: I- h* ~) j$ p
  1. #if 1# m' u2 d& z/ l& M4 @% x
  2. #pragma import(__use_no_semihosting)
    / R; y* I. @" \+ s! U5 p/ x
  3. //标准库需要的支持函数6 q2 S* w1 _' _: X) S
  4. struct __FILE
    0 ?- v; `0 X* t+ `( Y
  5. {
    - Z, m$ m) t- m+ B7 n2 L, k
  6.     int handle;  I3 O- ]% b! a& n! a/ ^5 e
  7. - ^) H* ]& W6 L) U
  8. };0 M2 |5 A* v1 e& n: \; ~' `
  9. 2 f5 L9 {2 [: X. I( \
  10. FILE __stdout;
    6 }9 |6 K/ o, h- T
  11. //定义_sys_exit()以避免使用半主机模式2 \* P5 M3 \: `/ \$ b3 G
  12. _sys_exit(int x)
    8 D5 ?$ n2 R/ v) v
  13. {5 r' B. X$ ]5 ^. K' {
  14.     x = x;# P0 d# `* o8 U: b0 T
  15. }2 I( ~# V. k/ j6 E3 M' ]
  16. //重定义fputc函数
    6 s7 `- K7 J  J$ h
  17. int fputc(int ch, FILE *f)
    : s+ I" _! p3 T' ?1 ?/ M
  18. {
    & \* Q) m  \* j1 b7 e' F+ M+ p( E
  19.     while((USART3->SR & 0X40) == 0); //循环发送,直到发送完毕
    ( G3 z% Q( I$ `& v( P! F- H
  20.     USART3->DR = (u8) ch;5 p3 B% P, i0 j) B7 r1 v& J/ F
  21.     return ch;
    ! R! \- p- R* A+ D1 w
  22. }
    - v( o" `$ c9 A. o# S2 \
  23. #endif6 g" o1 C1 E8 {7 [

  24. # t) H% |. r7 \3 G/ H7 N

  25. 1 Q# u) \0 Y+ Z: E! `0 w4 w2 D
  26. / K/ L8 B7 Y' J1 V; \3 X' f" L
  27. ; a2 t* r. v7 k' ?
  28. void  uart3_init(u16 baud)& P. x0 [9 t2 r$ C" k
  29. {) H* \, b8 y0 c$ U: U. {
  30.     GPIO_InitTypeDef GPIO_InitStructure;% @# L! O' R) _: ^5 Z" c6 U
  31.     USART_InitTypeDef USART_InitStructure;
    8 S* |; g4 a/ R! ~6 i
  32.     NVIC_InitTypeDef  NVIC_InitStructure;7 H& t! S: e7 b: V- W7 S2 w

  33. 4 ?9 f/ I2 S# A  \, S, Y
  34.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);, B5 U! Q$ V9 q9 O1 j$ a% w" E
  35.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);3 e* c9 p" V. e+ ?% c8 s5 Z

  36. : R/ e: m/ ]9 S9 H. Q' ?5 h! F
  37.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    8 F+ Z; i) ^  P$ V
  38.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;. G) D7 x9 W6 v6 A& |* b1 B
  39.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;% M4 U8 G4 i- e/ o
  40.     GPIO_Init(GPIOB, &GPIO_InitStructure);" Z( e( I7 N( j2 q& }; \9 h) K

  41. ; b/ h) P" H5 D( |5 P. N% ]; ]
  42.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    6 _1 c3 T5 X2 M$ x
  43.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    , v3 L4 I8 x$ P/ f2 p
  44.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    + ~5 x' e! A8 {9 k
  45.     GPIO_Init(GPIOB, &GPIO_InitStructure);' u2 L. \( S2 r

  46. 9 F, K% Z, e7 X* t1 ~8 c
  47.     NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;7 o0 ^% H; g  P
  48.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;6 z# R1 A& v! V0 S6 Z
  49.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;. R: ^' f9 r. m# k+ D- q
  50.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    ( y+ s; o' d0 v, S4 j7 {

  51. ! W- N4 z4 y# a1 x: g: X" Q
  52.     NVIC_Init(&NVIC_InitStructure);
    & A. a3 C3 b8 ?' r' l
  53. 3 c" [( V0 S6 q- a  m6 N7 [( p3 ~
  54.     USART_InitStructure.USART_BaudRate = baud;
    * I1 n6 t& b3 E# N& }
  55.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    * B+ E5 j- O, k( t
  56.     USART_InitStructure.USART_StopBits = USART_StopBits_1;0 w' ^9 Z4 |0 z* s" @. d( d: ~
  57.     USART_InitStructure.USART_Parity = USART_Parity_No;* h4 w) F* R# Y# {9 g. W* z. p
  58.     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    ! i( @" R3 |2 r
  59.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;: L2 M5 G' U5 b$ S2 U) E
  60. 0 {2 p! `; v/ R4 n7 N! Y3 U
  61.     USART_Init(USART3, &USART_InitStructure);
    : Z3 r' p# e8 w+ R- ]$ ]
  62. 0 Q' y+ L0 e8 E# k2 g
  63.     USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
    ! \" S( v; H. s/ b5 v
  64.     USART_Cmd(USART3, ENABLE);
    0 Q) T) t' a( L

  65. ! f2 s/ ]1 K" C. ^, }) U9 w# q' @
  66. }
    " e7 \% x5 u& B1 y/ \% E3 J5 k
复制代码

& g# ~& I+ O0 S( U  X" C9 T修改后再使用printf函数时,就可以通过串口3输出了。
9 S( F+ p- F9 E% ]关于printf函数的设置核心代码如下:1 G$ L7 ?' O& c8 {8 Y1 N* a

- ^% O6 F. m0 l+ i8 ^: q
  1. #pragma import(__use_no_semihosting)2 d" g6 Q& ]% C- y
  2. //标准库需要的支持函数
    & v9 r' F6 u+ S7 G9 s2 k0 ?( j9 M2 ~
  3. struct __FILE$ [; x6 ?/ A1 X
  4. {. k" u5 Y0 ?8 J& c, {" y4 x/ ?
  5.     int handle;' [) c1 s) j% g4 s( G, X
  6. ! u. g4 Q& A) R6 G
  7. };* @6 o; b* a8 z; F' ]& [& D
  8. # a. F# k- J7 B  l
  9. FILE __stdout;. V! @5 Y' p- [: e  z/ |
  10. //定义_sys_exit()以避免使用半主机模式7 I2 y' Y! _+ @9 D% r# d; J9 q
  11. _sys_exit(int x)9 x% T' y( C; @0 N) M8 H. z
  12. {. P5 x+ V) L3 _6 T7 f
  13.     x = x;
    , Y0 q9 v/ Q  S# J* I. F, ]
  14. }% |7 S1 o6 c% C9 v# {( m
  15. //重定义fputc函数$ t0 l4 b2 c' f% Z. w/ y8 y, Q+ y
  16. int fputc(int ch, FILE *f)
    5 }$ M% T7 Z" b+ F1 W) n, u! ~
  17. {
    1 [' V+ @" D: _0 W
  18.     while((USART3->SR & 0X40) == 0); //循环发送,直到发送完毕
    , B6 f5 P1 Z0 }4 b. p
  19.     USART3->DR = (u8) ch;
    / M$ M0 I/ L0 v
  20.     return ch;
    ; o3 n' e$ J& Q  {! k9 a5 ]: `/ U
  21. }/ b- i7 a  ~' ~  C" |$ B
复制代码
5 d0 Q" y! [/ U
通过上面几个函数可以看出,要重新定义printf函数的输出串口时,只需要修改fputc()函数中关于串口的定义就行。5 ?0 {4 R# d, h: g$ a
& R# d/ _' I) q$ @1 y

' @. u5 @7 u2 f' X8 s6 I. O
赞 收藏 评论0 发布时间:2022-3-22 13:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

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