keywords:
Windows XP 2000 NT Me 98 95 special baudrate MFC divider UART 16550

Windowsで特殊ボーレートを設定する方法

Copyright(C)2002 By H.Kashima
ec2-3-135-206-166.us-east-2.compute.amazonaws.com , 39769th 2002/12/10 UPDATED

  • マニュアル通りでは設定できない
  •  通常、VBやVCから通信ポートを初期化する場合、Win32のSetCommStateをDCB構造体から初期値を与えて初期化すると思われるが、うまい値を設定してあげないと正しく設定することができない。



  • 何で?
  • 下記はDeviceIoControlからIOCTL_SERIAL_SET(GET)_BAUD_RATEを使って変更する例である
    ヘッダ部分は、DDKのntddser.hからの抜粋である。 そのままファイルをインクルードすると、二重定義エラーがわんさか出てしまうので、必要なところだけを使っている。

    [ヘッダー]

    #include <winioctl.h>
    //
    // This structure used by set baud rate
    //
    typedef struct _SERIAL_BAUD_RATE {
        ULONG BaudRate;
    } SERIAL_BAUD_RATE,*PSERIAL_BAUD_RATE;
    
    #define IOCTL_SERIAL_SET_BAUD_RATE      CTL_CODE(FILE_DEVICE_SERIAL_PORT, 1, \
                                                     METHOD_BUFFERED,FILE_ANY_ACCESS)
    #define IOCTL_SERIAL_GET_BAUD_RATE      CTL_CODE(FILE_DEVICE_SERIAL_PORT,20, \
                                                     METHOD_BUFFERED,FILE_ANY_ACCESS)
    

     GET_BAUDで同じボーレートが返ってくれば、新しい値でボーレートがセットできたことを意味する。
    注意しなければならないのは、ボーレートの値は整数値で任意の値を設定できるが、実際の物理値は UART 16550のディバイダ baud = 115200/divからの値になることである。
    SET_BAUD_RATEの処理では、div = 115200/baud の結果の小数点以下が切り捨てられた値が設定されるので、入力に 10500を突っ込んでも、実際のボーレートは 11520ボーとなってしまう。
    10500にもっとも近いボーレートをセットするには、ディバイダの切り捨て値で、もっとも実計算値に近い値、div = 11となる値を入力せねばならない。 この場合、10472をセットすると、実ボーレートを、おおよそ10472.7ボーとすることができる。

    [設定の例]

    HANDLE	hComm;          // あらかじめCOMポートを初期化のこと
    
    int setbaud_W2K(int baud)
    {
        SERIAL_BAUD_RATE    sSB;
        DWORD   junk;
    
        sSB.BaudRate = baud;
        DeviceIoControl( hComm, IOCTL_SERIAL_SET_BAUD_RATE,
                         &sSB, sizeof(sSB), 0, NULL,
                         &junk, (LPOVERLAPPED) NULL);
    
        DeviceIoControl( hComm, IOCTL_SERIAL_GET_BAUD_RATE,
                         0, NULL, &sSB, sizeof(sSB),
                         &junk, (LPOVERLAPPED) NULL);
    
        return sSB.BaudRate;
    }
    


  • だからどうするの
  •  SetCommStateも内部でIOCTLを呼んでいるわけで、変なボーレートを与えて設定に失敗してしまう原因は、デバイダ値が切り捨てられて処理されるので、値によっては入力ボーレートと実設定ボーレートの差が大きくなってしまい、それが検出されてハネられてしまっているというわけである。

    であるので、rbaud = 115200/(int)(115200/baud)が正しい値になるものを与えてあげれば良いと言うことになる。

  • WinMe/95/98での強引技
  • こいつらは、勝手にディバイダレジスタを触ることができるので、強引に設定値を変えてしまうこともできる。

    void setbaud_W98(int baud)
    {
        div = 115200/baud;
        line = _inp( 0x3fb );           // COM1 デバイダ設定ビット
        _outp(0x3fb, line | 0x80 );     // bit7 = 1
        _outp(0x3f8, (unsigned char)(div & 0xff));          // デバイダ LSB
        _outp(0x3f9, (unsigned char)(div & 0xff00) >> 8);   // デバイダ MSB
        _outp(0x3fb, line);             // 設定終了
    }
    

    E-mail [注意]不適正な題名は即座ゴミ箱、名前を名乗らぬ者への返事はしない事があります。フリー系メールからは自動的に拒絶する場合があります。
    -- LINK FREE --
     
    HOME LAST