先日、USB⇔UART変換モジュールを使いたくて、手持ちのFTDIモジュール(下図)を探したのだけど見つかりません。「アレレ??」と思ったら、既に別な用途で使っていました。
「メガネ、メガネ👓、アレ?何処に置いたっけ?」
と、頭の上に乗せていた、みたいな……?
今回は、そんなお話です。
本HPのプログラムは、シリアルモニタからコマンドを送信したり、デバッグ情報を受信したりする物が多いです。故に筆者の使い方では、USB⇔UART変換機能は、必須機能なのです。
Arduino UNOやDUE等のマイコンボードでは、ボード上にUSB⇔UART変換チップが搭載されている(※)ため、FTDIの様な、外付けのモジュールが必要ありません。
※あるいは、マイコンボード上のMCUチップその物がUSBユニットを搭載している。
しかし、MCUチップATmega328やATtiny2313、ATtiny85等を生(単体)で使う場合には、外付けのUSB⇔UART変換モジュールが必要になります(以下記事など)。
これらのMCUを単体で使う場合、USB⇔UART変換モジュールが必要で、最低1個あれば充足するのですが、複数を組み合わせて同時に使おうとすると、その数だけUSB⇔UART変換モジュールも必要となります。
特に本HPでは、USB⇔UART変換モジュール(FTDI)の使用頻度は高く、なんやかんやと使っています。過去にも、たまに足りなくなって困る時があったのですが、さすがにUSB⇔UART変換モジュールを2個同時に使いたいケースは本当に稀なので、もう1個予備で買うか?と言うと、そこまでの必要を感じませんでした。
仮に、追加で予備を購入しようとすると、USB⇔UART変換モジュールは400円前後で購入可能なのですが、最近は400円〜600円と送料が高額なので、肝心なUSB⇔UART変換モジュールよりも高くつきます。「何してんのよ?」って感じで、無駄です。
※これでは、送ってもらう送料が主体で、商品がおまけ、みたいだ……?!「送ってもらうために商品を選んでいる」感じ。
でも、稀に2個同時に使いたい場合があるのも事実……、と、無限ループ……。
本当に必要なら、予備として買ってしまうのも良い考えです。でも、稀にしか使う機会が無いのなら無駄なので、自分で作ってしまおうと考えました。
ボード上にUSB⇔UART変換チップが載っているマイコンボード(手持ちの例では以下)が在れば、作ることができます。
Arduinoでは通常、マイコンボード上のUSB⇔UART変換チップとのシリアル通信はSerialクラスライブラリで使用可能です。ボード上のMCUに、追加のUARTユニットが搭載されている場合、2個目のUARTはSerial1、3個目はSerial2等のクラスでサポートされています。
なので、Serialクラス⇔Serial1クラス間をブリッジするソフトウェアを組んでコンパイル&書き込んでおけば、そのマイコンボードは、
USB ⇔ Serialクラス ⇔ Serial1クラス
と、2段階のブリッジを経て、USB⇔UART変換モジュールとして機能するのです。
ただただ、ひたすら、SerialクラスとSerial1クラス間で送受信データをブリッジするだけなので、プログラムの処理は以下の様に単純です。
何と、まあ、簡単ですこと。具体的なコードも、以下の通りです。
#define SERIALU Serial // USB <=> Serial
#define SERIALB Serial1 // Serial <=> UART to bridge
#define SERIALU_BAUD 9600 // SERIALU baud rate
#define SERIALB_BAUD 9600 // SERIALB baud rate
void setup (void)
{
// serial
SERIALU.begin (SERIALU_BAUD);
SERIALB.begin (SERIALB_BAUD);
while (!SERIALU || !SERIALB)
;
}
void loop (void)
{
// re-direct each other
if (SERIALU.available ()>0)
SERIALB.write (SERIALU.read ());
if (SERIALB.available ()>0)
SERIALU.write (SERIALB.read ());
}
シンプル(1^−^;)。
2つのUART通信速度が異なる場合も、プログラムとしては動作可能ですが、遅い方のUART通信に律速されてスルーレートが落ちたり、場合によってはデータを取りこぼしたりする可能性がある事には、留意してください(∵バッファオーバフロウ)。
3.3V定格のUSB⇔UART変換が必要な場合、候補となる手持ちのマイコンボードは:
5V定格のUSB⇔UART変換が必要な場合、候補となる手持ちのマイコンボードはArduino UNO一択でした。
ただ、UNOには、ハードウェアUARTユニットが1個しか搭載されておらず、その1個も、オンボードのUSB⇔UART変換チップ(ATmega16U2)との通信で使われているので、ブリッジ先に使えるUARTユニットがありません。
止むを得ないので、UNOの場合には、拙作高速ソフトウェアシリアルライブラリ(HsswSerial)を使う事にしました。一般に、ソフトウェアシリアルは半二重通信なので、データを取りこぼす恐れがありますが、これは止む無しです。
以下に、完成したプログラムをリンクします。
完成版プログラム:usb_uart.ino
UNOとDUEで動作確認してあります。他のマイコンボードでも、少し修正すれば問題なく使えるはずです。
修正が必要かもしれない箇所は:
以下の様な#defineマクロ等を使って、マイコンボード毎に場合分け(#ifdef〜#endif)して使ってください。
例えば、以下コードの様になります。
#ifdef ARDUINO_AVR_UNO
#define Serial1 SerialHssw // HsswSerialクラスライブラリを使う
#endif // ARDUINO_AVR_UNO
ここでは、Arduino DUEと、普通のUSB⇔UART変換モジュール(FTDI等)を使って、相互の通信ができる事を確認しておきましょう。DUEに、こちらのプログラムをコンパイル&書き込んで、DUEとUSB⇔UART変換モジュールを以下接続表に従って接続してください。
Arduino DUE | 接続 |
USB⇔UART変換 モジュール(FTDI等) |
GND | ⇔ | GND |
D18(TXD0※) | → | RXD |
D19(RXD0※) | ← | TXD |
※DUEのシルクでは、TXD1,RXD1の表示です。また、FTDIの電圧ジャンパは3.3V側に設定してください。
以下、実験中の様子です。
上の写真だと、DUEがUSB⇔UART変換モジュールとなって、外部のUART通信機器(上写真ではFTDI)とUART通信している様子です。
Arduino IDEのシリアルモニタやTera Term等の通信ソフトウェアを使い、互いにデータを送信し合って、動作を確認して見てください。
以上が確認できたら、OKです。
ただのUSB⇔UART変換モジュールとして、マイコンボードを1個使ってしまうのは勿体ない気もしますが、USB⇔UART変換モジュールが足りない時の代用としては、使えます。時々しか必要にならない、予備のUSB⇔UART変換モジュールを購入するのは、お金の無駄ですし、こんな簡単なプログラムでUSB⇔UART変換モジュールの代用にできるなら、活用すべきでしょう?