かみやんの技術者ブログ

主にプログラムの話です

H8用自動プログラムローダ開発

やー、久しぶりにロボットの時間が作れました。かなり滞っていた。
8月3日のつくばチャレンジ2008の第1回試走会では、去年出場したロボットが既に試走していましたが、私はまだロボットが動かないので試走できませんでした。非常に、悔しいので次回の9月7日第2回試走会では、少しは走らせたい。

という訳で、9月7日までにやりたいこと。

  1. ロボットにPCを載せて、H8/3069マイコンと通信
  2. PCにつないだUSBタイプのジョイパッドで操作
  3. Top-URGでログを取る
  4. ロータリーエンコーダのログを取る
  5. Webカメラを積んで録画する

あたりをやりたい。

1.を実装するために、まず、PC用のプログラムを書いてマイコンと通信できるようにしないといけない。
現在では、

  1. TeraTerm起動
  2. マイコンと通信開始
  3. マイコンのリセットボタン押下。モニタプログラムが起動。
  4. TeraTermで「ファイル>ファイル送信」コマンドでファイル選択ダイアログが表示されて、マイコンのプログラム(Toppers+自分のアプリケーション)のバイナリファイルを選択。
  5. 送信が終わると、Toppers+自分のアプリケーションが起動する。

という感じである。
H8/3069マイコンは、フラッシュROMが100回しか書き込めないので、ずっとRAMで動かしている。つまりマイコンをリセットする度に転送する必要がある。今は、TeraTermを使っているので手動。
まずは、これを自動で転送できるように、PC用のプログラムを作ることにした。

ロボットの名前がAibiなのでAibiUIと名付けた。開発環境は、VisualStudioで言語はC#。俺は、C++Javaの経験が長いのでC#にした。C#は昔1度だけ仕事で使ったレベル。

あっさりマイコンからの出力が表示できた。さすがC#。SerialPortコンポーネントを貼るだけ。ヘルプの中にサンプルソースが載っているし。強力だなVisualStudioのヘルプ。

次は、TeraTermのファイル送信機能を自分で実装しよう。
どんなプロトコル何だろう。

ソースを公開します。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace AibiUI
{
    public partial class AibiUIForm : Form
    {
        delegate void SetTextCallback(string text);//コンソールテキストボックスのスレッドセーフ用

        //コンストラクタ
        public AibiUIForm()
        {
            InitializeComponent();
        }

        //フォームロードイベント
        private void AibiUIForm_Load(object sender, EventArgs e)
        {
            //ComPortプルダウンの初期設定
            cbComPort.Items.AddRange(SerialPort.GetPortNames());
            if (cbComPort.Items.Count > 0)
            {   //有効なCOMポートがあるとき
                cbComPort.Text = (string)cbComPort.Items[0];
            }
        }

        //接続ボタン押下イベント
        private void btnConnect_Click(object sender, EventArgs e)
        {
            try
            {
                //接続開始
                if (serialPort.IsOpen == false)
                {   //接続していないとき
                    OpenSerial();
                }
                else
                {   //接続中のとき
                    CloseSerial();
                }
                txtConsole.Focus();
            }
            catch (System.IO.IOException ex)
            {
                MessageBox.Show(ex.Message, "Serial Port Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                CloseSerial();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                CloseSerial();
            }
        }

        //シリアル:データ受信イベント
        private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            byte[] buf = new byte[1024];
            int len = serialPort.Read(buf, 0, 1024);
            string str = Encoding.GetEncoding("Shift_JIS").GetString(buf, 0, len);
            AppendText(str);
        }

        //ファイル送信開始
        private void StartSendFile()
        {

        }

        //シリアル:エラーイベント
        private void serialPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
        {
            MessageBox.Show(e.ToString(), "Serial Port Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            CloseSerial();
        }

        //シリアル:ピン変更イベント
        private void serialPort_PinChanged(object sender, SerialPinChangedEventArgs e)
        {
            MessageBox.Show(e.ToString(), "Serial Port Error(Pin changed)", MessageBoxButtons.OK, MessageBoxIcon.Error);
            CloseSerial();
        }

        //コンソールテキストボックスに文字列を追加(スレッドセーフ)
        private void AppendText(string str)
        {
            if (txtConsole.InvokeRequired)
            {   //スレッドが違うとき
                SetTextCallback dele = new SetTextCallback(AppendText);
                this.Invoke(dele, new object[] { str });
            }
            else
            {   //スレッドが同じとき
                txtConsole.AppendText(str);
                txtConsole.Select(txtConsole.Text.Length, 0);
                txtConsole.ScrollToCaret();
            }
        }

        //シリアルポとのオープン
        private void OpenSerial()
        {
            serialPort.PortName = cbComPort.Text;
            serialPort.Open();
            btnConnect.Text = "Disconnect";
            txtConsole.BackColor = System.Drawing.Color.White;
        }

        //シリアルポートのクローズ
        private void CloseSerial()
        {
            serialPort.Close();
            btnConnect.Text = "Connect";
            txtConsole.BackColor = System.Drawing.Color.MistyRose;
        }
    }
}