GM65を使う

概要

 GM65というデバイスの取得データをLCD表示するプログラムを作成しました。ARDUINOとGM65は下図の通り、RS232C接続します。LCD接続は過去投稿同様にI2C接続なので省略します。

表示状態

 先ずシリアルモニター出力状態です。連続して同じコードを読み込んだ場合、“>” を出力します。

  

 次にLCD出力状態です。各行の最大表示文字数を超えた文字は出力しません。また、最大表示行を超えた場合は1行目に戻って、上書更新します。

プログラム

 LCD表示部は、ほぼコピペです。

#include <Wire.h>
#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3);          // RX,TXの割り当て

//int l_cn = 0;
String rcvDat = "" ;
String rDT_bf = "" ;
bool f_same = false;

// 00-1F:ASCII制御コード
// 20(SP),27('),7f(DEL)
char asc_c[] = { ' ', ' ', ' ', ' ', ' ', ' ' ,' ' , ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
                 ' ', ' ', ' ', ' ', ' ', ' ' ,' ' , ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
                 ' ', '!', '"', '#', '$', '%', '&' ,' ' , '(', ')', '*', '+', ',', '-', '.', '/', 
                 '0', '1', '2', '3', '4', '5' ,'6' , '7', '8', '9', ':', ';', '<', '=', '>', '?',
                 '@', 'A', 'B', 'C', 'D', 'E' ,'F' , 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
                 'P', 'Q', 'R', 'S', 'T', 'U' ,'V' , 'W', 'X', 'Y', 'Z', '[', ' ', ']', '^', '_',
                 '`', 'a', 'b', 'c', 'd', 'e' ,'f' , 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
                 'p', 'q', 'r', 's', 't', 'u' ,'v' , 'w', 'x', 'y', 'z', '{', '|', '}', '~', ' ',        
                };

byte dvs_adrs[4] = { 0x51 , 0x55 , 0x50 , 0x3F };  // EEPROM 24FC1025 BLOCK1,2  I2Cアドレス
int wrt_lin[2] = { 0 , 0 };
byte blk = 0x20 ;                             // スペース



void setup() {
  Serial.begin(9600);                    // シリアルモニタ出力
  mySerial.begin(9600);                   // ソフトウェアシリアル通信開始(ボーレート9600bps)

  int sz_bf ;
  uint8_t buf[5] = { 0x00, 0x01, 0x00, 0x00, 0x00 };    
  buf[0] = 0x07; buf[3] = 0x00; buf[4] = 0x01;          // 読込(アドレス・データ数指定)
  sz_bf = sizeof(buf);
  send_cmd_GM65( buf, sz_bf);
  wait_Serial_RCV();
  
  //buf[0] = 0x08; buf[3] = 0x00; buf[4] = 0x95;        // 書込(0x95:コマンドモード)  
  buf[0] = 0x08; buf[3] = 0x00; buf[4] = 0x96;          // 書込(0x96:連続モード)
  
  sz_bf = sizeof(buf);
  send_cmd_GM65( buf, sz_bf);
  wait_Serial_RCV();

  Wire.begin();
  lcdinit(0);                                 // LCD初期化(DVS1)
  lcdinit(1);                                 // LCD初期化(DVS2)

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

// ■メイン処理■
void loop() {
     
  while(mySerial.available() > 0){
    int val = mySerial.read();              // 受信データ読込
    if (val==13){ 
      if(rcvDat.indexOf("     31") < 0){
        if(rDT_bf != rcvDat ){
          if(f_same){ Serial.println(""); } 
          Serial.println(rcvDat); 

          int str_len=rcvDat.length();
          char MEM[str_len+1];
          rcvDat.toCharArray(MEM, str_len+1);

          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 ; }
                  
          f_same=false;
        }else{
          Serial.print(">");               // 前受信データと同じ
          f_same=true;
        }
      }
      rDT_bf = rcvDat ;
      rcvDat = "" ;
      
    }else{ 
      rcvDat += String(asc_c[val]);
    }
  }

  delay(20);
}

// データ受信待ち
void wait_Serial_RCV(){
  while(mySerial.available() > 0){
    int val = mySerial.read();            // 受信データ読込
  }
}

// コマンド送信(HEAD,CRC除く主要データ(TYPE,DATA数,アドレス,DATA)を渡す)
void send_cmd_GM65(uint8_t * buf , int sz_bf){
  uint8_t bf_cnv[ sz_bf + 4 ];
  uint8_t *buf_rtn = chkSumCalc( buf , sz_bf);                      // CRC計算

  bf_cnv[0] = 0x7E ; bf_cnv[1] = 0x00 ;                             // HEAD
  for(int i = 0 ; i < sz_bf ; ++i ){ bf_cnv[ i + 2 ] = buf[i] ; }   // DATA
  bf_cnv[sz_bf+2] = buf_rtn[0] ; bf_cnv[sz_bf+3] = buf_rtn[1] ;     // CRC

  for(int i = 0 ; i < sz_bf + 4 ; ++i ){  
    mySerial.write(bf_cnv[i]);
  }
  delay(150);
}


// CRC計算
uint8_t *chkSumCalc( uint8_t * buf , int sz_bf ){
  uint8_t dt_bf;
  static uint8_t rtn_ary[2] = { 0x00, 0x00 }; 
  int sz_dt = sz_bf + 3 ;
  uint8_t data[sz_dt];

  uint16_t rtn_crc = 0x0000;
  //d0 = 0x00; d1 = 0x00;
  
  for(int i = 0 ; i < sz_bf ; ++i ){ data[i] = buf[i] ; }
  data[sz_bf + 0] = 0x00 ; data[sz_bf + 1] = 0x00 ; data[sz_bf + 2] = 0x00;

  int sft_bit = 0;
  int sft_sum = 0;
  int sft_max = 8 * sz_bf ;
  int sft_lft = sft_max - sft_sum ;
  int loop_cn = 0;
  int lp_max = 50;                      // 最大ループ回数(とりあえず設定)

  while( loop_cn < lp_max ){
    sft_bit = calc_bit_shift(data[0]);  // シフト量算出処理
    sft_sum += sft_bit ;                // シフト合計
    sft_lft = sft_max - sft_sum ;       // 残ビット(0より小さくなる場合処理しない)

    if( sft_lft < 0 ){  
      break;                            //■残シフトビットがマイナスになる前に処理中止
    }       

    dt_bf = data[0];                    //■変換前データ保存
    // ■BITシフト処理■
    for(int i = 0 ; i < sz_dt - 1 ; ++i ){ 
      int sft_bit_r = 8 - sft_bit ;
      uint8_t tmp = (data[i] << sft_bit) | (data[i+1] >> sft_bit_r);
      data[i] = tmp ;
    }

    // ■排他的論理和■ ※変換前元データが0の時は実施しない。
    if(dt_bf != 0){ data[0] ^= 0x10; data[1] ^= 0x21; } 
    
    if(sft_lft<=16){
      uint16_t mask_bit = 0xFFFF ;                          // 最終検出用マスク
      int msk_sft = 16 - sft_lft ;                          // マスクシフト量
      mask_bit = mask_bit << msk_sft ;
      uint8_t msk_1 = (uint8_t) mask_bit;                   // 下位マスク
      uint8_t msk_0 = (uint8_t)(mask_bit >> 8);             // 上位マスク

      int tmp_chk = (msk_0 & data[0]) + (msk_1 & data[1]) ; // マスク処理により、データ判定

      if(tmp_chk==0){
        int sft_lft_r = 8 - sft_lft ;
        uint8_t tmp_0 = (data[0] << sft_lft) | (data[1] >> sft_lft_r);
        uint8_t tmp_1 = (data[1] << sft_lft);
        rtn_crc = tmp_0 << 8 ; rtn_crc += tmp_1 ;
        rtn_ary[0] = tmp_0; rtn_ary[1] = tmp_1;
        
        break; 
      }
    }
    loop_cn ++ ;
  }
  return rtn_ary;
}


// データ値からシフト量を計算
int calc_bit_shift(uint8_t buf){
  int sft_bit = 0;
  if( buf > 127 ){ sft_bit = 1;
  } else if( buf > 63 ){ sft_bit = 2;
  } else if( buf > 31 ){ sft_bit = 3;
  } else if( buf > 15 ){ sft_bit = 4;
  } else if( buf > 7 ){ sft_bit = 5;
  } else if( buf > 3 ){ sft_bit = 6;
  } else if( buf > 1 ){ sft_bit = 7;
  } else { sft_bit = 8; }
  return sft_bit;
}

// CRC計算(SAMPLE)
void chkSumTest(){
  int sz_bf ;
  uint8_t buf0[3] = { 0x00, 0x01, 0x3E };               // → E4AC
  sz_bf = sizeof(buf0);
  uint8_t *buf_rtn0 = chkSumCalc( buf0 , sz_bf);

  uint8_t buf1[5] = { 0x07, 0x01, 0x00, 0x0A, 0x01 };   // → EE8A
  sz_bf = sizeof(buf1);
  uint8_t *buf_rtn1 = chkSumCalc( buf1 , sz_bf);
}

// *********************************
// ********** 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);    
}

まとめ

 イメージしていたそれっぽいものが出来ました。

コメントを残す

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