シリアル読取&書き込みスケッチのリファイン


見えるぞ!私にもシリアルが見える!!




VS-RC003→Arduinoのシリアル解読」でVS-RC003のデータ表示に挑戦した後、
シリアル検証スケッチ」でシリアルの厳密な配列が判明してきました。
前回やや当てずっぽうだった必要データの切り出し方法を厳密なものに改め、スケッチを書き直してみました。
さらに、書き込んでベリファイするものも書いてみました。
だいぶスッキリしました。




PCでモニタリングするプログラムのため、
Arduinoはハードウェアシリアルが使えるMEGAがおすすめです。
Serial1が使えるMICROやLeonardoでも動くと思います。
VS-RC003の設定で好きな方をシリアルに設定し、また、
ArduinoのRXピン、TXピン、5V、GNDを、VS-RC003のTXピン、RXピン、5V,GNDにそれぞれ接続します。




補足ですが、VS-RC003の拡張コネクタは、
CN6:ゲームパッド使える/IXBUS使えない/シリアル使える
CN7:ゲームパッド使えない/IXBUS使える/シリアル使える

となっているようです。
IXBUS機器を複数使う場合CN7に数珠つなぎにします。
CN6にはコントロールパッドの代わりにシリアルをつなぐことが可能です。




まず読み取りです。
電圧の取得を例にします。
指定したアドレスのデータを読み込み、データを表示。
さらにエンディアンを交換し、整数データとして表示するところまでを行います。

// VS-RC003のシリアルを読み取るプログラム作例
// rコマンドで読み出し命令を出し、結果を変数VSmsgsに入れて表示する。
// 例では、r 2009dc 04で電圧を読み取る。
// 2009dc 02 00 xx yy が読み出されるが、xx yy の部分が、該当の電圧データとなる。
// また、リトルエンディアンからビッグエンティアンへ、
// さらにアスキーコードの16進数を数値に変換し、10進数に換算する。
// データの切り出し方を厳密化。

int vcc1, vcc2, vcc3, vcc4;// 換算用の変数を宣言。
bool ERR = false;// 読み取りエラーのフラグ用変数を宣言。
bool Loading = false; //必要データ読取中フラグ

void setup() {
 Serial.begin(115200); // 115200bpsでPCモニタ用ポートを開く
 Serial1.begin(115200);// 115200bpsでVS-RC003通信用ポートを開く
}

void loop() {
 char VSmsgs[64];// 読み取ったシリアルを入れる配列を宣言。
 Serial1.println("r 2009dc 04");//電圧を読み込む命令
 delay(30);//このディレイが小さすぎると失敗しやすい。
 if (Serial1.available() > 0 ) {
   int i = 0; //文字配列カウンタ
   while (1) {
     char data = Serial1.read();
     VSmsgs[i] = data; //文字配列に文字を一個入れる。
     if (VSmsgs[i - 1] == 0x0a && VSmsgs[i] == 0x23)// 「[LF]」と「#」が連続している文字列を探す。
     {
       Loading = true; //必要データ読取中のフラグを立てる。
       VSmsgs[0] = 0x23; //配列の1文字目にプロンプト記号#を入れ直しておく。
       i = 0;
     }
     if (VSmsgs[i] == 0x0D && Loading == true)//必要データ読取中なら「CR」が来たら読取終了。
     {
       Loading = false;
       break;
     }
     i ++;
   }

   VSmsgs[i] = 0x00;//データにヌル終端を追加
   Serial.println(VSmsgs);//取得データを表示。
   Serial.print("Big endian : ");//以下、該当の電圧データをエンディアンを交換して表示する。
   Serial.print(VSmsgs[17]);
   Serial.print(VSmsgs[18]);
   Serial.print(" ");
   Serial.print(VSmsgs[14]);
   Serial.println(VSmsgs[15]);
   Serial.print("ASCII to HEX to DEC : ");

   //以下、取得したASCIIコードを16進数に換算していく。
   //その際、範囲にない文字であれば、エラーフラグを立てる。
   if (VSmsgs[17] <= 0x2f) {//取得した文字が0よりも前の文字であればエラー。
     ERR = true;
   } else if (VSmsgs[17] >= 0x67) {//取得した文字がfよりも後の文字であればエラー。
     ERR = true;
   } else if (VSmsgs[17] >= 0x41) {
     vcc1 = VSmsgs[17] - 0x57;//取得した文字がa以上であれば10からの数字に換算。
   } else {
     vcc1 = VSmsgs[17] - 0x30;//それ以外であれば、0から9の数字に換算。
   }

   if (VSmsgs[18] <= 0x2f) {
     ERR = true;
   } else if (VSmsgs[18] >= 0x67) {
     ERR = true;
   } else if (VSmsgs[18] >= 0x41) {
     vcc2 = VSmsgs[18] - 0x57;
   } else {
     vcc2 = VSmsgs[18] - 0x30;
   }

   if (VSmsgs[14] <= 0x2f) {
     ERR = true;
   } else if (VSmsgs[14] >= 0x67) {
     ERR = true;
   } else if (VSmsgs[14] >= 0x41) {
     vcc3 = VSmsgs[14] - 0x57;
   } else {
     vcc3 = VSmsgs[14] - 0x30;
   }

   if (VSmsgs[15] <= 0x2f) {
     ERR = true;
   } else if (VSmsgs[15] >= 0x67) {
     ERR = true;
   } else if (VSmsgs[15] >= 0x41) {
     vcc4 = VSmsgs[15] - 0x57;
   } else {
     vcc4 = VSmsgs[15] - 0x30;
   }

   Serial.print(vcc1, DEC);//ビッグエンディアンに変更後の16進数を並べる。
   Serial.print(" ");
   Serial.print(vcc2, DEC);
   Serial.print(" ");
   Serial.print(vcc3, DEC);
   Serial.print(" ");
   Serial.println(vcc4, DEC);
   Serial.print("VCC : ");
   int vcc = vcc1 * 4096 + vcc2 * 256 + vcc3 * 16 + vcc4;//16進数を10進数に換算する。
   Serial.print(vcc, DEC);//結果の数値を表示する。
   Serial.println();
   //Serial1.flush();
   if (ERR == true) {//取得データにエラーが出ていればエラーと表示する。
     Serial.println("*** READ ERROR!! ***");
     ERR = false;
   }
     Serial.println();
   delay (1);
 }
}




実行結果は、

#2009dc 02 00 98 0f
Big endian : 0f 98
ASCII to HEX to DEC : 0 15 9 8
VCC : 3992

#2009dc 02 00 8f 0f
Big endian : 0f 8f
ASCII to HEX to DEC : 0 15 8 15
VCC : 3983
(以降くりかえし)


のように表示されます。




次に書き込みです。
VS-RC003にシリアルで指定アドレスに変数を書き込みます。
同じアドレスを読み取って比較することで書き込みの成否までを確認します。

// VS-RC003のシリアルを書き込み、ベリファイするスケッチ例
// シリアルでデータ書き込みコマンドを実行した後、該当箇所のデータを読み込んで、
// 書き込みが成功しているかを確認する。
// WRITE_MSG1で書き込み用のw文を指定し、
// WRITE_MSG2で書き込み検証用にデータを読み込むr文を指定する。
// 読み込みデータは#200...で始まるが、w 20..になるように書き換え、比較しやすくしておく。
// 書き込んだ文と読み込んだ文が合致して入れば、Verify OK!を表示する。

bool Loading = false; //必要データ読取中フラグ

String WRITE_MSG1 = "w 2009f6 01 00"; //書き込み用のライト文
String WRITE_MSG2 = "r 2009f6 02"; //検証用のリード文。該当アドレスから2バイト読み込む指示。

void setup() {
 Serial.begin(115200); // 115200bpsでPCモニタ用ポートを開く
 Serial1.begin(115200);// 115200bpsでVS-RC003通信用ポートを開く
}

void loop() {
 char VSmsgs[64];// 読み取ったシリアルを入れる配列を宣言。
 Serial1.println(WRITE_MSG1);//書き込み用のライト文を送信。
 Serial.print("wrote:");//モニタ用。
 Serial.println(WRITE_MSG1);//モニタ用書き込んだ文字列を表示する。
 delay(38);//18以下だと失敗する。すこし余裕をもたせるべき。
 if (Serial1.available() > 0 ) {
   for (int i = 0; i <= 64; i++) {//「#」を受け取るまで64文字まで待つ。普通は1発目で見つける。
     char data = Serial1.read();
     if (data == 0x23)//「#」を受け取り次第抜ける。
     {
       i = 64;
     }
   }
   Serial1.println(WRITE_MSG2);//検証用のリード文
   delay(30);//このディレイが小さすぎると失敗しやすい。
   if (Serial1.available() > 0 ) {
     int i = 0; //文字配列カウンタ
     while (1) {
       char data = Serial1.read();
       VSmsgs[i] = data; //文字配列に文字を一個入れる。
       if (VSmsgs[i - 1] == 0x0a && VSmsgs[i] == 0x23)// 「[LF]」と「#」が連続している文字列を探す。
       {
         Loading = true; //必要データ読取中のフラグを立てる。
         //取得するデータの冒頭を「#」から「w 」に変換して書式を合わせておき、あとで比較できるようにする。
         VSmsgs[0] = 0x77; //配列の1文字目にwを入れ直しておく。
         VSmsgs[1] = 0x20; //配列の2文字目にスペースを入れ直しておく。
         i = 1;
       }
       if (VSmsgs[i] == 0x0D && Loading == true)//必要データ読取中かつ「CR」が来たら読取終了。
       {
         Loading = false;
         break;
       }
       i ++;
     }

     VSmsgs[i] = 0x00;//データにヌル終端を追加
     Serial.print("read :");
     Serial.println(VSmsgs);//モニタ用。読み込んだデータ(#をw に書き換えたもの)を表示する。
     String VSmsgssrg = VSmsgs;
     if (WRITE_MSG1.compareTo(VSmsgssrg)) {//書き込んだ文字列と読み込んだ文字列を比較する。
       Serial.println("Veriy OK!");
     } else {
       Serial.println("Write ERROR!");
     }
     Serial.println();
     delay (1);
   }
 }
}




こちらの実行結果は、


wrote:w 2009f6 01 00
read :w 2009f6 01 00
Veriy OK!

wrote:w 2009f6 01 00
read :w 2009f6 01 00
Veriy OK!
(以降くりかえし)


のように表示されます。




実際にロボットと接続してみて安定的に動くようであれば、ベリファイの部分を省略してしまうのもArduinoへの負担が減ってよいかと思います。
ついでにユーザー関数化やライブラリ化ができれば運用しやすいのですが、そのやり方はまだいまいちわかっていません><




これでついにVS-RC003&Arduinoのシリアル制御を完全攻略!
・・・ができたような気がします^^
ここまでできれば、SBDBTのファームを書き換えてVS-RC003に直付けすることもできてしまいそうです。
(これはライト級的に欲しい機能です。)
スポンサーサイト

テーマ : 自然科学
ジャンル : 学問・文化・芸術

コメントの投稿

非公開コメント

プロフィール

二名川(ニナガワ)

Author:二名川(ニナガワ)
ホビーロボットをレトロゲームが発展したものと捉えて楽しく遊び倒します。
子供が夢を見ている時間帯に稼働します。

宣伝:電子出版しました。
「コンソロイド ガイドブック」
46107_CONSOLOID_GUID_FACE_200.jpg





■作成中の機体
汎用ヒト型決戦遊具 ~RX計画~
RX-7.5 ゼロタンク
RRf-0.6 ゼニィ
RXM-7.9 ゼムネス
RX-7.5R 量産型ゼロタンク
RX-7.5Fp ファミタンク仮設1号
RX-7.7 ゼロキャノン
RX-7.8 ゼログレイ
SMS-0.1 ゼロライナー
以下続く

ブログ内検索
最近の記事
最近のコメント
カテゴリ
月別アーカイブ
リンク