Arduino的AVR微控制器晶片裡,含有EEPROM,可在程式執行時動態讀寫資料,不因電源中斷而消失。可使用Arduino官方程式庫EEPROM進行存取,但其介面以「一個byte」為單位,用起來有點不便,底下介紹如何自訂C語言struct,作為讀寫單位。
我的環境是Arduino Uno板、軟體版本1.0.5。
分成兩個檔案,首先是eeprom_anything.h:
#ifndef eeprom_anything_h
#define eeprom_anything_h
#include <Arduino.h>
#include <EEPROM.h>
// 利用這兩個C++模板,讀寫整組資料
// 參數address是EEPROM位址,參數data是想讀寫的資料結構
template <class T> int EEPROM_writeAnything(int address, const T &data);
template <class T> int EEPROM_readAnything(int address, T &data);
// 函式模板的定義
// 使用EEPROM程式庫寫入一個一個的byte
template <class T> int EEPROM_writeAnything(int address, const T &data)
{
const byte *p = (const byte *)(const void *)&data;
int i, n;
for(i = 0, n = sizeof(data); i < n; i++)
EEPROM.write(address++, *p++);
return i;
}
template <class T> int EEPROM_readAnything(int address, T &data)
{
byte *p = (byte *)(void *)&data;
int i, n;
for(i = 0, n = sizeof(data); i < n; i++)
*p++ = EEPROM.read(address++);
return i;
}
#endif
然後是主草稿碼EEPROM_struct.ino:
#include <EEPROM.h>
#include "eeprom_anything.h"
// 自行定義struct,放入你想讀取的資料
struct dataType{
char name[10];
int age;
char gender;
float money;
float bank;
};
void setup(){
Serial.begin(115200);
dataType d; // 宣告結構變數,放入資料
strcpy(d.name, "Arduino");
d.age = 9;
d.gender = 'M';
d.money = 9876.54;
d.bank = 1234.56;
Serial.print("name: ");
Serial.println(d.name);
Serial.print("age: ");
Serial.println(d.age);
Serial.print("gender: ");
Serial.println(d.gender);
Serial.print("money: ");
Serial.println(d.money);
Serial.print("bank: ");
Serial.println(d.bank);
// 寫入EEPROM,回傳值count代表總共寫入幾個byte
int count = EEPROM_writeAnything(0, d);
Serial.print(count);
Serial.println(" bytes written.");
Serial.println("---------------");
}
void loop(){
// 讀取EEPROM,回傳值count代表總共寫入幾個byte
dataType d;
int count = EEPROM_readAnything(0, d);
Serial.print("name: ");
Serial.println(d.name);
Serial.print("age: ");
Serial.println(d.age);
Serial.print("gender: ");
Serial.println(d.gender);
Serial.print("money: ");
Serial.println(d.money);
Serial.print("bank: ");
Serial.println(d.bank);
Serial.print(count);
Serial.println(" bytes read.");
while(1){
}
}
其執行結果應輸出類似底下的訊息:
name: Arduino
age: 9
gender: M
money: 9876.54
bank: 1234.56
21 bytes written.
---------------
name: Arduino
age: 9
gender: M
money: 9876.54
bank: 1234.56
21 bytes read.
耶!
參考資料:
- Arduino官方文件 - EEPROM程式庫。
- Cooper Maa: Arduino 筆記 – EEPROM Library 使用簡介。
- Cooper Maa: 可讀寫任何資料的 EEPROM 函式,這篇文章主要的參考資料。
- Tutorial: Your Arduino's inbuilt EEPROM。
- Using EEPROM | Memories of an Arduino | Adafruit Learning System。
- EEPROM advanced usage on Arduino Uno / ATMega328 | Michael Bouvy。
This comment has been removed by the author.
ReplyDelete請問這是讀寫Arduino本身的EEPROM用的程式嗎?如果要用Arduino讀外部的EEPROM呢?
ReplyDeleteyes.
Delete需要適合外部EEPROM的arduino程式庫,
譬如http://playground.arduino.cc/Main/LibraryForI2CEEPROM
葉大,請問若要平均使用每個記憶體空間,程式碼要怎麼改會比較好。
ReplyDelete因為依照您的code是重複讀寫著address = 0 的位置。
希望能平均使用記憶體,還請賜教
你需要的功能叫做wear leveling(耗損均攤)。
Delete有找到一個程式庫https://github.com/drjoju/Arduino-wear-leveling
但我沒實際用過。
謝謝你指引方向,不然google整天也不知道有這東西,再次感謝
Delete