I2C接続EEPROM24C64Bの実験



T.ROM1個の実験

 I2C接続のEEPROM Atmel-24C64Bを使って書き込み、読み込みの実験をしてみました。24C64Bは8PDIOのI2CインターフェイスのEEPROMです。64Kビットのデータを保持できます。ピン配置は以下のようになっています。


  1:A0  スレーブアドレスのビット0(GNDに接続)
  2:A1  スレーブアドレスのビット1(   〃   )
  3:A2  スレーブアドレスのビット2(   〃   )
  4:VSS  GND
  5:SDA  I2Cデータ 
  6:SCL  I2Cクロック
  7:WP  ライトプロテクト(フリーにしてもOK 書き込み可)
  8:VCC  5V接続(今回は3.6Vで使っています)


スレーブアドレスは上位4ビットは1010の固定になっています。最下位ビットがR/Wビットになっています。つまり書き込み時は1、読み込み時は0になります。

    24C64B書き込み時のアドレス:0xa1(1010 0001)
    24C64B読み込み時のアドレス:0xa0(1010 0000)

I2C接続のLCDにSCL、SDAを延長してパラレルに配線しています。

写真のLCDは、
1行目には 0x1234番地に書き込んだデータ0x5bを表示し、
2行目には 0x1234番地から読み込んだデータを表示しています。


確かに、間違いなく書き込み、読み込みができているようです。

 LCDと違って、A0、A1、A2のピンをGNDかVCCに接続することによって、スレーブアドレスを変更できるので、次回の実験では複数のアドレスの異なるEEPROMを繋いで実験してみます。


U.ROM2個を使う

 I2C接続のEEPROMM24C64Bを2個使った書き込み、読み込みの実験をしてみました。1つめのEEPROMをEEPROM1、2つめのEEPROMをEEPROM2とします。


◎EEPROM2の配線は以下の通りです。
  1:A0  スレーブアドレスのビット0(VCCに接続)
  2:A1  スレーブアドレスのビット1(GNDに接続)
  3:A2  スレーブアドレスのビット2(  〃   )
  4:VSS  GND
  5:SDA  I2Cデータ 
  6:SCL  I2Cクロック
  7:WP  ライトプロテクト(フリーにしてもOK 書き込み可)
  8:VCC  5V接続(今回は3.6Vで使っています)

   従ってEEPROM2のスレーブアドレスは

    24C64B書き込み時のアドレス:0xa3(1010 0011)
    24C64B読み込み時のアドレス:0xa2(1010 0010)

   となります。




◎プログラム

 プログラムは、EEPROM1のアドレス0x0100番地に0x55を書き込み、EEPROM2のアドレス0x0100番地に0xaaを書き込み、それぞれのEEPROMの0100番地から値を読み込み、LCDに表示しています。


1)メインプログラム M12_I2C_ROM2.c

  /****************************************/
  /* インクルード */
  /*======================================*/
  #include "sfr_r8m12a.h" /* R8C/M12A SFRの定義ファイル */
  #include "i2c_rom2_ctrl.h"


  void main(void)
  {
    unsigned char data=0x5b; // EEPROM書き込むデータ
    unsigned char rdata; // EEPROMからの読み取りデータ
    unsigned char i;
    unsigned char s[2];
    init();
    I2C_LCD_init(); // LCD初期化
    wait_ms(100);
    /* 書き込み開始 */
    I2C_start();
    EEP_Write(EP_ADD1,0x0100,0x55); // EEPROM1の0100番地にデータ0x55書き込み
    wait_ms(100);
    EEP_Write(EP_ADD2,0x0100,0xaa); // EEPROM2の0200番地にデータ0xaa書き込み
    wait_ms(100);
    /* 読み込み、LCD表示開始 */
    rdata=EEP_Read(EP_ADD1,0x0100); // EEPROM1の0100番地に書き込んだデータを読み込む
    for(i=0;i<2;i++){ // ASCIIコードに変換する
      if(rdata%16 >=10){ // a〜fの範囲の時
        s[i]='a'+(rdata%16-10);
      }
      else{
        s[i]='0'+(rdata%16); // 0〜9の範囲の時
      }
        rdata = rdata/16;
    }
    I2C_LCD_cursor(1,0); // EEPROM1から読み込んだ値をLCD表示する
    I2C_LCD_str("0x0100 ROM1=0x");
    I2C_LCD_data(s[1]);
    I2C_LCD_data(s[0]);

    rdata=EEP_Read(EP_ADD2,0x0100); // EEPROM2wの0200番地に書き込んだデータを読み込む
    for(i=0;i<2;i++){ // ASCIIコードに変換する
      if(rdata%16 >=10){ // a〜fの範囲の時
        s[i]='a'+(rdata%16-10);
      }
      else{
        s[i]='0'+(rdata%16); // 0〜9の範囲の時
      }
      rdata = rdata/16;
    }
    I2C_LCD_cursor(2,0); // EEPROM2から読み込んだ値をLCD表示する
    I2C_LCD_str("0x0100 ROM2=0x");
    I2C_LCD_data(s[1]);
    I2C_LCD_data(s[0]);

    I2C_stop();
    while(1);
  }

  /* I/O 初期化関数 */
  void init(void)
  {
    int i;
    prc0 = 1; // プロテクトレジスタ解除
    hocoe = 1; // 高速オンチップオシレータ発振開始
    for(i=0;i<50;i++); // 発振安定まで待つ
    hscksel = 1; // 高速オンチップオシレータ選択ビットを1にする
    scksel = 1; // システム基準クロックを高速にする
    prc0 = 0; // プロテクトレジスタ禁止
    pd1 = 0x41; // p1_0,p1_6 出力設定 0100 0001
  }

2)ヘッダーファイル i2c_rom2_ctrl.h

  /********************************************/
  /* i2c_rom2_ctrl.h */
  /********************************************/

  #define I2C_S_SCL p1_6=1 // I2Cクロック p1_6を1にする
  #define I2C_C_SCL p1_6=0 // I2Cクロック p1_6を0にする
  #define I2C_S_SDA p1_0=1 // I2Cデータ p1_0を1にする
  #define I2C_C_SDA p1_0=0 // I2Cデータ p1_0を0にする
  #define I2C_SDA_IN pd1_0=0 // p1_0を入力ポートに設定
  #define I2C_SDA_OUT pd1_0=1 // p1_0を出力ポートに設定
  #define I2C_SDA_data p1_0 // データポートをp1_0に設定
  #define AD 0x7c // アドレス 0B 0111 110+0(c/w)
  #define CLOCK 20000

  #define EP_ADD1 0xa0 // EEPROM1 書き込み時のアドレス:0xa0,読み込み時のアドレス:0xa1
  #define EP_ADD2 0xa2 // EEPROM2 書き込み時のアドレス:0xa2,読み込み時のアドレス:0xa3
  /*======================================*/
  /* プロトタイプ宣言                     */
  /*======================================*/
  void wait_us(unsigned long usec); // us単位のタイマ
  void wait_ms(unsigned long msec); // ms単位のタイマ
  void delay(void); // 6usの遅延関数
  void I2C_start(void); // I2C開始
  void I2C_stop(void); // I2Cストップ
  void ack(void); // ACKNOWLEDGE信号受信
  void I2C_H_CLK(void); // クロックHigh
  void I2C_L_CLK(void); // クロックLow

  void I2C_LCD_init(void); // lcd初期化関数
  int I2C_write(unsigned char data); // 書き込みの基本関数
  static unsigned char I2C_read(void);// 読み込みの基本関数
  void I2C_LCD_cmd(unsigned char cmd) ; // 液晶へのコマンド出力関数
  void I2C_LCD_data(unsigned char data); // 液晶への1文字出力関数
  void I2C_LCD_str(char* ptr); // 液晶への文字列表示関数
  void I2C_LCD_clear(void); // 液晶のクリャー関数

  int EEP_Write(unsigned char dev_add,unsigned short add,unsigned char data);//EEPROM書き込み関数
  unsigned char EEP_Read(unsigned char dev_add,unsigned short add);//EEPROM読み込み関数

  // カーソル位置設定関数 line(行数):1 or 2 cursor(左端からの位置):1〜8
  void I2C_LCD_cursor(unsigned char line,unsigned char cursor);
  void init(void);

3)LCD制御関数 i2Clcd_ctrl.c

  /*********************************************************/
  /* I2Cインターフェイスを使うストロベリーリナックスのLCD ST7032iをコントロールする   */
  /* 改変:p1_1・・・I2Cクロック */
  /*    :p1_0・・・I2Cデータ */
  /* FILE :i2clcd_ctrl.c */
  /* 7月 3日改変 LCDクリヤーの後は最低でも2ms以上wait必要、文字化け解消 */
  /* 7月26日改変 LCD部分を分割コンパイル化 i2clcd_ctrl.c */
  /* 9月16日改変 LCD関連関数名変更 全てI2C・・・ */
  /* */
  /* DATE :Thu, Jun 26, 2014 */
  /* DESCRIPTION :main program file. */
  /* CPU GROUP :M12A */
  /* This file is generated by Renesas Project Generator (Ver.4.19). */
  /* NOTE:THIS IS A TYPICAL EXAMPLE. */
  /********************************************************/
  /* インクルード */
  /*======================================*/
  #include "sfr_r8m12a.h" /* R8C/M12A SFRの定義ファイル */
  #include "i2c_rom2_ctrl.h"


  /********************************************************/
  /* 液晶初期化関数 */
  /********************************************************/
  void I2C_LCD_init(void)
  {
    wait_ms(100);
    I2C_LCD_cmd(0x38); // Function set 8bit 21Line Normal mode
    wait_us(30);
    I2C_LCD_cmd(0x39); // Function set 8bit 21Line Extended mode
    wait_us(30);
    I2C_LCD_cmd(0x14); // Internal OSC Frequency 183Hz BIAS 1/5
    wait_us(30);

    I2C_LCD_cmd(0x70); // Contrast set 0x70:2.7V 〜 0x30:3.0v

    wait_us(30);
    I2C_LCD_cmd(0x56); // Power Icon Contrast control
    wait_us(30);
    I2C_LCD_cmd(0x6c); // Follow control 3.3v
    wait_ms(400);
    I2C_LCD_cmd(0x38); // Set normal mode
    wait_us(30);
    I2C_LCD_cmd(0x0c); // Display ON
    wait_us(30);
    I2C_LCD_cmd(0x01); // Clear Display
    wait_ms(10);

  }

  /********************************************************/
  /* タイマ本体 us単位のwait関数 */
  /********************************************************/
  void wait_us(unsigned long usec)
  {
    usec = (usec * CLOCK) / 45000;
    while(usec --);{}
  }
  /********************************************************/
  /* タイマ本体 ms単位のwait関数 */
  /********************************************************/
  void wait_ms(unsigned long msec)
  {
    unsigned int i;
    for(i=0;i<msec;i++){
      wait_us(1000);
    }
  }
  /********************************************************/
  /* 6usの遅れ関数 */
  /********************************************************/
  void delay(void)
  {
    unsigned char i;
    for(i=0;i<5;i++){}
  }
  /********************************************************/
  /* 開始条件 */
  /********************************************************/
  void I2C_start(void)
  {
    I2C_SDA_OUT;
    I2C_H_CLK();
    I2C_S_SDA;
    delay();
    I2C_C_SDA;
    delay();
    I2C_L_CLK();
    delay();
  }
  /********************************************************/
  /* 終了条件 */
  /********************************************************/
  void I2C_stop(void)
  {
    I2C_SDA_OUT;
    I2C_L_CLK();
    I2C_C_SDA;
    delay();
    I2C_H_CLK();
    delay();
    I2C_S_SDA;
    delay();
  }
  /********************************************************/
  /* クロックをHighにする */
  /********************************************************/
  void I2C_H_CLK(void)
  {
    I2C_S_SCL;
    delay();
  }
  /********************************************************/
  /* クロックをLowにする */
  /********************************************************/
  void I2C_L_CLK(void)
  {
    I2C_C_SCL;
    delay();
  }
  /********************************************************/
  /* ACKNOWLEDGE */
  /********************************************************/
  void ack(void)
  {
    I2C_SDA_IN;
    I2C_S_SCL;
    delay();
    I2C_C_SCL;
    delay();
    I2C_SDA_OUT;
  }
  /********************************************************/
  /* 書き込みの基本関数 */
  /* 引数 data 8ビットデータ */
  /* 戻り値 ack */
  /********************************************************/
  int I2C_write(unsigned char data)
  {
    int i;
    int ack;
    I2C_SDA_OUT;
    for(i=0;i<8;i++){ // 上位から1ビト毎にクロックと共に送信
      if(data & 0x80){
        I2C_S_SDA;
      }
      else{
        I2C_C_SDA;
      }
      delay();
      I2C_H_CLK();
      I2C_L_CLK();
      data<<=1;
    }
    I2C_SDA_IN;
    I2C_H_CLK();
    I2C_L_CLK();
    ack=I2C_SDA_data;
    I2C_SDA_OUT;
    delay();
    return ack;
  }
  /*********************************************************/
  /* 読み込み基本関数 */
  /* 引数 なし */
  /* 戻り値 読み込んだ8ビットデータ */
  /*********************************************************/
  static unsigned char I2C_read(void)
  {
    int i;
    unsigned char data;

    data=0;
    I2C_SDA_IN;
    for(i=0;i<8;i++){
      data<<=1;
      I2C_S_SCL;
      delay();
      data |=(I2C_SDA_data);
      I2C_C_SCL;
      delay();
    }
    I2C_S_SCL;
    delay();
    I2C_S_SDA;
    delay();
    I2C_C_SDA;
    delay();
    I2C_C_SCL;
    delay();
    return data;
  }
  /*********************************************************/
  /* 液晶へのコマンド出力関数 */
  /*********************************************************/
  void I2C_LCD_cmd(unsigned char cmd)
  {
    I2C_start(); // スタートコンディ゙ション
    I2C_write(AD); // アドレス指定
    // C0+RS+000000 C0=1:連続で通信可 C0=0:stopコンディションで終了
    // RS=0:次のバイトでコントロールコード送信可能
    // I2C_write(0x80); // 次はコマンド出力を指定 連続
    I2C_write(0x00); // 次はコマンド出力を指定 連続ではない
    I2C_write(cmd); // コマンド送信出力
    I2C_stop(); // ストップコンディション
  }

  /*********************************************************/
  /* 液晶への1文字出力関数 */
  /*********************************************************/
  void I2C_LCD_data(unsigned char data)
  {
    I2C_start(); // スタートコンディ゙ション
    I2C_write(AD); // アドレス指定
    // C0+RS+000000 C0=1:連続で通信可 C0=0:stopコンディションで終了
    // RS=1:次のバイトでデータ出力を指定
    // I2C_write(0xc0); // 次はデータ出力を指定 連続
    I2C_write(0x40); // 次はデータ出力を指定 連続ではない
    I2C_write(data); // 1文字データ出力
    I2C_stop(); // ストップコンディション
    delay();
  }


  /*********************************************************/
  /* 液晶への文字列表示関数 */
  /*********************************************************/
  void I2C_LCD_str(char* ptr)
  {
    while(*ptr !=0){
      I2C_LCD_data(*ptr++);
    }
  }

  /*********************************************************/
  /* 液晶画面のクリャー関数 */
  /*********************************************************/
  void I2C_LCD_clear(void)
  {
    I2C_LCD_cmd(0x01);
  }
  /*********************************************************/
  /* 液晶のカーソル位置設定関数 */
  /*********************************************************/
  void I2C_LCD_cursor(unsigned char line,unsigned char cursor)
  {
    if(line == 1){
      I2C_LCD_cmd(0x80 | cursor);
    }
    else{
      I2C_LCD_cmd(0xc0 | cursor);
    }
  }
  /*********************************************************/
  /* EEPROM 24LC64B への書き込み関数 */
  /* */
  /* dev_add:EEPROMデバイスのアドレス */
  /* add :書き込み番地 */
  /* data :書き込むデータ                  */
  /*********************************************************/
  int EEP_Write(unsigned char dev_add,unsigned short add,unsigned char data)
  {
    I2C_start();
    I2C_write(dev_add);
    I2C_write(add>>8); // アドレス上位8ビットから先に書き込み
    I2C_write(add & 0x00ff); // アドレス下位8ビットを書き込む
    I2C_write(data); // データ書き込み
    I2C_stop();
    return 0; // 成功ならACK(=0)を返す
  }
  /*********************************************************/
  /* EEPROM 2464B からのデータ読み込み関数 */
  /* dev_add:EEPROMデバイスのアドレス */
  /* add :書き込み番地 */
  /* data :読み込むデータ                  */
  /*********************************************************/
  unsigned char EEP_Read(unsigned char dev_add,unsigned short add)
  {
    unsigned char data;
    dev_add &= ~0x01; // 読み込み番地 0xa1(1010 0001)
    I2C_start();
    I2C_write(dev_add);
    I2C_write(add>>8); // アドレス上位8ビットから先に書き込み
    I2C_write(add & 0x0ff); // アドレス下位8ビットを書き込む
    dev_add |= 0x01; // 読み込み時のスレーブアドレス 0xa1(0xa0 | 0x01)
    I2C_start();
    I2C_write(dev_add); // ROMデータを読み込む
    data=I2C_read();
    I2C_stop();
    return data;
  }
写真のLCD画面は
1行目 EEPROM1の0x0100番地から読み込んだ0x55を表示
2行目 EEPROM2の0x0100番地から読み込んだ0xaaを表示



プロジェクトファイルのダウンロード

メニューに戻る