ArduinoでI2C通信　シリアルEEPROM(AT24C256)を使う

# はじめに
　この記事ではarduinoを使ってEEPROMの読み書きをします。

# 必要なもの
* Arduino (この記事ではR4 Minimaを使います)
* AT24C256B　(シリアルEEPROM)

https://akizukidenshi.com/catalog/g/g102323




# 接続構成

I2C通信は信号線(SCL,SDA)と電源電圧、GNDの４つを接続すれば良いです。
SCAとSDAはプルアップします。

![24LC256_ブレッドボード3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3943443/7148b809-182b-f39b-91f0-ad2ea28771f6.png)


**AT24C256のピンアサイン**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3943443/5ffed24d-cedc-f4b5-ce4a-9543933ceb80.png)

**デバイスアドレス**
A0-A2はデバイスアドレスの設定です。
今回はすべてGNDに接続しているので、アドレスは0b1010000(=**0x50**)です。
R/Wのbitはアドレスではなく、書き込みか読み出しの指定をする場所です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3943443/bf94d6d4-5197-a0fa-e9ce-e28dfc23d2d1.png)

# スケッチ


どうせarduinoの標準ライブラリ使うので、最初からデバイス向けのライブラリ使った方が良いですよね。(言い訳)
性能や使い勝手に問題があれば、用途に合わせて自作すべきだとは思いますが。
というわけで、AT24C向けのライブラリを使います。

https://github.com/stefangs/arduino-library-at24cxxx/blob/main/README.md

## 1byteの読み書き
**1. 書き込み**
メソッド：put(アドレス, 書き込む値)

```C:EEPROMwrite.ino
#include "Wire.h"
#include <at24c256.h>

AT24C256 eprom(AT24C_ADDRESS_0);

void setup() {
  Wire.begin();
  uint8_t Data = 55;
  eprom.put(0, Data);  //アドレス0の値を読み出し
}

void loop() {
}

```
**2. 読み出し**
メソッド：get(アドレス, 読み出す値を格納する変数)
```C:EEPROMRead.ino
#include "Wire.h"
#include <at24c256.h>

AT24C256 eprom(AT24C_ADDRESS_0);

void setup() {
  Wire.begin();
  Serial.begin(9600);
}

void loop() {
  uint8_t Data;
  eprom.get(0, Data);  //アドレス0に55を書き込み
  Serial.println(Data);
  delay(1000);
}
```

1.書き込みのスケッチをボードに書き込んだ後、2.読み出しスケッチをボードに書き込んで、
シリアルモニタで55が表示されれば成功です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3943443/a3418493-b20b-8586-f834-2269f725d976.png)

2.読み出しのスケッチは、読み出ししかしていません。
EEPROMの不揮発性メモリから、読み出せていることが確認できました。

## 連続データの読み書き

putやgetのメソッドは連続したデータもいい感じに読み書きできるようです。
例えば、引数に構造体を入れれば、構造体を丸ごと読み書きしてくれます。

```C:
#include "Wire.h"
#include <at24c256.h>

AT24C256 eprom(AT24C_ADDRESS_0);

struct HOGE{
  uint8_t X;
  uint8_t Y;
  uint8_t Z;
};

void setup() {
  Wire.begin();
  Serial.begin(9600);

  struct HOGE stHogeIn[10];               //30byteのデータ
  memset(stHogeIn, 0, sizeof(stHogeIn));  //RAM初期化

  for(int i=0;i<10;i++)                   //適当に値を書く
  {
     stHogeIn[i].X=i*10+1;
     stHogeIn[i].Y=i*10+2;
     stHogeIn[i].Z=i*10+3;
  }
  eprom.put(0,stHogeIn);                  //構造体丸ごと書き込み
}

void loop() {
  struct HOGE stHogeOut[10];              //30byteのデータ(EEPROMから読み出した値を入れる)
  memset(stHogeOut, 0, sizeof(stHogeOut));//RAM初期化
  eprom.get(0, stHogeOut);                //構造体丸ごと読み出し

  for(int i=0; i<10;i++)                  //シリアルモニタで読み出しデータを確認する
  {
    Serial.print(i);
    Serial.print(" ");
    Serial.print(stHogeOut[i].X);
    Serial.print(" ");
    Serial.print(stHogeOut[i].Y);
    Serial.print(" ");
    Serial.println(stHogeOut[i].Z);
  }
  
  delay(10000);
}
```

setup()の中で、RAM上のstHogeIn[10]のデータの中身は下記のようになっています。

|配列番号|X|Y|Z|
|---|---|---|---|
|0|1|2|3|
|1|11|12|13|
|2|21|22|23|
|3|31|32|33|
|4|41|42|43|
|5|51|52|53|
|6|61|62|63|
|7|71|72|73|
|8|81|82|83|
|9|91|92|93|

EEPROMへの書き込みはこの一行だけで、構造体30byte分がすべて書き込まれます。
```C:
eprom.put(0,stHogeIn); 
```

EEPROMからの読み出しも一行だけです。

```C:
eprom.get(0, stHogeOut); 
```

シリアルモニタで読み出した結果と一致していますね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3943443/465a852f-7139-2719-23c3-96e04e94c413.png)

構造体丸ごとコピーできれば、欲しいデータのアドレスを気にしなくてよいので便利そうですね。
通信データの量は増えてしまうので、性能とのトレードオフだと思います。