From f56051fa3102feb35ea60650ebda80f49e62d025 Mon Sep 17 00:00:00 2001
From: mrDarker <mr.darker@163.com>
Date: 星期二, 05 八月 2025 14:54:24 +0800
Subject: [PATCH] 1. SGMeasurement实现规划的地址 2. 优化读取位时输入的地址不是8的倍数的问题 3. 添加读写心跳的功能
---
SourceCode/Bond/SGMeasurement/PLCSignalListener.cpp | 196 +++++++++++++++++++++++++++++++++++++-----------
1 files changed, 151 insertions(+), 45 deletions(-)
diff --git a/SourceCode/Bond/SGMeasurement/PLCSignalListener.cpp b/SourceCode/Bond/SGMeasurement/PLCSignalListener.cpp
index 27ad0c9..d820ab9 100644
--- a/SourceCode/Bond/SGMeasurement/PLCSignalListener.cpp
+++ b/SourceCode/Bond/SGMeasurement/PLCSignalListener.cpp
@@ -7,17 +7,29 @@
#define LOG_TYPE_WARNING 1
#define LOG_TYPE_NORMAL 2
-// === PLC 控制命令输入位配置 ===
-#define PLC_CMD_BIT_START 0 // PLC命令起始位(通常为B0)
-#define PLC_CMD_BIT_COUNT 2 // 总共几个命令位(B0=Start, B1=Stop)
+// === 日志打印宏定义 ===
+#define LOG_MSG(msg, type) LogInfo(msg, type)
-// === PLC 信号监听器相关宏定义 ===
-#define PLC_ACK_MAX_LIFE 5 // PLC响应信号最大保留周期数(每周期为 m_nIntervalMs 毫秒)
-#define PLC_ACK_BASE_BIT 10 // PLC应答起始地址(B10表示B0的应答;B11表示B1)
+// === PLC 心跳相关配置 ===
+#define PLC_HEARTBEAT_PC_TO_PLC_ADDR 0x107F // PC -> PLC:PC 写入心跳
+#define PLC_HEARTBEAT_PLC_TO_PC_ADDR 0x6C40 // PLC -> PC:PC 读取 PLC 写入的心跳
+#define MAX_MISSED_HEARTBEAT 5 // 允许连续丢失心跳的最大次数,超过则判定 PLC 掉线
+
+// === PLC 命令输入配置(PLC -> PC) ===
+#define PLC_CMD_BIT_START 0x6CD3 // PLC命令起始位(通常为B6CD3)
+#define PLC_CMD_BIT_COUNT 2 // 总共几个命令位(B6CD3=Start, B6CD4=Stop)
+
+// === PLC 应答输出配置(PC -> PLC) ===
+#define PLC_ACK_MAX_LIFE 5 // PLC响应信号最大保留周期数(每周期为 m_nIntervalMs 毫秒)
+#define PLC_ACK_BASE_BIT 0x1060 // PLC应答起始地址(B1060表示B6CD3的应答;B1061表示B6CD4的应答)
// === PLC软元件类型宏(用于应答、数据写入)===
-#define PLC_BIT_DEVICE_TYPE DeviceType::B // 位操作设备类型(如M、B)
-#define PLC_WORD_DEVICE_TYPE DeviceType::W // 字操作设备类型(如D、W)
+#define PLC_BIT_DEVICE_TYPE DeviceType::B // 位操作设备类型(如M、B)
+#define PLC_WORD_DEVICE_TYPE DeviceType::W // 字操作设备类型(如D、W)
+
+// === PLC结果寄存器地址配置 ===
+#define PLC_RESULT_ADDR_START 0x37B0 // PLC结果寄存器起始地址(如W37B0)
+#define PLC_RESULT_ADDR_COUNT 4 // 结果寄存器数量(如W37B0, W37B2, W37B4, W37B6)
#define IS_RISING_EDGE(prev, curr) (!(prev) && (curr))
@@ -31,24 +43,22 @@
{
m_pPlc = std::make_unique<CCCLinkIEControl>();
if (!m_pPlc) {
- if (m_cbLog) {
- m_cbLog(_T("PLC控制器初始化失败,无法创建 CCCLinkIEControl 实例。"), LOG_TYPE_ERROR);
- }
+ LOG_MSG(_T("PLC控制器初始化失败,无法创建 CCCLinkIEControl 实例。"), LOG_TYPE_ERROR);
return false;
}
int ret = m_pPlc->Connect(CC_LINK_IE_CONTROL_CHANNEL(1));
if (ret != 0) {
- m_bConnected = false;
- if (m_cbLog) {
- CString strError;
- strError.Format(_T("PLC控制器连接失败,错误码:%d"), ret);
- m_cbLog(strError, LOG_TYPE_ERROR);
- }
+ m_bConnected = false;
+
+ CString strError;
+ strError.Format(_T("PLC控制器连接失败,错误码:%d"), ret);
+ LOG_MSG(strError, LOG_TYPE_ERROR);
+
return false;
}
- m_bConnected = true;
+ m_bConnected = true;
m_station = station;
m_nIntervalMs = nIntervalMs;
@@ -80,14 +90,14 @@
bool CPLCSignalListener::Start()
{
if (m_bRunning || !m_pPlc) {
- if (m_cbLog) {
- m_cbLog(_T("PLC信号监听器已在运行或PLC控制器未初始化。"), LOG_TYPE_ERROR);
- }
+ LOG_MSG(_T("PLC信号监听器已在运行或PLC控制器未初始化。"), LOG_TYPE_ERROR);
return false;
}
m_bRunning = true;
m_thread = std::thread(&CPLCSignalListener::ThreadProc, this);
+
+ StartHeartbeatMonitor();
return true;
}
@@ -97,25 +107,117 @@
if (m_thread.joinable()) {
m_thread.join();
}
+
+ StopHeartbeatMonitor();
}
-void CPLCSignalListener::PulseBitDevice(DeviceType eDevType, short nBitNo, int nDelayMs/* = 50*/)
+void CPLCSignalListener::LogInfo(const CString& strText, int nType)
{
- m_pPlc->SetBitDevice(m_station, eDevType, nBitNo);
+ if (m_cbLog) {
+ m_cbLog(strText, nType);
+ }
+}
+
+bool CPLCSignalListener::SendHeartbeat()
+{
+ if (!m_pPlc || !m_bConnected) {
+ return false;
+ }
+
+ static bool bToggle = false;
+ bToggle = !bToggle;
+
+ int ret = m_pPlc->WriteBitDataEx(m_station, PLC_BIT_DEVICE_TYPE, PLC_HEARTBEAT_PC_TO_PLC_ADDR, BitContainer{ bToggle });
+
+ return (ret == 0);
+}
+
+bool CPLCSignalListener::CheckHeartbeat()
+{
+ static bool bLastHeartbeat = false;
+
+ if (!m_pPlc || !m_bConnected) {
+ return false;
+ }
+
+ BitContainer vec;
+ int ret = m_pPlc->ReadBitDataEx(m_station, PLC_BIT_DEVICE_TYPE, PLC_HEARTBEAT_PLC_TO_PC_ADDR, 1, vec);
+ if (ret != 0 || vec.empty()) {
+ return false;
+ }
+
+ bool bCurrent = vec[0];
+ bool bChanged = (bCurrent != bLastHeartbeat);
+ bLastHeartbeat = bCurrent;
+
+ return bChanged;
+}
+
+bool CPLCSignalListener::MonitorHeartbeat()
+{
+ if (CheckHeartbeat()) {
+ m_nMissedHeartbeatCount = 0;
+
+ if (m_bHeartbeatLost) {
+ m_bHeartbeatLost = false;
+ LOG_MSG(_T("PLC心跳恢复!"), LOG_TYPE_SUCCESS);
+ }
+
+ return true;
+ }
+ else {
+ m_nMissedHeartbeatCount++;
+
+ if (m_nMissedHeartbeatCount > MAX_MISSED_HEARTBEAT) {
+ if (!m_bHeartbeatLost) {
+ m_bHeartbeatLost = true;
+ m_nMissedHeartbeatCount = 0;
+ LOG_MSG(_T("PLC心跳信号中断!"), LOG_TYPE_ERROR);
+ }
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void CPLCSignalListener::StartHeartbeatMonitor()
+{
+ m_bHeartbeatRunning = true;
+ m_heartbeatThread = std::thread([this]() {
+ while (m_bHeartbeatRunning) {
+ SendHeartbeat();
+ MonitorHeartbeat();
+ std::this_thread::sleep_for(std::chrono::milliseconds(m_nIntervalMs * 5));
+ }
+ });
+}
+
+void CPLCSignalListener::StopHeartbeatMonitor()
+{
+ m_bHeartbeatRunning = false;
+ if (m_heartbeatThread.joinable()) {
+ m_heartbeatThread.join();
+ }
+}
+
+void CPLCSignalListener::PulseBitDevice(DeviceType eDevType, long nBitNo, int nDelayMs/* = 50*/)
+{
+ m_pPlc->SetBitDeviceEx(m_station, eDevType, nBitNo);
::Sleep(nDelayMs);
- m_pPlc->ResetBitDevice(m_station, eDevType, nBitNo);
+ m_pPlc->ResetBitDeviceEx(m_station, eDevType, nBitNo);
}
void CPLCSignalListener::HandleAckLife(int i, bool bCurrTriggerBit)
{
if (m_vecAckSent[i] && !bCurrTriggerBit) {
- m_pPlc->ResetBitDevice(m_station, PLC_BIT_DEVICE_TYPE, short(PLC_ACK_BASE_BIT + i));
+ m_pPlc->ResetBitDeviceEx(m_station, PLC_BIT_DEVICE_TYPE, long(PLC_ACK_BASE_BIT + i));
m_vecAckSent[i] = false;
}
if (m_vecAckSent[i]) {
if (++m_vecAckCounter[i] > PLC_ACK_MAX_LIFE) {
- m_pPlc->ResetBitDevice(m_station, PLC_BIT_DEVICE_TYPE, short(PLC_ACK_BASE_BIT + i));
+ m_pPlc->ResetBitDeviceEx(m_station, PLC_BIT_DEVICE_TYPE, long(PLC_ACK_BASE_BIT + i));
m_vecAckSent[i] = false;
}
}
@@ -123,19 +225,17 @@
void CPLCSignalListener::ThreadProc()
{
- while (m_bRunning) {
+ while (m_bRunning && m_bConnected) {
BitContainer vecBits;
- int ret = m_pPlc->ReadBitData(m_station, PLC_BIT_DEVICE_TYPE, PLC_CMD_BIT_START, PLC_CMD_BIT_COUNT, vecBits);
- if (ret != 0/*&& vecBits.size() != PLC_CMD_BIT_COUNT*/) {
- ::Sleep(m_nIntervalMs);
+ int ret = m_pPlc->ReadBitDataEx(m_station, PLC_BIT_DEVICE_TYPE, PLC_CMD_BIT_START, PLC_CMD_BIT_COUNT, vecBits);
+ if (ret != 0 && vecBits.size() != PLC_CMD_BIT_COUNT) {
+ ::Sleep(m_nIntervalMs);
- if (m_cbLog) {
- CString strError;
- strError.Format(_T("PLC读取位数据失败,错误码:%d"), ret);
- m_cbLog(strError, LOG_TYPE_ERROR);
- }
+ CString strError;
+ strError.Format(_T("PLC读取位数据失败,错误码:%d"), ret);
+ LOG_MSG(strError, LOG_TYPE_ERROR);
- continue;
+ continue;
}
for (int i = 0; i < PLC_CMD_BIT_COUNT; ++i) {
@@ -146,7 +246,7 @@
if (m_cbStart) {
m_cbStart();
WriteOutValues(OutValuesArray{ 0.0, 0.0, 0.0, 0.0 });
- if (m_pPlc->SetBitDevice(m_station, PLC_BIT_DEVICE_TYPE, PLC_ACK_BASE_BIT + i) == 0) {
+ if (m_pPlc->SetBitDeviceEx(m_station, PLC_BIT_DEVICE_TYPE, PLC_ACK_BASE_BIT + i) == 0) {
m_vecAckSent[i] = true;
m_vecAckCounter[i] = 0;
}
@@ -156,7 +256,7 @@
case 1:
if (m_cbStop) {
m_cbStop();
- if (m_pPlc->SetBitDevice(m_station, PLC_BIT_DEVICE_TYPE, PLC_ACK_BASE_BIT + i) == 0) {
+ if (m_pPlc->SetBitDeviceEx(m_station, PLC_BIT_DEVICE_TYPE, PLC_ACK_BASE_BIT + i) == 0) {
m_vecAckSent[i] = true;
m_vecAckCounter[i] = 0;
}
@@ -180,21 +280,27 @@
bool CPLCSignalListener::WriteOutValues(const OutValuesArray& values)
{
- if (!m_pPlc) {
- if (m_cbLog) {
- m_cbLog(_T("PLC控制器未初始化,无法写入输出值。"), LOG_TYPE_ERROR);
- }
+ if (!m_pPlc || !m_bConnected) {
+ LOG_MSG(_T("PLC未连接或未初始化,无法写入输出值。"), LOG_TYPE_ERROR);
return false;
}
- static const short PLC_RESULT_ADDR[4] = { 100, 102, 104, 106 };
+ if (PLC_RESULT_ADDR_COUNT != 4) {
+ LOG_MSG(_T("PLC结果寄存器数量配置错误,必须为4个。"), LOG_TYPE_ERROR);
+ return false;
+ }
- for (int i = 0; i < 4; ++i) {
+ for (int i = 0; i < PLC_RESULT_ADDR_COUNT; ++i) {
+ // 放大100倍并四舍五入,转为PLC整数
uint16_t nScaled = static_cast<uint16_t>(std::round(values[i] * 100.0));
WordContainer vec = { nScaled };
- int ret = m_pPlc->WriteWordData(m_station, PLC_WORD_DEVICE_TYPE, PLC_RESULT_ADDR[i], vec);
+ short nTargetAddr = PLC_RESULT_ADDR_START + i * 2;
+ int ret = m_pPlc->WriteWordDataEx(m_station, PLC_WORD_DEVICE_TYPE, nTargetAddr, vec);
if (ret != 0) {
+ CString msg;
+ msg.Format(_T("写入OUT%d到地址%d失败,值=%.2f"), i + 1, nTargetAddr, values[i]);
+ LOG_MSG(msg, LOG_TYPE_ERROR);
return false;
}
}
--
Gitblit v1.9.3