You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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代码里的baudrateparity等参数,确保通信参数一致。
  • 超时设置COMMTIMEOUTS里的ReadTotalTimeoutConstant设为500,完美对应Python的timeout=.5
  • 读取逻辑:循环读取单个字节直到遇到换行符,和Python的readline()行为完全一致。

内容的提问来源于stack exchange,提问作者dieek

火山引擎 最新活动