cSerialPort 事件详解
📋 事件列表
| 事件名 | 说明 | 触发条件 |
|---|---|---|
DataReceived | 数据接收 | 输入缓冲区有新数据(需 StartMonitoring) |
FrameReceived | 帧接收 | 启用分帧(FrameInterval>0)后,每收到一个完整帧触发 |
ErrorOccurred | 通信错误 | 检测到线路错误 |
PinChanged | 信号线变化 | CTS/DSR/RING/RLSD 任一变化 |
TxEmpty | 发送缓冲区已空 | 发送完成 |
BreakDetected | 检测到 Break | 收到 Break 信号 |
RingDetected | 检测到振铃 | 收到振铃信号 |
📥 DataReceived 事件
说明
当输入缓冲区有新数据时触发。需要先调用 StartMonitoring 启动监控。
语法
vb
Private Sub object_DataReceived(ByVal BytesCount As Long)参数
| 参数 | 类型 | 说明 |
|---|---|---|
BytesCount | Long | 输入缓冲区中的字节数 |
使用示例
vb
Private WithEvents m_Port As cSerialPort
Private Sub m_Port_DataReceived(ByVal BytesCount As Long)
Dim s As String
s = m_Port.ReadExisting()
Debug.Print "收到 " & BytesCount & " 字节: " & s
End Sub注意事项
- 必须先调用
StartMonitoring才能触发此事件 - 事件中应尽快读取数据,避免缓冲区溢出
- 事件中不要执行耗时操作,否则会影响后续数据接收
🧩 FrameReceived 事件
说明
当启用分帧模式(FrameInterval > 0)后,每收到一个完整帧触发。这是解决"设备连发导致粘包"问题的核心事件。
详细的分帧原理与方案选型,请参阅 分帧协议专题。
语法
vb
Private Sub object_FrameReceived(FrameData() As Byte)参数
| 参数 | 类型 | 说明 |
|---|---|---|
FrameData | Byte 数组 | 这一帧的原始字节数据 |
启用方式
vb
' 启用分帧:30ms 无新数据 = 一帧结束
m_Port.FrameInterval = 30
m_Port.StartMonitoring 20 ' 轮询间隔建议 <= FrameInterval/2使用示例
vb
Private WithEvents m_Port As cSerialPort
Private Sub Form_Load()
Set m_Port = New cSerialPort
m_Port.PortName = "COM3"
m_Port.Config.BaudRate = br9600
If m_Port.OpenPort() Then
m_Port.FrameInterval = 30
m_Port.StartMonitoring 20
End If
End Sub
Private Sub m_Port_FrameReceived(FrameData() As Byte)
Dim s As String
s = StrConv(FrameData, vbUnicode)
Debug.Print "收到帧 (" & UBound(FrameData) + 1 & "字节): " & s
End Sub注意事项
- 必须设置
FrameInterval > 0才会触发;为 0 时仍走DataReceived路径 FrameInterval=0时DataReceived正常触发,两者互斥StopMonitoring/ClosePort时会自动 flush 缓冲区中剩余的帧,不会丢失最后一帧- 搭配
cSerialFrameParser可实现"协议分帧"(按分隔符/起止标记/长度字段精确切分)
⚠️ ErrorOccurred 事件
说明
检测到通信错误时触发。
语法
vb
Private Sub object_ErrorOccurred(ByVal ErrorCode As Long, ByVal ErrorMsg As String)参数
| 参数 | 类型 | 说明 |
|---|---|---|
ErrorCode | Long | 通信错误码(CE_ 常量组合) |
ErrorMsg | String | 中文错误描述 |
错误码
| 常量 | 值 | 说明 |
|---|---|---|
CE_RXOVER | &H1 | 接收缓冲区溢出 |
CE_OVERRUN | &H2 | 字符覆盖 |
CE_RXPARITY | &H4 | 校验错误 |
CE_FRAME | &H8 | 帧错误 |
CE_BREAK | &H10 | 中断检测 |
CE_TXFULL | &H100 | 发送缓冲区满 |
使用示例
vb
Private Sub m_Port_ErrorOccurred(ByVal ErrorCode As Long, ByVal ErrorMsg As String)
Debug.Print "通信错误 [" & ErrorCode & "]: " & ErrorMsg
Select Case ErrorCode
Case CE_RXOVER
' 接收缓冲区溢出,清空缓冲区
m_Port.PurgeRx
Case CE_RXPARITY
' 校验错误,记录日志
LogError "校验错误"
Case CE_FRAME
' 帧错误,检查波特率配置
LogError "帧错误,请检查波特率"
End Select
End Sub📊 PinChanged 事件
说明
CTS/DSR/RING/RLSD 任一信号线变化时触发。
语法
vb
Private Sub object_PinChanged(ByVal Events As Long)参数
| 参数 | 类型 | 说明 |
|---|---|---|
Events | Long | 事件掩码(EV_CTS/EV_DSR/EV_RLSD/EV_RING 组合) |
使用示例
vb
Private Sub m_Port_PinChanged(ByVal Events As Long)
If (Events And EV_CTS) Then
Debug.Print "CTS 变化: " & m_Port.CtsHolding
End If
If (Events And EV_DSR) Then
Debug.Print "DSR 变化: " & m_Port.DsrHolding
End If
If (Events And EV_RLSD) Then
Debug.Print "CD 变化: " & m_Port.CdHolding
End If
End Sub注意:
PinChanged事件仅在WaitForEvent同步模式中触发。异步监控模式(StartMonitoring)目前不监控信号线变化。
📤 TxEmpty 事件
说明
发送缓冲区已空时触发。
vb
Private Sub m_Port_TxEmpty()
Debug.Print "发送完成"
End Sub仅在
WaitForEvent同步模式中触发。
⚡ BreakDetected 事件
说明
检测到 Break 信号时触发。
vb
Private Sub m_Port_BreakDetected()
Debug.Print "收到 Break 信号"
End Sub仅在
WaitForEvent同步模式中触发。
🔔 RingDetected 事件
说明
检测到振铃信号时触发。
vb
Private Sub m_Port_RingDetected()
Debug.Print "检测到振铃"
End Sub仅在
WaitForEvent同步模式中触发。
事件触发模式对比
异步监控模式(StartMonitoring)
| 事件 | 是否触发 | 说明 |
|---|---|---|
DataReceived | ✅ | 轮询检测到缓冲区有数据 |
ErrorOccurred | ✅ | 轮询检测到通信错误 |
PinChanged | ❌ | 不监控信号线变化 |
TxEmpty | ❌ | 不监控发送完成 |
BreakDetected | ❌ | 不监控 Break |
RingDetected | ❌ | 不监控振铃 |
同步等待模式(WaitForEvent)
| 事件 | 是否触发 | 说明 |
|---|---|---|
DataReceived | ✅ | 收到 EV_RXCHAR 事件 |
ErrorOccurred | ✅ | 收到 EV_ERR 事件 |
PinChanged | ✅ | 收到 EV_CTS/EV_DSR/EV_RLSD 事件 |
TxEmpty | ✅ | 收到 EV_TXEMPTY 事件 |
BreakDetected | ✅ | 收到 EV_BREAK 事件 |
RingDetected | ✅ | 收到 EV_RING 事件 |
⚠️:
WaitForEvent会阻塞调用线程,不建议在 UI 线程使用。
最后更新: 2026-07-05