CPUにシリアルモニタ機能を追加する

PIC18F45K22CPUボードに搭載したシリアルモニタ機能の紹介です

FT231Xを搭載したPIC18F45K22CPUボードのKiCadデータと回路図

KiCad5-pic18f45k22-v2cpubrd

回路図PDF

pic18f45k22-v21_sch

ここで紹介するシリアルモニタ機能を試して見ようと思われる方は、上の回路図やKiCadデータを参考にしてください。

組み込みプログラミングで活躍するシリアルモニタ機能

手軽に組み込みプログラムに入門できるツールとして大人気のArduino開発環境には、プログラム実行中の情報を出力できるシリアルモニタ機能、シリアルプロット機能があります。
これはArduinoのCPUから送信する、シリアルデータをボード上のUSBシリアル機能を持つICでPCのUSBポートへ送り、PCのターミナルソフトで表示するもので、プログラムのデバッグやデータ収集に活用されています。

あまり使われないMPLAB-Xの高度なデバッガ

PICの書き込みツールであるPicKit3とPICの開発環境MPLAB-Xでは、プログラムを中断して、変数やレジスタの内容を表示したり、プログラムをステップ送り出来る高機能なデバッガが使えるようになっていますが、あまり使われていないのが実情です。

プログラムの実行状態を詳しく見るには、こちらのデバッガがはるかに高機能なのですが、多くのユーザーに活用されて役に立つのはシリアルモニタの方です。

何故かというと、デバッガは基本的にプログラムを中断しないと情報を取得することが出来ず、組み込みプログラムのデバッグに必要なのは動作中の情報という基本的な問題のせいです。

現在の開発環境はとても便利になり、ArduinoのスケッチやMPLAB-Xが提供してくれるライブラリのおかげで、デバッガで詳しく調べないとわからないようなトラブルは殆ど無くなりました。
初心者にとっては、デバッガを使ってプログラムをステップ送りして、どのように動作しているのかを確認することは大いに勉強になります。ただ、デバッガの使い方が難しいせいで初心者にとって、デバッガは使いづらいのが残念な点です。

ベテランプログラマはシリアルモニタや測定器を上手く使う

組み込みプログラミングに少し慣れてくると、プログラムの構造上のバグはデバッガを使わないくても直ぐに検討がつくようになります。
しかし、スイッチのチャタリングや回転するエンコーダの信号などは、パーツの種類やシステムごとに異なった動きをすることが多く、ベテランプログラマでも動作中にCPUの端子に入力されている信号を確認しないと予測できないものです。

むしろ、シリアルモニタやオシロスコープ等の測定器を使って、動作中の入出力信号の状態を上手く把握できるのが、ベテランプログラマのテクニックと言えます。

FT231Xを使って CPUボードにシリアルモニタ機能を追加する

以上のような理由で、シリアルモニタはトレーニングボードに必須の機能ですし、組み込みの現場で実際に使うボードにもシリアルモニタ機能を搭載することで、開発時やトラブルシューティングを効率的に進めることが出来ます。

秋月電子で300円程度で入手できるUSBシリアルICのFT231XとUSBコネクタをCPUボードに追加するだけで、シリアルモニタ機能が使えるようになります。
Arduinoも以前はこれと同じメーカー(FTDI)のICでUSBシリアル機能を実現していましたが、今はAtmelのCPUを使っています。(おそらくコストダウンのためだと思います。)

PIC18F45K22CPUボードのUSBシリアル回路

上の図はPIC18F45K22CPUボードに搭載したUSBシリアル回路用ICとコネクタで、下はそのUSBシリアル部分の回路図です。
SW1は電源SW、PTCはポリスイッチ(保護用の自動復帰型ヒューズ)で、必ずしも必要な部品ではありません。
右上のP-D365Qの記号がある部分は画像を切り取る時に入ってしまっただけなので無視して下さい。

シリアルモニタの使い方

Arduino用ツールのインストール時には、USBシリアルIC用のデバイスドライバが自動的にインストールされ、開発環境にはシリアルターミナル機能が組み込まれているので、ユーザーは特に意識することなくシリアルモニタが使えますが、MPLAB-Xを使う場合は、FT231X用のデバイスドライバをインストールして、別のシリアルターミナルソフトを使う必要があります。

1.FT231X用デバイスドライバのインストール

ドライバ用インストーラの入手先
https://www.ftdichip.com/Drivers/VCP.htm
参考サイト
FTDIのUSBシリアル変換器のドライバのインストール法

2.シリアルモニタ用ターミナルソフトの紹介

TeraTerm
Tera Term (テラターム) プロジェクト日本語トップページ – OSDN

TeraTermは実績のあるターミナルソフトで、色々な人が紹介しているので、使い方も判り易いと思います。

JTW32

これは私が作った組込開発用ターミナルソフトで、シリアルプロッタ機能を備えて、最大3Mbpsの通信まで対応しているなど、機能てんこ盛りのソフトです。
ただ、俺様ソフトでまともなヘルプを用意していないので、使い方は判りにくいかと思います。
上のリンクからダウンロードして、好きなフォルダに展開しjtw32.exeを起動すれば使えます。
ライセンスの制限はありませんので自由にお使いください。

マイコンカーラリーのアナログセンサ

マイコンカーラリーのアナログセンサについて

マイコンカーラリーのラインセンサ(写真で前方に伸びたアームの先についているセンサ)はコース中央の白線をトレースするためのセンサで、デジタルセンサとアナログセンサが使われています。

M-S199:アナログセンサー基板 TypeSとして提供されているセンサには5つのデジタルセンサと白線を挟む位置にある2つのアナログセンサがあります。

取り付け拡大部分(SCITECS_MCR日記)より

LEDとペアで取り付けられているのがデジタルセンサでセンサ取り付けネジの斜め前部分にあるのがアナログセンサとして使う反射型フォトインタラプタ(下図)です。


デジタルセンサはマーカー検出や誤動作防止に使い、アナログセンサで姿勢制御をおこなうことでスムーズな高速走行が可能になります。

アナログセンサの信号をADコンバータの数値で見てみる

アナログセンサの信号はR8CでAD変換して姿勢制御に使います
次のグラフはコースと同じ白線パターン上でアナログセンサを振ってみた時のAD値をグラフにしたものです。
縦軸はAD変換の値で0~1023、横軸は時間でmS単位です。

アナログセンサ回路は次のようになっています。

フォトトランジスタは光の反射が多いほど多く電流を流し出力電圧が下がるため、コースの黒い部分で電圧が高く、白線の部分で電圧が低くなります。

グラフは左右のアナログセンサ(a0,a1)とその差分(ad1-ad0)の値を表示しています。
色の変わり目でスムーズに変化していることが判りますad0とad1の最低値、最高値が違うのは素子特性のバラつきによるものです。

制御プログラムを効率よく開発するための秘訣

制御プログラムで難しいのは上のグラフにあるような素子特性のバラつきや機構の特性によって生じるセンサ信号や挙動の変化をいかにうまく補正するかということです。
ロボットを走らることを繰り返してパラメータを調整する前に、各センサがどのような特性を持つかを把握しておけば問題の解決がずっと容易になります。

上のグラフはCPUボードをUSBでPCに接続してリアルタイムデータをグラフ表示したものです、センサやステアリング部分の挙動を調べるときにはリアルタイムデータを観察する方がプログラムの修正が手早く出来るので便利です。

そして、実際にコースを走行する時のデータはmicroSDに記録して後から解析するという使い分けをすることで開発をより効率的におこなうことが出来ます。

 

 

マイコンカーラリー printfデバッグ (5) 割り込み周期の確認

printfデバッグで原因が判って問題は解決しましたが、制御ループが正確なタイミングで実行されていないと制御が不安定になる原因になりますので、タイマ割り込みと制御ループの実行間隔を調べて見ました。

(4)のtimeに表示されている数値は1ms毎の割り込み関数でインクリメントされているので正確に増えていますが実際には消去関数は130mS程度割り込みを禁止しているのでその間は実際の周期は狂っているはずです。

そこで今度はタイマーRFを使って割り込み関数の起動タイミングを調べてみます。

init()の最後に次の処理を追加してタイマRFを20MHz/32のクロックでインクリメントします。
本当ならばもっときりの良いクロックを使いたかったのですが空いているタイマーの制約上このようなクロックを使うことになりました。

 /* タイマ 時間 計測 */
 trfcr0 = 0x05; /* f32 フリーランカウント開始 */

タイマRFが0-0xFFFFまでカウントアップする時間は 約(1/9.5)秒、およそ0.1秒です。

次のようにタイマ関数の先頭にprintf文を入れてタイマRFの値を表示してみます。

/************************************************************************/
/* タイマRB 割り込み処理 */
/************************************************************************/
#pragma interrupt /B intTRB(vect=24)
void intTRB( void )
{
   static int line_no; /* 行番号 */
   unsigned int i;

   asm(" fset I "); /* タイマRB以上の割り込み許可 */

#ifdef DEBUG
   printf("%04X\n",trf); // TRF 表示 20/32 MHzクロック 
#endif
   uTimer1ms++; // 時間計測用タイマ
   cnt0++;
   cnt1++;
   cnt2++;
   cnt_lcd++;
   check_sen_cnt++;
   check_enc_cnt++;

   ...

実行結果は次のようになります

これをグラフ表示で見ると次のように周期的に間隔が乱れているのが判ります。

間隔の乱れているところを拡大してみると次のようになっています。

縦軸がタイマの値で横軸はデータの数です、タイマの値は16bitで65535を超えると0に戻るためノコギリ波のような形になります、真ん中の大きい段がDataFlashの消去で割り込みが止まっている時でおよそ(57+105×n)mS止まっています。
ここで57mSはグラフから読み取れる値で、105mSはTRFがタイムアウトする時間です。
DataFlash消去中はデータも出力されないためその間に何度TRFがタイムアウトしているかはわかりません。
止まっている時間を正確に知りたければ例えば10KHzクロックでカウントアップするタイマがあれば6.5秒までは測れることになります。
手がかりとしてdata_flash_lib.cのソースに次のような記述があります。

/************************************************************************/
/* モジュール名 blockEraseDataFlash */
/* 処理概要 ブロックイレーズ */
/* 引数 unsinged int アドレス */
/* 戻り値 1:エラーなし 0:エラーあり */
/* メモ 実測で135ms程度 */
/************************************************************************/
int blockEraseDataFlash( unsigned int address )
{
   volatile int ret = 1;
   volatile int block;

   block = checkBlockAddress( address );
   if( block == -1 ) return 0;

   asm( "FCLR I" ); /* 全体の割り込み禁止 */
   
   ...

これを考慮すれば n=1で 162mSの間割り込みが止まっていると考えるのが妥当でしょう。

両側の小さい段は書き込みの時で書き込みの時も割り込み禁止期間があり数ミリ秒は割り込みが止まるようです。

マイコンカーラリーではロボットが高速走行します。
例えば2m/秒の速度で走っているとすれば2mm / 1msの間隔で制御をしていますが、162mS制御不能になればその間に 2mm × 162 = 324mm 進んでしまうことになります。
カーブ等で324mmの間制御が止まればコースアウトは確実です。

 

次にメインループの先頭にtrfを表示するprintfを入れてメインループの実行間隔も確認してみます。

while( 1 ) {
   // デバッグ表示
#ifdef DEBUG
   printf("%04X\n",trf); // TRF 表示 20/32 MHzクロック
#endif
   // LCD表示、パラメータ設定処理
   lcdProcess();
 
   ...

結果のグラフ表示は次のようになりました

当然ですがこちらも同じように制御周期が乱れています。
拡大してみます。

メインループの周期はノコギリ波の周期とその間のデータ数から求められます。
ノコギリ波の1周期は105msでその間におよそ120のデータが出力されていますから、105/120=約0.9msとほぼ割り込みと同じ周期でメインループが繰り返されていることがわかります。。