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

用库#include <stdarg.h>实现串口printf函数

[复制链接]
GKoSon 发布时间:2018-4-27 14:31
本帖最后由 与龙共舞 于 2018-4-27 14:57 编辑 8 M' [1 n1 Q; E& ]

7 X! f( Q5 ?) h2 B问题引入:上位机C编程,第一句一般是printf你好世界到终端,而下位机没有终端,一般就是串口了。
2 x4 h. b, P9 |( D1 j串口输出并不困难,本文第一步也就是再次完成这个实验。
: j1 e& h; h1 ~6 X而格式化输出就要想办法了,比如刘洋说的三个步骤是Keil打钩用编译器来帮助。本文第二部分就是自己用库函数来实现。
( F. X* h9 T( g7 b9 n4 f& a第一步:串口输出
/ d" ~, g% L( k' Q; c5 \ 11.png
- G% e5 ]# |$ x/ G" m# f+ { 22.png
$ Z& F- S4 r, H2 I7 g& |! B 33.png $ z# a( A! B7 \, n+ I- a; n
44.png : Q: ?4 _' p4 L2 A6 ?
没有文字介绍了,挺容易的吧。
7 c$ O% G) f( JPC找一个USB--TTL的CH340: I( c" f8 M4 P! K6 S. ~
TX RX GND和板子的3个对应连接。% T1 M$ [+ M2 t
就可以看到实验效果。
  |( l. I2 E% d- f* {- }
6 o0 |! _5 y8 Y# h3 p  R第一步:串口格式化输出+ {% c& f, U# o2 v. G' G0 h
为了方便移植,我们自己做一个模块。# a. B' |( ~4 l% ~  _, q
logger.c
4 F6 N6 `$ R# @3 y$ z; @0 |logger.h+ R8 G8 G. }% ]6 d' X: r: d' M) L
最后主函数如下。8 c+ A& ~9 n2 f" G, Z8 K- m
66.png
6 I4 [% N$ a. h也就是要从5 [# m0 T  Y9 k( @( W' o$ V
HAL_UART_Transmit(&huart1, (uint8_t *)Buffer, 10,0xFFFF);
& L* `" Q; ~6 ~) D( K* ?升级到
0 Z$ _3 X" t3 p7 H$ c0 I! ylogUsart("%d\t++++%s\n",a,s);        ( V5 ?1 z: E. P# {, }+ S8 g
1 q! h' \% P6 e8 [9 f+ t2 @
下面开始实行这个模块。
1 q, L3 s: ^) C( }/ O" _- R& ?直接放代码
8 t8 f) B  \1 t) S4 S
  1. #ifndef _LOGGER_H_
    8 ?% ?/ k, ]+ A: k
  2. #define _LOGGER_H_; k4 p3 |0 V9 x" A/ e
  3. 1 n2 ]. }) I' t( ^9 J
  4. #include        "stm32f1xx_hal.h"
    4 I/ I; l. A1 M) V4 i2 w

  5. 1 y& V6 b6 C) @
  6. % |& a) ~  Q5 {, o0 Z$ x* F& w* A6 W' p

  7. & y' S9 |: e) t- J
  8. extern void logUsartInit(UART_HandleTypeDef *husart);& f% q3 O; R! z! ?  {
  9. extern int logUsart(const char* format, ...);! ?3 x* R& k5 R5 P

  10. / j7 w2 @& E6 _% M& [% Q1 e
  11. #endif9 e' R) H& v( q. e
复制代码
  1. #include "logger.h"
    ( \' b+ Q1 {9 @' n: S$ B' l
  2. #include <string.h>, R- Y; S8 @( ]' z! d% }  _
  3. #include <stdarg.h>  j# m# |: U$ W
  4. typedef unsigned char uint8_t;
    6 q0 ]* y& I3 w
  5. 8 V5 L# h+ t/ `+ O: p* v* j1 D3 {
  6. 6 q+ M& r9 ?+ j, J! n
  7.       
    / U, `7 z& P- f9 B
  8. #define MAX_HEX_STR         4
    ! q: K& J9 T, N( x
  9. #define MAX_HEX_STR_LENGTH  128$ [; S7 v# E* L1 R) E
  10. char hexStr[MAX_HEX_STR][MAX_HEX_STR_LENGTH];* [. l( _1 Z2 O! R3 O6 B
  11. uint8_t hexStrIdx = 0;5 `, a4 I" U  d7 f& P
  12. #define USART_TIMEOUT          1000
    8 l" N) P7 u& Z; @1 u
  13. 3 X% [7 m! r% B1 ?( [' \0 `

  14. 3 L9 h$ x& M6 O- {. Q. d
  15. UART_HandleTypeDef *pLogUsart = 0;
    $ q# X7 R& X' w7 `! _
  16. uint8_t logUsartTx(uint8_t *data, int dataLen);
    5 M$ v, i: M* D$ \

  17. ) M1 u8 ?8 D$ s/ N: g" _" L
  18. + g0 f, d0 P$ a0 A" y. Z' ?1 V
  19. void logUsartInit(UART_HandleTypeDef *husart)' v" y( v9 l' I& E" b: @
  20. {
    4 z6 ^: k6 ]9 W! v+ Q
  21.     pLogUsart = husart;
    / H( J7 Q, q: s1 V' J
  22. }
    % ?9 E1 q$ k& l1 B; N( M

  23. 7 t7 y  e  X' w  k0 D- k
  24. uint8_t logUsartTx(uint8_t *data, int dataLen)
    + |# m& v* d  n1 q9 i& C  }' Z
  25. {
    1 k0 q6 L  s" D% W" a) ~' V
  26.   if(pLogUsart == 0); y# ^: X, Q1 W- d- A  h" h8 z  ~
  27.     return 0;8 {' s, g8 v, J; b
  28.   return HAL_UART_Transmit(pLogUsart, data, dataLen, USART_TIMEOUT);1 i( I) L0 L# D% E  f6 ?8 E/ D6 O
  29. }
    # E+ w0 K6 k- N% ^3 H

  30. : p, o4 P, q% r$ {: ^
  31. int logUsart(const char* format, ...)! d" F* M1 y3 X0 X3 f
  32. {- p( S# n. N2 Y2 O
  33.     #define LOG_BUFFER_SIZE 256
    2 [  o- A: P$ V  d! U
  34.     char buf[LOG_BUFFER_SIZE];
    & c9 p' _7 |$ o' B
  35.     va_list argptr;' |* z0 a8 d& C% t3 E
  36.     va_start(argptr, format);1 V) D7 Y6 G8 {
  37.     int cnt = vsnprintf(buf, LOG_BUFFER_SIZE, format, argptr);8 K9 W" `% m: A+ x# Q
  38.     va_end(argptr);  
    0 r1 [' l1 ~  y0 v

  39. 0 [- l- b1 p/ c/ \* E
  40.     logUsartTx((uint8_t*)buf, strlen(buf));' p. P, a$ U& S
  41.     return cnt;( X4 m. t# C3 p
  42. }
复制代码
效果如下
+ b8 _; s5 m# W  P0 Z 77.png + A) T  g- s( ~8 ]) G- F. ^2 ~- p0 l3 h
1 [8 f& q6 D8 {, d5 ]- c" {: W
初始化是 挂钩你需要debug的串口。
" h+ D: j( z7 N; d: d! ]格式化的核心是如下几句话:" F. y  I, r' P' J8 ?# R
va_list argptr;* e$ v9 d- Q& [! L/ d% _( U
va_start(argptr, format);" m' o7 e- c3 W$ E, d
int cnt = vsnprintf(buf, LOG_BUFFER_SIZE, format, argptr);" S" m3 ~9 Q- Y2 y! y
va_end(argptr);
9 L  m6 ^' L2 {5 K# z5 K  d3 u& G: A5 L* g# W& r! X1 Y

- M+ y) }# R% x+ {++++参考ST开发板代码+++9 Y* X5 S9 s) E6 c& s+ I
附近是即插即用的模块。3 e' D: t$ d. V( r; b+ M. j
注意:在头文件中#include 不合理 会有很多错误!6 i/ A+ Z. c, p* A& J

logger.zip

下载

1.02 KB, 下载次数: 4

模块

收藏 评论3 发布时间:2018-4-27 14:31

举报

3个回答
Inc_brza 回答时间:2018-4-28 10:02:56
嗯嗯,很好,我现在就是这么用的,不过,也又一个比较明显的缺点,就是编译出来的bin会很大,你可以从map中看的到,所以其实也不难,自己写一个很简单的。
GKoSon 回答时间:2018-4-28 11:13:46
Inc_brza 发表于 2018-4-28 10:02
1 P- O8 c$ m+ L% |+ Y' o- i$ `3 s嗯嗯,很好,我现在就是这么用的,不过,也又一个比较明显的缺点,就是编译出来的bin会很大,你可以从map中 ...
& F/ C; v4 A. E6 n
哦 那要做一个开关  正式版本程序把logger关闭
废鱼 回答时间:2018-4-28 11:28:57
可以直接使用printf的,楼主难道不知道吗?自己写bug还不少,不如直接用底层驱动库,ST的例程里面也都写了。* C+ D6 p: S. K: i/ D* ^

5 @/ l# Z- z* l#ifdef __GNUC__
! p. U. x4 y/ v: u$ S7 r" z- y# R  /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf; x9 v0 O; ^6 g1 k/ S* d; J+ m
     set to 'Yes') calls __io_putchar() */0 W6 k, p+ z( N' p! ~
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
9 ~$ @( b( ]% D+ z#else
0 I" `' A: _7 |/ E9 E; w2 \  e0 O1 q  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)5 Y8 D! U$ p7 ~
#endif /* __GNUC__ */
: G8 {2 z6 [# f$ A  , |  x9 e' Z( A9 ~! [
/**" F( U8 k2 F( n+ k8 a9 s
  * @brief  Retargets the C library printf function to the USART.
( `5 G6 [2 {1 E" p  * @param  None$ @1 K; Z$ E7 j% ^9 M' A# o
  * @retval None
, Y5 r4 }0 Y5 S# a3 s  */' A1 N) |0 X0 s! f. B9 w
PUTCHAR_PROTOTYPE
( s  ]9 D7 P/ x2 ]# w  Y* d{4 ~$ D4 |- l& H3 X
        USART_SendData(USART1,ch);: q" i# f( G' z! w' ^
        while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)3 `+ e! C3 `. T- O' T8 P! `
        {}" L/ Y6 V- B$ {1 ^
  return ch;4 a  E' R9 O% O. p5 A
}

所属标签

相似分享

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