
GU-Dシリーズ/タッチスイッチ付VFD

GU-Dシリーズ/タッチスイッチ付VFD
今回は、Arduinoの中でもコンパクトな「Arduino micro」を使って、タッチスイッチ付VFDモジュールのGU-Dシリーズを動かしてみます。 テンキーによる数値入力例も含まれますのでご期待ください。フォントも内蔵しますので非力なコントローラでも漢字表示ができます。
制作テーマはタッチスイッチで操作する「タッチタイマー」としました。設定した時間をカウントダウンします。Arduinoのサイトから開発環境をダウンロードしてお試しください。回路は試作用のブレッドボードで組み立てています。
タッチ操作のタイマーを作ります

初めにラーメンどんぶりをイメージした枠の中に内蔵フォントでタイトルを表示します。これが出れば、表示機能はOKです。この画面で表示面をタッチすると左側写真の中央の入力画面に進みます。
画面右側の10個のスイッチで0~9の数値入力できます。他にCLRキーとGOキーを用意しました。また、入力した数字を表示する部分にはユーザーウインドウ機能を使っています。10キーを使ってタイマー時間を入力したらGOにタッチしてください。
左側写真の下がカウントダウン中の表示です。この画面の文字は内蔵フォントを拡大文字と組み合わせて使っています。キャンセルにタッチすると時間の入力画面に戻ります。
時間が来ると「タイムアップ!」を5回スクロール表示します。
使用部品
- 蛍光表示管モジュール
GU128X32D-D903S
CMOSシリアル接続ができ、タッチスイッチと漢字フォントを搭載したグラフィック表示器です。 - Arduino本体
Arduino micro
コンパクトな外形が電子工作に便利です。 - 抵抗4個(1Kオーム2個、1.8Kオーム1個、2.7Kオーム1個)1/4Watt 5%級
- 小信号用NPNバイポーラトランジスタ 1個(2SC3504を使っていますが、類似品でOKです。)
- シリコンダイオード(小型のスイッチング用)1個
- 小型ブザー(発振回路の無いスピーカタイプ)1個
- 回路試作用ブレッドボード
- その他
USBケーブル、ピンヘッダ・ソケット、半田・配線材料 等
適切なものをご用意ください。
回路図

GU-Dシリーズは電源5Vで信号は3.3V仕様です。Arduino microは信号5Vです。このため、Arduino microの出力をGU-Dシリーズの入力に接続するにはレベル変換が必要です。
今回は、ArduinoのTX出力端子をGU-DシリーズのRxD入力端子に接続するところが該当します。方法は抵抗2個による分圧方式としました。GU-Dシリーズの出力電圧は3.3V信号ですがArduino microはこれを入力できますので、こちらは直結でOKです。表示器の5V電源は、Arduino経由でUSBから供給しています。
組み立て例

回路試作用のブレッドボード上に組み立てた例
日本語が文字化けするときに(Unicode<>Shift-JIS変換ツール)
PCの多くはUnicodeで動作していますが、VFDモジュールのフォントテーブルはShift-JISになっています。 文字コードが違うため、PCからモジュールに文字を書き込むと、文字化けすることがあります。
そこで、クリップボードにコピーされているUnicodeのテキストを、Shift-JISの16進数列表記に変換するツールを用意しました。 ダウンロードしてご活用ください。
サンプルスケッチ(サンプルプログラム)
「スケッチ」とは、本開発環境でのプログラムを指します。下記は今回制作したタッチタイマーのスケッチです。
/*
** NORITAKE IRTRON GU-D Series
** Touch Switch code sample
** 2015 May 13rd by MN
*/
#define _frame1_leng 73
unsigned char frame1_code[ _frame1_leng ] =
{
0x1f, 0x28, 0x66, 0x11, 0x0d, 0x00, 0x04, 0x00, 0x01, 0x07, 0xb7, 0xb7, 0xb7, 0xe4, 0x94, 0x94,
0x95, 0xa6, 0xf6, 0xf6, 0xf1, 0x20, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00,
0x05, 0xa0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00,
0x05, 0xa0, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x04, 0x8f, 0x6f, 0x6f,
0x65, 0xa9, 0x29, 0x29, 0x27, 0xed, 0xed, 0xed, 0xe0,
};
#define _tenkey_leng 521
unsigned char _tenkey_code[ _tenkey_leng ] =
{
0x1f, 0x28, 0x66, 0x11, 0x80, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80,
0x01, 0x00, 0x00, 0x9e, 0x01, 0x00, 0x00, 0xa1, 0x01, 0x00, 0x00, 0xa1, 0x7d, 0x00, 0x00, 0xa1,
0x05, 0x00, 0x00, 0x92, 0x05, 0x00, 0x00, 0x80, 0x05, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x83,
0xf9, 0x00, 0x00, 0x82, 0x41, 0x00, 0x00, 0x82, 0x61, 0x00, 0x00, 0x82, 0x51, 0x00, 0x00, 0x81,
0x89, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80,
0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x8f,
0xf1, 0x00, 0x00, 0x98, 0x19, 0x00, 0x00, 0x90, 0x09, 0x00, 0x00, 0x90, 0x09, 0x00, 0x00, 0x90,
0x09, 0x00, 0x00, 0x90, 0x89, 0x00, 0x00, 0x90, 0x89, 0x00, 0x00, 0x90, 0x89, 0x20, 0x00, 0x90,
0xf9, 0x52, 0x00, 0x80, 0x01, 0x9c, 0x00, 0x80, 0x01, 0x90, 0x00, 0x80, 0x01, 0x52, 0x00, 0x8f,
0xf1, 0x3c, 0x00, 0x90, 0x09, 0x00, 0x00, 0x90, 0x09, 0x00, 0x00, 0x90, 0x09, 0x00, 0x00, 0x90,
0x09, 0x00, 0x00, 0x90, 0x09, 0x00, 0x00, 0x90, 0x09, 0x04, 0x00, 0x90, 0x09, 0xa8, 0x00, 0x90,
0x09, 0xfc, 0x00, 0x8f, 0xf1, 0xa8, 0x00, 0x80, 0x01, 0x22, 0x00, 0x80, 0x01, 0xf4, 0x00, 0x80,
0x01, 0x38, 0x00, 0x80, 0x01, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0x80,
0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x9f, 0x91, 0x87, 0xe1, 0x91, 0x09, 0x88,
0x11, 0x92, 0x09, 0x90, 0x09, 0x92, 0x09, 0x90, 0x09, 0x92, 0x09, 0x90, 0x09, 0x92, 0x09, 0x90,
0x09, 0x92, 0x09, 0x90, 0x09, 0x91, 0x11, 0x88, 0x11, 0x90, 0xe1, 0x87, 0xe1, 0x80, 0x01, 0x80,
0x01, 0x80, 0x01, 0x80, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0x80,
0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x87, 0xe1, 0x80, 0x01, 0x89, 0x11, 0x82,
0x09, 0x92, 0x09, 0x84, 0x09, 0x92, 0x09, 0x88, 0x09, 0x92, 0x09, 0x90, 0x09, 0x92, 0x09, 0x9f,
0xf9, 0x92, 0x09, 0x80, 0x09, 0x89, 0x11, 0x80, 0x09, 0x80, 0xe1, 0x80, 0x09, 0x80, 0x01, 0x80,
0x01, 0x80, 0x01, 0x80, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0x80,
0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x98, 0x01, 0x86, 0x19, 0x90, 0x01, 0x88,
0x29, 0x90, 0x01, 0x90, 0x49, 0x90, 0x01, 0x90, 0x49, 0x90, 0x79, 0x90, 0x49, 0x90, 0x81, 0x90,
0x89, 0x91, 0x01, 0x90, 0x89, 0x92, 0x01, 0x89, 0x09, 0x9c, 0x01, 0x86, 0x09, 0x80, 0x01, 0x80,
0x01, 0x80, 0x01, 0x80, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0x80,
0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x84, 0x61, 0x90, 0x11, 0x8a, 0x91, 0x90,
0x09, 0x91, 0x09, 0x91, 0x09, 0x91, 0x09, 0x91, 0x09, 0x91, 0x09, 0x93, 0x09, 0x91, 0x09, 0x95,
0x09, 0x91, 0x09, 0x95, 0x09, 0x8a, 0x91, 0x98, 0x91, 0x84, 0x61, 0x90, 0x61, 0x80, 0x01, 0x80,
0x01, 0x80, 0x01, 0x80, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0x80,
0x01, 0x80, 0x01, 0x80, 0x01, 0x87, 0x81, 0x80, 0x01, 0x88, 0x41, 0x81, 0xe1, 0x90, 0x21, 0x8e,
0x21, 0x90, 0x21, 0x90, 0x21, 0x90, 0x21, 0x80, 0x21, 0x90, 0x21, 0x80, 0x21, 0x90, 0x39, 0x80,
0x21, 0x90, 0x39, 0x9f, 0xf9, 0x88, 0x41, 0x80, 0x21, 0x87, 0x81, 0x80, 0x21, 0x80, 0x01, 0x80,
0x01, 0x80, 0x01, 0x80, 0x01, 0xff, 0xff, 0xff, 0xff,
};
unsigned char text003[ 14] = {
0x83, 0x5e, 0x83, 0x43, 0x83, 0x80, 0x83, 0x41, 0x83, 0x62, 0x83, 0x76, 0x81, 0x49,
};
// Function prototype
void vfd_initialize(); // VFDモジュールを初期化
void vfd_print(unsigned char message[], int L); //VFDモジュールに送信
void vfd_put(unsigned char unebyte); //VFDモジュールに1バイト送信
void vfd_kanjiOn(); //漢字モード設定
void vfd_kanjiOff(); //漢字モード解除
void vfd_setCursor(int X, int Y); //VFDカーソル移動
void vfd_cls(); //VFD画面クリア
void touch_set( byte mode); //タッチモード設定
void vfd_setUserWindow(int uwNo, int x, int y, int w, int h); //VFDユーザーウインドウ設定
void vfd_selectCurrWindow(int uwNo); //VFDユーザーウインドウ選択
void vfd_HorizontalScroll(int spd); //VFD横スクロールモード設定 spdは速度
int vfd_touch_tenkey(); //10キー入力画面 戻り値は4桁
void vfd_enlarge(int w, int h); //VFD文字拡大指定
void vfd_port_set(int n, int a); //VFD汎用ポート方向設定
void vfd_port_out(int n, int a); //VFD汎用ポート出力
void vfd_click(); //クリック音発生
// 広域変数
int mbusy = 8; // BUSY signal pin = 8
int timer_initial = 300; // タイマー初期値=3分
// 最初に一回実行される関数
void setup()
{
int i;
Serial1.begin(38400);//38400BPSでシリアルポート使用開始
// mbusyを入力に設定
pinMode(mbusy,INPUT);
vfd_initialize();
// 枠の描画 左端
vfd_print( frame1_code , 61);
// 枠の描画 中央
for(i=0; i< 13; i++)
{ vfd_setCursor( i*8+11, 0);
vfd_print( frame1_code, 4);
Serial1.write(0x08);
Serial1.write(0x00);
Serial1.write(0x04);
Serial1.write(0x00);
Serial1.write(0x01);
vfd_print( frame1_code+21, 32);
}
// 枠の描画 右端
vfd_setCursor( i*8+11, 0);
vfd_print( frame1_code, 4);
Serial1.write(0x0d);
Serial1.write(0x00);
Serial1.write(0x04);
Serial1.write(0x00);
Serial1.write(0x01);
vfd_print( frame1_code+21, 52);
//漢字モード設定
vfd_kanjiOn();
vfd_setCursor( 8, 1);
// "タッチタイマー ( Shift-JIS)"と表示
unsigned char text001[ 14] = {
0x83, 0x5e, 0x83, 0x62, 0x83, 0x60, 0x83, 0x5e, 0x83, 0x43, 0x83, 0x7d, 0x81, 0x5b,
};
vfd_print(text001, 14);
//タッチスイッチ設定
touch_set(0x02);
vfd_kanjiOff();
// VFDのPort0-Bit0を出力に設定(クリック音用)
vfd_port_set(0,0x01); // Port0 bit0 as output
// 使用者のタッチ操作待ち
while(Serial1.read()!=0x11){}
// クリック音を出す
vfd_click();
// シリアル入力バッファを空にする
while(Serial1.available()>0){Serial1.read();}
}
// 繰り返しループ
void loop()
{
int ti; // カウントダウンタイマー値 単位:秒
unsigned long target_time; //1秒経過時のArduinoのミリ秒タイマー値
int touch1;
// VFD初期化
vfd_initialize();
// タッチ設定 2(個別キー自動送信)
touch_set(0x02);
// 10キーを表示しタイマー値を得る
ti = vfd_touch_tenkey(); // get timer value with ten key
// タッチ設定 1(全キー自動送信)
touch_set(0x01);
//VFD画面消去
vfd_cls();
// 画面右下に"キャンセル”と表示する
vfd_setCursor(48,2);
vfd_kanjiOn();
// "キャンセル" (Shift JIS)
unsigned char text004[ 10] =
{0x83, 0x4c, 0x83, 0x83, 0x83, 0x93, 0x83, 0x5a, 0x83, 0x8b };
vfd_print(text004, 10);
// カウントダウン値が0でなければカウントダウンを行う。
if(ti!=0){
// 現在のArduinoのタイマー値から1秒後のタイマー値を得る
target_time=millis()+1000;
// カウントダウン値がゼロになるまで、以下を繰り返す。
while(ti>0){
// 大きく分を表示
vfd_enlarge(2,2);// 縦横2倍で文字表示
vfd_kanjiOn(); // 16ドット文字を使う
vfd_setCursor(0,0);
vfd_put(ti/1000+0x30);
vfd_put((ti%1000)/100+0x30);
vfd_enlarge(1,1);//文字拡大を解除する
vfd_put(0x95);
vfd_put(0xaa);// 分
vfd_put((ti%100)/10+0x30);
vfd_put(ti%10+0x30);
vfd_put(0x95);
vfd_put(0x62); //秒
vfd_kanjiOff();
ti--; // カウントダウンする。
if((ti%100)==99) {ti-=40;} // 99秒のとき59秒に補正する。
//Arduinoのタイマで1秒後を待つ。
while( millis() <= target_time)
{
// 待つ間にタッチがあったか調べる
if(Serial1.read() == 0x10)
{
while(Serial1.available()==0){}
if(Serial1.read() != 0) { }
while(Serial1.available()==0){}
touch1=Serial1.read(); Serial1.read();
// タッチされたキーが下側の右半分かどうか調べる
// そうであれば、クリック音を出してLOOPを抜ける
if((touch1 & 0xf8) != 0) {vfd_click(); goto relooping;
}
}
}
// 1秒後のArduinoタイマの値を設定する
target_time+=1000; // set next target
}
}
// カウントダウンが終わったら、”タイムアップ!”と5回スクロール表示する
vfd_kanjiOn();
vfd_setCursor(0,0);
vfd_enlarge(2,2);
vfd_HorizontalScroll(02);
vfd_print(text003,14);
vfd_print(text003,14);
vfd_print(text003,14);
vfd_print(text003,14);
vfd_print(text003,14);
relooping:;
}
void vfd_print(unsigned char message[], int L)
{
int i;
for(i=0; i< L; i++)
{
vfd_put(message[i]);
}
}
void vfd_put(unsigned char onebyte)
{
while(digitalRead(mbusy)==HIGH){} // wait for module ready
Serial1.write(onebyte);
}
void vfd_kanjiOn()
{
unsigned char data[15]={
0x1f, 0x28, 0x67, 0x01, 0x02, 0x1f, 0x28, 0x67,
0x02, 0x01, 0x1f, 0x28, 0x67, 0x0f, 0x00,
};
vfd_print(data,15);
}
void vfd_kanjiOff()
{
unsigned char data[5]={
0x1f, 0x28, 0x67, 0x01, 0x01};
vfd_print(data,5);
}
void vfd_setCursor(int X, int Y)
{
unsigned char data[6]={
0x1f, 0x24};
data[2] = X % 256;
data[3] = X / 256;
data[4] = Y % 256;
data[5] = Y / 256;
vfd_print(data,6);
}
void vfd_cls()
{
vfd_put(0x0c);
}
void touch_set( byte mode)
{
unsigned char data[4]={
0x1f, 0x4b, 0x18};
data[3] = mode;
vfd_print(data,4);
}
void vfd_setUserWindow(int uwNo, int x, int y, int w, int h)
{
unsigned char data[14]={
0x1f, 0x28, 0x77, 0x02 };
data[4] = uwNo;
data[5] = 0x01;
data[6] = x % 256;
data[7] = x / 256;
data[8] = y % 256;
data[9] = y / 256;
data[10] = w % 256;
data[11] = w / 256;
data[12] = h % 256;
data[13] = h / 256;
vfd_print(data,14);
}
void vfd_selectCurrWindow(int uwNo)
{
unsigned char data[5]={
0x1f, 0x28, 0x77, 0x01 };
data[4] = uwNo;
vfd_print(data,5);
}
void vfd_HorizontalScroll(int spd)
{
unsigned char data[5]={
0x1f, 0x03, 0x1f, 0x73 };
data[4] = spd;
vfd_print(data,5);
}
void vfd_enlarge(int w, int h)
{
unsigned char data[6]={
0x1f, 0x28, 0x67, 0x40 };
data[4] = w;
data[5] = h;
vfd_print(data,6);
}
void vfd_port_set(int n, int a)
{
vfd_port_out(n,0);
unsigned char data[6]={
0x1f, 0x28, 0x70, 0x01 };
data[4] = n;
data[5] = a;
vfd_print(data,6);
}
void vfd_port_out(int n, int a)
{
unsigned char data[6]={
0x1f, 0x28, 0x70, 0x10 };
data[4] = n;
data[5] = a;
vfd_print(data,6);
}
void vfd_click()
{
vfd_port_out(0,0x01);
vfd_port_out(0,0x00);
vfd_port_out(0,0x01);
vfd_port_out(0,0x00);
vfd_port_out(0,0x01);
vfd_port_out(0,0x00);
}
void vfd_initialize()
{
vfd_put(0x1b);
vfd_put(0x40);
delay(100);
}
int vfd_touch_tenkey()
{
byte k, tk;
int nuk, ti, touchGo;
// 初期値設定
nuk=0;
ti=timer_initial;
// 10キーの画面を描く
vfd_setCursor(0,0);
vfd_print( _tenkey_code,_tenkey_leng );
// シリアル入力を空にする
while(Serial1.available()>0){ Serial1.read();}
// 数値表示窓にユーザーウインドウを設定する
vfd_setUserWindow(1,20,1,28,1);
vfd_selectCurrWindow(1);
vfd_HorizontalScroll(02);
vfd_setCursor(21,0);
Serial1.print(ti);
touchGo=1;
// GO にタッチあるまでループを繰り返す
while( touchGo != 0){
//タッチを待つ タッチがあれば、キー番号を内部データに変換しておく
while(Serial1.read()!=0x11){}
while(Serial1.available()==0){} //wait for a data
k=Serial1.read();
if(k>=0x0b) k+=(0x30-0x0b);
else if (k==0x8)k+=0x43;
else if (k>=0x03)k+=(0x35-0x03);
else k+=0x21;
while(Serial1.available()==0){} //wait for a data
//タッチがあれば、押されたか離れたかを判定。
switch (Serial1.read())
{
// 離れたときは押されているキーのカウントを減らす。
case 0x00:
nuk--;
if(nuk< 0) nuk=0;
break;
case 0x01:
// 他にキーが押されていない場合のみ入力として扱う。
if(nuk==0) {
// clear クリアキーにタッチ
if(k==75)
{
vfd_click();
ti=0;
Serial1.print(" 0");
}else
// GO キーにタッチ
if( k >= 59)
{
vfd_click();
touchGo = 0; // end of data entry loop
}else
if( k>=0x30)
{
vfd_click();
Serial1.write(k);
// 下4桁のみを使う
ti= (ti % 1000) * 10 + k - 0x30;
}
}
// 押されたときは押されているキー数のカウントを増やす。
nuk++;
break;
default: // error
{}
}
}
vfd_selectCurrWindow(0);
return ti;
}