FT232RLを利用したUSB virtual COMポートターミナルソフトの習作


FT232RLは、USB−RS232 シリアル通信を変換してくれる便利なICです.(RS232と呼称してしまう用語の誤用は承知していますが、このまま進めます)

FT232RLがUSBをRS232に変換してくれると言っても、PCから見えるのはあくまでもUSBにすぎないわけなので、物理的実態はUSBなんだが、windows OSにとってはCOMポートに見えているというふうに化かすソフトウエアレイヤーが必要なわけです.それをドライバと呼びますが、FTDIのページからダウンロードできます.2010年9月現在、ここに最新版 があるようです.

実体がUSBであろうとも、windowsにとってCOMポートに見えてしまうわけですから、「Hyper Terminal」や「HideTerm」のようなターミナルソフトをつかえば、通信ができるわけです.

けれど、ターミナルソフトを使いたくなくて、自分が作ったアプリケーションソフトで通信したい人のために API が公開されています.(ソースコードは非公開)      zip版のドライバを解凍すると、いろいろなファイルが出てきます.それらのうち、ftd2xx.h ftd2xx.dll ftd2xx.lib を以下では使います.

私も、簡単な通信アプリを自分で作ってみたかったので 「ターミナルソフト習作」 をつくってみました.実用性はありません.

-----
FT232RLは、すべてハードウエアで実装されているらしく、FT232RLのfirmwareというモノはないらしいです.よって、FT232RLの動作を変更する余地は限られています.FT232RLの動作を変更するには、ftdibus.inf を書き換えてやりますが、詳細を私は知りません.




「ターミナルソフト習作」を動かすとなにができるか?

別の製作例で紹介した 「熱帯魚水槽の温度ロガー」 を、USB接続します.この回路は、エンドレスで毎秒文字列を送信してきます.それを受信するのがこの「ターミナルソフト習作」のほぼ全てです.受信した文字列をファイルに落とすような機能はありません.

「ターミナルソフト習作」を実行すると、このような画面が現れて、プログラムが停止します.

com port number is 38
---\\.\COM38---
Port configured
14 bytes send
ELLO WORL  DHMS 000 01 09 25  TEMP(AIN2,AIN6,AIN7) 141.19 112.58 107.11
DHMS 000 01 09 26  TEMP(AIN2,AIN6,AIN7) 141.12 112.45 107.17
DHMS 000 01 09 27  TEMP(AIN2,AIN6,AIN7) 141.09 112.54 107.01
DHMS 000 01 09 29  TEMP(AIN2,AIN6,AIN7) 141.09 112.54 107.11
DHMS 000 01 09 30  TEMP(AIN2,AIN6,AIN7) 140.99 112.41 107.11
DHMS 000 01 09 31  TEMP(AIN2,AIN6,AIN7) 141.19 112.74 107.14
DHMS 000 01 09 32  TEMP(AIN2,AIN6,AIN7) 141.09 112.74 107.24
DHMS 000 01 09 33  TEMP(AIN2,AIN6,AIN7) 141.12 112.61 107.24
DHMS 000 01 09 34  TEMP(AIN2,AIN6,AIN7) 141.09 112.80 107.24
ending

「ターミナルソフト習作」の動作を簡単に説明します.
●FT232RLが接続され、windowsがvirtual COMポートとして認識しているCOMポートを探索します.上の例は、COM38が発見された様子です.
●COM38に接続します.COM38のボーレートを115200に設定します.
●COM38へ、HELLO WORLD  と送信します.
●COM38から、9行受信します.最初の行の先頭が文字化けしているのは、送信した HELLO WORLDのエコーバックが混ざっているからです.この混ざり方は、ホストPC次第で変わると思います.
●プログラムを停止します.

これらを実行するためのAPIとして、ftd2xx.h ftd2xx.dll ftd2xx.lib というファイルを活用しています.





VS2008 のプロジェクトファイルを、ここに 起きます. (zip)

プロジェクトフォルダ内の ftd2xx.h ftd2xx.dll ftd2xx.lib だけは、FTDIのページからダウンロードしたものです.

自分で記述したファイルは FT232RL-terminal.cpp だけです.












以下は、ソースコードの説明をします.

●ftd2xx.hをインクルードします.
 #include "stdafx.h"
 #include <windows.h>
 #include <stdio.h>
 #include "ftd2xx.h"

●FT_ほにゃらら( ) という関数が、FT232RLのAPIです.
とりあえずOPENして、FT232RLが存在するCOMポート番号を探索します.どういうカラクリで探索しているのかは知りません.
一旦CLOSEします.

 res = FT_Open(0, &fthandle);
 res = FT_GetComPortNumber(fthandle,&COMPORT);
 FT_Close(fthandle);

●上で調べたCOMポートを再度OPENします.
COMxという文字列に、\\.\COM38 のような謎の文字列を作っていますが、この「\\.\」の部分が重要です.これをつけないと、その後の、CreateFile( ) の返値=−1になってしまい動きません.これはCreateFile( )関数の仕様なんですが、「COM9」は受け付けますが、「COM10」とか「COM38」のような10以上のポート番号を受け付けないんです.それを回避するために、ファイル名にエスケープシーケンスをひっつけているという操作です.ネットでもあまり流通してない情報のようです.

 n = sprintf(COMx, "\\\\.\\COM%d",COMPORT);

●COMポートを開きます.このCreateFile( )には、もうひとつ地雷がありました.
「COM38」のようなファイル名が正しく関数に入らないのです.その理由は、VS2008の処理系がdefaultでUnicode文字列を採用しているからでした.VS2008のプロジェクトのプロパティページの文字セットを下記のように変えてください.そうすれば、正常化します.裏には、8bit文字列を扱うCreateFileA( )と、16bit文字列を扱うCreateFileW( ) の2つが存在して、ソースコード上に単に CreateFile( ) とだけ記述すると、プリプロセッサが処理系に合わせて、CreateFileA と CreateFileW を選択してくれてしまうのだそうです.なので、ソースコードで最初からCreateFileA( )と記述してしまえば、それも解決策足りえます.知らないとハマります.

もうひとつ、ビルドすると、 (LPCSTR)COMx のキャストが悪いと文句を言われてエラーになることがありますが、慌てずエラーメッセージを読んで、キャストを変更すればビルドが通るようになります.

  hCommPort = CreateFile(
        (LPCSTR)COMx,
        GENERIC_READ | GENERIC_WRITE,
        0,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL
     );




●ボーレートを定義します.「熱帯魚水槽の温度ロガー」のボーレート設定に合わせます.
  fSuccess = GetCommState(hCommPort, &dcb);
  dcb.BaudRate = 115200;
  dcb.ByteSize = 7;
  dcb.Parity   = ODDPARITY;    // EVENPARITY,NOPARITY;
  dcb.StopBits = ONESTOPBIT;
  fSuccess = SetCommState(hCommPort, &dcb);

●COMポートへ、文字列を出力します.
  DWORD dwwritten = 0, dwErr;
  char data_out[] = "HELLO WORLD  \n";
  DWORD w_data_len = strlen(data_out);
  fSuccess = WriteFile(hCommPort, &data_out, w_data_len, &dwwritten, NULL);

●COMポートから、受信します.9行受信して終わるようにしてあります.一行受信するごとに表示します.
  char buf[256];
  char abuf[5];
  int cnt;
  DWORD dwRead;
  buf[0]=0;
  cnt=0;
  while(1){
     if(ReadFile(hCommPort, abuf, 1, &dwRead, NULL)) {
        if(abuf[0]==9 || abuf[0]==13) {
            sprintf(buf,"%s\n",buf);
            printf("%s",buf);
            buf[0]=0;
            cnt++;
            if(cnt==9) break;
        }
        else if(abuf[0]>=32) strcat(buf,abuf);
     }
  }




release 2010.9


inserted by FC2 system