■ Xportによる PC(Windows)−PIC間通信         

   PCのWindowsソフトから Xportをつかって電子回路を制御するには、Lantronix社から提供されている
     ComPortRedirectorというソフトをつかうと簡単に制御できます。ComPortRedirectorはXportやWiport
    (無線デバイスサーバ)など  Lantronix製品からのTCP/IP信号をRS232Cシリアル信号に相互変換する
  ソフトです。   これをインストールして仮想COM ポートに所定の設定をおこなうと、Windowsアプリケーション
  からはCOMポート経由  RS232Cで制御するのと全く同じに 制御できます。
  
  <試作品仕様>
   ★ PC(Windows)側
      ・ アプリケーションソフトから英数字を1〜1000msec毎に1文字づつ以下の経路でPIC側に送る。
         仮想COM3ポート(ComPortRedirector) → LANケーブル(TCP/IP) → Xport → PIC
      ・ 送信している文字、受信している文字を表示すること
      ・ 受信した文字をエディタリストに表示すること。また必要に応じてエディタリストはクリアできること
   ★ PIC側
      ・ 受信した文字をPC側に送信すること
      ・ XportのCTS、RTSを使ったハードウェアフロー制御を行い、時間のかかる液晶表示中に文字の受信
        などを避けたエラーがおこりにくい制御をおこなうこと
      ・ 液晶(16文字×2桁)には受信した文字を順次表示してゆくこと。文字がいっぱいになったら画面を
        クリアしてまた受信した文字を順次表示してゆくこと

       

  <回路図>
   ・  PIC18F452をつかった場合の回路図を以下に示します。(→回路図ののPDFファイル
     
    ★ハブ+ルータを除いてPCとXportをクロスケーブルで直結しても動作しました。この場合、PCのDHCP(Dynamic Host
          Configuration Protocol)機能はOFFとして手動でURLを設定する必要があります。
  



  <試作品外観>  下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています。

  


以下のプログラム例の中にある液晶表示器制御ライブラリ 1llcd_lib.cは 後閑哲也さんが設計されたものです。
   <プログラム例 PIC側 >

 
/*
------------------------------------------------------------------
< 構成>
 Builder(PC) → ComportRedirector→ Xport → PIC18F452 → 16文字キャラクタ液晶
<PC program>   英数字1文字送信 周期1000〜1msec  
<備考> Xport側                IP address  192.168.0.44
                               Local port  14001  
        PC(Windows)側          IP adress   192.168.0.2                                         
                               TCP port (remote port)    3001
       // COM Port:   desk/note PC  COM3/COM4                                                                                         2006.9.25
--------------------------------------------------------------------
*/


#include "18f452.h"
#use delay(clock=40000000)
#FUSES  EC,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP
#use RS232(BAUD=9600,XMIT=PIN_C6,RCV=PIN_C7)    // TX=RC6,RX=RC7



#use fast_io(D)
//////// Port define and link LCD library 
#define mode     0

//   液晶
#define input_x         input_D
#define output_x        output_D
#define set_tris_x      set_tris_D
#define rs PIN_D2       //chip select
#define stb PIN_D0      //strobe

#include <1lcd_lib.c>

main(){
        unsigned int moji = 0 ;
        char cmnd;

        setup_timer_1(T1_INTERNAL |T1_DIV_BY_8);
        set_tris_c(0b10000000);// 必須 in = RC7 of Rx
        lcd_init();
        lcd_cmd(0b00001100);                    // カーソル:OFF    ブリンク:OFF
        lcd_clear();
        printf(lcd_data,"start!!");
        delay_ms(2000);
        
        lcd_clear();

        while(1)
        {
                cmnd = getc();
                if(input(PIN_C0) == 1)putc(cmnd);//XportのCP1端子から送信許可の信号がでていれば送信する
                                                                                //CP1(6番端子)を CTS(Clear To Send 送信許諾)に設定
                                                                                //CP1は出力ポートモード
                                                                                //CTS信号: 1 = 送信許可 、 0 = 送信不可
        
                output_low(PIN_C2);             // XportのCP3端子へ送信禁止信号を出力  RTS= 0
                                                                // CP2(8番端子)をRTS(Request To Send 送信要求))
                                                                //CP3は入力ポートモード  
                                                                //RTS信号: 1 = 送信許可 、0 = 送信不可
                moji++;
                switch(moji)
                {
                        case 16:        lcd_cmd(0xC0); // 2行目の先頭へ
                                break;
                        case 32:        lcd_cmd(0x01); // 全消去
                                                moji = 0;
                                break;
                        default:        // 
                                break;
                }
                lcd_data(cmnd);
                output_high(PIN_C2);    //Xportからの送信許可  RTS = 1 
        }               
        return 0;
}
//---------------------------------------------------------------------------

//**************************************
//インクルードファイル    1lcd_lib.c
//このファイルは後閑哲也さんが設計されたものです
//**************************************


///////////////////////////////////////////////
//  液晶表示器制御ライブラリ
//  内蔵関数は以下
//    lcd_init()    ----- 初期化
//    lcd_cmd(cmd)  ----- コマンド出力
//    lcd_data(chr) ----- 1文字表示出力
//    lcd_clear()   ----- 全消去



//////// データ出力サブ関数
void lcd_out(int code, int flag)
{
        output_x((code & 0xF0) | (input_x() & 0x0F));
        if (flag == 0)
                output_high(rs);                //表示データの場合
        else
                output_low(rs);                 //コマンドデータの場合
        delay_cycles(4);                        //NOP 1         
        output_high(stb);                       //strobe out
        delay_cycles(8);                        //NOP 2
        output_low(stb);                        //reset strobe
}
//////// 1文字表示関数
void lcd_data(int asci)
{
        lcd_out(asci, 0);                       //上位4ビット出力
        lcd_out(asci<<4, 0);            //下位4ビット出力
        delay_us(50);                           //50μsec待ち
}
/////// コマンド出力関数
void lcd_cmd(int cmd)
{
        lcd_out(cmd, 1);                        //上位4ビット出力
        lcd_out(cmd<<4, 1);                     //下位4ビット出力
        delay_ms(2);                            //2msec待ち
}
/////// 全消去関数
void lcd_clear()
{
        lcd_cmd(0x01);                          //初期化コマンド出力
        delay_ms(15);                           //15msec待ち
}
/////// 初期化関数
void lcd_init()
{
        set_tris_x(mode);                       //モードセット
        delay_ms(15);
        lcd_out(0x30, 1);                       //8bit mode set
        delay_ms(5);
        lcd_out(0x30, 1);                       //8bit mode set
        delay_ms(1);
        lcd_out(0x30, 1);                       //8bit mode set
        delay_ms(1);
        lcd_out(0x20, 1);                       //4bit mode set
        delay_ms(1);
        lcd_cmd(0x2E);                          //DL=0 4bit mode
        lcd_cmd(0x08);                          //display off C=D=B=0
        lcd_cmd(0x0D);                          //display on C=D=1 B=0
        lcd_cmd(0x06);                          //entry I/D=1 S=0
        lcd_cmd(0x02);                          //cursor home
}


//**************************************************************************************
//**************************************************************************************
//            < プログラム例   Windows側 >
//
// このプログラムは C++ Buider Ver.6 でかかれています。 プログラムのソースコード
//**************************************************************************************
//**************************************************************************************


#include <vcl.h>
#include <stdio.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "MsTimer"
#pragma resource "*.dfm"
TForm1 *Form1;

 HANDLE        hPort;          // ポートハンドル
    BYTE          bSendBuffer[1]; // 送信データ
    DWORD         dwSendSize;     // 送信データサイズ
    DCB           dcb;            // DCB構造体
    COMMTIMEOUTS  Timeout;        // COMMTIMEOUTS構造体
    BOOL          Ret;            // 関数戻り値
    int           n;              // ループ用


 char In[1];
 DWORD lRead;

 unsigned int count = 47;
 unsigned long int posCount=0;


//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{


 // ポート初期化
    hPort = CreateFile("COM3", GENERIC_READ | GENERIC_WRITE, 0, NULL,
                          OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if(hPort == INVALID_HANDLE_VALUE){
        printf("Port could not open.\n");
         exit(0);
    }

      // 送受信バッファ初期化
    Ret = SetupComm(hPort, 512, 512);
    if(Ret == FALSE){
        printf("SetupComm failed.\n");
        CloseHandle(hPort);
        exit(0);
    }
    Ret = PurgeComm(hPort, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
    if(Ret == FALSE){
        printf("PurgeComm failed.\n");
        CloseHandle(hPort);
        exit(0);
    }
  /*
    // タイムアウト設定 [msec]  COMMTIMEOUTS構造体で設定
    Timeout.ReadIntervalTimeout = 500; // 文字読込時の全体の待ち時間
    Timeout.ReadTotalTimeoutMultiplier = 0;  //読込の1文字あたりの時間
    Timeout.ReadTotalTimeoutConstant = 500; //読込エラー検出用のタイムアウト時間
    Timeout.WriteTotalTimeoutMultiplier = 0;  //書き込み1文字あたりの待ち時間
    Timeout.WriteTotalTimeoutConstant = 500;//書き込みエラー検出用のタイムアウト時間
  */
    // タイムアウト設定 [msec]  COMMTIMEOUTS構造体で設定
    Timeout.ReadIntervalTimeout = 5; // 文字読込時の全体の待ち時間
    Timeout.ReadTotalTimeoutMultiplier = 0;  //読込の1文字あたりの時間
    Timeout.ReadTotalTimeoutConstant = 5; //読込エラー検出用のタイムアウト時間
    Timeout.WriteTotalTimeoutMultiplier = 0;  //書き込み1文字あたりの待ち時間
    Timeout.WriteTotalTimeoutConstant = 5;//書き込みエラー検出用のタイムアウト時間


    Ret = SetCommTimeouts(hPort, &Timeout);
    if(Ret == FALSE){
        printf("SetCommTimeouts failed.\n");
        CloseHandle(hPort);
        exit(0);
    }

    // 通信設定   →  DCB( デバイス制御ブロック)構造体へのポインタ
    Ret = GetCommState(hPort, &dcb);
    if(Ret == FALSE){
        printf("GetCommState failed.\n");
        CloseHandle(hPort);
        exit(0);
    }
    dcb.BaudRate = 9600;
    dcb.Parity = 0;
    dcb.StopBits = ONESTOPBIT;
    dcb.ByteSize = 8;
    Ret = SetCommState(hPort, &dcb);
    if(Ret == FALSE){
        printf("SetCommState failed.\n");
        CloseHandle(hPort);
        exit(0);
    }





   Button1->Tag = false ;
   ComboBox1->ItemIndex = 0;
   MsTimer1->Interval = 1000;
   RichEdit1->Lines->Clear();






}

//---------------------------------------------------------------------------
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
     
    // 終了処理
   CloseHandle(hPort);


}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{



  if(Button1->Tag == false)
  {
    Button1->Tag = true;
    Button1->Caption = "送信停止";
    MsTimer1->Enabled = true;

  }
  else
  {
    Button1->Tag = false;
    Button1->Caption = "送信開始";
    MsTimer1->Enabled = false;
  }




}


//---------------------------------------------------------------------------

void __fastcall TForm1::ComboBox1Change(TObject *Sender)
{
    switch(ComboBox1->ItemIndex)
    {
        case 0: MsTimer1->Interval = 1000;  break;
        case 1: MsTimer1->Interval = 700;   break;
        case 2: MsTimer1->Interval = 500;   break;
        case 3: MsTimer1->Interval = 300;   break;
        case 4: MsTimer1->Interval = 200;   break;
        case 5: MsTimer1->Interval = 100;   break;
        case 6: MsTimer1->Interval = 70;    break;
        case 7: MsTimer1->Interval = 50;    break;
        case 8: MsTimer1->Interval = 30;    break;
        case 9: MsTimer1->Interval = 20;    break;
        case 10: MsTimer1->Interval = 10;   break;
        case 11: MsTimer1->Interval = 7;    break;
        case 12: MsTimer1->Interval = 5;    break;
        case 13: MsTimer1->Interval = 3;    break;
        case 14: MsTimer1->Interval = 2;   break;
        case 15: MsTimer1->Interval = 1;    break;
        default: break;
    }

}
//---------------------------------------------------------------------------

void __fastcall TForm1::MsTimer1Timer(TObject *Sender)
{
    char s[1];
    int itemp;
    AnsiString As;


    count++;
    if(count == 58)count = 65;
    if(count >= 91)count = 48;
    Label1->Caption = count;
    sprintf(s,"%c",count);
    Label3->Caption = s;


    bSendBuffer[0] = count;

    // データ送信
    Ret = EscapeCommFunction(hPort, SETRTS);
    if(Ret == FALSE){
        printf("EscapeCommFunction failed.\n");
        CloseHandle(hPort);
        exit(0);
    }
    Ret = WriteFile(hPort, bSendBuffer, 1, &dwSendSize, NULL);
    if(Ret == FALSE){
        printf("WriteFile failed.\n");
        CloseHandle(hPort);
        exit(0);
    }

     if( ReadFile(hPort,In,1,&lRead,NULL)==0){    // ADコンバータの値をunsigned char で読込み 失敗したら
        itemp = Application->MessageBox("データ入力のパイプ0の読み出しでエラーが発生", "警告", MB_OK   ) ;
        if(itemp == IDYES) return;
    }


    sprintf(s,"%c",In[0]);
     Label2->Caption = s;

     As = AnsiString(s);

 

 //  RichEdit1->Lines->Add(As) ;


   //    RichEdit1->Text = As;

         RichEdit1->SelText = As;
         if(As == 'Z')   RichEdit1->Lines->Add("") ;




}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button2Click(TObject *Sender)
{
   RichEdit1->Lines->Clear();

}


<動作手順>

 @ Lantronix社のホームページから ComPortRedirectorとDeviceInstallerをダウンロードしてPCにインストールします。
     以下は下記の場合のものです
     Xport側         IP address    192.168.0.44        Local port           14001
     PC(Windows)側    IP adress    192.168.0.2         TCP port (remote port)    3001      
 
  A Redirectorを起動して以下の画面になるように設定します



  B 一方 DeviceInstallerを下記のように設定します。


     C 下記のようなPC操作画面から英数字をPIC側に送信します。送信した文字のASCIIコードとASCII文字が上段に
      また 受信した文字のASCII文字が下段に表示されています。 下記の画面は50msec毎に1文字ずつ送られて
      いる場合のものです。送信周期はコンボボックスで1〜1000msecの値が選択できるようになっています。
       エディットボックスにはPICからこのソフトに送られてきた文字が0から順番に並んでZまで表示すると改行する
      ようになっています。またclearボタンでいつでもこのエディットボックスはクリアできます。
                送信した文字が J で受信した文字が G となっていて送信と受信でかなりの時差が発生していることがわかり
      ます。




   D PIC側の液晶には送信されてきた順番に文字が表示されるようになっています。文字がいっぱいになると
     液晶がクリアされて 再び送信されてきた文字が表示されます。(写真参照)