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

【源码】STM32的printf重定向解决方案——史上最强?

[复制链接]
radio2radio 发布时间:2020-12-13 19:15
为什么要用printf,废话,不用你用啥? 我在下面的把printf换了一个名,LOG,少打3个字。您也可以换成您喜欢的字母组合,这不是重点。9 y7 g  i6 o# L

, i* R' @5 j9 P+ P8 |/ D说是“解决方案+史上最强”,也不过就是下面的几行代码。
2 D* q2 B/ Y/ g8 d! K" I笔者仅在CubeMX+HAL+MDK+AC5下,测试过F1和F4。 其他环境要修改后使用。
: T9 M; w4 C. U+ {2 x5 |0 Z
% z' x* L0 }, f1 X3 p* b
  1. #include <stdio.h>* x+ u: H6 z; O9 J! J* R
  2. #include <stdlib.h>" ?, d0 q- J4 a2 p2 ?
  3. #include <string.h>6 ?% S  U! p: ]: E
  4. 6 B2 Q) m' _# T+ E% h. t
  5. //Debug mode On/Off switch $ f& W% F7 E$ }, S+ ^
  6. #define DEBUG                   1 //set=0, disable all LOG lines
    - Z, q" B1 a4 q5 [) I
  7. 2 `$ i/ H. O* `/ |4 G) c
  8. //select one of the following "printf" retarget methods
    % a5 w7 J" m( `3 T1 Y5 }. |! o
  9. #define PRINTF_UART             0 //printf using UART port, 1-use this, 0-not. U' ]5 P. N1 q4 L, t4 X/ J
  10. #define PRINTF_RTT              1 //printf using Segger RTT, 1-use this, 0-not
    ! d6 I, G; Y! ^
  11. #define PRINTF_SWO              0 //printf using SWO port, 1-use this, 0-not% a( I1 \/ T+ ]8 p& S5 p3 }, l
  12. #define PRINTF_CDC              0 //printf using USBD_CDC, 1-use this, 0-not
    / G8 n% k% \% O' h! u
  13. 1 T6 x8 L# W- O) N
  14. #if ((PRINTF_UART + PRINTF_CDC + PRINTF_SWO + PRINTF_RTT) != 1)
    , y. F$ k; [( [5 P% ~3 V* R
  15. #error "!!!!!! printf retarget function Not define or Multi-defined !!!!!!"
    : f6 N" N3 s# Y
  16. #endif
    & I) U/ N0 j' y3 Y- j
  17. 8 [8 ^4 n, M, A& w
  18. #if DEBUG
    % ?% A# A5 r3 E, T  \9 V
  19.   #if PRINTF_RTT
    " t! H# S: f# f9 ?9 p% y4 f
  20.     #include "SEGGER_RTT.h"' k$ \- l  l* B* x
  21.     #define LOG(format, args...)  SEGGER_RTT_printf(0, "[%s:%d] "format, __FILE__, __LINE__, ##args)
    % V$ a, p1 z2 F* s5 v! v* M' x
  22.     #define printf(format, args...)  SEGGER_RTT_printf(0, format, ##args)' x/ n; a; V5 o( }2 ?4 I2 h# O
  23.    
    1 u5 O1 D' d/ J0 d0 U
  24.   #else //#if PRINTF_RTT" ^/ x2 f! h# h0 b% `% _
  25.     #define LOG(format, args...)  printf("[%s:%d] "format, __FILE__, __LINE__, ##args)
    0 @' u( D8 O9 _
  26.     % f' r# c: \  x' q4 G: j  G7 Z
  27.     #if PRINTF_CDC
    : n$ |! q2 ]$ d6 a# X$ G
  28.     #include "usbd_cdc_if.h"7 Z& T9 o8 E! j2 R( _; p
  29.     #endif7 J% A" `6 G: S2 O, F! w; x
  30.    
    , Q. K8 b  V& q: B- e! o2 b
  31.     int fputc(int ch, FILE *f)/ G/ Z8 e# k7 X  G
  32.     {
    # F7 O6 m* ?) K2 f  V0 y4 b+ `1 K! }
  33.       #if PRINTF_UART
    1 C( Y' |4 }! r& e) \3 ^) t
  34.         HAL_UART_Transmit(&huart3, (uint8_t*)(&ch), 1, 1000); //UART3
      U+ a3 m0 A9 s7 a
  35.         
    1 ]' J" C# {# C- P2 ]/ V9 `- z
  36.       #elif PRINTF_SWO+ V) Y0 K) }/ E
  37.         ITM_SendChar(ch);
    3 E" Q- j7 L$ u" m: V( {
  38.         
    * }3 s2 b0 n0 N+ v9 N; j
  39.       #elif PRINTF_CDC( w, ~: {* Z5 R. B* P; `2 s
  40.         uint8_t u8Temp = 0;
    - N$ X, S6 k. \/ N( w3 e9 Q5 g9 Y
  41.         while(CDC_Transmit_FS((uint8_t*)(&ch), 1) != USBD_OK)
    9 L% S* I$ {4 W4 {
  42.         {2 m0 H' N6 U; X  O7 o2 @
  43.           HAL_Delay(1);$ X( J3 ]; o3 j& C
  44.           if (++u8Temp >= 3) break;! n1 M7 ^5 A" o% z7 Z' o% c
  45.         }
    " i, e3 v: n5 B1 p' h
  46.       #endif //#if PRINTF_UART; [6 U( Q* T4 e4 A
  47.         
    $ J3 V) k9 j6 L& S
  48.       return(ch);8 `0 T. |' m+ }/ c: L8 G
  49.     }' b$ v. [8 a" e" y9 X; h
  50.   #endif //#if PRINTF_RTT( r% @0 ^0 O* s0 B1 h
  51.   4 A. n5 K% ]9 t; D: B9 w5 }, o
  52. #else //#if DEBUG == 09 n# V  p0 n& h# u" i9 h
  53.   #define LOG(args...) //disable all LOGs when compiling5 `7 E$ P+ P' G8 L" e% L2 D1 z# ?1 I
  54. #endif //#if DEBUG6 c2 U& A1 a' A
复制代码

# K, Y$ M1 J9 ^6 _  Q- O这里有4种方法重定向printf,必有一款适合你:4 D3 S* g! A; C; q, n1 U  u  o( C6 ~5 J

; r6 @( |) \3 F# ^0 n1. PRINTF_UART == 1,串口方法。 & I5 e- {2 H2 D7 V* q3 w
优点: 就是最多人使用的,大家也最熟悉。 配置简单,容易使用。 各种“PC终端软件”都能用。
# r6 d3 ?. ?$ }缺点: 硬件上要有串口可以用,有时还需要UART转USB接口板(或者仿真器自带VCP/CDC的东东)配合。
. G& C. ?: V9 q3 c
) r$ P; o. m+ ~/ p. s. N3 ]* M2. PRINTF_RTT == 1,Segger_RTT 方法。  (笔者推荐此方法,至少值得尝试一次), 要安装RTT包,简单!2 U" s8 E$ d, m0 b" B" E( X/ i
优点: 不占用额外的硬件资源, 据说速度超级快。 有多快,我不知道。
- K9 N% ]& J4 b8 n6 d' n( x1 W缺点: 要使用专用的PC软件接收,既然是仿真器大佬Segger的产品,自然是Segger的驱动程序功能多多。( u/ ]' y- J: C1 z) {
           使用J-LINK仿真器,就一定要用JLinkRTTViewer等终端软件。2 L4 i# Z4 _  O, V
           使用CMSIS-DAP仿真器,可以用DRTTView终端软件, 多谢XIVN1987网友 ,不然DAP就不能用RTT了。; a. u4 o& P7 H% S+ i; B
           使用STLINK仿真器,对不起,用不了。
) l0 m0 l4 c+ M9 e, `, U. `* F$ U) t5 U; X; ]  _
3. PRINTF_SWO == 1,SWO的方法,这个是启动内核的ITM功能。
9 e9 }$ n5 ~9 {' w& M9 u优点: 对原程序流的影响最小。 标准的JTAG/SWD/STLINK连接器,都已经准备好了SWO线,也算方便。
1 G# u" K" ^+ r缺点: 相比2线的SWD,需要硬件连接一条SWO的输出线。 不能实现双向通信(其他方法都能)。
$ \( d( O% ^6 z0 @: I8 N3 H5 ~            软件配置SWO功能比较复杂很容易失败,重点是要做SWO速度匹配。
8 H, X/ q% ?$ t2 n            SWO方法不能在JTAG模式下使用,只能是SWD模式。另外,ARM Cotex-M0/M0+也不能用。" J- M0 I- k9 t, Y3 A1 G9 ^1 g6 F
            MDK/Keil有内置的SWO Viewer,不过不好用,一定要进入Debug模式,好处是各种仿真器都可以用。
, {# Z# L3 |, K6 w            J-LINK 和 STLINK 仿真器,有自己的独立的SWO Viewer,不需要Keil进入Debug模式那么麻烦。+ G0 D: B0 c% C& D1 l
" s1 u/ T7 f( T0 C* O* J8 A
4. PRINTF_CDC == 1, CDC的方法,比较逆天的,属于玩具级别,你想用我都拦不住。
) Z4 c2 b# B! @( T优点: 用法与UART一样,各种串口终端软件通杀。
6 C& `# `2 p8 L. R! z           不占用串口。 利用IC本身的CDC-VCP节省了UART转USB接口板。4 D7 a: i2 O4 |% n6 y7 P8 M9 T" t
缺点: IC要有USB硬件,代码增加,软件复杂度增加。
* M- d# F& t* @4 B1 e% N4 t9 I; I1 R/ e5 J$ w: A: z
实用中,还有一种方法,称为半主机模式(semihosting),据说速度慢和影响原程序运行严重,没有认真研究过。我甚至怀疑,上面的4种方法里面,有可能有后台使用了半主机模式,知道详情的朋友,请介绍一下。+ Y. y; |" c1 e* f. P2 N6 U
! W0 C4 a% b, ]0 s6 _5 `
毕竟printf指令对原程序流是多余的操作,或多或少都会干扰原程序流,特别是在一些速度比较慢的MCU上面。因此,printf的输出项要尽量简短,避免大量连续使用。 如果估计占用MCU时间太多,就要做需求评估。
1 ]& J" R2 d% l5 T7 z5 n
5 M. Q8 x4 w6 k8 j
8 [3 U: O' Z+ H附件是F103/F407用的完整的工程,与github上传的一样,上面的4种方法都有,可以试一试实现。
; e% K- l2 f' K; V' A& ~github:https://github.com/RadioOperator/STM32_HAL_retarget_printf
* W# u# o5 P/ |9 a7 b8 T
& K: A" d7 _6 R$ c/ @: v: b- V2 B' l) L8 u6 E) _. d
( d7 z3 d2 O) B, M

STM32_HAL_retarget_printf-master.zip

下载

1.36 MB, 下载次数: 12

评分

参与人数 1 ST金币 +10 收起 理由
子曰好人 + 10 很给力!

查看全部评分

收藏 3 评论5 发布时间:2020-12-13 19:15

举报

5个回答
goyhuan 回答时间:2020-12-14 08:20:52
强大
七哥 回答时间:2020-12-14 09:14:10
纳百家之所长,长己之技能
子曰好人 回答时间:2020-12-14 09:32:46
支持老兄,点个赞
kylixyao 回答时间:2020-12-14 18:21:45
非常不错!
radio2radio 回答时间:2020-12-15 12:22:34
子曰好人 发表于 2020-12-14 09:32- e: y* E- V3 ?# c5 n2 z
支持老兄,点个赞

; F0 k* Y$ X5 e% t多谢您的鼓励。
7 \. W' Z  G6 D( z$ N3 Q% h我还是把F407的例程放出来了,同时也上传了github,留个记录。

所属标签

相似分享

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