MFC实现 Modbus-TCP 实时采集ZH-T08R 电阻模块阻值实例

连接 ZH‑T08R

发送:00 00 00 00 00 06 01 03 00 00 00 02

定时器 200ms 自动循环读取

实时显示:原始报文 + 第一通道电阻(十进制 Ω)

需要添加 ws2_32.lib 库

界面控件 ID 清单(必须对应)

IP 编辑框:IDC_EDIT_IP

端口编辑框:IDC_EDIT_PORT

开始按钮:IDC_BTN_READ(标题:开始实时读取)

停止按钮:IDC_BTN_STOP(标题:停止)

电阻显示:IDC_EDIT_RESIST

原始接收框:IDC_EDIT_RECV

ModbusTCPDlg.h

cpp 复制代码
#if !defined(AFX_MODBUSTCPDLG_H__12345678_ABCD_1234_5678_000000000001__INCLUDED_)
#define AFX_MODBUSTCPDLG_H__12345678_ABCD_1234_5678_000000000001__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif

#include <winsock2.h>

class CModbusTCPDlg : public CDialog
{
public:
	CModbusTCPDlg(CWnd* pParent = NULL);

	enum { IDD = IDD_MODBUSTCP_DIALOG };

protected:
	virtual void DoDataExchange(CDataExchange* pDX);

protected:
	HICON m_hIcon;
	SOCKET m_sock;
	BOOL m_bConnected;
	UINT m_nTimerID;

	BOOL ConnectServer(CString ip, int port);
	void ReadModbusData();
	void CloseSocket();
	void StartTimer();
	void StopTimer();
//{{AFX_MSG(CModbusTCPDlg)    // 类向导必须的消息开始标记
	afx_msg void OnTimer(UINT nIDEvent);
	afx_msg void OnBtnRead();
	afx_msg void OnBtnStop();

	virtual BOOL OnInitDialog();
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	afx_msg void OnCancel();
//}}AFX_MSG                   // 类向导必须的消息结束标记
	DECLARE_MESSAGE_MAP()
};

#endif

ModbusTCPDlg.cpp

cpp 复制代码
#include "stdafx.h"
#include "ModbusTCP.h"
#include "ModbusTCPDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif



BEGIN_MESSAGE_MAP(CModbusTCPDlg, CDialog)
//{{AFX_MSG_MAP(CModbusTCPDlg)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_WM_TIMER()
	ON_BN_CLICKED(IDC_BTN_READ, OnBtnRead)
	ON_BN_CLICKED(IDC_BTN_STOP, OnBtnStop)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

CModbusTCPDlg::CModbusTCPDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CModbusTCPDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	m_sock = INVALID_SOCKET;
	m_bConnected = FALSE;
	m_nTimerID = 0;
}

void CModbusTCPDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BOOL CModbusTCPDlg::OnInitDialog()
{
	CDialog::OnInitDialog();
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2,2), &wsaData);

	SetDlgItemText(IDC_EDIT_IP, "192.168.0.7");
	SetDlgItemText(IDC_EDIT_PORT, "20108");
	return TRUE;
}

void CModbusTCPDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this);
		SendMessage(WM_ICONERASEBKGND, (WPARAM)dc.GetSafeHdc(), 0);
		int cx = GetSystemMetrics(SM_CXICON);
		int cy = GetSystemMetrics(SM_CYICON);
		CRect rc; GetClientRect(&rc);
		int x = (rc.Width()-cx)/2;
		int y = (rc.Height()-cy)/2;
		dc.DrawIcon(x,y,m_hIcon);
	}
	else
		CDialog::OnPaint();
}

HCURSOR CModbusTCPDlg::OnQueryDragIcon()
{
	return (HCURSOR)m_hIcon;
}

BOOL CModbusTCPDlg::ConnectServer(CString ip, int port)
{
	m_sock = socket(AF_INET,SOCK_STREAM,0);
	if(m_sock == INVALID_SOCKET) return FALSE;

	sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.S_un.S_addr = inet_addr(ip);

	if(connect(m_sock,(sockaddr*)&addr,sizeof(addr)) == SOCKET_ERROR)
	{
		closesocket(m_sock);
		m_sock = INVALID_SOCKET;
		return FALSE;
	}
	return TRUE;
}

void CModbusTCPDlg::CloseSocket()
{
	if(m_sock != INVALID_SOCKET)
	{
		closesocket(m_sock);
		m_sock = INVALID_SOCKET;
	}
	m_bConnected = FALSE;
}

void CModbusTCPDlg::StartTimer()
{
	if(m_nTimerID == 0)
		m_nTimerID = SetTimer(1001,200,NULL);
}

void CModbusTCPDlg::StopTimer()
{
	if(m_nTimerID != 0)
	{
		KillTimer(m_nTimerID);
		m_nTimerID = 0;
	}
}

void CModbusTCPDlg::OnTimer(UINT nIDEvent)
{
	if(nIDEvent == 1001)
		ReadModbusData();
	CDialog::OnTimer(nIDEvent);
}

// ===================== 核心发送与解析 =====================
void CModbusTCPDlg::ReadModbusData()
{
	if(!m_bConnected || m_sock == INVALID_SOCKET) return;

	BYTE sendBuf[12] = {
		0x00,0x00,
		0x00,0x00,
		0x00,0x06,
		0x01,
		0x03,
		0x00,0x00,
		0x00,0x02
	};

	send(m_sock,(char*)sendBuf,12,0);

	BYTE recvBuf[1024] = {0};
	int len = recv(m_sock,(char*)recvBuf,1024,0);
	if(len <= 0) return;

	CString strRecv;
	for(int i=0;i<len;i++){
		CString t; t.Format("%02X ",recvBuf[i]);
		strRecv += t;
	}
	SetDlgItemText(IDC_EDIT_RECV,strRecv);

	// 解析 32 位电阻(0.01Ω)
	if(len >= 13)
	{
		DWORD h16 = (recvBuf[9]<<8) | recvBuf[10];
		DWORD l16 = (recvBuf[11]<<8) | recvBuf[12];
		DWORD val = (h16<<16) | l16;
		float r = val / 100.0f;

		CString strR;
		strR.Format("%.2f Ω",r);
		SetDlgItemText(IDC_EDIT_RESIST,strR);
	}
}

void CModbusTCPDlg::OnBtnRead()
{
	CString ip,portStr;
	GetDlgItemText(IDC_EDIT_IP,ip);
	GetDlgItemText(IDC_EDIT_PORT,portStr);
	int port = atoi(portStr);

	StopTimer();
	CloseSocket();

	if(ConnectServer(ip,port))
	{
		m_bConnected = TRUE;
		StartTimer();
		MessageBox("连接成功,开始实时采集","提示");
	}
	else
		MessageBox("连接失败!检查IP/网络/模块","错误");
}

void CModbusTCPDlg::OnBtnStop()
{
	StopTimer();
	CloseSocket();
	MessageBox("已停止读取","提示");
}

void CModbusTCPDlg::OnCancel()
{
	StopTimer();
	CloseSocket();
	WSACleanup();
	CDialog::OnCancel();
}

运行程序

相关推荐
ComputerInBook2 小时前
C++ 14 相比 C++ 11新增之特征
开发语言·c++·c++ 14
Peter·Pan爱编程2 小时前
成员函数与 this 指针:函数属于数据
c++
music score2 小时前
google 的C++自动化测试框架详解(Google Test)(2)
c++·qt·lucene
charlie1145141912 小时前
基于开源项目的现代C++实战——OnceCallback 实战(五):then 链式组合
开发语言·c++·开源
Shan12052 小时前
在C++中尝试封装为函数
开发语言·c++·算法
Shadow(⊙o⊙)2 小时前
Linux进程地址空间——钻入Linux内核架构性剖析 硬核手搓!
java·linux·运维·服务器·开发语言·c++
郝学胜-神的一滴3 小时前
干货版《算法导论》04:渐近复杂度与序列接口实战
java·开发语言·数据结构·c++·python·算法
Jinkxs3 小时前
LoadBalancer- 核心术语详解:转发 / 监听 / 节点池 / 虚拟 IP 等必知概念
网络·网络协议·tcp/ip
Peter·Pan爱编程3 小时前
构造与析构:对象生命周期的“自动挡“
c++