Step06 eepromを使ったセーブ/ロード


#1

電源を切っても消えないメモリ領域。それがeepromです。
サイズは1024バイト(0x0000 - 0x03ff)もあります。

今までArduboyライブラリを通して色々なことをして来ましたが、
今回はavr-libcライブラリを使います。Arduboy側からの提供がないからです。

uint8_t eeprom_read_byte (const uint8_t *__p) __ATTR_PURE__
void    eeprom_write_byte (uint8_t *__p, uint8_t __value)

ちなみにArduinoリファレンスでは、EEPROM.write、EEPROM.readを使うように書いてあります。
ソースを追いかけると上記の関数を仲介しているだけでしたのでここでは使わないことにしました。

コードを見てみましょう。

#include <Arduboy.h>
#include <avr/eeprom.h>

Arduboy ab;

uint8_t* eepAdr = (uint8_t*)EEPROM_STORAGE_SPACE_START;
uint8_t  num = 0;


void EepSeek(uint16_t adr)
{
    eepAdr = (uint8_t*)EEPROM_STORAGE_SPACE_START + adr;
}

uint8_t EepRead8(void)
{
    eeprom_busy_wait();
    return eeprom_read_byte(eepAdr++);
}

uint16_t EepRead16(void)
{
    uint16_t ret = 0;

    ret |= EepRead8();
    ret |= EepRead8() << 8;

    return ret;
}

void EepWrite8(uint8_t dat)
{
    eeprom_busy_wait();
    eeprom_write_byte(eepAdr++, dat);
}

void EepWrite16(uint16_t dat)
{
    EepWrite8(dat & 0xff);
    EepWrite8(dat >> 8);
}

bool isSave()
{
    EepSeek(0);

    if(EepRead8() != 'T') return false;
    if(EepRead8() != 'E') return false;
    if(EepRead8() != 'S') return false;
    if(EepRead8() != 'T') return false;

    return true;
}

void save()
{
    EepSeek(0);

    EepWrite8('T');
    EepWrite8('E');
    EepWrite8('S');
    EepWrite8('T');

    EepWrite8(num);
}

void load()
{
    EepSeek(4);

    num = EepRead8();
}

void setup()
{
    ab.beginNoLogo();
    ab.setFrameRate(30);
    ab.clear();

    if(isSave() == false)
    {
        save();
    }

    load();

    char t[16];
    sprintf(t, "num = %u", num);

    ab.setCursor(0, 0);
    ab.print(t);
    ab.display();

    num++;
    save();
}

void loop()
{
    if(!(ab.nextFrame()))
    {
        return;
    }

    // EMPTY
}

電源をON/OFFするたびにカウントアップしていきます。

EEPROM_STORAGE_SPACE_STARTは、Arduboyライブラリ側の指定位置です。
先頭の0~15バイト目はライブラリが予約しています。

read、write関数は、8ビット単位だけでなく16ビット単位でも使えるようにしています。
仮に8ビットだけしか用意していない場合、hi, loと2回に分けて呼び出ししなくてはいけません。

また、インデックス変数を持つのもゲームスコアを書くとき、
i+0、i+1、i+2などの引数を使いたくないからです。

まあ愚痴っぽくなりましたけど・・・物は試し、実際コンパイルしてやってみてください。(^^;
最後にArduinoリファレンスマニュアルでは以下の補足説明がありました。

EEPROMへの書き込みには3.3ミリ秒かかります。
EEPROMの書込/消去サイクルは100,000回で寿命に達します。頻繁に書き込みを行う場合は注意してください

#2

eepromを毎回ゲームごとに上書きするのではなく、共有して使おうという議論はあります。
実際のところまだ標準規格までは行っていません。今のところ無視してかまわないと思います。
http://community.arduboy.com/t/eeprom-techniques-and-best-practices-are-there-any/1656


(Holmes) #3

Any chance you can write these tutorials in English? :slight_smile:


#4

sry. no.

my english sentence is not good.
It is better google translation than my English. lol


(Holmes) #5

Haha. I understand! Can I translate these to English? :slight_smile:


#6

yes pls. :slight_smile:

copy&paste, translate, steal, a revised and enlarged edition, all welcome!