Excel VBAでTCP/IP通信するプログラムを紹介します。
TCP/IP通信にはwsock32.dllを使います。
VBAのModuleにwsock32.dllを使用するための宣言と関数を記述して、Sheetにユーザーインターフェーズのプログラムを記述します。
VBAでTCP/IP通信するときのイメージ
VBAのプログラムは、Sheetにユーザーインターフェースのプログラムを記述して、ModuleにTCP/IP通信プログラムを記述します。
具体的な動きは、Sheetにボタンを配置してユーザーからの要求を受け取り、ModuleのTCP/IP関数を使って、接続した機器と通信します。
プログラミング
VBAの標準モジュールの追加
標準モジュールの追加方法です。
『開発』ー『Visual Basic』から『Microsoft Visual Basic for Applications』を表示します。
『挿入(I)』ー『標準モジュール(M)』を選択します。
『Book1 ー Module1(コード)』が表示されます。左側のプロジェクトエクスプローラーに『標準モジュール』ー『Module1』が追加されます。
Module1にプログラムを記述する準備が出来ました。
Module1 プログラム
TCP/IP通信のプログラムです。これを『Book1ーModule1(コード)』に記述します。
宣言、IPアドレス取得関数、接続関数、切断関数、送受信関数、ウェイト関数です。
※コードを分けて掲載してますが、すべてModule1に記述します。
1.宣言
Option Explicit
Public Const INADDR_NONE = &HFFFF
Public Const INADDR_ANY = &H0
Public Const WSA_DESCRIPTIONLEN = 256
Public Const WSA_DescriptionSize = WSA_DESCRIPTIONLEN + 1
Public Const WSA_SYS_STATUS_LEN = 128
Public Const WSA_SysStatusSize = WSA_SYS_STATUS_LEN + 1
Public Const INVALID_SOCKET = -1
Public Const SOCKET_ERROR = -1
Public Const SOCK_STREAM = 1
Public Const SOCK_DGRAM = 2
Public Const MAXGETHOSTSTRUCT = 1024
Public Const AF_INET = 2
Public Const PF_INET = 2
Public Const FIONREAD = &H8004667F
Public Const FIONBIO = &H8004667E
Public Const FIOASYNC = &H8004667D
Public Const WORK_TRUE = 0
Public Const WORK_FALSE = -1
Public Declare PtrSafe Function closesocket Lib "wsock32.dll" _
(ByVal s As Long) As Long
Public Declare PtrSafe Function connect Lib "wsock32.dll" _
(ByVal s As Long, _
sName As sockaddr, _
ByVal namelen As Long) As Long
Public Declare PtrSafe Function ioctlsocket Lib "wsock32.dll" _
(ByVal s As Long, _
ByVal cmd As Long, _
argp As Long) As Long
Public Declare PtrSafe Function recv Lib "wsock32.dll" _
(ByVal s As Long, _
ByVal buf As Any, _
ByVal lngLen As Long, _
ByVal flags As Long) As Long
Public Declare PtrSafe Function send Lib "wsock32.dll" _
(ByVal s As Long, _
buf As Any, _
ByVal lngLenlen As Long, _
ByVal flags As Long) As Long
Public Declare PtrSafe Function Socket Lib "wsock32.dll" Alias "socket" _
(ByVal af As Long, _
ByVal lngType As Long, _
ByVal protocol As Long) As Long
Public Declare PtrSafe Function htons Lib "wsock32.dll" _
(ByVal hostshort As Long) As Integer
Public Declare PtrSafe Function inet_addr Lib "wsock32.dll" _
(ByVal cp As String) As Long
Public Declare PtrSafe Function gethostbyname Lib "wsock32.dll" _
(ByVal strName As String) As Long
Public Declare PtrSafe Function WSAStartup Lib "wsock32.dll" _
(ByVal wVersionRequested As Long, _
lpWSAData As WSADataType) As Long
Public Declare PtrSafe Function WSACleanup Lib "wsock32.dll" () As Long
Public Declare PtrSafe Function WSAGetLastError Lib "wsock32.dll" () As Long
Public Declare PtrSafe Sub MemCopy Lib "kernel32" Alias "RtlMoveMemory" _
(hpvDest As Any, _
hpvSource As Any, _
ByVal cbCopy As Long)
Type HostEnt
h_name As Long
h_aliases As Long
h_addrtype As Integer
h_length As Integer
h_addr_list As Long
End Type
Type sockaddr
sin_family As Integer
sin_port As Integer
sin_addr As Long
sin_zero As String * 8
End Type
Type WSADataType
wVersion As Integer
wHighVersion As Integer
szDescription As String * WSA_DescriptionSize
szSystemStatus As String * WSA_SysStatusSize
iMaxSockets As Integer
iMaxUdpDg As Integer
lpVendorInfo As Long
End Type
Type SocketCtrlData
mlngSock As Long
musrSockBuf As sockaddr
musrStartup As WSADataType
End Type
2.IPアドレス取得
'IPアドレス取得
Private Function wrkHostNameAlias(ByVal hstName As String) As Long
Dim ret As Long
Dim adr As Long
Dim ip As Long
Dim heHost As HostEnt
ip = inet_addr(hstName)
If ip = INADDR_NONE Then
If gethostbyname(hstName) <> WORK_TRUE Then
MemCopy heHost, ByVal ret, Len(heHost)
MemCopy adr, ByVal heHost.h_addr_list, 4
MemCopy ip, ByVal adr, heHost.h_length
Else
ip = INADDR_NONE
End If
End If
wrkHostNameAlias = ip
End Function
関数
wrkHostNameAlias(ByVal hstName As String) As Long
引数
hstName:文字列のIPアドレス
戻り値
数値化したIPアドレス
3.接続
'接続
Public Function wrkConnectTCP(Sockdat As SocketCtrlData, address As String,
port As String) As long
Dim adr As Long
wrkConnectTCP = WORK_FALSE
'初期化
If WSAStartup(&H101, Sockdat.musrStartup) <> WORK_TRUE Then Exit Function
'Socket
Sockdat.mlngSock = Socket(AF_INET, SOCK_STREAM, 0)
If Sockdat.mlngSock = WORK_FALSE Then Exit Function
'Connect
With Sockdat.musrSockBuf
adr = wrkHostNameAlias(address)
.sin_family = AF_INET
.sin_port = htons(CLng(port))
.sin_addr = adr
.sin_zero = String$(8, 0)
End With
If connect(Sockdat.mlngSock, Sockdat.musrSockBuf, _
Len(Sockdat.musrSockBuf)) <> WORK_TRUE Then
Exit Function
End If
DoEvents
'ioctlsocket
If ioctlsocket(Sockdat.mlngSock, FIONBIO, True) <> WORK_TRUE Then
Exit Function
End If
wrkConnectTCP = WORK_TRUE
End Function
関数
wrkConnectTCP(Sockdat As SocketCtrlData, address As String, port As String) As long
引数
Sockdat:SocketCtrlData構造体のポインタ
address:文字列のIPアドレス
port:ポート番号
戻り値
WORK_TURE/WORK_FALSE
4.切断
Public Sub wrkDisconnectTCP()
closesocket mySockdat.mlngSock
Call WSACleanup
End Sub
関数
wrkDisconnectTCP()
5.送受信
'送受信
Public Function wrkCommTCP(sckn As Long, bSnddat() As Byte, _
strRet As String) As Long
Dim lngRet As Long
Dim lngAll As Long
Dim strRev As String * 1000
wrkCommTCP = 0
strRet = ""
'送信
Call send(sckn, bSnddat(0), UBound(bSnddat) + 1, 0)
'ウェイト
Call timewait(0.1)
'受信
Do
DoEvents
lngRet = recv(sckn, ByVal strRev, 1000, 0)
If lngRet > 0 Then
strRet = strRet & Left$(strRev, lngRet)
wrkCommTCP = wrkCommTCP + lngRet
If InStr(strRet, vbCrLf) > 0 Then Exit Do
ElseIf lngRet = SOCKET_ERROR Then
wrkCommTCP = SOCKET_ERROR
Exit Do
End If
Loop
End Function
関数
wrkCommTCP(sckn As Long, bSnddat() As Byte, strRet As String) As Long
引数
sckn: SocketCtrlData構造体のmlngSock
bSnddat():送信するバイナリ配列
strRet:返送データ文字列
戻り値
受信した文字数/SOCKET_ERROR
※受信終了の条件は様々なので、接続する機器の仕様を確認してください。
※バイナリデータの場合は可変長のバイト配列を使います。終了条件はバイト数です。
6.ウェイト
'ウェイト
Private Sub timewait(sec As Single)
Dim sttmr As Single
Dim ctmr As Single
If sec < 0 Then Exit Sub
sttmr = Timer
Do
ctmr = Timer
If ctmr < sttmr Then ctmr = ctmr + 24# * 60 * 60
If ctmr > sttmr + sec Then Exit Sub
DoEvents
Loop
End Sub
関数
timewait(sec As Single)
引数
sec:一時停止する時間(秒)
Sheet1 プログラム
ユーザーインターフェースのプログラムです。
Sheet1にCommandButton1、CommandButton2、CommandButton3を配置します。
ボタンは以下の処理を行います。
①CommandButton1:接続
②CommandButton2:切断
③CommandButton3:送信
C4、C6、C7のセルは以下の内容となります。
④セルC4:接続成功/失敗
⑤セルC6:送信コマンド
⑥セルC7:受信データ
※コードを分けて掲載してますが、すべてShee1に記述します。
1.変数の宣言
Option Explicit
'ソケットデータ
Private mySockdat As SocketCtrlData
2.接続
'接続
Private Sub CommandButton1_Click()
Dim ip As String
Dim port As String
ip = "192.168.0.102"
port = "56789"
'TCP接続
If wrkConnectTCP(mySockdat, ip, port) = SOCKET_ERROR Then
Range("C4") = "NG"
else
Range("C4") = "OK"
End If
End Sub
サンプルプログラムは以下の設定になっているので、実際に接続する機器の設定にしてください。
IPアドレス:”192.168.0.102”
ポート番号:56789
3.切断
'切断
Private Sub CommandButton2_Click()
closesocket mySockdat.mlngSock
Call WSACleanup
Range("C4") = ""
End Sub
4.送受信
'送受信
Private Sub CommandButton3_Click()
Dim strSnd As String
Dim binSnd() As Byte
Dim strRev As String
Dim lenStr As Long
Dim cnt As Long
'C6セルの内容を送信する
strSnd = Range("C6") & vbCrLf
lenStr = Len(strSnd) - 1
ReDim binSnd(lenStr)
For cnt = 0 To lenStr
binSnd(cnt) = Asc(Mid(strSnd, cnt + 1, 1))
Next
'送受信
If wrkCommTCP(mySockdat.mlngSock, binSnd, strRev) = SOCKET_ERROR Then
If WSAGetLastError() > 0 Then
closesocket mySockdat.mlngSock
Call WSACleanup
End If
End If
'返送データをC7のセルに表示する
Range("C7") = strRev
End Sub
受信の成功/失敗に関わらず、wrkCommTCPからの受け取ったデータをC7セルに表示します。
今回紹介したプログラムを使用してRaspberry PIとWiFi通信している動画の紹介です。
(1分46秒)
(3分29秒)
Excelのグラフをアニメーションで動かす方法を紹介しています。
(47秒)
動作確認
接続と切断、データの送信と受信を確認します。手順は以下の通りです。
(1.と4.は接続している機器側の動きです)
1.接続機器を接続待ち状態にします
2.VBAで接続機器と接続します
3.VBAから接続機器にコマンドを送信します
4.接続機器はコマンドを受け取りVBAにデータ返送します
5.VBAは受信したデータをSheetに表示します
6.VBAから接続機器と切断します
Command1をクリックして接続します。成功すればC4セルに”OK”を表示します。失敗すると”NG”を表示します。
Command3をクリックして接続した機器にコマンドを送信します。
下図はC6のセルに『SET,1,1』と記述していますが、実際は接続した機器のコマンドにします。
接続した機器からデータを受信します。VBAはデータの終了を示すデリミタ(Cr/Lf)を検出します。
受信データをC7セルに表示します。
CommandButton2をクリックして接続した機器とから切断します。
以上で動作確認終了です。
まとめ
Excel VBAでTCP/IP通信するプログラムを紹介しました。
特別なプログラムの開発環境がなくても、ExcelでTCP/IP通信に対応したオシロスコープやデジタルマルチメータを直接制御できるようになります。
VBAでRS232C通信する方法を紹介しています。
いろいろなセンサーの使い方を紹介しています。
コメント