EEPROMデータをLCD表示する

概要

 最近投稿した下記3つの記事の総まとめです。ARDUINOシリアルモニターからデータ番号入力し、対応するEEPROMメモリデータを読み取り、シリアルモニター、LCDに表示します。
 ■EEPROM(24FC1025)を使う
 ■ARUDUINOでI2C接続LCDを使う①
 ■ARUDUINOでI2C接続LCDを使う②

接続変更

 LCDとI2Cスレーブアドレスが重複していました。LCD側アドレスは固定なので、EEPROM接続を一部変更し対応します。LCDはI2Cディジーチェーン接続で変更はありません。

  

出力結果(表示状態)

 結果はシリアルモニターとLCDに出力します。
 下図はシリアルモニター出力結果です。

<シリアルモニター出力結果>

 下図はLCD1(16X2行)出力です。16文字を超える文字は破棄されます。2行を超える場合、1行目に戻り上書きします。

I2C接続キャラクタLCDモジュール 16×2行 [ACM1602NI-FLW-FBW-M01]

 下図はLCD2(20X4行)出力です。20文字を超える文字は破棄されます。4行を超える場合、1行目に戻り上書きします。

I2Cキャラクター液晶ディスプレイ 20文字×4行 [ACM2004D-FLW-FBW-IIC]

プログラム

#include <Wire.h>

const int BTN_DN = 9;
const int BTN_UP = 8;
const int inp_swDelay = 50;           // 50 ms (SW入力安定待ち時間)

byte dvs_adrs[4] = { 0x51 , 0x55 , 0x50 , 0x3F };  // EEPROM 24FC1025 BLOCK1,2  I2Cアドレス
char MEM[32];

int wrt_blk = 32;
int loop_cnt = 2048 ;
int rd_no = 2045 ;

int wrt_lin[2] = { 0 , 0 };
byte blk = 0x20 ;                             // スペース

// 初期設定
void setup() {
  Serial.begin(9600);
  Wire.begin();

  pinMode(BTN_UP, INPUT_PULLUP);
  pinMode(BTN_DN, INPUT_PULLUP);
  lcdinit(0);                                 // LCD初期化(DVS1)
  lcdinit(1);                                 // LCD初期化(DVS2)

  char myMsg[wrt_blk] ;

  Serial.println("PROGRAM START!");
  return;

  // 文字列単位でアドレス指定し書き込む場合
  Serial.println("Memory Writing Start");
  for(int ii = 0 ; ii < 2 ; ii++){
    for(int jj = 0 ; jj < loop_cnt ; jj++){
      sprintf( myMsg, "%s%d,%s%d  %s", "BLK:",ii," ADRS:",jj,"$$$$$$$$$$$$$$$" );
      //dtostrf( ii , 10 , 0 , myMsg );
      writeEEPROM_SER( ii , jj * wrt_blk , myMsg , false);

      if(jj%500==0){
        Serial.println(myMsg);
      }
    }
  }
  Serial.println("Finished");
  Serial.println("");
}

// ■連続処理■
void loop() {
  if (Serial.available() > 0 ) {
    String data = Serial.readStringUntil('\n');     // シリアルデータ受信 (改行まで)
    //data.toCharArray(myMessage, sizeof(MEM));      // 受信データ出力

    // 文字列の長さが1文字以上の場合
    if (data.length() > 0) {
        rd_no = data.toInt();                       // 文字列を整数に変換する
        rd_EEPROM_BY_SER();
    }
  }

  // EEPROM 読み込み(位置アップ)
  if(!inp_sw(BTN_UP)){
    rd_no++; 
    rd_EEPROM_BY_SER();
  }

  // EEPROM 読み込み(位置ダウン)
  if(!inp_sw(BTN_DN)){     
    rd_no--;
    rd_EEPROM_BY_SER();
  }    
}

// *********************************
// ******* EEPROM READ/WRITE ******* 
// *********************************
// ■関数■
// 書き込み(文字列単位→書込時間短縮)
// ARDUINO I2C送信バッファ32byte
void writeEEPROM_SER(unsigned int block, unsigned int address, byte *data, bool sp_wrt){
  if(sp_wrt){
    int adr_space = address + 30;
    Wire.beginTransmission(dvs_adrs[block]);
    Wire.write((int)highByte(adr_space));
    Wire.write((int)lowByte(adr_space));
    Wire.write(0x20);                       // スペース
    Wire.write(0x20);                       // スペース
    Wire.endTransmission();
    delay(5);                               // 書込サイクル完了待機
  }
   
  Wire.beginTransmission(dvs_adrs[block]);
  Wire.write((int)highByte(address));
  Wire.write((int)lowByte(address));

  for(unsigned int i=0; i < wrt_blk; i++){
      Wire.write(data[i]);
  }
  Wire.endTransmission();
  delay(5);                                 // 書込サイクル完了待機
}

// 書き込み(1文字づつ)
void writeEEPROM(unsigned int block, unsigned int address, byte data){
  Wire.beginTransmission(dvs_adrs[block]);
  Wire.write((int)highByte(address));
  Wire.write((int)lowByte(address));
  Wire.write(data);
  Wire.endTransmission();
  delay(5);                                 // 書込サイクル完了待機
}

// アドレス指定データ読込(block1、2 連番)
void rd_EEPROM_BY_SER(){

    //block1:0-2047,block2:2048-4095
    if( rd_no < 0 ){ rd_no = 4095 ; }
    else if( rd_no > 4095 ){ rd_no = 0 ; }

    int blk_no = (int)(rd_no / loop_cnt) ; 
    int s_adrs = (int)(rd_no % loop_cnt) ; 
  
    for (unsigned int j = 0; j < wrt_blk; j++){
      MEM[j] = readEEPROM( blk_no , j + wrt_blk * s_adrs );
    }

    char MSG[32];
    sprintf( MSG , "< %d , %d , %d >", rd_no, blk_no, s_adrs );
    Serial.print(MSG);
    Serial.println(MEM);

    //transDataToLcd( 0 , 0 , 0x01 , 10);         // 画面消去(DVS1)
    //transDataToLcd( 1 , 0 , 0x01 , 10);         // 画面消去(DVS2)

    //char* tmp = str_ary1[i];
    lcd_DispStrAry( 0, MEM , wrt_lin[0] );
    lcd_DispStrAry( 1, MEM , wrt_lin[1] );

    wrt_lin[0]++ ;
    wrt_lin[1]++ ;
    if( wrt_lin[0] > 1 ){ wrt_lin[0] = 0 ; }
    if( wrt_lin[1] > 3 ){ wrt_lin[1] = 0 ; }
}

// EEPROM データ読込(block、アドレス指定)
byte readEEPROM(unsigned int block , unsigned int address){
  byte data;
  byte EEP_AD = dvs_adrs[block];
  Wire.beginTransmission(EEP_AD);
  Wire.write((int)highByte(address));
  Wire.write((int)lowByte(address));
  Wire.endTransmission();
  
  Wire.requestFrom( EEP_AD , (byte)1 );
  while(Wire.available() == 0);           
  data = Wire.read();
  
  return data;
}

// ボタンSW入力安定待ち
boolean inp_sw(int pin){
  boolean c_st;
  boolean p_st;
  p_st = digitalRead(pin);       
  
  for(int counter = 0; counter < inp_swDelay; counter++){
    delay(5);                             
    c_st= digitalRead(pin);             
    if( c_st != p_st){
      counter = 0;                        
      p_st = c_st;              
    }
  }
  return c_st;                   
}


// *********************************
// ********** LCD DISPLAY ********** 
// *********************************
// 文字表示1(1文を複数行に分けて表示)
// dvs_no(0:DVS1、 1:DVS2)
void lcd_Disp_Str(int dvs_no , char* str){
  int l_cnt = 16 ;
  int ln_cn = 2 ;
  if(dvs_no!=0){ 
    l_cnt = 20 ; 
    ln_cn = 4 ;
  }
  
  for(int j = 0; j < ln_cn ; j++){
    pos_cursor( dvs_no , j , 0);              //座標指定
    for(int i = 0;i < l_cnt ;i++){
      if(*str == '\0'){
        transDataToLcd( dvs_no , 1 , blk , 0);
      }else{
        transDataToLcd( dvs_no , 1 , *str++ , 0);
      } 
    }
  }
}

// 文字表示2(1文を各行に表示)
// dvs_no(0:DVS1、 1:DVS2)
void lcd_DispStrAry(int dvs_no , char* str , int l_n ){
    int l_cnt = 16 ;
    if(dvs_no!=0){ l_cnt = 20 ; }
    
    pos_cursor( dvs_no , l_n , 0);            //座標指定
    for(int i = 0 ; i < l_cnt ; i++){
      if(*str == '\0'){
        transDataToLcd( dvs_no , 1 , blk , 0);
      }else{
        transDataToLcd( dvs_no , 1 , *str++ , 0);
      } 
    }
}


// LCD初期化
// dvs_no(0:DVS1、 1:DVS2)
void lcdinit(int dvs_no) {
  if(dvs_no == 0){
    transDataToLcd( 0 , 0 , 0x01 , 10);      //画面消去
    transDataToLcd( 0 , 0 , 0x38 , 10);      //ファンクション設定
    //transDataToLcd( 0 , 0 , 0x0F , 10);    //ディスプレイON、CURSOR-ON、blinking-ON
    transDataToLcd( 0 , 0 , 0x0C , 10);      //ディスプレイON、CURSOR-OFF、blinking-OFF
    transDataToLcd( 0 , 0 , 0x06 , 10);      //データ書き込み後アドレス加算モード設定
  } else {
    transDataToLcd( 1 , 0 , 0x01 , 10);      //画面消去
    transDataToLcd( 1 , 0 , 0x38 , 10);      //ファンクション設定
    //transDataToLcd( 1 , 0 , 0x0F , 10);    //ディスプレイON、CURSOR-ON、blinking-ON
    transDataToLcd( 1 , 0 , 0x0C , 10);      //ディスプレイON、CURSOR-OFF、blinking-OFF
    transDataToLcd( 1 , 0 , 0x06 , 10);      //データ書き込み後アドレス加算モード設定
  }
}

// LCDデータ送信
// dvs_no(0:DVS1、 1:DVS2)
// typ_d ( 0:コマンド、1:データ )
// trsDat( コマンド、もしくはデータ )
// dTime ( データ送信後、待機時間 )
void transDataToLcd(int dvs_no , int typ_d , byte trsDat , int dTime){
  byte typCmd = 0x00 ;
  if(typ_d != 0){ 
    if(dvs_no == 0){ typCmd = 0x80 ; }
    else{ typCmd = 0x40 ; } 
  }
  
  Wire.beginTransmission(dvs_adrs[dvs_no + 2]);   // ◆LCD DVS アドレス変更対応◆
  Wire.write(typCmd);
  Wire.write(trsDat);                   
  Wire.endTransmission();
  if(dTime>0){ delay(dTime); }
}

// 表示位置指定(カーソル座標指定)
// dvs_no(0:DVS1、 1:DVS2)
// loc_x (0:1行目、1:2行目)
// loc_y (0:最左、15:再右)
void pos_cursor(int dvs_no , int loc_x , int loc_y){
  byte p_inf = 0x80 + loc_y;
  if(loc_x == 1){ p_inf = 0x80 + 0x40 + loc_y; }
  else if(loc_x == 2){ p_inf = 0x80 + 0x14 + loc_y; }
  else if(loc_x == 3){ p_inf = 0x80 + 0x54 + loc_y; }
  
  transDataToLcd( dvs_no , 0 , p_inf , 5);    
}

まとめ

 固定でなく、内容を変化させたかったので試してみました。とりあえず、EEPROM, LCD関連の評価は一旦完了です。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です