shihaipeng04 发表于 2014-3-9 21:26:37

PROGMEM的使用问题

本帖最后由 shihaipeng04 于 2014-3-11 21:50 编辑

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

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

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

shihaipeng04 发表于 2014-3-9 22:52:05

好像找到点问题。。。例子文件的 .H 上面还有一句 #define PROGMEM
虽然不知道是干啥的,但是感觉肯定和我这个问题有关系。

histamine 发表于 2014-3-11 16:30:31

PROGMEM关键词声明的数据需要用pgmspace系列函数先读到内存里面,再使用

http://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html
http://arduino.cc/en/Reference/PROGMEM

shihaipeng04 发表于 2014-3-11 21:51:36

histamine 发表于 2014-3-11 16:30 static/image/common/back.gif
PROGMEM关键词声明的数据需要用pgmspace系列函数先读到内存里面,再使用

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

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

histamine 发表于 2014-3-12 09:17:06

shihaipeng04 发表于 2014-3-11 21:51 static/image/common/back.gif
诶,洋文的真心看不懂了,不过按照原来例子的使用方法到是学会啦。也谢谢你哈。 能用就好,深的技术面不研 ...

#define PROGMEM就是用宏定义,使得编译时预处理器会把PROGMEM关键词删除掉,然后就和没有使用PROGMEM一样了:L

shihaipeng04 发表于 2014-3-12 15:47:31

histamine 发表于 2014-3-12 09:17 static/image/common/back.gif
就是用宏定义,使得编译时预处理器会把PROGMEM关键词删除掉,然后就和没有使用PROGMEM一样了

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

Super169 发表于 2014-4-2 22:57:14

本帖最后由 Super169 于 2014-4-2 23:00 编辑

shihaipeng04 发表于 2014-3-12 15:47 static/image/common/back.gif
大致明白了, 反正前面加上 #define PROGMEM,后面再有 uint8_t PROGMEMfont6x8[] = {....}就正常了。

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

我看過好幾個庫, 都是不明白 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 PROGMEMfont6x8[] = {****}就變回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 的語句.
页: [1]
查看完整版本: PROGMEM的使用问题