概要
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);
}
まとめ
イメージしていたそれっぽいものが出来ました。