Excel VBA基于Win32api串口通信及Python pyserial数据采集通信咨询
嘿,我来帮你把Python里的串口逻辑转到Excel VBA用Win32API实现~ 下面是完全对应你现有Python代码的实现方案,包含详细的注释和说明:
在Excel VBA中用Win32API实现串口通信(匹配你的Python pyserial逻辑)
VBA没有原生的串口库,但我们可以直接调用Windows的Win32API来实现和pyserial底层一致的串口操作,完美对应你现有的Python代码逻辑。
第一步:声明Win32API函数和必要结构体
先在VBA模块的顶部声明这些内容(必须先声明才能调用外部API):
Option Explicit ' Win32API函数声明(兼容32/64位Excel) Private Declare PtrSafe Function CreateFileA Lib "kernel32" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, lpSecurityAttributes As Long, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As LongPtr Private Declare PtrSafe Function GetCommState Lib "kernel32" (ByVal hFile As LongPtr, lpDCB As DCB) As Long Private Declare PtrSafe Function SetCommState Lib "kernel32" (ByVal hFile As LongPtr, lpDCB As DCB) As Long Private Declare PtrSafe Function WriteFile Lib "kernel32" (ByVal hFile As LongPtr, lpBuffer As Any, ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, lpOverlapped As Long) As Long Private Declare PtrSafe Function ReadFile Lib "kernel32" (ByVal hFile As LongPtr, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, lpOverlapped As Long) As Long Private Declare PtrSafe Function CloseHandle Lib "kernel32" (ByVal hObject As LongPtr) As Long Private Declare PtrSafe Function SetCommTimeouts Lib "kernel32" (ByVal hFile As LongPtr, lpCommTimeouts As COMMTIMEOUTS) As Long ' 串口配置结构体(用于设置波特率、奇偶校验等) Private Type DCB DCBlength As Long BaudRate As Long fBinary As Long fParity As Long fOutxCtsFlow As Long fOutxDsrFlow As Long fDtrControl As Long fDsrSensitivity As Long fTXContinueOnXoff As Long fOutX As Long fInX As Long fErrorChar As Long fNull As Long fRtsControl As Long fAbortOnError As Long wReserved As Integer 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 wReserved1 As Integer End Type ' 超时配置结构体(对应Python的timeout参数) Private Type COMMTIMEOUTS ReadIntervalTimeout As Long ReadTotalTimeoutMultiplier As Long ReadTotalTimeoutConstant As Long WriteTotalTimeoutMultiplier As Long WriteTotalTimeoutConstant As Long End Type ' 常量定义 Private Const GENERIC_READ As Long = &H80000000 Private Const GENERIC_WRITE As Long = &H40000000 Private Const OPEN_EXISTING As Long = 3 Private Const FILE_ATTRIBUTE_NORMAL As Long = &H80 Private Const NOPARITY As Byte = 0 ' 无校验,对应Python的PARITY_NONE Private Const ONESTOPBIT As Byte = 0 ' 1位停止位
第二步:实现和你Python代码等价的串口通信过程
下面的子过程完全复刻你Python代码的逻辑:打开COM1、配置9600波特率+无校验、设置0.5秒超时、发送#02\r命令、读取一行数据、关闭串口。
Sub SerialCommunication() Dim hSerial As LongPtr ' 串口句柄 Dim dcb As DCB ' 串口配置对象 Dim timeouts As COMMTIMEOUTS ' 超时配置对象 Dim sendBuffer() As Byte ' 发送缓冲区 Dim readBuffer As String ' 读取结果缓冲区 Dim bytesWritten As Long ' 实际发送字节数 Dim bytesRead As Long ' 实际读取字节数 Dim singleChar As Byte ' 单次读取的字节 ' 1. 打开串口(对应Python的ser.open()) hSerial = CreateFileA("COM1", GENERIC_READ Or GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0) If hSerial = -1 Then MsgBox "无法打开串口COM1,请检查端口是否被占用" Exit Sub End If ' 2. 配置串口参数(对应Python的ser.baudrate、ser.parity等) ' 先获取当前串口默认配置 If GetCommState(hSerial, dcb) = 0 Then MsgBox "无法获取串口状态" CloseHandle hSerial Exit Sub End If ' 修改配置为需求值:9600波特率、无校验、8位数据位、1位停止位 dcb.BaudRate = 9600 dcb.Parity = NOPARITY dcb.ByteSize = 8 dcb.StopBits = ONESTOPBIT dcb.fParity = 0 ' 禁用奇偶校验检查 ' 应用修改后的配置 If SetCommState(hSerial, dcb) = 0 Then MsgBox "无法设置串口参数" CloseHandle hSerial Exit Sub End If ' 3. 设置超时(对应Python的ser.timeout=.5) timeouts.ReadIntervalTimeout = 0 timeouts.ReadTotalTimeoutMultiplier = 0 timeouts.ReadTotalTimeoutConstant = 500 ' 读取总超时500毫秒=0.5秒 timeouts.WriteTotalTimeoutMultiplier = 0 timeouts.WriteTotalTimeoutConstant = 500 If SetCommTimeouts(hSerial, timeouts) = 0 Then MsgBox "无法设置超时参数" CloseHandle hSerial Exit Sub End If ' 4. 发送命令(对应Python的ser.write(b'#02\r')) sendBuffer = "#02" & vbCr ' vbCr对应Python里的\r If WriteFile(hSerial, sendBuffer(0), UBound(sendBuffer) + 1, bytesWritten, 0) = 0 Then MsgBox "发送命令失败" CloseHandle hSerial Exit Sub End If ' 5. 读取一行数据(对应Python的ser.readline()) ' 模拟readline逻辑:循环读取直到遇到换行符或超时 readBuffer = "" Do ' 每次读取1个字节 If ReadFile(hSerial, singleChar, 1, bytesRead, 0) = 0 Then Exit Do ' 读取失败或超时 End If If bytesRead > 0 Then readBuffer = readBuffer & Chr(singleChar) ' 转成字符串保存 ' 遇到换行符就停止读取(匹配Python的readline行为) If singleChar = vbCr Or singleChar = vbLf Then Exit Do End If Else Exit Do ' 超时无数据 End If Loop ' 输出读取到的数据(对应Python的print(ser.readline())) Debug.Print "读取到的数据:" & readBuffer ' 如果你需要处理原始字节(比如你示例里的b'>-999999...'),可以直接操作singleChar的数值 ' 6. 关闭串口(对应Python的ser.close()) CloseHandle hSerial End Sub
关键细节说明
- 串口打开:用
CreateFileA是Win32操作串口的标准方式,和pyserial底层调用的是同一个API;如果是COM10及以上的端口,需要写成\\.\COM10格式。 - 参数匹配:
DCB结构体的配置完全对应你Python代码里的baudrate、parity等参数,确保通信参数一致。 - 超时设置:
COMMTIMEOUTS里的ReadTotalTimeoutConstant设为500,完美对应Python的timeout=.5。 - 读取逻辑:循环读取单个字节直到遇到换行符,和Python的
readline()行为完全一致。
内容的提问来源于stack exchange,提问作者dieek




