クモとの距離は80cm

STATUS: 故障中x2


 先日買って来た距離センサーをUSBSPYDER08に繋いで見ました。


 A/D変換はもうやったので、そこの回路のボリュームの変わりに、距離センサーをつけただけ。
 センサーからの距離に応じて、LEDの明るさが変わります。遠いと暗く、近づくと明るく…


/
 今回使っているセンサーは、シャープのPSD方式距離センサ「GP2D12」
 原理は、前回もちょっと書きましたが、わかりやすい説明がをみつけました。→このページ

 
 推奨動作条件は、4.5 〜 +5.5Vですが、USBSPYDER08の電源の3.3Vでもちゃんと動作しましたよ(一応使用限度内)。
 接続は、専用コネクタを買わなかったので、裏面に露出している基板から直接ICクリップで繋ぎました(外れやすい!)。
 左から、Vdd,GND,信号ピン(ADP3)を接続しました。


 GP2D12で、測れる距離は、10cm〜80cmの距離です。
 志向性はけっこうあって、15度くらいでしょうか。
 LEDの明るさだけでは、大体のところしかわからないので、デバッガで入力値(8bit A/Dモード時)をみてみると…
・測定距離以上(80cm以上) 7〜10くらいで変動
・測定最短距離(10cm弱) 183くらい
・測定最短距離未満(5cmくらい) 50


 センサーの前になにもないと、7〜10くらいの値を示し、80cmくらいの距離から近づくにしたがって数値が大きくなります。10cmをすこし切るくらいの距離で、最大183のなりました。
 それより近づくと、今度は逆に減って50くらいまでおちこんでいきます。この辺は注意が必要ですね。
 また、入力値はリニアではなく、距離に反比例するようです。
 あんまり高精度で測定してもしょうがないので、8bitで測定するモードで実用することとして、入力値と距離のテーブルを作ればいいかな。


 距離と電圧の関係をグラフにしいてるページがありました。たしかにこんな感じでした。
 →4.赤外線センサGP2D12(回路システムについて)


/
 というわけで、今回は距離センサーつないでみました。
 基本が出来ちゃえばなんでも簡単に繋がるのでいいですね。
 こうやってどんどん感覚が増えていくのって、どろろ百鬼丸が失った体の部分を1つずつ取り戻して行く過程みたいだなーって思ったりして。最後はどこまでいくのでしょう。

クモの時計コレクション

STATUS: 故障中x2


 USBSPYDER08のCPU、MC9S08QG4(コア:HCS08)には2種類のタイマーがあります。

 
 単純なタイマーの「モジュロ・タイマ(S08MTIMV1)」、高精度なクロック、PWM制御、外部ピンへの出力機能などをもつ高機能な「タイマ/ パルス幅モジュレータ(S08TPMV2)」。
 とりあえずこの二つをタイマー(割り込み発生)として使うことが出来るようになりました。


 それぞれのタイマーは、どちらも大元のクロック源を分周して使います。
 クロック源としては、バスクロック(CPUのクロックのもと)や外部に接続したクロックなどを選べるのですが、回路を増やさなくてよいという意味ではバスクロックを使うのが一番お手軽です。
 でも、バスクロックは8MHz(ですよね?※)もあるので、そのままではでは早すぎます。1秒間に800万回も割り込みが起きても困るというか処理しきれないし。


 そこで、何分の1かに分周して(クロックが何回か来たら1とするようにして、もとのクロックを間引いて遅くする)使います。
 クロックの発生から割り込みが起きるまでは以下のように2段構えになっています。


1.「プリスケーラ」でだいたいのところまで落とす(1/16とか、1/64とか、1/256とか)。
 タイマーの中には「カウンター」があり、ここで指定した回数の分クロックがきたら、カウンターを1増やすという処理が行われています。たとえば、プリスケーラに「1/64」を指定すると、16回クロックがきて初めてカウンターが1増加します。


2.カウンターが「モジュロ値」を超えたら割り込み発生
 モジュロ値はもっと詳細に指定できる値(モジュロ・タイマでは1〜255、タイマ/パルス幅モジュレータでは、1〜65535)で、数値が小さいほど割り込みは発生する感覚が短くなります。



● モジュロ・タイマ(S08MTIMV1)


 こちらは単純なほうのタイマーです。


 プログラムの初期化部分では、以下のように書きます。

   // M TIMER
   //            54      CLKS = 00   : クロック源としてバスクロックを選択 (00はBUSLCKの意味。データシート P.170参照)
   //              3210  PS   = 1000 : プリスケーラを1/256を選択 (1000は1/256という意味。P.170参照)
   MTIMCLK = 0b00001000;
   MTIMMOD = 100;         // モジュロ値(1-255で選択可)として、100を指定
   //          7         TOF         : オーバーフローフラグ
   //           6        TOIE = 0->1 : Interrupt Enable , 割り込み許可
   //            5       TRST = 1->0 : Reset TOI , TOFリセット
   //             4      TSTP = 0    : MTIM Counter Active
   MTIMSC  = 0b00100000;  // TOFリセット
   MTIMSC  = 0b01000000;  // タイマースタート

 これで、タイマーが一定周期で割り込みを発生するようになります。
 割り込み周期は、上記のプログラムでは…

・クロック元 = バスクロック → 8Mhz = 秒間8000000回
・プリスケーラ = 1/256 → 8Mhzを1/256にするので、秒間約31250回、カウンターが加算される
・モジュロ値 = 100 → カウンターが100を超えるごとに割り込み発生(カウンターは100を超えると0に戻る) → 秒間約312回割り込み発生

ということで、秒間312回割り込みが発生する設定です。

で、割り込みを実際に処理するルーチンは以下のように書きます。

interrupt 12 void MTimerOverflow (void) {
  MTIMSC_TOF=0;   // TOFをリセット ※忘れると大変なことになるよ
  n3++;
  if ( n3>=100 ) {
    PTAD ^= 0b00000001;  // LEDのON/OFF
    n3=0;
  }
}


ここでは、割り込みでLEDのON/OFFを切り替えています。
(PTADのbit0をOn/offしている。事前に、PTADDのbit0を1にしておくこと)
ただ、毎回ON/OFFすると高速すぎて人間が認識できないので、変数を加算していき100になったら処理することにしています。
これで、1/3.1秒ごとにLEDのON/OFFがかわることになります。


ちなみに、「interrupt 12」という記述は、ベクター12番の割り込みルーチンだよーという指定をしています。(専用の文法)
ベクター番号は、割り込みの発生源ごとに決まっていて、モジュラ・タイマの場合は、12と決まっています。
割り込みベクタの一覧は、データシートの、64ページに記載されています。


 そうだ!大事なことを書き忘れてた。
 割り込みルーチンの銭湯には、「MTIMSC_TOF=0;」と書いておきましょう。
 こうやってTOFをリセットしないと、次の割り込みが発生しないばかりか、CPUがハングアップしちゃいますよー。
 これ入れ忘れててかな〜り悩みました。
 (ハングアップすると約1秒間隔で、WatchDogで強制リセットされるので、びみょーな動きになった)
 まあ、これさえ忘れなければ難しいところはないでしょう。


 詳しくはデータシートの13章「モジュロ・タイマ(S08MTIMV1)」を読んでください。


※ 上記記事では、バスクロック=8Mhzということで書きましたが、デフォルトっていくつでしたっけ? 実測するとバスクロック=4Mhzになってるような気がするー。ここまで書いたのは、だいたいの考え方ということで、実体にあわせて値を設定してくださいな(って、いいかげんな…)



● タイマ/ パルス幅モジュレータ(S08TPMV2)


 こっちは機能がいっぱいなのでまだ全部の機能は使っていません。
 PWMの出力をちゃんと使えば、LEDの明るさ制御もチップ任せでできちゃうんだろうなー


 とりあえずタイマーとして使ってます。
 これはちょっと複雑で、メインのカウンターが一つあって、そこにサブのカウンターが複数個(MC9S08QGでは0と1の計2チャンネル)つながってPWMなどの制御を行います。
 ここでは一番単純に、メインのカウンターだけを利用してみます。

   // TPM
   //          7         TOF         : (ReadOnly)オーバーフローフラグ
   //           6        TOIE = 1    : Interrupt Enable (割り込み許可)
   //            5       CPWMS = 0   : 
   //             43     CLKS = 01   :  クロック源としてバスクロックを選択 (00はBUSLCKの意味。データシート P.211参照)
   //               210  PS = 111    : プリスケーラを1/128に指定
   TPMSC   = 0b01001111;
   TPMMOD  = 20000;         // モジュロ値(1-65535で選択可)として、20000を指定


 初期化は、こんな感じ。
 メインのカウンターでは、クロック源にバスクロックを選択。
 それをプリスケーラで、1/128にして、 そのカウントがモジュロ値で指定した20000をになったら、カウンターがオーバーフローして0にもどります。この際に割り込みが発生します。


 割り込み処理ルーチンはこんな感じ。

interrupt 7 void Timer1Overflow (void) {
  TPMSC_TOF=0;    // TOFをリセット ※忘れると大変なことになるよ
  PTAD ^= 0b00000001;    
}

 割り込みベクタ番号は7番なので、「interrupt 7」と指定してあります。
 ベクタ番号が重要なので、関数名はなんでもいいです(最初のモジュロタイマーのほうも同様)。
 こちらは、割り込み発生間隔を細かく指定できるので、割り込みのたびにLEDをON/OFFしています。



 タイマーはこんな感じ。
 割り込みの処理のしかたもわかったしよきかな。

クモ、手足を得る (1)準備編

STATUS: 故障中x2


 マイコンでメカを制御しようとするときは、ラジコンのサーボを使うのが一番簡単なようです。
 サーボへの信号については、以下のページの解説がわかりやすいです。 


ワンチップマイコンPICを用いたRC用サーボモータのコントローラ


 15〜20ミリ秒間隔でパルス信号を送り、そのパルスの時間でサーボの切れ角が制御できるようです(PWMってこと)。
 実際のところどうなのかオシロスコープで測定してみました。

 
 ラジコンは、以前組み立てたスウィフトを利用しました。受信機は、タミヤTRU-02です。
 受信機からステアリング用サーボへの信号をとりだしオシロに繋ぎました。(近藤科学のサーボ延長コードを途中で切断してオシロの接続しています)


 オシロのほうは、とても古い機種かつ数年ぶりにひっぱりだしてきたので測定の精度はまったくあてになりませんが、だいたい20ミリ秒弱の間隔でパルスがきているのがわかりました。
 パルスの幅は、だいたい1.5ミリ秒くらいかなあ。
 送信機のステアリングを回すと、長さが変動します。
 ステアリングセンターで1.5ミリ秒くらい。右に回しきると、1.7ミリ秒くらい。左に回しきると、1.3ミリ秒くらい。…と、アナログ的に変化します。※秒数はテキトーな感覚です


(実際の波形)


 マイコンからも同じような信号をだしてやれば、サーボの制御ができそうですね。
 ステアリング使っているサーボは、フタバのS-3003という製品です。
 詳細な仕様は、ココに載ってました。
 「Direction: Counter Clockwise/Pulse Traveling 1520-1900usec」と、あるので、パルス幅を、1.530ミリ秒から1.900ミリ秒の間で変化させればサーボホーンを左右いっぱいにふれるのでしょう。 
 パルス間隔については特に載ってなかったので、こちらはそんなに厳密じゃなくてもいいのかな。
 パルス幅の制御は厳密にやらないといけないけど、タイマー機能でPWM出力を直接だせるので、CPUの負荷なく出来るはず。CPU占有してもいいなら、もっと簡単にできそうだし。


 次回は、実際にサーボを制御してみようと思います。



/
 ところで、サーボの信号って信号自体はデジタルだけど、値はアナログ(パルス幅の時間)なのね。だからアナログサーボっていうんだ…と、思ったらそうではなくて、デジタルサーボも制御信号は同じらしい。何が違うんだろう?
 それにしても20ミリ秒間隔というのは意外と長いと思いました。たったの秒間50サンプルでしょ?
 僕がラジコンカーの運転下手なのは、サンプリング間隔が長すぎて僕の繊細な操作についてこれないからに違いない!(絶対違う)