KOSAKA LABORATORY->Tips

秋月VFD 文字表示

秋月VFDで文字表示を行うプログラムを作成します。

1.プロジェクトの作成
Visual C#で「VFDTest」というWindowsフォームアプリケーションの新規プロジェクトを作成します。
2.フォームの作成
フォーム上に、以下のようにコントロールを配置します



フォーム、ラジオボタン、ボタンをダブルクリックし、イベントを登録します



3.文字表示プログラム
form1.csに以下のプログラムを貼り付けます
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.Collections;

namespace VFDTest
{
    public partial class Form1 : Form
    {
        private SerialPort serialPort = new SerialPort();
        private Boolean is58 = false;
        public Form1()
        {
            InitializeComponent();
            this.serialPort = new SerialPort();
        }

        //フォームロード
        private void Form1_Load(object sender, EventArgs e)
        {
            this.comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;

            string[] ports = SerialPort.GetPortNames();

            foreach (string port in ports)
            {
                this.comboBox1.Items.Add(port);
            }

            this.comboBox1.SelectedIndex = 0;

            //ラジオボタン
            this.radioButton1.Checked = true;
            this.is58 = false;

            this.button2.Enabled = false;
            this.button3.Enabled = false;
        }

        //接続
        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                this.serialPort.BaudRate = 19200;//通信速度 19200bps
                this.serialPort.PortName = (string)this.comboBox1.SelectedItem;//ポート番号はコンボボックスから選択
                this.serialPort.Open();//ポートオープン

                //GP1058の場合
                if (this.is58 == true)
                {
                    //画素数336x24
                    this.send_commandFrame(0x25, 0x00);
                }
            }
            catch (Exception ex)
            {
                //ポートオープンに失敗
                MessageBox.Show(ex.ToString());
                return;
            }

            //ボタン各種有効、無効
            this.radioButton1.Enabled = false;
            this.radioButton2.Enabled = false;

            this.comboBox1.Enabled = false;

            this.button1.Enabled = false;
            this.button2.Enabled = true;
            this.button3.Enabled = true;
        }


        //切断
        private void button2_Click(object sender, EventArgs e)
        {
            //ポートクローズ
            this.serialPort.Close();

            //ボタン各種有効、無効
            this.radioButton1.Enabled = true;
            this.radioButton2.Enabled = true;
            this.comboBox1.Enabled = true;

            this.button1.Enabled = true;
            this.button2.Enabled = false;
        }

        //コマンドフレーム送信
        private void send_commandFrame(byte command, byte frame)
        {
            byte[] send = new byte[7];
            byte[] byteSum = new byte[2];
            send[2] = command;
            send[3] = frame;

            int nSum = send[0] + send[1] + send[2] + send[3];

            byteSum = BitConverter.GetBytes(nSum);

            send[4] = byteSum[1];
            send[5] = byteSum[0];

            send[6] = 0xEF;
            if (this.serialPort.IsOpen == true)
            {
                try
                {
                    this.serialPort.Write(send, 0, send.Length);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }
            }
        }

        //テキスト送信
        private void send_Message(String message)
        {
            byte[] sendMessage = new byte[256];

            //シフトjis->jis
            byte[] byteMessage = Encoding.GetEncoding(50220).GetBytes(message);
            //jis->vfd漢字ロムコード
            byte[] vfdCode = toVFDCode(byteMessage);

            int nFrame = vfdCode.Length / 256 + 1;

            if (vfdCode.Length > 4096)
            {
                MessageBox.Show("エラー:文字数オーバー");
                return;
            }

            this.send_commandFrame(0x04, (byte)nFrame);

            //FFHで埋める
            for (int i = 0; i < 256; i++)
            {
                sendMessage[i] = 0xff;
            }

            int frameCount = 0;
            int byteCount = 0;

            for (int i = 0; i < vfdCode.Length; i++)
            {
                sendMessage[byteCount] = vfdCode[i];

                byteCount++;
                if (byteCount == 256 || i == vfdCode.Length - 1)
                {
                    frameCount++;
                    byteCount = 0;

                    this.send_dataFrame(sendMessage, (byte)frameCount);

                    //FFHで埋める
                    for (int j = 0; j < 256; j++)
                    {
                        sendMessage[j] = 0xff;
                    }
                }
            }
        }

        //データフレーム送信
        private void send_dataFrame(byte[] message, byte frame)
        {
            byte[] send = new byte[262];
            byte[] byteSum = new byte[2];

            //アドレス
            send[0] = 0x00;
            //フレーム番号
            send[1] = frame;
            //コマンド
            send[2] = 0x00;

            //メッセージ
            for (int i = 3; i < 256 + 3; i++)
            {
                send[i] = message[i - 3];
            }

            //サム計算
            int nSum = 0;
            for (int i = 0; i < 256 + 3; i++)
            {
                nSum += send[i];
            }

            byteSum = BitConverter.GetBytes(nSum);

            //SUM
            send[259] = byteSum[1];
            send[260] = byteSum[0];

            //END
            send[261] = 0xEF;
            if (this.serialPort.IsOpen == true)
            {
                this.serialPort.Write(send, 0, send.Length);
            }
        }

        //文字コード変換 jis->VFD独自コード
        private byte[] toVFDCode(byte[] jisCode)
        {
            ArrayList arrayVFDCode = new ArrayList();
            byte[] byteVFDCode;
            Boolean isAscii = true;
            for (int i = 0; i < jisCode.Length; i++)
            {
                //アスキー、jis切り替え
                if (jisCode.Length - i >= 2)
                {
                    if (jisCode[i] == 0x1b && jisCode[i + 1] == 0x24 && jisCode[i + 2] == 0x42)
                    {
                        isAscii = false;
                        i += 2;
                        continue;
                    }
                    else if (jisCode[i] == 0x1b && jisCode[i + 1] == 0x28 && jisCode[i + 2] == 0x42)
                    {
                        isAscii = true;
                        i += 2;
                        continue;
                    }
                }

                if (isAscii)
                {
                    //アスキーコード
                    short tmp1, tmp2;
                    tmp1 = jisCode[i];
                    tmp2 = (short)(tmp1 & 0xE0);
                    tmp2 = (short)(tmp2 >> 5);
                    tmp2--;
                    tmp2 = (short)(tmp2 << 7);
                    tmp1 = (short)(tmp1 & 0x1f);
                    tmp2 = (short)(tmp2 | tmp1);
                    tmp2 = (short)(tmp2 | 0x4000);
                    tmp1 = (short)(tmp2 & 0x00FF);
                    tmp2 = (short)(tmp2 >> 8);
                    arrayVFDCode.Add((byte)tmp1);
                    arrayVFDCode.Add((byte)tmp2);
                }
                else
                {
                    short tmp1 = jisCode[i], tmp2 = jisCode[i + 1], tmp4 = 0;
                    int flag = jisCode[i] >> 4;
                    switch (flag)
                    {
                        case 2:
                            //非漢字                            
                            tmp1 = (short)(tmp1 & 0x7F);
                            tmp4 = (short)(tmp1 & 0x7);
                            tmp1 = (short)(tmp2 >> 2);
                            tmp1 = (short)(tmp1 & 0x18);
                            tmp1 = (short)(tmp1 | tmp4);
                            tmp1 = (short)(tmp1 << 7);
                            tmp1 = (short)(tmp1 & 0xF9F);

                            tmp2 = (short)(tmp2 & 0x1F);
                            tmp2 = (short)(tmp2 | tmp1);
                            tmp2 = (short)(tmp2 & 0xFFF);
                            break;
                        case 3:
                        case 4:
                            //3:漢字第一水準1   4:漢字第一水準2
                            tmp1 = (short)(tmp1 & 0x7F);
                            tmp4 = (short)(tmp1 & 0xF);
                            tmp1 = (short)(tmp1 >> 2);
                            tmp1 = (short)(tmp1 & 0x30);
                            tmp1 = (short)(tmp1 | tmp4);
                            tmp1 = (short)(tmp1 << 7);

                            tmp2 = (short)(tmp2 & 0x7F);
                            tmp2 = (short)(tmp2 | tmp1);
                            tmp2 = (short)(tmp2 & 0xFFF);
                            break;
                        case 5:
                        case 6:
                            //5:漢字第二水準1   6:漢字第二水準2
                            tmp1 = (short)(tmp1 & 0x7F);
                            tmp4 = (short)(tmp1 & 0xF);
                            tmp1 = (short)(tmp1 >> 1);
                            tmp1 = (short)(tmp1 & 0x10);
                            tmp1 = (short)(tmp1 | tmp4);
                            tmp1 = (short)(tmp1 << 7);

                            tmp2 = (short)(tmp2 & 0x7F);
                            tmp2 = (short)(tmp2 | tmp1);
                            tmp2 = (short)(tmp2 | 0x1000);
                            break;
                        case 7:
                            //漢字第二水準3
                            tmp1 = (short)(tmp1 & 0x7F);
                            tmp4 = (short)(tmp1 & 0x7);
                            tmp1 = (short)(tmp2 >> 2);
                            tmp1 = (short)(tmp1 & 0x18);
                            tmp1 = (short)(tmp1 | tmp4);
                            tmp1 = (short)(tmp1 << 7);

                            tmp2 = (short)(tmp2 & 0x1F);
                            tmp2 = (short)(tmp2 | tmp1);
                            tmp2 = (short)(tmp2 | 0x1000);
                            break;
                        default:
                            //その他
                            //スルー
                            continue;
                    }

                    tmp1 = (short)(tmp2 & 0x00ff);
                    tmp2 = (short)(tmp2 >> 8);

                    //リストに追加
                    arrayVFDCode.Add((byte)tmp1);
                    arrayVFDCode.Add((byte)tmp2);

                    //2バイト分進めるために、先に+1しておく
                    i++;
                }
            }
            byteVFDCode = new byte[arrayVFDCode.Count];
            for (int i = 0; i < arrayVFDCode.Count; i++)
            {
                byteVFDCode[i] = (byte)arrayVFDCode[i];
            }

            return byteVFDCode;
        }

        //テキストメッセージ送信
        private void button3_Click(object sender, EventArgs e)
        {
            this.send_Message(textBox1.Text);
            this.textBox1.Text = "";//テキストボックスクリア
        }

        //ラジオボタン
        private void radioButton1_CheckedChanged(object sender, EventArgs e)
        {
            this.is58 = false;
        }

        //ラジオボタン
        private void radioButton2_CheckedChanged(object sender, EventArgs e)
        {
            this.is58 = true;
        }
    }
}

実行
1 VFDに電源を入れ、PCに繋ぎます。
2 F5ボタンを押し、プログラムを実行します。
3 GP1022かGP1058、自分が使用しているVFDの型番を選択します。
4 VFDが接続されているCOMポートを選び、接続ボタンを押します。


5 テキストボックスに文字を入れて送信ボタンを押し、VFDに文字が表示されることを確認します。


6 切断ボタンを押して、終了します。
解説
VFDにテキストボックスの文字を表示します。


シリアルポートを開きます。
this.serialPort.BaudRate = 19200;//通信速度 19200bps
this.serialPort.PortName = (string)this.comboBox1.SelectedItem;//ポート番号はコンボボックスから選択
this.serialPort.Open();//ポートオープン

通信速度は19200bpsで固定です。コンボボックスで選んだシリアルポートを開きます。


文字表示
秋月VFDには漢字ROMが搭載されており、日本語の表示が行えます。
漢字ROMコードはjisコードをベースにしたオリジナルのコードであるため、シフトJISコードからjisコードに変換した後、さらに漢字ROMオリジナルコードへ変換する必要があります。

//シフトjis->jis
byte[] byteMessage = Encoding.GetEncoding(50220).GetBytes(message);
//jis->vfd漢字ロムコード
byte[] vfdCode = toVFDCode(byteMessage);


jisから漢字ロムコードへの変換はこのメソッドで行っています。
private byte[] toVFDCode(byte[] jisCode)

jisと漢字ROMコードの対応表はマニュアルの図のとおりです


秋月VFDへデータを送信するには、コマンドフレームとデータフレームの2種類を送信する必要があります。ここでは0x04「送信したデータを即時表示する」というコマンドを送信しています。

実際に送信されるコマンドフレームの内容は



の7バイトです。

//アドレス
send[0] = 0x00;
//フレーム番号
send[1] = frame;
//コマンド
send[2] = 0x00;


アドレスはDont' careとのことなので、何を入れても動作に違いはありません。
フレーム番号はコマンドフレームの場合、常に0x00を送信します。

コマンドにはこれらの種類があります。






フレーム数にはこれから送信するデータフレームの総数を送信します。
データフレーム内のメッセージ部に入れられるデータは256バイトなので、漢字ROMコードへ変換されたバイト配列の総数からフレーム数を割り出します。

int nFrame = vfdCode.Length / 256 + 1;
this.send_commandFrame(0x04, (byte)nFrame);


SUMにはアドレスからフレーム数までのデータを合計した値を入れます。
int nSum = send[0] + send[1] + send[2] + send[3];
byteSum = BitConverter.GetBytes(nSum);
send[4] = byteSum[1];
send[5] = byteSum[0];

ENDは0xFEで固定です
send[6] = 0xEF;

データフレームの構成はこのようになっています





メッセージに、漢字ROMコードへ変換されたバイト配列を256バイトづつ入れて送信していきます。
フレーム番号はそのたびにカウントしていきます。

//FFHで埋める
for (int i = 0; i < 256; i++)
{
 sendMessage[i] = 0xff;
}

int frameCount = 0;
int byteCount = 0;

for (int i = 0; i < vfdCode.Length; i++)
{
 sendMessage[byteCount] = vfdCode[i];

 byteCount++;
 if (byteCount == 256 || i == vfdCode.Length - 1)
 {
  frameCount++;
  byteCount = 0;
  this.send_dataFrame(sendMessage, (byte)frameCount);
  //FFHで埋める
  for (int j = 0; j < 256; j++)
  {
   sendMessage[j] = 0xff;

  }
 }
}

データフレームのメッセージ内には、このようなコマンドを入れることが出来ます。




しかし、今回は文字をそのまま表示するだけなので、使用しません。


リンク
とめくぎヨロズ製作所
http://www.harukaze.ne.jp/tomekugi/win/index.html