查看: 434|回复: 0
打印 上一主题 下一主题

Arduino内存架构之PROGMEM简介——神奇的F( )

[复制链接] qrcode

36

主题

42

帖子

123

积分

注册会员

Rank: 2

积分
123
楼主
跳转到指定楼层
发表于 2016-4-15 01:46 PM | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

图片看不到请看 这里


在介绍PROGMEM之前先看这段代码。


编译,你会发现不可思议的事情。

这个程序没有申请任何变量,但“全局变量”居然436字节! 
代码中注释部分数字,是到这行为止使用的Flash空间和全局变量字节数,每打印一行,全局变量会增加很多。

这是为啥?因为,所有字符串都复制到了内存一份!不像51单片机字符串属于常量,不占内存,AVR是哈弗结构,数据和代码分开放置,代码中的“数据”必须先载入到数据区,才能被程序使用。

接下来看增加的一个小改动。

细心的你一定发现,仅仅在字符串外面套了个 F( ),全局变量就完全没有增加! 这个神秘的F( )就是告诉编译器,后面的内容给我放到PROGMEM中去,不要占用程序内存。PROGMEM就是程序存储空间(Flash),代码上传时写入的地方。

刚才说了,代码空间(Flash)不能直接访问,此处宏F起到把代码地址空间的字符,映射到程序内存空间,很简单吧。其实后面的原理真比较复杂,有兴趣可以参考这里的讨论,非常精彩。

只要玩Arduino一段时间了,你一定见过类似这样的定义。
  
想直接打印是徒劳的,Text2不在程序能访问的空间,必须通过变通的方法,最常用的方法是,先复制到普通对象中,然后再使用。
 

或者直接使用pgm_read_byte从代码空间读出字节。

如果是PROGMEM数组,那么使用起来需要强制类型转换一次,写法有点怪

写起来有点别扭,但为了节省为数不多的内存,这点开销还是值得的。

这里是字符串(程序小bug应该用byte而不是word)单字节,所以直接用地址+i偏移,如果是int(word) / long(dword)类型数据,需要偏移i*sizeof(int) or i*sizeof(long),这也是为什么文档中大多会使用(&(string_table)) 这种怪异的写法!上面的代码也是。

上面都是在用全局变量,如果是局部变量,还要加上static修饰符,PROGMEM只能在全局变量中使用,static关键表示局部“全局”变量。

总结,存储大量字符串、数字常量或数组,请把它们放入PROGMEM(对应51的code关键字)。使用时用strcpy_P先复制出来,或者用pgm_read_byte/word/dwrod一个个读出来。如果只为显示给串口,直接在字符串两边加上宏F()即可,可能稍微多消耗几个纳秒的时间,但节省了内存!(可惜,这个方法只能在串口输出中使用,串口print/println重载了方法处理它,其它地方不能这么用。。。。)


参考:
https://www.arduino.cc/en/Reference/PROGMEM
http://forum.arduino.cc/index.php?topic=91314.0


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表