シリアルポートを介したパソコンによる鉄道模型の制御
1.概要
制御をソフトウェアで行うと、制御内容が複雑な場合でも簡単に実現でき、また、変更も容易にできます。
そこで、シリアルポートを介してパソコンで制御することを考えてみました。
実演の模様はこんな感じになります(クリックすると動画が始まります)。
シリアルポートの各ピンの ON/OFF のさせ方は、一般的には RS-232C の規格に従って行われていますが、
実は、いくつかのピンは、ピン毎に自由に ON/OFF させることができ、
接続先のものを自分で作る場合、RS-232C の規格を一切無視して勝手に決めても全く問題ありません。
[注] 自由に ON/OFF させるのは、Windows-98まで可能でしたが、Windows-2000 からできないように変更されているようです。標準手順しか許さない思想のようです。
下図は大まかな構成です。
駆動モジュールは最大8個まで繋ぐことができ、1モジュールのデータは16ビットです。
2ビットで1つの装置(走行用給電 or 分岐器)を制御します。
センサモジュールの方は繋げる個数に制限はなく(ただし提供するDLLは2モジュールまでしかサポートしていない)、
1モジュールのデータは16ビットです。
動作についてですが、モジュール番号とデータをすべての駆動モジュールに送ります。
各駆動モジュールは、送られて来たモジュール番号が自分の番号と一致していたら送られて来たデータを採用し、
自分の番号と食い違っていたら無視します。
データは16ビットありますが、シリアルポートなので1ビットずつしか送れません。
シフト信号とラッチ信号は1ビットずつ送るときの同期をとるためのものです。
センサモジュールの方には番号が付いておらず、モジュールを選択して状態を取り出すことはできません。
これは、どっちみちすべての箇所について均等に状態を読み取って行かないといけないので、
選択できるようにしても意味がないと考えたからです。
この図には書いていませんが、駆動モジュールには異常検出回路を付けており、
シフト信号が OFF の状態が 0.2〜0.3 秒以上続くと全出力を OFF にするようにしてあります。
ですから、最低でも 0.1 秒に1回くらいはシフト信号が ON になるような使い方をしてください。
シリアルポートのコネクタの各ピンとの対応は、以下のようになります。
3 : TxD
4 : DTR
5 : GND
6 : DSR
7 : RTS
2.構造
2.1 駆動モジュールの構造
下図は駆動モジュールの構造と信号の変化を表したものです。
24ビットのシフトレジスタには Pos Edge のDフリップフロップを24個使っています。
Pos Edge のDフリップフロップは、CK(クロック端子)の状態が OFF から ON に変化した瞬間のD(データ端子)の状態を覚えるもので、
CK が ON のときにDの状態が変ってしまっても影響しません。
また、装置への出力用の16個のFF(フリップフロップ)にも Pos Edge のDフリップフロップを使っています。
動きを大まかに示すと、以下のようになります。
(1) パソコンから、モジュール番号とデータを繋いだ24ビットのビット列を送り、24ビットのシフトレジスタに設定する。
(2) シフトレジスタの右8ビットの内容(モジュール番号が入っている)が自分のモジュール番号と一致する場合のみ、
シフトレジスタの左16ビットの内容(データが入っている)を装置への出力用の16個のFFに設定する。
(1)を詳しく説明すると、以下のようになります。
・「モジュール番号+データ」の信号線の電圧を、データの1番目のビットの内容の高さにする。
・シフト信号を ON にする。
(この結果、シフトレジスタの内容が1ビットずつ右にシフトされ、
シフトレジスタの一番左のビットに、データの1番目のビットの内容が設定される)
・シフト信号を OFF にする。
・データの2番目〜24番目のビットについても同様に行う。
(2)を詳しく説明すると、以下のようになります。
・ラッチ信号を ON にする。
(この結果、もしシフトレジスタの右8ビットの内容が自分のモジュール番号と一致していたら
シフトレジスタの左16ビットの内容が装置への出力用の16個のFFに設定される)
・ラッチ信号を OFF にする。
上には書きませんでしたが、どの信号線についても、ON/OFF を変化させた後は、
次の操作をすぐに行わずに、回路が安定するまで(1μ秒くらい)待ってから行うようにしてください。
この図でのビットの順序は、グラフや提供するDLLでのビットの順序と左右逆になっていますので、
勘違いのないように注意してください。
モジュール番号は2進数ではなくビット位置で表すようにしました。
シフトレジスタの右8ビットが 10000000 なら #0、01000000 なら #1、00000001 なら #7 を表します
(【注】提供するDLL内では 00000001 なら #0、00000010 なら #1、10000000 なら #7 を表す)。
この図の場合、モジュール番号が #1 のとき一致とみなされます。
出力端子のところには、説明の都合上、ラッチ信号 ON よりも後の状態を書きました。
「正」と「逆」を一緒に囲った箱はフルブリッジと呼ばれるもので、以下のような動作をします。
・正=0、逆=0: モータの端子を未接続と同じ状態にする(モータは回転しないか惰性で回転しているだけ)
・正=1、逆=0: モータを正転
・正=0、逆=1: モータを逆転
・正=1、逆=1: モータの端子を両方とも0Vにする(モータの端子を短絡したのと同じで、ブレーキがかかる)
モータの代わりに分岐器を繋いだ場合も、回転方向の話が転換方向の話に変わるだけで、同じです。
これでモータの正転と逆転は制御できますが、12V固定のため、回転速度を変えられないように思えます。
ところが、PWM(Pulse Width Modulation(パルス幅変調))という技法を使うと回転速度も変えることができます。
PWMとは、数十Hz〜100Hz くらいの周期で ON と OFF を繰り返し、
ON の時間(つまりパルス幅)と OFF の時間の比率を変えることで、回転速度を変える技法です(下図参照)。
今回は、PWMの ON/OFF の切替えも、ソフトウェアで行うことにしました。
ただし、たまに、OSの処理が割り込んで来て、数十m秒間だけですが、切替えが行われずに ON に固定されることがあります。
車両が一瞬だけ暴走してどこかにぶつかってしまう危険性がありますので、ご承知おきください。
2.2 センサモジュールの構造
下図はセンサモジュールの構造と信号の変化を表したものです。
16ビットのシフトレジスタには Pos Edge のDフリップフロップを16個使っていますが、
別の端子から読み込むモードに切替え可能なものを使っています。
動きを大まかに示すと、以下のようになります。
(1) 16箇所の状態を一斉に取得し、16ビットのシフトレジスタに保持する。
(2) シフトレジスタの内容を右にシフトしながらパソコンに送る。
(1)を詳しく説明すると、以下のようになります。
・ラッチ信号を ON にすることで S/L を OFF にする。
(この結果、シフトレジスタのモードが別の端子から読み込むモードになる)
・ラッチ信号を OFF にすることで S/L を ON にする。
(この結果、シフトレジスタのモードが元に戻り、モードが戻る直前の別の端子の状態が保持されて、
取得データの1番目のビットの内容がシフトレジスタの一番右のビットの出力に現れ、DSR にも現れる)
(2)を詳しく説明すると、以下のようになります。
・DSR に現れている内容を、取得データの1番目のビットの内容としてパソコンで読み取る。
・シフト信号を ON にする。
(この結果、シフトレジスタの内容が1ビットずつ右にシフトされ、
取得データの2番目のビットの内容が DSR に現れる)
・シフト信号を OFF にする。
・取得データの2番目〜16番目のビットについても同様に行う。
上には書きませんでしたが、どの信号線についても、ON/OFF を変化させた後は、
次の操作をすぐに行わずに、回路が安定するまで(1μ秒くらい)待ってから行うようにしてください。
また、電圧変換回路は、負電源として RTS、つまりラッチ信号の信号線の出力電圧を利用しているので、
ラッチ信号が ON のとき、負電源が+10Vになってしまうために正しく動きません。
ラッチ信号を ON から OFF にした直後の DSR からの読取りは、電圧変換回路が安定するまで(1μ秒くらい)待ってから行ってください。
ところで、ラッチ信号は駆動モジュールと共有しているため、
ラッチ信号を安易に出してしまうと、駆動モジュールにでたらめな値が設定されてしまいます。
そこで読取り処理は以下の場合にだけ行います。
・駆動モジュールへの設定のためにラッチ信号が出された直後に、ついでに行う。
・全駆動モジュールのシフトレジスタの右8ビットの内容(モジュール番号が入っている)が確実に 00000000 のときにだけ、
ラッチ信号を自主的に出して行う。
提供するDLLでは、駆動モジュールへの設定を行わないときは「モジュール番号+データ」の信号線には必ず0を送るようにし、
その状態で連続してシフト信号を24回以上出した場合に、
全駆動モジュールのシフトレジスタの右8ビットの内容(モジュール番号が入っている)が確実に 00000000 になっていると判断しています。
3.回路図
3.1 駆動モジュールの回路図
下図は駆動モジュールの回路図です。
シリアルポートの出力は−10V〜+10Vで、OFF や0を表すときは−10Vに、ON や1を表すときは+10Vにします
(TxD については RS-232C の規格と異なるので注意してください)。
汎用論理ICの入力は0V〜5Vなので本来なら電圧変換が必要ですが、
CMOS-IC の 74HC シリーズの入力端子には保護ダイオード(静電気で壊れるのを防ぐためのもの)が入っているので、
それを活用して回路を簡素化しています。
保護ダイオードを介して電流が流れ、IC内の MOS-FET には−0.6〜5.6Vの範囲内でしか電圧がかからず保護されます。
しかし、シリアルポートを直接繋いでしまうと、保護ダイオードに大電流が流れて、保護ダイオードの方が壊れてしまいますので、
33kΩくらいの抵抗を通して繋いでいます。
74HC164のピン番号nは、割り当てたいモジュール番号によって異なり、下表のようになります。
モジュール番号 | #0 | #1 | #2 | #3 | #4 | #5 | #6 | #7 |
ピン番号 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | 13 |
図の下の方に8個並んでいる TA7257P は、今回の成功に大きく貢献した部品で、フルブリッジです。
モータ1個あたりの正転/逆転がこの部品1個でできます。
モータの逆起電力を吸収するダイオードも組み込まれていて、他に部品を付ける必要もありません。
もしこれと同じ働きをするものをトランジスタ等を組み合せて何組も作らないといけないとなったら、途中でめげてしまいます。
ところで、回路図を見ると、フィーダ線の青や黒の方を3番ピンに、白や赤の方を5番ピンに繋いでいますが、
実は、この繋ぎ方だと、パワーパックに直接繋いだ場合と+−が逆になります。
これは、私のミスで、データシートにどちらが ON だとどちらが+なのか載っていないので測定してから決めるべきだったのですが、
それを怠って、フィーリングで、分岐器が直進側に転換される方を正転と決めてしまったせいです。
気づいたのが実演の撮影よりも後なので、そのままにしてあります。
正転時のフィーダ線は、青が+で白がー、あるいは黒が+で赤が−なんだと思ってください。
下に TA7257P の写真を載せます。ピン番号は左から順に 1, 2, 3, 4, 5, 6, 7 です。
1番ピン : 正転入力
2番ピン : 逆転入力
3番ピン : 出力1
4番ピン : GND(制御回路用電源とモータ用電源で共通)
5番ピン : 出力2
6番ピン : モータ用電源
7番ピン : 制御回路用電源
各入力端子の状態と動作は下表のとおり。
正転入力 | 逆転入力 | 動 作 |
OFF | OFF | 出力1と出力2が未接続状態となる。 |
ON | OFF | 出力1がモータ用電源電圧、出力2が0Vとなる(筆者の測定結果)。 |
OFF | ON | 出力1が0V、出力2がモータ用電源電圧となる(筆者の測定結果)。 |
ON | ON | 出力1と出力2がともに0Vになる(ブレーキがかかる)。 |
制御回路用電源の電圧は 6〜18Vが、モータ駆動用電源の電圧は 0〜18Vが可能で、
2者の大小関係はどのようになっていてもよい。
出力電流は平均で 1.5Aまで、瞬間で 4.5Aまで可能。
ただし、この TA7257P は、電源電圧が激しく振動していると、モータが電源に中途半端に繋がった状態になってしまい、
モータが動かないだけでなく、強く発熱して持てない程熱くなり壊れます。
ですから、必ず、定電圧モジュール(後述)に繋いでください。
パワーパックには絶対に直接繋がないでください。
パワーパックには D.C.12Vと書かれていますが、実際には激しく振動しています(例えば、つまみ最大時で8Vから20Vの間を激しく振動)。
図の左上にあるトランジスタとコンデンサと抵抗は、異常検出回路で、
パソコンが凍り付いてモータや分岐器への給電が ON になり放しになったときに OFF にするためのものです。
シフト信号が OFF の状態が 0.2〜0.3 秒以上続くと、74HC595 の13ピンをHにしています。
これがHになると、74HC595 の出力端子は、未接続と同じ状態になり、抵抗を通してグランドに繋がっていることにより0Vになります。
シフト信号が ON のときにパソコンが凍り付いた場合には役に立ちませんが、
すべての処理をシフト信号が OFF のときに行うようにすればそんなことはまずないだろうと思い、これで充分と考えました。
なお、左の方にあるダイオードは、TxD が−10Vになったときにトランジスタを保護するためのものです。
図の右上にあるダイオードと抵抗の対を2つ並べたものは AND 回路です。
図の右下にある TA7805S は5V供給用の3端子レギュレータ(定電圧IC)で、1Aまで流せます。
型名の見える面を前、端子を下にして、左から I, G, O の順です。回路図上と同じ順です。
74HC164 と 74HC595 の仕様を書いておきます。図中の VDD は電源(+5V)、VSS は GND(0V)です。
・8ビットのシフトレジスタが入っている。
・CK が L から H が変化したとき、シフトレジスタの内容が1ビット上位にシフトされ、
それと同時にそのときの A と B の AND 値がシフトレジスタの最下位ビットに保持される。
・CK が H のときに A と B の AND 値が変化しても、シフトレジスタの内容は変化しない。
・QA〜 QH には常時シフトレジスタの内容が出力されている。
対応の仕方は、下位ビットから順に QA , QB ,...である。
・CLR が L になると、シフトレジスタの内容がクリアされる。
・8ビットのシフトレジスタとラッチ用のFFが入っている。
・SCLR が L の状態で SCK が L から H に変化したとき、シフトレジスタの内容がクリアされる。
・SCLR が H の状態で SCK が L から H に変化したとき、シフトレジスタの内容が1ビット上位に
シフトされ、それと同時にそのときの SI の状態がシフトレジスタの最下位ビットに保持される。
・SCK が H のときにSIの状態が変化しても、シフトレジスタの内容は変化しない。
・QH′には常にシフトレジスタの最上位ビットの内容が出力されている。
・RCK が L から H に変化したとき、そのときのシフトレジスタの内容がラッチ用のFFに保持される。
・RCK が H のときにシフトレジスタの内容が変化しても、ラッチ用のFFの内容は変化しない。
・G が L のとき、QA〜 QH には、常時、ラッチ用のFFの内容が出力されている。
対応の仕方は、下位ビットから順に QA , QB ,...である。
・G が H のとき、QA〜 QH は、ハイ・インピーダンス(未接続と同じ状態)になる。
コラム: C-MOS の C って何?
3.2 センサモジュールの回路図
下図はセンサモジュールの回路図です。
図の左上にあるトランジスタと抵抗は NOT 回路です。
それらの左にあるダイオードは、RTS が−10Vになったときにトランジスタを保護するためのものです。
図の右上にあるオペアンプは電圧を変換するためのものです。
0を表すとき、ICの出力電圧は0Vなのですが、シリアルポートの規格では−3V以下にしないといけないので、電圧変換が必要です。
ところが、負電源がありません。
そこで、RTS の出力電圧を負電源として利用することにしました。
電圧変換が必要なタイミングではたまたま RTS が必ず−10Vになっているので利用できます。
ただし、RTS が+10Vから−10Vに変化した直後は不安定なので、パソコンでの読取りは少し待ってからにしないといけません。
オペアンプの下にある2つのダイオードは、RTS が+10Vになったときに負電源を+0.6Vに抑えるためのもので、
これがないと負電源よりも入力電圧の方が低い状態になってしまい、オペアンプが壊れるかもしれません。
CdSは16個すべて繋ぐ必要はなく、使わないところは未接続のままでかまいません。
未接続の箇所は抵抗が∞、つまり暗い場合と同じになります。
74HC165 の仕様を書いておきます。図中の VDD は電源(+5V)、VSS は GND(0V)です。
・8ビットのシフトレジスタが入っている。
・S/L が L のとき、A 〜 H の状態が常時シフトレジスタに反映される(素通しの状態)。
つまり、S/L が L から H に変化したとき、そのときの A 〜 H の内容がシフトレジスタに保持される。
・S/L が H の状態で、CK が L から H が変化したとき、シフトレジスタの内容が1ビット上位にシフトされ、
それと同時にそのときの SI の状態がシフトレジスタの最下位ビットに保持される。
・S/L が H の状態で、CK が H のときに SI の状態が変化しても、シフトレジスタの内容は変化しない。
・QH には常時シフトレジスタの最上位ビットの内容が出力されている。
・ ̄QH には常時シフトレジスタの最上位ビットの内容の NOT 値が出力されている。
・CLR が L になると、シフトレジスタの内容がクリアされる。
3.3 定電圧モジュールの回路図
下図は定電圧モジュールの回路図です。
78T12CT は、12V供給用の3端子レギュレータです。3Aくらいまで流せます。
モータを動かすと大きな電流が流れますので、一応、放熱器を付けてください。
パワーパックには D.C.12Vと書かれていますが、実際には電圧が激しく振動していて谷の部分では8Vくらいしかないので、
それを直接3端子レギュレータに繋いでも12V供給できません。
振動の山の部分でコンデンサに貯めておく必要がありますが、
モータ1個あたり0.3Aくらい流れるにもかかわらず、振動の谷は数ミリ秒も続き、
その間、モータにはコンデンサだけで供給し続けなければなりません。かなり容量の大きなものが必要です。
そこで 10000μF のものを使うことにしました。
10000μF くらいのものになると値段が結構高いので、値段の差が大きくなくなります。
性能が悪くて安いもので充分ですので、頑張って捜してください(私が使っているのは350円のものです)。
なお、耐圧は25V必要ですので注意してください。
出力側にある 0.1μF のコンデンサは、発振を防止するために必ず必要だそうです。
78T12CT は入手が難しいかもしれません。
入手できない場合、どれくらいの台数走らせるつもりかにもよりますが、
2Aくらいまで流せる3端子レギュレータで大丈夫かもしれません。
4.モジュールの写真
4.1 駆動モジュールの写真
4.2 センサモジュールの写真
4.3 定電圧モジュールの写真
4.4 全体の写真
5.アクセス用DLL
入口一覧と各インタフェース
DLLファイル
プロトタイプ宣言(Delphi 6)
型定義 (Delphi 6)
ソース (Delphi 6)
下図のレイアウトと接続形態を制御する場合を例に、本DLLの使い方を説明します。
図の状態から、列車Aを分岐の直進側に入れた後、列車Bを左端まで走らせる場合のコーディングは、
以下のようになります。
var
SPCB: TSerialPort_CtrlBlock;
begin
SerialPort_InitCtrlBlock(@SPCB, 0.01, 16, 20);
SerialPort_GenerateOneShot(@SPCB, 0, 1, 100);
SerialPort_SetPWMPwRate(@SPCB, 0, 0, 400000);
while (SerialPort_GetTakenData(@SPCB) and $0001) <> 0 do
SerialPort_ExecRealtime(@SPCB);
SerialPort_GenerateOneShot(@SPCB, 0, 1, -100);
SerialPort_SetPWMPwRate(@SPCB, 0, 0, -400000);
while (SerialPort_GetTakenData(@SPCB) and $0002) <> 0 do
SerialPort_ExecRealtime(@SPCB);
SerialPort_TermCtrlBlock(@SPCB);
end;
ここで大事なのは SerialPort_ExecRealtime を定期的に呼び出さないといけないということです。
SerialPort_ExecRealtime を必ず1m秒以内の間隔で定期的に呼び出してください。
DLL内の処理を呼び出してから戻って来るまでの時間は無視していいほど短い時間ですので、
問題なのはループです。ループの中では SerialPort_ExecRealtime を呼び出すようにしてください。
6.使用例
使用例として、複線終端の2面4線の駅について制御を行ってみました。
下図は、レイアウトと接続形態です。
各シーサスクロッシングは、外側のレールも電気的に分断してあります(金属用のノコギリで切断)。
すべての線路に同一電源から供給しているため、
もしそこを分断しないと、ポイントを交差側に転換したときにショートしてしまうからです。
左の分岐器が置いてある付近は、駅の構内の外側のつもりで、その分岐器をもっと離れたところに置いた方が実感が沸くのですが、
撮影した動画ファイルがあまりにも大きくなると困るので、実演時間を縮めるために仕方なく駅の近くに置きました。
下に実物の写真を載せます。
この制御に使用したプログラムはこれです。
ソース(Delphi 6)
実演の模様はこんな感じになります(クリックすると動画が始まります)(この頁の先頭のものと同じ)。