|
发表于 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 的語句.
|
|