はじめまして、KEIです。
APIを使ったRS232Cの通信をしています。
StopBitに1を入れるとSetCommStateの所で必ずエラーが発生してしまいます。
0、1.5、2ではエラーが発生しません。
DCBの構造体が間違っていると思い調べてみたのですが間違っていないようでした。
御教授いただけませんでしょうか。
Private Structure DCB
Public DCBlength As Int32 'DCB構造体の大きさ(バイト単位)
Public BaudRate As Int32 '通信速度
Public fBitFields As Int32 'ビット単位のフィールド定義'See Comments in Win32API.Txt
Public wReserved As Int16 '予約領域
Public XonLim As Int16 'XON文字送信の閾値
Public XoffLim As Int16 'XOFF文字送信の閾値
Public ByteSize As Byte '1バイトのビット数
Public Parity As Byte 'パリティの方式を指定
Public StopBits As Byte 'ストップビットの長さ指定
Public XonChar As Byte 'XON文字のコード指定
Public XoffChar As Byte 'XOFF文字のコード指定
Public ErrorChar As Byte 'パリティエラー時の代替使用文字の指定
Public EofChar As Byte '非バイナリモード時のデータ終了コード
Public EvtChar As Byte 'イベント発生文字のコード指定
Public wReserved1 As Int16 '予約領域'Reserved; Do Not Use
End Structure
Private Declare Auto Function SetCommState Lib "kernel32.dll" (ByVal nCid As IntPtr, _
ByRef lpDCB As DCB) As Boolean
Public Function Connect(ByVal PortName As String, ByVal BaudRate As int32, _
ByVal ByteSize As Byte, ByVal Parity As Byte, ByVal StopBit As Byte) As Boolean
Dim MyDCB As DCB
Dim MyCommTimeouts As COMMTIMEOUTS
'シリアル ポートへのハンドルを取得します。
hSerialPort = CreateFile(PortName, GENERIC_READ Or GENERIC_WRITE, 0, IntPtr.Zero, _
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero)
'取得したハンドルが有効かどうか確認します。
If hSerialPort.ToInt32 = -1 Then Return False
'現在のコントロールの設定を取得します。
If Not (GetCommState(hSerialPort, MyDCB)) Then Return False
'必要に応じて MyDCB のプロパティを変更します。
'警告 : 各プロパティでサポートされている値に応じて変更を行うようにしてください。
MyDCB.BaudRate = BaudRate
MyDCB.ByteSize = ByteSize
MyDCB.Parity = Parity
MyDCB.StopBits = StopBit
'MyDCB のプロパティに基づいて COM? を再構成します。
If Not (SetCommState(hSerialPort, MyDCB)) Then Return False
'SetCommState(hSerialPort, MyDCB)
'現在のタイムアウトの設定を取得します。
'If Not (GetCommTimeouts(hSerialPort, MyCommTimeouts)) Then Return False
GetCommTimeouts(hSerialPort, MyCommTimeouts)
' MyCommTimeouts のプロパティを必要に応じて変更します。
' 警告 : プロパティでサポートされている値に応じて変更を行うようにしてください。
MyCommTimeouts.ReadIntervalTimeout = 0 'タイムアウトの時間
MyCommTimeouts.ReadTotalTimeoutConstant = 4 '受信関数コール時間(インターバル0〜250ms)
MyCommTimeouts.ReadTotalTimeoutMultiplier = 1 '受信1Byteあたりの時間
MyCommTimeouts.WriteTotalTimeoutConstant = 1 '送信関数コール時間
MyCommTimeouts.WriteTotalTimeoutMultiplier = 1 '送信1Byteあたりの時間
' MyCommTimeouts のプロパティに基づいてタイムアウトの設定を再構成します。
If Not (SetCommTimeouts(hSerialPort, MyCommTimeouts)) Then Return False
Return True
End Function
環境
WIN7
VS2010
これだけでは、エラーを特定できません。
データビット数とパリティーがどのように設定されていたのか
エラーした時の各々の設定内容を記載して下さい。
組み合わせ上、設定できない値があります。
以上。
オショウさん、朝一番にありがとうございます。
今回テストしたのは以下のパターンです。
他のパターンは未だ試していません。
BaudRate=4800
ByteSize=8
Parity=0
StopBit=1
BaudRate=19200
ByteSize=8
Parity=1
StopBit=1
BaudRate=9600
ByteSize=7
Parity=2
StopBit=1
設定できない組み合わせが有るとは知りませんでした。
ちなみに、どのような組み合わせが、「設定できない組み合わせ」でしょうか。
よろしくお願いします。
回答ではありませんが・・・
.NETでしょう?
何故、API?
.NET Framework 2.0 以降なら、SerialPortクラスがあるので
APIを使う必要はありませんが・・・
以上。
コメント文等は、下記にそっくりですね。
http://7ujm.net/VB/VBNetRS232c.html
> StopBitに1を入れるとSetCommStateの所で必ずエラーが発生してしまいます。
> 0、1.5、2ではエラーが発生しません。
StopBit というのは、
StopBitsのことでしょうか。
「1 は OK、0/1.5/2 は NG」という質問内容から、4 種の組み合わせを
試そうとしているものと読み取れますが、下記の 3 値しか
サポートしていなかったような…?
' System.IO.Ports.StopBits 列挙帯でも代用可能
Const ONESTOPBIT As Byte = 0 '1 ストップビット
Const ONE5STOPBITS As Byte = 1 '1.5 ストップビット
Const TWOSTOPBITS As Byte = 2 '2 ストップビット
具体的にはどのようにして値をセットされていますか?
Byte 型のフィールドに、非Byte値(1.5 など)を直接代入してはいませんか?
また、「SetCommStateの所で必ずエラーが発生」とのことですが、失敗時に
System.Runtime.InteropServices.Marshal.GetLastWin32Error
(あるいは Err.LastDLLError)は何を返していますか?
> Public fBitFields As Int32 'ビット単位のフィールド定義'See Comments in Win32API.Txt
Win32API って、旧VB向けの簡易定義ファイルですよね。
コーディングの補助的に使う分には良いですが、正式な資料として使うべきものでは無いでしょう。
ftp://ftp.microsoft.com/developr/drg/WWLive/broadcas/msdnnews/WIN32API.TXT
http://download.microsoft.com/download/7/A/E/7AE13E42-5BDE-42B1-A91E-9BBCD7C9DF83/Win32Api.exe
本来であれば、SDK およびヘッダファイルを参照すべきかと思いますよ。
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363214.aspx
> Public Function Connect(ByVal PortName As String, ByVal BaudRate As int32, _
宣言部が As Int32 ではなく As int32 になっているようですが、もしかして、
実際に使っているコードを貼ったものでは無く、掲示板上で書き起こしたコードですか?
オショウさん、魔界の仮面弁士さん、ありがとうございます。
先輩からの引継ぎなのでそのまま使用しています。
ですので、
オショウさんのSerialPortクラス案も、APIがダメだったら使用する予定です。
魔界の仮面弁士さんの似たソースも上記理由だと思います。
魔界の仮面弁士さんの指摘通り、「1 ストップビット」を渡すつもりがそのまま「1」を与えていました。
ヘッダファイルの参照から以下のようにしてみました。(かなり時間が掛かりました)
Enum DTR_CONTROL As Int32
DISABLE = &H0
ENABLE = &H1
HANDSHAKE = &H2
End Enum
Enum RTS_CONTROL As Int32
DISABLE = &H0
ENABLE = &H1
HANDSHAKE = &H2
TOGGLE = &H3
End Enum
Enum Parity As Int32
NOPARITY = 0 'パリティなし: NOPARITY
ODDPARITY = 1 '奇数パリティ: ODDPARITY
EVENPARITY = 2 '偶数パリティ: EVENPARITY
MARKPARITY = 3 '常にマーク
SPACEPARITY = 4 'スペース
End Enum
Enum StopBits As Byte
ONESTOPBIT = &H0 '1ビット: ONESTOPBIT
ONE5STOPBITS = &H1 '1.5ビット: ONE5STOPBITS
TWOSTOPBITS = &H2 '2ビット: TWOSTOPBITS
End Enum
Private Structure DCB
Public DCBlength As Int32
Public BaudRate As Int32 '通信速度
Public fBinary As Boolean
Public fParity As Boolean
Public fOutxCtsFlow As Boolean
Public fOutxDsrFlow As Boolean
Public fDtrControl As DTR_CONTROL
Public fDsrSensitivity As Boolean
Public fTXContinueOnXoff As Boolean
Public fOutX As Boolean
Public fErrorChar As Boolean
Public fNull As Boolean
Public fRtsControl As RTS_CONTROL
Public fAbortOnError As Boolean
Public fDummy2 As Int32 '予約済み。
Public wReserved As Int16 '予約済み。
Public XonLim As Int16
Public XoffLim As Int16
Public ByteSize As Byte
Public Parity As Parity
Public StopBits As Byte
Public XonChar As Char
Public XoffChar As Char
Public ErrorChar As Char
Public EofChar As Char
Public EvtChar As Char
Public wReserved1 As Int16
End Structure
> オショウさんのSerialPortクラス案も、APIがダメだったら使用する予定です。
ではなく・・・
.NET では、APIをなるべく使わずに提供されている
機能を使った方が、安全で確実。と言う話です。
以上。参考まで
> ヘッダファイルの参照から以下のようにしてみました。(かなり時間が掛かりました)
どのような対処をしたのか、は分かりましたが、
その結果はどうだったのでしょうか?
同じような問題を抱えたままなのか、それとも結果が変わったのか。
引き続きエラーがでるのだとしたら、先に確認をお願いしていた
Marshal.GetLastWin32Error の結果はどうだったのか。
>「1 ストップビット」を渡すつもりがそのまま「1」を与えていました。
という事は、「1 ストップビット(= 0)」や「2 ストップビット(= 2)」では
エラーが発生せず、「1.5 ストップビット(= 1)」のみがエラーになる、という
質問に変更ということでしょうか。
それとも、1 ストップビットは指定できているので、問題は解決したのでしょうか。
> 先輩からの引継ぎなのでそのまま使用しています。
恐らくは .NET 1.x 時代のコードを使いまわしていたのであろうと推測します。
今回は VB2010 なので、最低でも .NET 2.0 向け…できれば .NET 4 用に
コードを見直すべきかと思いますが、そのような工数を取りにくいかと思います。
それでも、標準の SerialPort クラスでも同じ現象になっていまうのかどうかについては
簡単な実験用アプリを作るなどして、試しておいた方が良いと思いますよ。
その結果、SerialPort クラスでも失敗するようであれば、プログラムではなく
機器側環境側あるいはハード仕様について確認が必要かも知れません。
あるいはその逆に SerialPort であれば成功するようであれば、
API の呼び出しを見直す工数と、SerialPort に変更するための工数を
それぞれ天秤にかけて、調査を続行するか修正するかを判断できるかと。
オショウさん
速度を上げるためにAPIを使ったそうです。
魔界の仮面弁士さん
正式な資料として使用しないほうが良いとの事でしたので作り直しましたが、作り直しにかかわらすエラーの原因は「1.5 ストップビット(= 1)」を与えていたせいでした。
今回は私が担当なので、SerialPortクラスも作成して双方較しよう考えています。
オショウさん、魔界の仮面弁士さん 本当にありがとうございました。
ツイート | ![]() |