极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 14601|回复: 6

PROGMEM的使用问题

[复制链接]
发表于 2014-3-9 21:26:37 | 显示全部楼层 |阅读模式
本帖最后由 shihaipeng04 于 2014-3-11 21:50 编辑

PROGMEM 说是可以把常量储存到flash里,这样就不用占用sram的空间了。 我在捣鼓小屏幕,想重写一下卖家送的库,因为不太方便。现在刚开头就困难重重的。呵呵。

字库文件用一个数组存放,6个字节一个字母,大约500多个字节。人家原来程序也是用PROGMEM存的,就一切正常。 我自己啥也没改,读出来的字库就是混乱的,可是如果就是用 uint8_t font6x8[] = {****};就正常。加上 uint8_t PROGMEM  font6x8[] = {}就是乱码。 太神奇了。

唯一的区别是,原来库是在一个 .c的文件里,include到主程序里的,我只是为了修改方便,都放到主程序里了,这应该没影响啊。换了uno和mrico 2种板子,故障现象一样。
回复

使用道具 举报

 楼主| 发表于 2014-3-9 22:52:05 | 显示全部楼层
好像找到点问题。。。例子文件的 .H 上面还有一句 #define PROGMEM
虽然不知道是干啥的,但是感觉肯定和我这个问题有关系。
回复 支持 反对

使用道具 举报

发表于 2014-3-11 16:30:31 | 显示全部楼层
PROGMEM关键词声明的数据需要用pgmspace系列函数先读到内存里面,再使用

http://www.nongnu.org/avr-libc/u ... _avr__pgmspace.html
http://arduino.cc/en/Reference/PROGMEM
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-3-11 21:51:36 | 显示全部楼层
histamine 发表于 2014-3-11 16:30
PROGMEM关键词声明的数据需要用pgmspace系列函数先读到内存里面,再使用

http://www.nongnu.org/avr-lib ...

诶,洋文的真心看不懂了,不过按照原来例子的使用方法到是学会啦。也谢谢你哈。 能用就好,深的技术面不研究。呵呵
回复 支持 反对

使用道具 举报

发表于 2014-3-12 09:17:06 | 显示全部楼层
shihaipeng04 发表于 2014-3-11 21:51
诶,洋文的真心看不懂了,不过按照原来例子的使用方法到是学会啦。也谢谢你哈。 能用就好,深的技术面不研 ...
  1. #define PROGMEM
复制代码
就是用宏定义,使得编译时预处理器会把PROGMEM关键词删除掉,然后就和没有使用PROGMEM一样了
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-3-12 15:47:31 | 显示全部楼层
histamine 发表于 2014-3-12 09:17
就是用宏定义,使得编译时预处理器会把PROGMEM关键词删除掉,然后就和没有使用PROGMEM一样了

大致明白了, 反正前面加上 #define PROGMEM,后面再有 uint8_t PROGMEM  font6x8[] = {....}就正常了。
回复 支持 反对

使用道具 举报

发表于 2014-4-2 22:57:14 | 显示全部楼层
本帖最后由 Super169 于 2014-4-2 23:00 编辑
shihaipeng04 发表于 2014-3-12 15:47
大致明白了, 反正前面加上 #define PROGMEM,后面再有 uint8_t PROGMEM  font6x8[] = {....}就正常了。


你不是明白了, 而是受騙了.

我看過好幾個庫, 都是不明白 PROGMEM 的用法, 而加上了 #define PROGMEM (之前買的 OLED 的庫也是一樣).

當你加入 #define PROGMEM 後沒有問題, 以為可以用到, 其實是因為你只是在用 SRAM 中, 並沒有真正使用 flash memory.
不信的話, 你嘗試加入 #define PROGMEM 後, 再用 PROGMEM create 一個 4K 的 array.  你的 flash 應該足夠的, 但也會出現問題.

因為 #define PROGMEM 之後沒東西, 結果就會把程式中 PROGMEM 的字除去.  #define 同時有取代的作用, 就如 #define _width_ 128, 當程式中出現 _width_ 時, 都會被轉換成 128 去 compile.

結果  uint8_t PROGMEM  font6x8[] = {****}  就變回  uint8_t font6x8[] = {****} 了, 當然沒問題, 只是做不到想要的效果.

之前寫庫的人, 用 #define PROGMEM 去 當成已"解決"問題, 有點誤導成份.

正確使用方法, 是要改變讀取數值的方式, arduino.cc 中有清楚的例子, 必須用 pgm_read_??? 去讀取資料.
例如 http://arduino.cc/en/Reference/PROGMEM 中的例子,

如果用 SRAM 時, string_table[ i ] 的數值, 當便用 PROGMEM 時, 就要用 pgm_read_word(&(string_table[ i ])) 去讀取.

補充少少解釋, 希望容易明白一點:
- string_table[ i ]        是原來的資料, 在 SRAM 中的話, 直接讀取就可以
- &(string_table[ i ])   是資料的地址

本來, 地址指向的地方, 直接讀取就可以.  但現在有兩個放資料的地方 (SRAM 及 flash), 預設是 SRAM.
當你直接讀取是, 系統會在 SRAM 對應的位置讀取, 結果就出亂碼了.

舉一個簡單例子, 假設你住在 北京大廈, 而世上只有一座大廈時, 當你說 10樓 8室, 自然是北京大廈的 10 樓 8室.
如果還有另一座 上海大廈的存在, 又如何?  由於你本身在北京大廈, 當你只說 10樓 8室, 會被看成是 北京大廈 10 樓 8室.
但當你想找的 是在 上海大廈 10 樓 8 室時, 就不可以用預設的方式了, 必須清楚說明了.

PROGMEM 亦是一樣, 系統預設是在 SRAM 中讀取, 因此如不加說明, 系統就會走到 SDRAM 那個地址去了.
所以你一開始出現亂碼, 是正常的, 證明你成功放到 PROGMEM 中, 在 SRAM 相同位置中找錯對象了.
後來你加入 #define PROGMEM 而成功讀出, 表面上的成功, 只是證明了不是放到 PROGMEM 中.

要讀出 PROGMEM 中的資料, 就要告訴系統你的地址是在 PROMEM 中, 不能用 SRAM 的讀法.

pgm_read_word(&(string_table[ i ]))  就是這個作用了.

所以, 如果你想真正用到 flash 而不是 SRAM, 就要把原來讀取資料的地方改了, 而不是加入 #define 的語句.
回复 支持 反对

使用道具 举报

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

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-5-18 09:24 , Processed in 0.100426 second(s), 20 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

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