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

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

[复制链接]
STMCU小助手 发布时间:2022-3-22 13:00
在调试程序的时候经常需要使用printf’函数来打印相关调试信息,在STM103单片机中printf函数默认只能在串口1使用,有时候串口1被占用了,想要输出调试信息时会比较麻烦。现在就总结一下如何在其他串口上使用printf函数。这里使用正点原子的例程来做说明。
. `/ C2 e$ p! X$ d+ p- E! s默认串口1初始化代码如下
0 I- t/ ~" p5 ~* a: I( i! d2 i4 s% f0 v
2 Y& \1 Q+ z) n8 i! t+ l9 d
  1. #if 11 E- |; K/ P. e. W0 k
  2. #pragma import(__use_no_semihosting)
    ' U0 E, }3 T$ o
  3. //标准库需要的支持函数; |% p4 |2 i. {. |' r4 b
  4. struct __FILE: h& _% [: \: P: m
  5. {
    7 R6 m$ Y. B: d2 R' P
  6.     int handle;4 c2 l5 E. I0 y- ~) v& a+ P
  7. };: J! u7 [4 c; k1 ?# a' h9 V: }
  8. FILE __stdout;4 W$ I+ ^! {; N
  9. //定义_sys_exit()以避免使用半主机模式) c3 {, L4 \' v! o, h
  10. _sys_exit(int x)
    5 S2 T: B# `9 X  i, v# O  I
  11. {8 ~( B; U) r8 h( l0 ?! N) C
  12.     x = x;
    ! G3 ^2 p2 A1 w% @' D9 D3 X
  13. }
    / o6 u$ t5 R+ t7 ?. v- Z$ d
  14. //重定义fputc函数
    " S5 e  V  z" \9 a) ^' T$ C
  15. int fputc(int ch, FILE *f)( Y' }2 U0 L2 `: C' h
  16. {
    2 ?% a( e  j# f
  17.     while((USART1->SR & 0X40) == 0); //循环发送,直到发送完毕
    ' ]4 {8 r( c4 [, ?
  18.     USART1->DR = (u8) ch;
    3 _& Y5 v- d. U1 B  s
  19.     return ch;
    7 V$ q8 q: Y; T' L' Z/ ]
  20. }+ z0 O8 f! Y' Q" q8 M
  21. #endif! J0 A; T, d4 o  s! _5 |% |) p
  22. : x! C$ q; w  m, M' W
  23. void uart_init(u32 bound) {/ I3 _+ M! J9 Y: X) |
  24.     //GPIO端口设置
    , G% k- n$ B6 ^7 M1 D0 a/ s( E
  25.     GPIO_InitTypeDef GPIO_InitStructure;
      Y( m1 S- S) Z; }
  26.     USART_InitTypeDef USART_InitStructure;$ ^1 x! Q. h  H9 t
  27.     NVIC_InitTypeDef NVIC_InitStructure;
    8 F# N3 n( |9 c

  28. 7 y/ q/ H: r1 |$ O, Y/ Q  @( \
  29.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);        //使能USART1,GPIOA时钟
    & z# u! ?6 V9 y
  30. 9 \. K+ F( e3 w/ o! M' r
  31.     //USART1_TX   GPIOA.9* G( |8 X" R# u$ W/ W
  32.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
    8 j4 c& v1 T7 l
  33.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;- [; d7 s& H' H* p0 p: {$ h) k) F
  34.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        //复用推挽输出
    4 E6 b2 \: Z7 x, @; j
  35.     GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9( m6 `! l  ^/ M1 k- |2 t4 e& x

  36. 0 E# p' ~" a9 T( n6 C  s& O& W
  37.     //USART1_RX          GPIOA.10初始化" q2 C) l* i3 k' p2 E
  38.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
    1 m9 X( v6 O4 R- K' u: y1 t/ w
  39.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入$ @* K: W! m9 d% ?1 t# v
  40.     GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
    ' K$ w+ ^( [6 h# @9 \5 T; U

  41. 9 B: X% f8 ^5 _) l& j8 P
  42.     //Usart1 NVIC 配置
    1 `  Z! `! Q# r& t, \& H* v+ A! v5 H
  43.     NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
      M4 y1 H7 b' ?( F
  44.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3 ; //抢占优先级3/ @8 m! V/ h! @+ F
  45.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;                //子优先级3% Z2 ?* ?$ P  b' x
  46.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //IRQ通道使能. Q( h% x4 K% K% \& E
  47.     NVIC_Init(&NVIC_InitStructure);        //根据指定的参数初始化VIC寄存器
    . H! ?8 t7 y; g3 z/ i: s
  48. . O4 l& o! e9 {( V) b3 T/ K9 ^) f
  49.     //USART 初始化设置, E9 R& k# G' i; t3 ?2 ^5 ^

  50. & W. ]5 F& C0 e- \
  51.     USART_InitStructure.USART_BaudRate = bound;//串口波特率
    + i1 `% Y, c" e0 o8 q9 h: p: d! S
  52.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式: |. y: e. W) n( C3 R( U% a
  53.     USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
      k8 c! J; H* g7 U9 d
  54.     USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
    7 m9 {! a3 j, y8 K7 _
  55.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制  b+ {( o" d8 i$ L6 D
  56.     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;        //收发模式) D( _) ?# f3 ~+ N% G# Q3 z. Q
  57. , t' y5 p2 G' S$ m/ c! k0 R! s+ J
  58.     USART_Init(USART1, &USART_InitStructure); //初始化串口1! c" ?/ h8 M/ u, ]9 k1 `
  59.     USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
    + e  G5 T. y. {
  60.     USART_Cmd(USART1, ENABLE);                    //使能串口19 m8 K6 S& ?1 L1 I: a
  61. / H2 B% k7 a5 f8 n7 l: h
  62. }
    . n0 q8 E* C, [! U. x% M/ z  ~
复制代码
: a3 U" ^% [* |8 m( ]
初始化函数uart_init()上面的部分就是关于printf函数的相关设置,默认情况下printf函数是通过串口1输出数据的。" L8 k2 Z" |7 Y* h! y
假如我们现在要将printf函数重新定义到串口3上,那么就可以将uart_init()上面的一部分代码剪切到串口3初始化函数前面去,同时将fputc()函数中的串口1修改为串口3就行。
" \( N) d; w  F2 O& W重新修改后的代码如下:
) {. Q4 k  W' C" Z" x串口1初始化代码: H4 C3 b: d; K) [4 Y

) O7 t7 z9 H* \( Q& @2 Z2 F* ]) Q
  1. + z( Y3 g' g' H; @1 `6 j
  2. void uart_init(u32 bound) {# E& b0 B3 W' [4 q5 H. O5 s
  3.     //GPIO端口设置9 ^& T8 w1 Y5 H* ~9 K; R
  4.     GPIO_InitTypeDef GPIO_InitStructure;
    + N7 _! B2 o" ?# G0 F# u% h* Q: U
  5.     USART_InitTypeDef USART_InitStructure;7 ^& M4 ]5 u* _2 z/ `
  6.     NVIC_InitTypeDef NVIC_InitStructure;% y) {, n5 H0 \+ O8 A( ~7 A! {
  7. 1 N* W6 |/ N& l( F) x2 r
  8.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);        //使能USART1,GPIOA时钟) ~# |5 X4 _' G, c: I* v

  9. 4 v0 k' k% t2 F: R
  10.     //USART1_TX   GPIOA.9
    # q% J2 a, m' Z+ M5 u+ w  @
  11.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9. u8 q" V! y, _. X
  12.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;2 k: C9 V, u  i' e; e! `
  13.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        //复用推挽输出
      i6 I  C9 ~! J4 T) T. R# j2 Z
  14.     GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
    ' D9 D1 {+ z% v( i; o' R8 |8 }/ [# j

  15. # @  O$ b3 b& z: [* ?
  16.     //USART1_RX          GPIOA.10初始化
      l6 Z2 d# `* x6 b2 |' [
  17.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
    * {3 _4 W6 I& [& X
  18.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入) X7 u" a8 e0 T* J
  19.     GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
    : Y/ `$ c9 h/ M+ Q% Z# H! `
  20. 6 w7 E9 w$ L3 F/ g/ Q, g
  21.     //Usart1 NVIC 配置  L4 k7 d1 F+ N: k1 t
  22.     NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;& S6 H: g& a5 n8 b- c" C  \
  23.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3 ; //抢占优先级3
    7 _! [- |- F1 _# S1 Y1 Q- G: [
  24.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;                //子优先级3
    * s& E. L* w1 _0 X- X4 H* h5 Y% H
  25.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //IRQ通道使能
    8 g! X; S/ T1 f) F3 @# b% K+ U
  26.     NVIC_Init(&NVIC_InitStructure);        //根据指定的参数初始化VIC寄存器7 N- U8 x, y" m' _$ ^

  27. + L' q% S* `) p+ l
  28.     //USART 初始化设置* @! e/ B8 ^& E5 l: X
  29. % f1 _" V3 N. q; Z* p
  30.     USART_InitStructure.USART_BaudRate = bound;//串口波特率
    9 O. ?% s% c3 ^6 [$ N& f. G
  31.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
    % r* N" \/ W# a0 m  }! A  ]1 s1 L
  32.     USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
    $ Y% J4 v3 h4 e7 n: n
  33.     USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位- u, I$ w5 r: n
  34.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制$ k1 o5 {: v6 W3 Z! C
  35.     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;        //收发模式- W3 g% v1 i& a$ S! i. d

  36. 7 E' }; z- m8 v1 C3 f* ~# I* _7 X
  37.     USART_Init(USART1, &USART_InitStructure); //初始化串口1
    % j' j" _0 E% |4 {
  38.     USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
    - A" _2 N$ F3 ^! p$ B( X) z
  39.     USART_Cmd(USART1, ENABLE);                    //使能串口13 r" ^8 p, T# N& v8 v9 K. {* V& k

  40. 0 n0 D! B2 |: {- E, i3 K
  41. }9 U* X$ l& T5 \: N: E+ I6 e
复制代码

) l: n3 d" R) d  t  g串口3初始化代码
' t' Q* n8 q5 v) d0 {
0 k; O3 L/ ^$ p7 F
  1. #if 1$ [8 |( q4 y; k
  2. #pragma import(__use_no_semihosting)
    : h! m3 w( W3 d# Z" P
  3. //标准库需要的支持函数
    , q5 X$ H) F( t7 b8 G
  4. struct __FILE
    6 M( l# P6 ]" R* h9 V, s
  5. {
    ' c+ x5 t1 n! X* F
  6.     int handle;0 Q: b- ^! `$ Z! X4 }* p& o, A
  7. 6 ^1 o8 Z6 n! y1 K! B0 j. |
  8. };9 T# M5 V5 _9 c' j# H' L! Y& \% Y$ ^
  9. 5 _6 I# l% L' x$ o; K
  10. FILE __stdout;
    7 k  O: |( m6 d; c- S
  11. //定义_sys_exit()以避免使用半主机模式; ~5 Z8 p/ y* B1 n' M) E
  12. _sys_exit(int x)4 T! P2 w# n- u* g. V1 m3 e3 ^
  13. {
    9 F. u" @3 M1 ^8 P$ U
  14.     x = x;
    ( ]6 S1 \7 D) {5 X/ L) N7 m7 L
  15. }5 F0 `8 p  M) Y# z$ x! i1 I
  16. //重定义fputc函数/ m7 t( r+ ?: a
  17. int fputc(int ch, FILE *f): U8 W( O/ I, K/ ~
  18. {! Z2 u3 ~% ?& @, T0 m) ~
  19.     while((USART3->SR & 0X40) == 0); //循环发送,直到发送完毕
    2 ?4 v6 Y9 q: O" w
  20.     USART3->DR = (u8) ch;
    / F; w. g1 g! _: _
  21.     return ch;" [* ]$ R% r$ l5 s( v9 A
  22. }
    4 s9 X) ~9 h6 O4 d9 l/ e+ l
  23. #endif
    % b* P" _, }7 m/ b2 u

  24. - E+ [2 O9 {( k/ |
  25. 4 y# Z/ U" ]4 D# ?+ F* I- i

  26. 6 m4 Y% t8 M; b, K6 V

  27. 9 y/ d, s' W( z7 d. v; `
  28. void  uart3_init(u16 baud)
    9 l; ~3 X) E8 [6 e
  29. {: G0 [. i1 @* X. L0 }7 P# g; T/ q) |
  30.     GPIO_InitTypeDef GPIO_InitStructure;
    / d! I1 c5 z- @
  31.     USART_InitTypeDef USART_InitStructure;4 k0 r3 }& K& E$ [' N
  32.     NVIC_InitTypeDef  NVIC_InitStructure;
    / z5 g. Q% e  o! x* P

  33. + T$ e2 U- h9 h6 ]! f' G4 p) l
  34.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    & C+ S3 W, Y7 ?1 x2 f5 D8 K
  35.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
    5 V6 }. K! U- Z' c# K6 R
  36. ) }' c" w& Q' m% W5 P% q
  37.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;' c2 I2 j& d! }& Z; A4 L* w
  38.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;/ y! t1 W( t* W+ {! @9 D
  39.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;( l; W5 Z  B; B5 Y
  40.     GPIO_Init(GPIOB, &GPIO_InitStructure);
    2 \% `; i1 J. Q* V1 Y
  41. 1 E9 }: e/ l) ], `7 X3 }
  42.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;+ k, M; U. u7 u% p3 ^$ q0 L
  43.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    0 D! x& q; ~% F7 D- w
  44.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;; f- h2 W5 g3 E0 L8 B  r' ]/ r( J# B
  45.     GPIO_Init(GPIOB, &GPIO_InitStructure);
    3 Q5 s$ s/ q5 b" _, O4 o

  46. ! @2 g# d$ t( V# U" e$ E, B+ l
  47.     NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;$ n: t5 I' x) @; @& y/ @
  48.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;; h! g5 Q+ j1 w0 z5 J
  49.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;3 v) d1 `& v" Y2 t9 H$ ~6 @
  50.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;* _5 `: d3 J6 x; k6 l' u

  51. 8 |  y1 x- h3 k" t
  52.     NVIC_Init(&NVIC_InitStructure);/ @1 H; J9 E% U1 g+ ~! ^; _
  53. ) [; a) ^) K/ a3 I6 b4 g% g
  54.     USART_InitStructure.USART_BaudRate = baud;
    9 o) a- {! Z3 c, i+ m
  55.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;7 `' F0 H  e) N$ \8 L3 ]* Z
  56.     USART_InitStructure.USART_StopBits = USART_StopBits_1;
    - d% V% E- e, o/ `2 k
  57.     USART_InitStructure.USART_Parity = USART_Parity_No;
    % Y4 P4 h7 C; V! Q- l( e
  58.     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    ( h* N- M* b& _9 h2 f/ Z
  59.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    - X5 W# p1 G5 R- A- Z1 T
  60. 3 x* s/ s. Q# {7 X  _& V4 N8 e
  61.     USART_Init(USART3, &USART_InitStructure);, F* e, H; w& J( Y8 I% {
  62. - W( u6 R! h8 S0 t( Y- i0 e
  63.     USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
    % O( |% ^" _. u7 d
  64.     USART_Cmd(USART3, ENABLE);
    , ]8 r: n/ g: v
  65. 5 Z2 [. p' i, f& c/ P. ]: z9 n
  66. }
    1 J4 G& F, N7 W) o9 T+ R" r
复制代码
6 E$ n$ {4 _, Z: ?4 k
修改后再使用printf函数时,就可以通过串口3输出了。' w; c: W; f/ g- @6 V& f  O$ T
关于printf函数的设置核心代码如下:& R/ u: d& u: I/ b% h
# V: t, q8 f( A; c! t
  1. #pragma import(__use_no_semihosting)
    6 j9 Z9 Z) o3 Z2 c7 S, R
  2. //标准库需要的支持函数0 N- n" C% V6 n+ k1 l' ~5 L+ U
  3. struct __FILE
    ! j: R- Q- L; O: y
  4. {1 k1 e2 [: ?  F* T* c. U% D
  5.     int handle;
    ; J: P, h1 U& R+ U1 m
  6. % B* H2 t; i0 S) ~7 X+ P
  7. };
    3 K" u- Q5 X, f; R* S" q! @+ i' }
  8. ( I1 o- ]8 j- x, d& S2 W8 W
  9. FILE __stdout;
    & Y9 S1 _) U8 g. B
  10. //定义_sys_exit()以避免使用半主机模式
    ' J0 a; S* Y0 _
  11. _sys_exit(int x)
    9 H% A: W) y# D
  12. {, B2 p- C! @. M1 X2 J* |
  13.     x = x;
    8 ?2 L* v7 M5 G/ k' t) T- l
  14. }- }4 N. J" v5 N& c
  15. //重定义fputc函数
    # }* L$ k* R0 Q# s/ r
  16. int fputc(int ch, FILE *f)7 n4 _& ^" K3 C% t
  17. {
    # D9 `0 D2 {) v7 r. y$ l& o& t$ I' W& @
  18.     while((USART3->SR & 0X40) == 0); //循环发送,直到发送完毕
    9 i: ~* M9 d6 J, |
  19.     USART3->DR = (u8) ch;+ U3 a9 ], q% g
  20.     return ch;, @4 X) i) N  H4 d$ q
  21. }! j' `% H  f# r: @* K$ ~9 ^- A! b$ `
复制代码
/ p2 x* C0 N# j
通过上面几个函数可以看出,要重新定义printf函数的输出串口时,只需要修改fputc()函数中关于串口的定义就行。
: s/ j* S% q4 H9 P' d- d# H
- q) K" ?( _; J# S6 J+ f% ]4 p" u7 A  p0 Z3 p+ L
收藏 评论0 发布时间:2022-3-22 13:00

举报

0个回答

所属标签

相似分享

官网相关资源

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