EEPROM(24LC256/1024)と接続して読み書きを行って見ます

〔PICの動かせ方入門に戻る〕


 前回の記事でArduinoとPICを接続してI2C通信を行いました、I2Cの概要等はそちらを参考にして
下さい。
この頁ではPIC16F1827とEEPROM(24LC256)をI2Cで接続してデータを読書きして見たいと思います。
(PIC12F1822でも利用可能です)
尚、24LC256は秋月電子のこちらから購入しています。
また、24LC256のマニュアルはこちらを参照下さい。

 ここでは24LC256を利用しましたが24xx32〜24xx512までは利用可能です。
(たぶん、ATMELのAT24C256もいけると思いま〜す。)
念の為に、256は256Kバイトではなく256Kビットです、間違えの内容に、私は間違えました。
256K有るならぁグラフィックLCDのぉ漢字フォントがぁ190K有るので全部書き込んでぇLCDにぃ表示出来るねぇみたいなぁ。
が、アドレスを計算していて合わないのですよぉ、よ〜くマニュアル見たら、
なぁに〜、256Kビットじゃん!だめじゃん!orz
でぇ、256Kビットって事は32Kバイトの容量って事です。
このEEPROMは最大8個まで接続する事が可能なようです。
(256kbit x 8 = 2Mbit[256Kbyte] んん...8個接続ねぇ.... でもねぇ....)

PS. *2)
 24FC1025(24xx1025)のEEPROMを手に入れたのでこのデバイスについても追記を行って置きます。
1024Kビット(128Kバイト)ですが、このデバイスには512Kビット(64Kバイト)が2個入ってます
なので、1ブロック512Kビットで2ブロック有り何方にアクセスするのかを指定する必要が有ります。
また、このEEPROMは最大4個まで接続する事が可能なようです。
尚、24FC1025は通信速度1MHzまで対応の様ですが、ここでは100KHzで行っています。
24FC1025のマニュアルは、秋月電子の販売HPからダウンロードしましょう。 *4)

[ピンの配置図]

配置図  配置図
今回使用するPIC16F1827のピンは、電源ピンの14番(VDD:+5V)と5番(VSS:GND)、
I2Cピンの10番(RB4:SCL)と7番(RB1:SDA)です。
それとEEPROMから読み出したデータ表示用として18番(RA1)から、
別途作成した自作のLCDモニターに出力しています。
また、24LC256の電源ピンは8番(VCC:+5V)と4番(VSS:GND)です。

[配線図]

配線図1
24xx1024も同じ配線です(但し、A2のみVDDに配線します)。

SDA/SCL ピンについて
SDA(RB1)/SCL(RB4)のピンは必ずデジタル入力に設定を行います。

I2Cのプルアップ抵抗について
I2C伝送路のプルアップ抵抗として、PIC内蔵のプルアップ抵抗を利用したので配線図には在りません。
外部で取付ける場合、データシートには通常は通信速度が100KHzで10KΩ、400KHz/1MHzで2KΩと
書いて有ります。

WPピンについて
24LC256/1024の7番ピン(WP:上配線図のオレンジ線)は、書き込み防止用のライトプロテクトピンです。
+5V(VDD)に配線すると書き込みが禁止です、読み込みはできます。
GND(VSS)に配線すると書き込みが可能になります、このピンは必ずどちらかに配線を行います

A0/A1/A2ピンについて

24xx32〜24xx512
24LC256の1番ピン(A0)・2番ピン(A1)・3番ピン(A2)は、複数のEEPROMを使った場合に識別をする為のチップ選択ビットピンです。
それぞれのピンを+5V(VDD)かGND(VSS)に配線しそのパターンで識別します、
+5V(VDD)に接続するとHigh(1)でGND(VSS)に接続でLow(0)です、3ビットなので8個までOKですね。
なので、スレーブアドレス(EEPROMのデバイスアドレス)は下記の様になります。
A2 A1 A0 R/W
今回の実験では全てGNDに配線(上配線図の黄色線)しています、だから"1010000"です。

24xx1024 *2)
24FC1025の1番ピン(A0)・2番ピン(A1)は、複数のEEPROMを使った場合に識別をする為のチップ選択
ビットピンです、2ビットなので4個までOKですね。尚、A2ピンはVDDに配線しないと動作しません
スレーブアドレス(EEPROMのデバイスアドレス)は下記の様になります。
B0 A1 A0 R/W
B0が"512Kビットのブロック"選択ビットです。

AT24C1024B(ATMEL) *2)
ATMEL製の場合はA0ピンがNCとなっています、
P0が最上位アドレスビット"A16"となっています。(B0と同じ意味です)
A2 A1 P0 R/W
これ用にソフトは対応していないのでこれを使用する場合は自分で変更して下さい。

《ダウンロードプログラムについて》

↓ここからサンプルプログラムソースファイルをダウンロードして下さい。
MC24.lzh(2014/02/02) *1)
MC24.lzh(2014/09/19) MPLABXと24xx1024に対応 *2)
MC24.lzh(2014/11/01) Write2/Read2のバグを修正 *3)

プログラムソースをダウンロードしたら、MPLAB Xにてプロジェクトを作成します。
以下のファイルをプロジェクトディレクトリにコピーしてプロジェクトに取込んで下さい。
次にコンパイルPIC書き込みを実行して下さい。
MPLAB(R) XC8 C Compiler Version 1.32コンパイラを使用しています。

ダウンロードしたら解凍して下さい、以下のファイル構成です。
 MC24.c ・・・・・・・・本体のソースプログラム
 MC24_1024.c・・・・本体のソースプログラム(24xx1024用) *2)
 skI2Clib.c  ・・・・・・I2C通信部分の関数を記述したライブラリソースプログラム
 skI2Clib.h  ・・・・・・ヘッダファイル
 skMC24xxx.c ・・・・Microchip I2C EEPROM(24xxxファミリ)関数を記述したライブラリソースプログラム
 skMC24xxx.h ・・・・ヘッダファイル

MC24.cかMC24_1024.cのどちらか1つでコンパイルします

このプログラムにはデバッグモニタープログラム「skMonitorLCD.c」「skMonitorLCD.h」が必要です。
デバッグLCDモニターについてはこちらを参照して下さい。
「skMonitorLCD.c」は送信データをTimer2のタイミングで送る様に変更しました、
その為にMC24.cプログラムを変更しています。
 *1)

また、LCDモニターの出力はRA1から行っているので「skMonitorLCD.h」を下記の様に変更します。
#define _XTAL_FREQ 8000000  // 使用するPIC等により動作周波数値を設定する
#define BAUDRATE 51      // 9600bps(8MHz=51)(4MHz=25)(16MHz=103)(20MHz=129)
#define MONITOR_PIN RA1      // モニタ出力するピンの番号を設定する


MC24.c

モニター表示  起動が成功すると左図の様に表示されます。
 "Error"表示された場合は、配線等を見直して下さい。
 EEPROMの0番地から3バイト[1][2][3]を書き込み、
 その後に3バイト読み込んでHEXで表示しているだけです。

 24LC256は256Kbit(32Kbyte)なので0番地から32767番地までアクセス出来ます。

 尚、書き込んだ後にすぐ読み出すとエラーが出る場合が有ると言う話が有ります、その場合は
 書き込みと読み込みの間に遅延(__delay_ms(100))を入れればOKです。
 データシートに"Write cycle time (byte or page) 5ms"と有るので最低delay(5)は必要でしょう。

MC24_1024.c *2)

このファイルが"24xx1024"対応のサンプルプログラムです。
ブロックをまたがっての読み書きは出来ません、これが出来る様に新たに[Read2][Write2]関数を
追加しています。
例えば、下の様に65533番地から6バイト読み取る事は出来ません。
ans = MEM_Read(65533,dt1,6) ;
ブロック0で3バイト読み、ブロック1にして3バイト読みと分けないとダメです。
ans = MEM_Read(65533,dt1,3) ; // B0=0に設定してから読込む
ans = MEM_Read(0,dt1,3) ;   // B0=1に設定してから読込む
これを今回追加した関数を使えば読み取れます。
ans = MEM_Read2(65533,dt1,6) ;
(書き込みも同様です)
ですので、"24xx1024"を読み書きする場合は、[Read2][Write2]関数を使います。

動作としては、65533番地から6バイト[a][b][c][d][e][f]を書込みと読込みを行っているだけです。

skI2Clib.c

このライブラリはデバイス(RTC/EEPROM等)と接続を行う為の関数集です。
前回の記事で紹介した"skI2Cmaster.c"のライブラリでも利用可能ですが、
デバイスと接続する場合はI2Cのリピート・スタートを使えばプログラム容量も減らせるので、
こちらを利用した方が良いでしょう。
尚、"skI2Clib.c"はPIC16F1827だけでなく、12F1822やおそらく他のPICでF1シリーズは使用できると
思います、たぶん....、他のPIC持ってないのでぇにゃんともですがぁ、試してみてみてぇ。

I2C通信の関数ライブラリの使い方を説明します。

InitI2C_Master()
 I2C通信のマスターモードで初期化を行う処理です。
 I2C通信用の速度クロック周波数は100KHzでの設定です、
 この速度はFOSC(PICのCPU周波数)8MHzの場合で初期化されています。
 FOSCを変えた場合はこちらを参考にSSP1ADDレジスタを変えて下さい。

 また、24LC256/1024はI2C通信用の速度クロック周波数400KHzにも対応しています。
 FOSCを8MHzとし400KHzで動作させる場合は下記の様に変更します。
  SSP1STAT= 0b00000000 ; // 高速モードに設定する(400kHz)
  SSP1ADD = 0x4 ;

 24FC1025はI2C通信用の速度クロック1MHzに対応しているので折角だから動作させて見ました。*2)
 FOSCを8MHzとし1MHzで動作させる場合は下記の様に変更します。
  SSP1STAT= 0b10000000 ; // 標準速度モードに設定する(100kHz and 1MHz)
  SSP1ADD = 0x1 ;

ans = I2C_Start(adrs,rw)
 スレーブにスタートコンディションを発行する処理です。
  adrs  :スレーブのアドレスを指定します
  rw     :スレーブに対する動作の指定をします
       0 = スレーブに書込みなさい要求  1 = スレーブに送信しなさい要求
  ans   :0 = 正常 1 = 異常(相手からACKが返ってこない)

ans = I2C_rStart(adrs,rw)
 スレーブにリピート・スタートコンディションを発行する処理です。
  adrs  :スレーブのアドレスを指定します
  rw     :スレーブに対する動作の指定をします
       0 = スレーブに書込みなさい要求  1 = スレーブに送信しなさい要求
  ans   :0 = 正常 1 = 異常(相手からACKが返ってこない)

I2C_Stop()
 スレーブにストップコンディションを発行する処理です。

ans = I2C_Send(dt)
 スレーブにデータを1バイト送信する処理です。
  dt     :送信するデータを指定します
  ans   :0 = 正常 1 = 異常(相手からACKが返ってこない又はNOACKを返した)
 例)slave_adrsへの2バイト送信
     ans = I2C_Start(slave_adrs,RW_0);  // スタートコンディションを発行する
     if (ans == 0) {
          I2C_Send(dt) ;                // 1バイト目を送信する
          I2C_Send(dt) ;                // 2バイト目を送信する
     } else 異常 ;
     I2C_Stop() ;                       // ストップコンディションを発行する
c = I2C_Receive(ack)
 スレーブからデータを1バイト受信する処理です。
  ack    :スレーブからデータを受信した後に返答するデータを指定します
       0 = ACKをスレーブに返す 1 = NOACKをスレーブに返す(受信データが最後なら1)
  c       :受信した1バイトのデータを返す
 例)slave_adrsから2バイト受信する
     ans = I2C_Start(slave_adrs,RW_1) ;  // スタートコンディションを発行する
     if (ans == 0) {
          dt1 = I2C_Receive(ACK) ;       // 1バイト目を受信する
          dt2 = I2C_Receive(NOACK) ;     // 2バイト目を受信する
     } else 異常 ;
     I2C_Stop() ;                        // ストップコンディションを発行する
InterI2C()
 I2C関連の割り込み処理です。
 今回は割込み発生したらフラグをクリアしているだけです。
 メインプログラム(例"MC24.c")の割込み処理で必ず呼びます。
 例)
     void interrupt InterFunction( void )
     {
          // I2C関連の割り込み処理
          InterI2C() ;
     }
skI2Clib.h

I2C通信の関数ライブラリ用インクルードファイルです。
"skI2Clib.c"を利用する場合に
#include "skI2Clib.h" をプログラムの先頭で記述しないとだめです。

skMC24xxx.h

Microchip I2C EEPROM(24xxxファミリ)関数ライブラリ用インクルードファイル
"skMC24xxx.c"を利用する場合に
#include "skMC24xxx.h" をプログラムの先頭で記述しないとだめです。

skMC24xxx.c

このライブラリは24LC256(24xx32〜24xx512/1024)とデータのやり取りを行う為の関数集です。
このライブラリ自体は他のPICでも使用出来ます。

Microchip I2C EEPROM(24xxxファミリ)関数ライブラリの使い方を説明します。

MEM_Init(A0,A1,A2)
 EEPROM関数ライブラリを使用する為の初期化を行う処理です。
 24xx1024でA2=0ならブロック0、A2=1ならブロック1が使用されますが、[Read2][Write2]関数を
 使用する場合は0/1は関係ないです。
  A0 :チップ選択ビットA0ピンの情報を設定します。(1=High 0=Low)
  A1 :チップ選択ビットA1ピンの情報を設定します。(1=High 0=Low)
  A2 :チップ選択ビットA2ピンの情報を設定します。(1=High 0=Low)
 例)上記配線図の黄色線の場合での設定例です
     MEM_Init(0,0,0) ;
ans = MEM_Read(adrs,*data,num)
ans = MEM_Read2(adrs,*data,num) *2)
 EEPROMの指定番地から指定した個数だけデータを読み出す処理です。
  adrs  :読み出し開始のデータアドレス位置を指定します。(24LC256なら0〜32767番地)
  *data:読み出したデータを保存する為の配列変数を指定します。
  num  :読み出すデータの個数を指定します。(この個数分だけ配列変数は確保します)
  ans   :0=正常 1=異常(相手からACKが返ってこない)
 例)0番地から2バイト読み込み、LCDモニターに表示する
     int ans ;
     char dt[4] ;

     ans = MEM_Read(0x00,dt,2) ;
     if (ans == 0) {
          MonitorPutc(0x11) ;
          MonitorPuth(dt[0]) ;
          MonitorPutc(' ') ;
          MonitorPuth(dt[1]) ;
     } else {
          MonitorPutc(0x01) ;
          MonitorPuts(" EEPROM R_Error ") ;
     }
 ※ 32766番地から4バイト読み出した場合は、[32766][32767][0][1]番地と言った感じに0番地に
   戻って読み出されます。
 ※ 24xx1024なら0〜131071番地までアクセス可能です、但し[Read2][Write2]を使った場合です。 *2)

ans = MEM_Write(adrs,*data,num)
ans = MEM_Write2(adrs,*data,num) *2)
 EEPROMの指定番地へ指定した個数だけデータを書き込む処理です。
  adrs  :書き込み開始のデータアドレス位置を指定します。(24LC256なら0〜32767番地)
  *data:書き込むデータを保存した配列変数を指定します。
  num  :書き込むデータの個数を指定します。
  ans   :0=正常 1=異常(相手からACKが返ってこない)

  注意)書き込む個数(num)はデバイスのページサイズ以上は連続書き込みは出来ません。
     (24xx32/64は32byte 24xx128/256は64byte 24xx512/1024は128byte)
 例)0番地から2バイト書き込む
     int ans ;
     char dt[4] ;

     dt[0] = 1 ;
     dt[1] = 2 ;
     ans = MEM_Write(0x00,dt,2) ;
     if (ans == 0) {
          MonitorPutc(0x01) ;
          MonitorPuts(" Write  Success ") ;  // EEPROM書き込み成功
     } else {
          MonitorPutc(0x01) ;
          MonitorPuts(" EEPROM W_Error ") ;  // EEPROMが応答しない
     }
 ※ 32767番地を超えた場合は捨てられます、また、送信データは一旦ページバッファに保存され、
   ストップコンディション発行で実際にメモリに書き込まれます、だから、ページサイズ以上のデータ
   を送信したらバッファの先頭から上書きされその内容がメモリに書き込まれます。
   (書き込みには"Write cycle time (byte or page) 5ms"かかります。)
 ※ WPピンの書き込み禁止状態で書き込んだ場合、メモリには書き込まれませんが、
   書き込み通信は正常に終了するので注意が必要かもね。

整数型(int)で読み書きする技
 上のMEM_Read/MEM_Writeはバイト単位(char)で読み書きを行いますが、
 この関数で整数型(int)でも読み書き出来ます。
下の例はint型で書き込んでint型で読み込んでいます、int型は2バイトですね、だから

     int dt ;

     dt = 123 ;
     ans = MEM_Write(0x00,&dt,2) ;   // 書き込み
     ans = MEM_Read(0x00,&dt,2) ;    // 読み込み

ってやればOKです、当然int型で書き込んだらint型で読み込まないとだめですよ。

《その他》

ここの記事では"複数のデバイスに対する連続アドレッシング"には対応していません、
単品デバイスに対するアクセスのみです。

24FC1025を24FC1024と思って記事が24xx1024となっていますが変更するのがメンドイので、
ここのサイトではこのまま行きます。m(_ _)m

・ EEPROM(24LC256/1024)とArduinoを接続した記事はこちらを参照下さい。
・ EEPROM(AT93C86)とPICを接続した記事はこちらを参照下さい。



リンク切れ見直し(*4) 2017/01/11
Write2/Read2のバグを修正(*3) 2014/11/01
MPLABX対応と24xx1024を追記(*2) 2014/09/19
"skMonitorLCD.c"変更により"MC24.c"のプログラム変更(*1) 2014/02/02


【きむ茶工房ガレージハウス】
Copyright (C) 2006-2017 Shigehiro Kimura All Rights Reserved.