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

Ubuntu下开发STM32---7.使用printf

[复制链接]
qianfan 发布时间:2015-10-30 18:46
    开始尝试使用标准库的一些东西的时候,也就意味着我们的linux环境下开发STM32的教程已经接近尾声了。标准库的使用我们这里仅仅介绍使用printf和malloc。: O6 b5 o( L( J6 a; r% S, t: Q

0 v3 _/ K- v* k/ w1 D* wsyscalls! n* P. K6 i5 h8 G5 x( U
想使用标准库,我们需要自己完成一些系统调用。像keil mdk下使用printf一样,至少要完成fputc和fgetc。然而newlibc下使用printf却不这么简单。并不是一个__io_getchar, __io_putchar能够完成的。幸好,ST的固件库中有我们使用的大部分源码。都在TrueStudio的模板下。大家可以自行查找。我们这次使用的文件是syscalls.c。因为这个文件中使用了gnu的一些特殊的语法,所以编译工程的时候不要使用-std=c99,而是应该使用对应的gnu99(-std=gnu99)。相关的文件在printf_v1.zip中。* m* P; M3 ]6 U- N
2 G' y- x6 R& ?
在syscalls.c中有许多系统调用。比如我们前面介绍的_exit函数。这次我们主要介绍_write,_read两个函数。这两个函数是输入输出使用的。
9 D- T: g% h  T8 x6 p- gint _read (int file, char *ptr, int len)
0 m" t8 K* d* ^* R+ U{
7 R  {. e, E( [% m* `/ o  |    int DataIdx;6 I4 D6 A* ?" a, S" E. D7 g' y
# K6 v. j  ]7 H! z1 @  n
    for (DataIdx = 0; DataIdx < len; DataIdx++)
2 c! V- u4 k" }1 g6 ^8 L    {. s/ l/ I4 B# ^! j" C0 @
      *ptr++ = __io_getchar();' E$ f  s' s) g2 y* f' G! i& x
    }9 @3 V# g9 I! w, T
8 B* _' ^4 b8 K+ b3 S" S
return len;
4 {8 y; h# \2 ~2 l- F6 K) P}, j$ q+ d" [. Q4 E6 V
! Q4 ^$ x, A( I7 d: {8 |+ k
int _write(int file, char *ptr, int len): f8 ^1 Y6 z5 ~3 k
{
7 I; v* g5 A% |% h+ D' B    int DataIdx;/ ~# U2 ?, B2 B; M6 W

. C: w$ Y; S3 W    for (DataIdx = 0; DataIdx < len; DataIdx++)
% \# v2 e( x3 D8 [  T, V    {
* F3 i( V- k- H& U1 ~+ A       __io_putchar( *ptr++ );
% u. ~) e0 u3 {5 X% G' `    }
# p  i- s7 E$ z/ I- F- m# O    return len;5 q# ]3 Z5 P% h3 }# B
}
" |# _3 ^2 [( e# |- q) K5 ^
__io_putchar,__io_getchar这两个函数在上一节使用串口的时候就已经测试通过了。这里仅仅使用就好了。
. B* y, b/ _) P- O& [2 z* ^, b6 h) I" m  L/ {6 I; ?2 h
测试printf" C$ \8 U- b, w% }
写点简单的代码来测试一下printf。
! N. W; s5 B+ ?! ?8 d5 N& d5 C- c 2015-10-30 15:12:51屏幕截图.png
7 b' }5 x' Y: u+ H* s/ y, V# u( d之后make sram,sudo make burns将代码下载至SRAM中运行测试。
2 [7 ?& O0 o6 q- @* T. c 2015-10-30 15:13:53屏幕截图.png
- p" {% |- r0 D- f从测试结果上来看,貌似newlib对double当作float处理了。如果对double还有其他的设置,麻烦告知
2 \; e* T9 D$ \% w- }. z$ X1 j( \这里还是要多罗嗦几句。printf是行缓冲的。也就是说,在printf的末尾添加\n或者使用fflush刷新,或者main结束。否则是不会输出的。
. N  ?9 |. @( E4 j
' ~) Z  ]. d; k: U( R* v使用Newlib-nano& X1 J* F' W3 x
刚开始看到printf的代码大小的时候,我也是吃了一惊。在keil mdk下,单纯的使用一个printf并没有这么大的代码。虽然我们的参数中也使用了ffunction-sections,fdata-sections,-Os来优化,但是代码量确实偏大。
* ^4 E# }1 A! d 2015-10-30 15:17:19屏幕截图.png
6 P6 [5 _4 y" R, N" Z; A. f- [4 q
" x" t/ p* L' g$ u9 ^9 k2 k可以尝试使用nano库来进行优化。在链接参数中使用-specs=nano.specs.相关的代码在printf_v2.zip中。
( ]0 w6 W$ Q: R6 l+ Z加入使用nano库这个链接参数之后,编译出的代码缺少小了。减小到6K左右。
# L- z7 y/ N; U# c- w 2015-10-30 18:20:05屏幕截图.png 8 Y) l  M# `2 B
不过printf只能输出整数,不能输出小数了。
# F/ x$ g8 \3 t* I9 G 2015-10-30 18:27:51屏幕截图.png
# a+ {( m& s" A9 t0 S1 X关于这个问题,在链接 http://community.arm.com/groups/embedded/blog/2013/01/21/shrink-your-mcu-code-size-with-gcc-arm-embedded-47中也说到了。原文如下:' _9 H( K/ x! S) ]  C
Libraries also need optimizing, because the libraries included in GCC ARM Embedded were not actually designed for MCU programming. Newlib, the C library in the toolchain, implements printf functions that are so complicated they require about 37K bytes of FLASH and 5K bytes of RAM to run a simple hello-world program. That's far too large for MCU programming where you might need printf functionality for debugging and logging purposes. The good news is that there is plenty of unnecessary "fat" in libraries that can be cut.”7 T: }: N  N8 m1 i6 v( T
newlib如果不经优化的话,大约占用37K的FLASH和5K的RAM来运行一个简单的hello-world程序(使用printf输出)。对MCU编程来说,这确实是大了点。
. B7 X3 E+ r& RNewlib-nano cuts some features that were added after C89, which are believed to be rarely used in MCU programming. By limiting the format converter to the C89 standard, format string processing code in printf is greatly reduced. By removing the iov buffering, all IO function sizes are again significantly reduced. Removal of wide char support in non-wide char function further squeezes string IO logic. Newlib-nano also extensively uses the weak symbol technique to exclude features that are rarely used in normal MCU programs. For example, referencing floating point IO and atexit as weak functions dramatically cuts the size of printf() and exit().”) ?5 U+ r  g7 g3 e1 Y
为了减小体积,Newlib-nano库砍掉了很多C89之后的特性。(后面那一句不知道怎么翻译了。。。)
) c% [4 S1 q: q看来,为了减小体积砍掉了一些东西。比如printf输出浮点以及atexit函数。1 m5 ?0 K' U6 P2 s. ?) W" |
/ U( r# b' G! o
为Newlib-nano添加浮点输出功能
8 O! w4 ~8 |9 O' T% {* M如果你的代码实在是需要浮点输出的功能,可以尝试自己编写一个函数,将浮点数转换成字符串在输出。或者在链接命令中添加-u_printf_float命令。相关的代码在printf_v3.zip中。. D; {: h5 {  {8 [
: ?2 c( j: L  _
2015-10-30 18:42:31屏幕截图.png
3 ]0 I7 z9 {- V+ r8 g; z9 Z0 Z- D$ o& w6 l9 g- s* ~
2015-10-30 18:42:18屏幕截图.png
2 F6 h! x% x4 N/ b$ e在给Newlib-nano添加printf float支持之后,代码增至15K。至于在你的项目中该如何选择,还是要自己做决定吧。
9 J( W/ K5 M! f0 |; Z' O* E6 b

printf_v3.zip

下载

401.18 KB, 下载次数: 240

printf_v2.zip

下载

401.15 KB, 下载次数: 137

printf_v1.zip

下载

504.7 KB, 下载次数: 173

1 收藏 5 评论17 发布时间:2015-10-30 18:46

举报

17个回答
zbber 回答时间:2017-5-9 10:16:04
大师作品,必须支持
qianfan 回答时间:2017-5-9 09:54:20
黑皮男 发表于 2017-5-9 09:42% s( G/ ^$ ]7 s( Y2 W" N6 R
楼主的帖子很好,不过 目前遇到 一个问题。裸机的话printf没有问题,上了FreeRTOS的时候就有问题了。首先需 ...

2 c) U1 h! R6 y8 d/ [! \; A可以试试只在一个任务中使用printf看看,如果没问题,应该就是不可重入导致的吧。
+ _) I; K. D- C0 \* \可以在查查看看有没有编译选项解决可重入的,或者在什么地方加锁的。
黑皮男 回答时间:2017-5-9 13:31:56
QianFan 发表于 2017-5-9 09:546 G9 e: B0 L" P, R; f
可以试试只在一个任务中使用printf看看,如果没问题,应该就是不可重入导致的吧。
( P' R: _# d0 I+ d, P( V5 }可以在查查看看有没有 ...
+ |! S& y& w$ q1 o: Y
多谢楼主,任务跑不起来是我任务堆栈分配的太小。在不加nano.specs的时候,RTOS和printf现在都正常,但是加了 nano.specs后printf就没有输出了
wyxy163@126.com 回答时间:2015-10-30 20:17:23
提示: 作者被禁止或删除 内容自动屏蔽
qianfan 回答时间:2015-10-30 20:38:14
数码小叶 发表于 2015-10-30 20:17
, j4 _0 Y9 E# M, t8 H  o测试printf下那张截图啥编辑软件?
, o$ _8 }9 x0 U
Ubuntu下自带的记事本软件---gedit
Paderboy 回答时间:2015-10-30 21:26:03
大师作品,必须支持
tg1991 回答时间:2015-10-30 21:28:42
哎呀,keil编程就是不太方便我感觉,智能程度不强
埃斯提爱慕 回答时间:2015-10-30 22:05:07
提示: 作者被禁止或删除 内容自动屏蔽
me浩 回答时间:2015-10-31 08:59:44
暴强啊
你好我好大家好! 回答时间:2015-10-31 09:34:10
学习学习               
沐紫 回答时间:2015-11-2 09:56:33
谢谢楼主,这个系列必须加精
qianfan 回答时间:2015-11-2 10:46:18
沐紫 发表于 2015-11-2 09:568 \8 _, `) M" f
谢谢楼主,这个系列必须加精

0 z1 l, E1 ^+ J沐紫姐英明啊
黑皮男 回答时间:2017-5-9 09:42:35
楼主的帖子很好,不过 目前遇到 一个问题。裸机的话printf没有问题,上了FreeRTOS的时候就有问题了。首先需要nano.specs这个选项,RTOS才能正常运行,但printf没有作用了,如果取消nano.specs,printf可以正常,但RTOS就不争正常运行了,不知楼主有何高见
红晨_ 回答时间:2017-8-14 17:52:44
我移植到 F103上面  eclipse + cdt  编译没问题, printf 一使用 就死机呢,什么原因 求助
12下一页

所属标签

相似分享

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