PC/AT 互換機のシリアルポートを Linuxから DIOポートとして利用する。

はじめに

電子工作を楽しむ人にとって、自作デバイスをPCに繋げる目的で最も便利 に使用されて来たのが、プリンターとの接続に使用されていたパラレルポート でしょう。しかしながら、そろそろパラレルポートを持たないPCも出始めて、 今後どうなるかちょっと心配な所です。
一方シリアルポートですが、制御信号( RTS, CTS 等)は個別に アクセスできるので、点数は少ないもののDIOポートとして流用する事が 可能です。もちろん シリアルポートも、パラレルポート同様メーカ主導の レガーシーデバイス排斥運動の対象ですので、先行き不安で ある事には変わりありません。しかしながら、Linux での利用に限れば ちょっとだけ良い事があります。パラレルポートに自作デバイスを接続 した場合、自作のデバイスドライバを書くか、直接I/Oポートを叩くか するのが普通ですが、COMポート(シリアルポート)用の標準のデバイス ドライバには、入力信号の状態を調べたり、出力信号を制御する ioctl() が用意されています。つまり、/dev/ttyS* へのアクセス権限さえあれば、 一般ユーザの権限で、シリアルポートを自在に操る事が出来ると言う事です。 それだけではありません。シリアルポートの無いマシンで、USB-シリアル変換 コネクタを利用している方もいると思いますが、この場合も、デバイスファイル 名を替えるだけで、内蔵シリアルポートとほぼ同じプログラムを使用する事が 出来るのです。このように、シリアルポートには、パラレルポートには無い 魅力があるので、ここでは、シリアルポートを単純なDIOポートとして利用する 方法について簡単に書いてみます。

レベルコンバータの製作

パラレルポートの信号は TTL レベルですので、自作機器の接続に大変便利 なのですが、シリアルポートは、RS232C レベル( 0 のとき +3V〜+15V, 1 のとき -15V〜-3V ) ですので扱いが面倒です。出力信号は、適当につじつま合わせを する事は出来ますが、入力はどうしましょう? どうしても外部電源を用意する のがいやだと言う場合、出力信号2点を 1, 0 に設定しておいて、C-MOS オペアンプをを使った TTL2RS232.ps.gz とった回路もあります。
しかし、どうせ接続する自作デバイスで電源が必要になる訳ですから、無理をせずに 5Vの外部電源と、RS232Cドライバ/レシーバ用のICを使う方が良いでしょう。 今回製作した回路は次のようなものです。



使用したのは、 SP3232ECP です。秋葉原の秋月電子通商で、 コンデンサー5個とICソケットがセットで 250円でした。別にこのICでなくても、 同様の機能を果たすICはたくさんありますが、ピン配置は基本的に互換性 はないので、注意して下さい。
出来上がりはこんな感じ。[写真1]
COMポートの制御信号は、出力は RTS, DTR, 入力は CTS, DSR, DCD の合計 5点がありますが、RS232CレベルコンバータICは、入力2, 出力2 の品種が 圧倒的に入手しやすいので、今回は 入力2, 出力2 と言う事にしました。
さて、この先に繋がる物が何もないと寂しいので、テスト用の回路として、 以下のようなものを作ってみました。



RTS, DTR の出力信号をセット、クリアする事で、LED1, LED2 を on/off 出来ます。また SW1, SW2 の押しボタンスイッチを押しているか離しているか を、CTS, DCD の入力信号を調べる事で知る事が出来ます。 出来上がりはこんな感じ。[写真2]

テストプログラム

入力信号の読み取りには chk_com_in.c を見て下さい。実際に使用する時は、 #define DEVICE の所を、環境に 合わせて、書き換えて下さい。プログラムは短いので、見れば何をしているか すぐに分かるでしょう。このプログラム実行するためには、/dev/ttyS0 の 読み書きの権限が必要になります。このプログラムは、入力信号 CTS, DCD の状態を調べて、結果を標準出力に出力する事を永遠に繰り返します。 終了させるには [CTRL]+C で終了して下さい。このプログラムを実行させ ながら、SW1, SW2 を押して、状態が変化するか確認して見て下さい。
次に出力のサンプルとして、chk_com_out.c を見て下さい。このプログラムを実行すると、1秒毎に、LED1, LED2 が 交互に点滅するはずです。注意点は先程のサンプルと同様です。

割り込みの利用

少し高度な使い方として、割り込みの利用を紹介します。本体内蔵のCOM ポートの場合、16550互換である事が多いので大丈夫だと思いますが、 中にはここで紹介する方法が利用できない機種もあると思います。 注意して下さい。私の利用している、USB-シリアル変換コネクタでも 利用できませんでした。
先程示したサンプルプログラムchk_com_in.c ですが、CPU をほぼ100%使いきってしまいます。はっきりいって無駄です。 最近のPC/AT互換機で良く使われている 16550互換のUART を含む一部のUARTでは、 制御信号の変化で割り込みを発生させる事が出来ます。この割り込みハンドラを ユーザプログラムで持つ事は困難ですが、割り込みが発生するまで、プログラムを 一時中断させる(もちろん他のプロセスは動作しています)ioctl() が用意されて います。入力信号が変化するまで、何もしなくて良いならこの ioctl() を利用 すれば、無駄に CPU を食い潰す事が無いので良いでしょう。繰り返しになりますが、 全ての UART に対応していませんので、自分の使用する環境を確認してから 使用して下さい。ちなみに、私の使用している USB-シリアル変換ケーブルは、 対応していませんでした。
サンプルプログラムは chk_com_in2.cです。 さて、このプログラムを実際に試した方は分かると思いますが、時々、 押しボタンスイッチの変化に反応しない事がある事に気がついたと思います。 これは、ioctl( fd, TIOCMIWAIT, arg ); が終了してから、次の ioctl( fd, TIOCMIWAIT, arg ); を実行するまでの間に変化が発生した場合、 とりこぼしが発生するからです。人間がボタンを押す程度の速度の変化で とりこぼしが頻繁に起こるのは変な気もします。通常のスイッチでは、 チャタリングといって、スイッチを押した時、短い周期で ON-OFF を繰り返して ON の状態になります。このチャタリングが影響するのです。これは、 適当な積分回路を抵抗とコンデンサで作って(時定数はスイッチによって 調整する必要があります)、間にはさめばほぼ解決します。また、予算が 絡まなければ、RSフリップフロップを利用すれば安定するでしょう。

さて、私が、このシリアルポートをDIOとして使用する目的は、GPSや、 長波JJY を利用した時刻情報の取得にありました。そこで気になるのは、 信号の変化をどの程度の遅れで知る事が出来るかと言う事です。正確な 測定は難しいのですが、おおよその見当をつける事は簡単に出来ます。



このような回路を追加して、RTS を 変化させた時刻と、 CTS の変化を検出した時刻を比較すれば良いのです。 chk_com_port.cが、測定に使用した プログラムです。使用したのが PC/AT互換機でしたので、TSC レジスタを 時間の測定に利用しました。Athlon XP 1.2GHz のマシンで、 Linux 2.6.8.1 を利用した時、100μ秒程度の遅延がある事がわかりました。当然ですが、 負荷の増加に応じて、遅延時間は長くなって行きます。カーネルのバージョンに よる違いをみておくのも面白いかも知れません。
同様のテストを、直接シリアルポートの CTS, RTS を接続して測定すれば、 RS232Cドライバ/レシーバ用のIC内での遅延を見積もる事も出来ます。 実際に測定してみた所、今回使用した SP3232ECPでは、RS232C->TTL 変換と TTL->RS232C を合わせて 10μ秒程度の遅延がありそうです。


このページに関する、ご意見、感想、苦情はこちらまで 松本 徳真 / matsu@netfort.gr.jp