RS232C データ受信のタイミングでプログラムを動かす
投稿者 daive  (社会人)
投稿日時
2014/11/29 18:56:07
>VBA7.0でデータを受信しシートに印字するプログラムを自作しています。
と書かれても、何をしているか、掲示板では解りません。
1.OFFICEの何を使っているのか?EXCEL 20xx SPx , ACCESS 20xx SPx など具体的に。
32ビット(x32 or x86)、64ビット版どちらを使っているのか?
VBAは、OFFICE製品内でも、同一仕様ではありません。
2.OSは何を使っているのか、具体的に
Windows 7 Professional SP1 32ビット など
3.232通信は、Windows API で行っているのか?
何らかのコンポーネント(DLL等)を使って行っているのか?(具体的な製品名など)
4.232通信は何で行っているのか?通信設定は、しかじか。
PC本体の232ポート、USB-シリアルアダプタ(メーカーは、、、、)
9600、8ビット、1ストップ、パリティ無
など
5.出来れば回答者が再現可能であるような、最低限のコード(プログラム)やら、
コードが出せないのであれば、
質問者さんが、回答者に解るように、何時何処で誰が何をどの様に如何する如何したを
書かれないと伝わらないかと。
'
Visual Studio Cmmunity 2013
が、使用許諾範囲で無償使用できるように
なりました。
(VS2013 Professiona 相当)
http://www.microsoft.com/ja-jp/dev/products/community.aspx
’
処理内容次第ですが、VBAで無理無理作るより、
1.通信系部分: VB.NET / C# で作成、データをファイル化
2.データ処理部分:VBA7で
という事の方が簡単では?
’
内容によっては、VB.NET / C# で完結するかもしれません。
’
232通信コード例、検索ワード
nonsoft 232 通信
VBA 232 通信
VBA 232 Windows API
VBA 232 ドライバー
VB6 のランタイム、モジュールを使う場合は、使用許諾に十分に注意してください。
VB6用アプリの一部としてのみ使用許諾される事が前提の筈です。
(VBA用としては使用許諾されない可能性を、要検討)
対して、.NET Framework は、使用許諾範囲が緩いです。
と書かれても、何をしているか、掲示板では解りません。
1.OFFICEの何を使っているのか?EXCEL 20xx SPx , ACCESS 20xx SPx など具体的に。
32ビット(x32 or x86)、64ビット版どちらを使っているのか?
VBAは、OFFICE製品内でも、同一仕様ではありません。
2.OSは何を使っているのか、具体的に
Windows 7 Professional SP1 32ビット など
3.232通信は、Windows API で行っているのか?
何らかのコンポーネント(DLL等)を使って行っているのか?(具体的な製品名など)
4.232通信は何で行っているのか?通信設定は、しかじか。
PC本体の232ポート、USB-シリアルアダプタ(メーカーは、、、、)
9600、8ビット、1ストップ、パリティ無
など
5.出来れば回答者が再現可能であるような、最低限のコード(プログラム)やら、
コードが出せないのであれば、
質問者さんが、回答者に解るように、何時何処で誰が何をどの様に如何する如何したを
書かれないと伝わらないかと。
'
Visual Studio Cmmunity 2013
が、使用許諾範囲で無償使用できるように
なりました。
(VS2013 Professiona 相当)
http://www.microsoft.com/ja-jp/dev/products/community.aspx
’
処理内容次第ですが、VBAで無理無理作るより、
1.通信系部分: VB.NET / C# で作成、データをファイル化
2.データ処理部分:VBA7で
という事の方が簡単では?
’
内容によっては、VB.NET / C# で完結するかもしれません。
’
232通信コード例、検索ワード
nonsoft 232 通信
VBA 232 通信
VBA 232 Windows API
VBA 232 ドライバー
VB6 のランタイム、モジュールを使う場合は、使用許諾に十分に注意してください。
VB6用アプリの一部としてのみ使用許諾される事が前提の筈です。
(VBA用としては使用許諾されない可能性を、要検討)
対して、.NET Framework は、使用許諾範囲が緩いです。
投稿者 ザボン  (社会人)
投稿日時
2014/12/1 14:17:37
質問しなれてないので申し訳ありませんでした。
1、エクセル2010 32ビット
2、Windows 7 Professional SP1 32ビット
3、API使ってます。kernel32?下のプログラムを見ていただいたらわかりますでしょうか?
4、PC本体の232ポート(9600、7ビット、1ストップ、パリティなし、単方向、非同期、無手順)
5、プログラムを載せます。
受信データは「ON_MEAS2,141201,0100,S#1,TN,1.23,F%%,456.7,890CRLFON_MEAS2,141201,0100,S#1,TP,1.23,F%%,456.7,890CRLF」
「固定文、日付、時間、固定文、固定文、値、固定文、値、値改行コード固定文、日付・・・」
このように2行1時間毎に出力されてきます。
1、エクセル2010 32ビット
2、Windows 7 Professional SP1 32ビット
3、API使ってます。kernel32?下のプログラムを見ていただいたらわかりますでしょうか?
4、PC本体の232ポート(9600、7ビット、1ストップ、パリティなし、単方向、非同期、無手順)
5、プログラムを載せます。
受信データは「ON_MEAS2,141201,0100,S#1,TN,1.23,F%%,456.7,890CRLFON_MEAS2,141201,0100,S#1,TP,1.23,F%%,456.7,890CRLF」
「固定文、日付、時間、固定文、固定文、値、固定文、値、値改行コード固定文、日付・・・」
このように2行1時間毎に出力されてきます。
投稿者 ザボン  (社会人)
投稿日時
2014/12/1 14:18:03
標準モジュール
Public Const GENERIC_READ As Long = &H80000000
Public Const GENERIC_WRITE As Long = &H40000000
Public Const OPEN_EXISTING As Long = 3
Public Const INVALID_HANDLE_VALUE As Long = -1
Public hCom As Long
Public Declare Function GetCommState Lib "kernel32" (ByVal hCom As Long, ByRef lpDCB As DCBstructure) As Long
Public Declare Function BuildCommDCB Lib "kernel32" Alias "BuildCommDCBA" (ByVal lpDef As String, ByRef lpDCB As DCBstructure) As Long
Public Declare Function SetCommState Lib "kernel32" (ByVal hCom As Long, ByRef lpDCB As DCBstructure) As Long
Public Type DCBstructure
DCBlength As Long
BaudRate As Long
Flags As Long
XonLim As Integer
XoffLim As Integer
ByteSize As Byte
Parity As Byte
StopBits As Byte
XonChar As Byte
XoffChar As Byte
ErrorChar As Byte
EofChar As Byte
EvtChar As Byte
wReserved2 As Integer
End Type
' Comm Baud Rate indices
Public Const CBR_110 = 110
Public Const CBR_300 = 300
Public Const CBR_600 = 600
Public Const CBR_1200 = 1200
Public Const CBR_2400 = 2400
Public Const CBR_4800 = 4800
Public Const CBR_9600 = 9600
Public Const CBR_14400 = 14400
Public Const CBR_19200 = 19200
Public Const CBR_38400 = 38400
Public Const CBR_56000 = 56000
Public Const CBR_57600 = 57600
Public Const CBR_115200 = 115200
Public Const CBR_128000 = 128000
Public Const CBR_256000 = 256000
Public Const DTR_CONTROL_DISABLE = &H0
Public Const DTR_CONTROL_ENABLE = &H1
Public Const DTR_CONTROL_HANDSHAKE = &H2
Public Const RTS_CONTROL_DISABLE = &H0
Public Const RTS_CONTROL_ENABLE = &H1
Public Const RTS_CONTROL_HANDSHAKE = &H2
Public Const RTS_CONTROL_TOGGLE = &H3
Public Type COMMTIMEOUTS
ReadIntervalTimeout As Long
ReadTotalTimeoutMultiplier As Long
ReadTotalTimeoutConstant As Long
WriteTotalTimeoutMultiplier As Long
WriteTotalTimeoutConstant As Long
End Type
Public Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" ( _
ByVal lpFileName As String, _
ByVal dwDesiredAccess As Long, _
ByVal dwShareMode As Long, _
ByVal lpSecurityAttributes As Long, _
ByVal dwCreationDisposition As Long, _
ByVal dwFlagsAndAttributes As Long, _
ByVal hTemplateFile As Long _
) As Long
Public Declare Function ReadFile Lib "kernel32" ( _
ByVal hFile As Long, _
lpBuffer As Any, _
ByVal nNumberOfBytesToRead As Long, _
lpNumberOfBytesRead As Long, _
ByVal lpOverlapped As Long _
) As Long
Public Declare Function WriteFile Lib "kernel32" ( _
ByVal hFile As Long, _
lpBuffer As Any, _
ByVal nNumberOfBytesToWrite As Long, _
lpNumberOfBytesWritten As Long, _
ByVal lpOverlapped As Long _
) As Long
Public Declare Function SetCommTimeouts Lib "kernel32" ( _
ByVal hFile As Long, _
lpCommTimeouts As COMMTIMEOUTS _
) As Long
Public Declare Function CloseHandle Lib "kernel32" ( _
ByVal hObject As Long _
) As Long
Public Function CommOpen(ByVal strPort As String) As Long
CommOpen = CreateFile(strPort, GENERIC_READ Or GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0)
End Function
Public Function CommInput(ByVal hCom As Long, strBuffer As String, ByVal lngLen As Long) As Long
Dim lngRead As Long
Call ReadFile(hCom, ByVal strBuffer, lngLen, lngRead, 0)
CommInput = lngRead
End Function
Public Function CommOutput(ByVal hCom As Long, ByVal strBuffer As String, ByVal lngLen As Long) As Long
Dim lngWrite As Long
Call WriteFile(hCom, ByVal strBuffer, lngLen, lngWrite, 0)
CommOutput = lngWrite
End Function
Public Function CommClose(ByVal hCom As Long) As Boolean
CommClose = CloseHandle(hCom)
End Function
Public Function SetCommTimeout(ByVal hCom As Long, typTimeout As COMMTIMEOUTS) As Boolean
SetCommTimeout = SetCommTimeouts(hCom, typTimeout)
End Function
Public Const GENERIC_READ As Long = &H80000000
Public Const GENERIC_WRITE As Long = &H40000000
Public Const OPEN_EXISTING As Long = 3
Public Const INVALID_HANDLE_VALUE As Long = -1
Public hCom As Long
Public Declare Function GetCommState Lib "kernel32" (ByVal hCom As Long, ByRef lpDCB As DCBstructure) As Long
Public Declare Function BuildCommDCB Lib "kernel32" Alias "BuildCommDCBA" (ByVal lpDef As String, ByRef lpDCB As DCBstructure) As Long
Public Declare Function SetCommState Lib "kernel32" (ByVal hCom As Long, ByRef lpDCB As DCBstructure) As Long
Public Type DCBstructure
DCBlength As Long
BaudRate As Long
Flags As Long
XonLim As Integer
XoffLim As Integer
ByteSize As Byte
Parity As Byte
StopBits As Byte
XonChar As Byte
XoffChar As Byte
ErrorChar As Byte
EofChar As Byte
EvtChar As Byte
wReserved2 As Integer
End Type
' Comm Baud Rate indices
Public Const CBR_110 = 110
Public Const CBR_300 = 300
Public Const CBR_600 = 600
Public Const CBR_1200 = 1200
Public Const CBR_2400 = 2400
Public Const CBR_4800 = 4800
Public Const CBR_9600 = 9600
Public Const CBR_14400 = 14400
Public Const CBR_19200 = 19200
Public Const CBR_38400 = 38400
Public Const CBR_56000 = 56000
Public Const CBR_57600 = 57600
Public Const CBR_115200 = 115200
Public Const CBR_128000 = 128000
Public Const CBR_256000 = 256000
Public Const DTR_CONTROL_DISABLE = &H0
Public Const DTR_CONTROL_ENABLE = &H1
Public Const DTR_CONTROL_HANDSHAKE = &H2
Public Const RTS_CONTROL_DISABLE = &H0
Public Const RTS_CONTROL_ENABLE = &H1
Public Const RTS_CONTROL_HANDSHAKE = &H2
Public Const RTS_CONTROL_TOGGLE = &H3
Public Type COMMTIMEOUTS
ReadIntervalTimeout As Long
ReadTotalTimeoutMultiplier As Long
ReadTotalTimeoutConstant As Long
WriteTotalTimeoutMultiplier As Long
WriteTotalTimeoutConstant As Long
End Type
Public Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" ( _
ByVal lpFileName As String, _
ByVal dwDesiredAccess As Long, _
ByVal dwShareMode As Long, _
ByVal lpSecurityAttributes As Long, _
ByVal dwCreationDisposition As Long, _
ByVal dwFlagsAndAttributes As Long, _
ByVal hTemplateFile As Long _
) As Long
Public Declare Function ReadFile Lib "kernel32" ( _
ByVal hFile As Long, _
lpBuffer As Any, _
ByVal nNumberOfBytesToRead As Long, _
lpNumberOfBytesRead As Long, _
ByVal lpOverlapped As Long _
) As Long
Public Declare Function WriteFile Lib "kernel32" ( _
ByVal hFile As Long, _
lpBuffer As Any, _
ByVal nNumberOfBytesToWrite As Long, _
lpNumberOfBytesWritten As Long, _
ByVal lpOverlapped As Long _
) As Long
Public Declare Function SetCommTimeouts Lib "kernel32" ( _
ByVal hFile As Long, _
lpCommTimeouts As COMMTIMEOUTS _
) As Long
Public Declare Function CloseHandle Lib "kernel32" ( _
ByVal hObject As Long _
) As Long
Public Function CommOpen(ByVal strPort As String) As Long
CommOpen = CreateFile(strPort, GENERIC_READ Or GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0)
End Function
Public Function CommInput(ByVal hCom As Long, strBuffer As String, ByVal lngLen As Long) As Long
Dim lngRead As Long
Call ReadFile(hCom, ByVal strBuffer, lngLen, lngRead, 0)
CommInput = lngRead
End Function
Public Function CommOutput(ByVal hCom As Long, ByVal strBuffer As String, ByVal lngLen As Long) As Long
Dim lngWrite As Long
Call WriteFile(hCom, ByVal strBuffer, lngLen, lngWrite, 0)
CommOutput = lngWrite
End Function
Public Function CommClose(ByVal hCom As Long) As Boolean
CommClose = CloseHandle(hCom)
End Function
Public Function SetCommTimeout(ByVal hCom As Long, typTimeout As COMMTIMEOUTS) As Boolean
SetCommTimeout = SetCommTimeouts(hCom, typTimeout)
End Function
投稿者 ザボン  (社会人)
投稿日時
2014/12/1 14:19:33
シート3に以下のプログラムを
Private DCB As DCBstructure
Private Settings As String
Sub Worksheet_Activate()
'↑シート3がアクティブ(選択状態)になると実行される
'シートを保護するが、マクロではセルの値変更可能になる
Sheet2.Protect UserInterfaceOnly:=True
'シート3を隠す
Worksheets("Sheet3").Visible = False
'受信データを書き込むシート2を選択する
Sheet2.Select
'セルを選択できない用にロックする
ActiveSheet.EnableSelection = xlUnlockedCells
' スクロール範囲を設定する
ActiveSheet.ScrollArea = "$A$1:$R$26"
Dim cto As COMMTIMEOUTS
Dim Last_Row As Long
Dim today, niti, getumatu, tuki As String
Dim buf As String * 256
Dim deta1, deta2 As Variant
Dim i, j, k, o, nipo As Integer
' COMポートを開く
hCom = CommOpen(Sheet1.Range("C3")) 'シート1のC3にCOMポート番号
Call InitializeComm
If hCom = INVALID_HANDLE_VALUE Then
Call MsgBox("COMポートが開けません", vbOKOnly Or vbCritical)
Call CommClose(hCom) 'COMポートを閉じる
End If
' タイムアウトを設定
cto.ReadTotalTimeoutConstant = 1000 'タイムアウト時間(ms)
Call SetCommTimeout(hCom, cto) 'Module1内のタイムアウト命令を呼び出す
'シート2の測定値を書き込む空白行はBの何行目かを探す
Last_Row = ActiveSheet.Cells(27, 2).End(xlUp).Row
j = Last_Row + 1
'23時のデータを受信するまで常にデータを受信する
Do While nipo <> 2300
DoEvents
k = 2 'シート2の2列目から受信データを書き込む
buf = ""
deta1 = ""
deta2 = ""
'この部分を変更したいです。ループでずっと読み込むんじゃなくてbufにデータが入ったら読み込む様に
Do While CommInput(hCom, buf, Len(buf)) = 0 ' 受信する(Module1内の受信命令を実行)
DoEvents
Loop
deta1 = Split(buf, vbCrLf)
For o = 0 To UBound(deta1) - 1
deta2 = Split(deta1(o), ",")
For i = 0 To UBound(deta2)
Sheet2.Cells(j, k) = deta2(i)
k = k + 1
Next i
Next o
nipo = Sheet2.Cells(j, 4)
j = j + 1
Loop
Call CommClose(hCom) 'Module1内のCOMポートを閉じる命令を実行
End Sub
Private Function InitializeComm() As Boolean 。
Settings = Sheet1.Range("C4") '9600,N,7,1" ”ボーレート,パリティーチェックなし,データ長,ストップビット
If hCom > 0 Then
BuildCommDCB Settings, DCB
DCB.Flags = DCB.Flags Or 1 ' Binary Mode ON
DCB.Flags = DCB.Flags Or &H1010 ' DTR and RTS Enable
SetCommState hComm, DCB
InitializeComm = True
Else
MsgBox "COMポートが開けません" , vbOKOnly + vbCritical + vbApplicationModal
InitializeComm = False
End If
End Function
投稿者 daive  (社会人)
投稿日時
2014/12/1 19:40:33
お役にたつかどうか解りませんが、
1.Windows API による 232 通信でも、受信バッファに受信されたデータ数を
検出する事が可能です。
⇒やさしく書いた過去サイトが、無いか検索してみました。
例えば、
WindowsでRS232Cを使う
http://members.jcom.home.ne.jp/0434383301/vc10.htm
受信されたデータ数を実際にReadFile()を呼び出す前に知りたい場合があります。
省略
⇒データが固定長であれば、決まった長さになるまで、受信データ数を、定期的にチェックする。
↑説明通りであれば、固定長の筈ですよね?
可変長であれば、ターミネータ(C/R、L/F、EOT etc)で判別、
固定長でもなく、ターミネータでも判定出来ない、適当通信であれば、
データ数の増加がなくなったら、1回分受信終了と判定するなど。
’
現状のコード構成に近いままで行うには、
> Do While CommInput(hCom, buf, Len(buf)) = 0 ' 受信する(Module1内の受信命令を実行)
> DoEvents
> Loop
固定長データなのですから、
上記のコードの後に、決まったデータ数に達するまで、
データを追加で読込むコードを追加すれば良いのでは?
2.イベント駆動型プログラミングでは、
>'23時のデータを受信するまで常にデータを受信する
>Do While nipo <> 2300
> DoEvents
> :中略
> Loop
の様な、無限ループ的プログラムは、書かない事が前提です。
DoEventsは、現在の環境では、DoEventsの利点よりも、欠点の方が多く、
安易な使用は避けるべきものです。
EXCEL-VBAでは、標準でインターバルタイマが実装されていないので、
application.ontime(検索ワード:vba application.ontime)の使い方を工夫して、
定周期に、受信バッファのデータ数を調べる方法へ、変更をお勧めします。
(データ受信間隔:1時間に1回程度ですので、対応可能。)
または、1分以上に1回程度チェックするのであれば、テーブルクエリのデータ更新間隔を
イベントに使う事も可能。
3.苦労して、Windows API から 232 を使わなくても、VB.NET であれば、
232 通信は、簡単にできるのですが、敷居が高いようであれば、
受信バッファに受信されたデータ数を検出する事
からかも。
’
VB.NET から EXCEL を使う方法もありますが、
慣れていないと混乱するかもしれません。
EXCEL-DNA という手段もあります。
1.Windows API による 232 通信でも、受信バッファに受信されたデータ数を
検出する事が可能です。
⇒やさしく書いた過去サイトが、無いか検索してみました。
例えば、
WindowsでRS232Cを使う
http://members.jcom.home.ne.jp/0434383301/vc10.htm
受信されたデータ数を実際にReadFile()を呼び出す前に知りたい場合があります。
省略
⇒データが固定長であれば、決まった長さになるまで、受信データ数を、定期的にチェックする。
↑説明通りであれば、固定長の筈ですよね?
可変長であれば、ターミネータ(C/R、L/F、EOT etc)で判別、
固定長でもなく、ターミネータでも判定出来ない、適当通信であれば、
データ数の増加がなくなったら、1回分受信終了と判定するなど。
’
現状のコード構成に近いままで行うには、
> Do While CommInput(hCom, buf, Len(buf)) = 0 ' 受信する(Module1内の受信命令を実行)
> DoEvents
> Loop
固定長データなのですから、
上記のコードの後に、決まったデータ数に達するまで、
データを追加で読込むコードを追加すれば良いのでは?
2.イベント駆動型プログラミングでは、
>'23時のデータを受信するまで常にデータを受信する
>Do While nipo <> 2300
> DoEvents
> :中略
> Loop
の様な、無限ループ的プログラムは、書かない事が前提です。
DoEventsは、現在の環境では、DoEventsの利点よりも、欠点の方が多く、
安易な使用は避けるべきものです。
EXCEL-VBAでは、標準でインターバルタイマが実装されていないので、
application.ontime(検索ワード:vba application.ontime)の使い方を工夫して、
定周期に、受信バッファのデータ数を調べる方法へ、変更をお勧めします。
(データ受信間隔:1時間に1回程度ですので、対応可能。)
または、1分以上に1回程度チェックするのであれば、テーブルクエリのデータ更新間隔を
イベントに使う事も可能。
3.苦労して、Windows API から 232 を使わなくても、VB.NET であれば、
232 通信は、簡単にできるのですが、敷居が高いようであれば、
受信バッファに受信されたデータ数を検出する事
からかも。
’
VB.NET から EXCEL を使う方法もありますが、
慣れていないと混乱するかもしれません。
EXCEL-DNA という手段もあります。
投稿者 (削除されました)  ()
投稿日時
2014/12/10 10:30:05
(削除されました)
投稿者 ザボン  (社会人)
投稿日時
2014/12/10 10:45:17
返答ありがとうございます!
application.ontimeで1時間毎に読み込むように変更しました。
まだテストしていないですがおそらくいけると思います。
ありがとうございました!
application.ontimeで1時間毎に読み込むように変更しました。
まだテストしていないですがおそらくいけると思います。
ありがとうございました!
投稿者 ザボン  (社会人)
投稿日時
2014/12/10 10:46:25
遅くなって申し訳ありませんでした
VBA7.0でデータを受信しシートに印字するプログラムを自作しています。
データは1時間毎に機械から送信されてきます。
プログラムはループで常に受信データ格納先を確認し、データが入ったらループを抜け次の処理をするプログラムです。
この方法ではたまにデータを取りこぼしたりおかしなデータになってしまいます。(24回に1回か2回)
原因の予想ですが
非同期で通信しているため、データを少しでも格納したらReadFileが受信完了!みたいに思って次の 動作に移ってしまうのではないかと。
理想はループを使用せず、受信データ格納先にデータがすべて入ったらイベントが発生?プログラムが動作するようにしたいのですが、可能でしょうか?
ついでにですが、
ネットで調べまくって何とかここまでできたのですが、基礎をあんまり勉強していないので標準モジュールとかReadFileやCreateFileが完全に理解できていません。
標準モジュールに作ったプログラムは常に実行されているんでしょうか?
ポートを開きReadFileを常に実行しているからデータを受信できるのでしょうか?
質問のしかたが下手で申し訳ないですがご指導よろしくお願いいたします。