创建modbus通信,创建线程

使用libmodbus库实现。​​​​​​GitHub - stephane/libmodbus: A Modbus library for Linux, Mac OS, FreeBSD and Windows

编译后得到:modbus.lib和modbus.dll

包含文件:

modbus.h
modbus-rtu.h
modbus-tcp.h
modbus-version.h

使用说明:

初始化与释放:

/* 
  以TCP的方式创建libmobus实例
  char *ip:连接的IP地址
  int port: 连接的IP端口
*/
modbus_t *modbus_new_tcp(const char *ip, int port);

/* 
  以串口的方式创建libmobus实例
  onst char *device:连接的串口号,类似是这样'\\\\.\\COM10'
  int baud: 波特率
  char parity:奇偶校验
  int data_bit:数据位
  int stop_bit:停止位
*/
modbus_t *modbus_new_rtu(const char *device, int baud, char parity, int data_bit, int stop_bit);

/* 
  释放libmodbus实例,使用完libmodbus需要释放掉
  modbus_t *ctx:libmodbus实例
*/
void modbus_free(modbus_t *ctx);

读取:

/* 
  读取线圈状态,可读取多个连续线圈的状态
  modbus_t *ctx:Modbus实例
  int addr: 线圈地址
  int nb:读取线圈的个数
  uint8_t *dest: 传出的状态值
*/
int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);

/* 
  读取输入状态,可读取多个连续输入的状态
  modbus_t *ctx:Modbus实例
  int addr:输入地址
  int nb:读取输入的个数
  uint8_t *dest:传出的状态值
*/
int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);

/* 
  读取输入寄存器的值,可读取多个连续输入输入寄存器
  modbus_t *ctx:Modbus实例
  int addr:输入地址
  int nb:读取输入寄存器的个数
  uint8_t *dest:传出的寄存器值
*/
int modbus_read_input_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);

/* 
  读取保持寄存器的值,可读取多个连续输入保持寄存器
  modbus_t *ctx:Modbus实例
  int addr:输入地址
  int nb:读取保持寄存器的个数
  uint8_t *dest:传出的寄存器值
*/
int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);

写入:

/*
  写入单个线圈的状态
  modbus_t *ctx:Modbus实例
  int addr:线圈地址
  int status:线圈状态
*/
int modbus_write_bit(modbus_t *ctx, int addr, int status);

/*
  写入多个连续线圈的状态
  modbus_t *ctx:Modbus实例
  int addr:线圈地址
  int nb:线圈个数
  const uint8_t *src:多个线圈状态
*/
int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *src);

/*
  写入单个寄存器
  modbus_t *ctx:Modbus实例
  int addr:寄存器地址
  int value:寄存器的值 
*/
int modbus_write_register(modbus_t *ctx, int addr, int value);

/*
  写入多个连续寄存器
  int addr:寄存器地址
  int nb:寄存器的个数
  const uint16_t *src:多个寄存器的值 
*/
int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src);

float浮点数转换:

float modbus_get_float(const uint16_t *src);

void modbus_set_float(float f, uint16_t *dest)

模拟通信:使用Modbus Slave和Modbus Poll  序列号:5455415451475662

Modbus Poll是服务端

Modbus Slave是客户端

01:线圈状态 可用上文中modbus_read_bits读取状态数据。

03:保持寄存器状态 可用上文 modbus_read_registers读取数据。

代码实现:

通信功能不能对程序阻塞,所以需要通过创建线程来实现。


//ConnectModbus.h
#include "CameraControlDlg.h"

class ConnectModbus : public CCameraControlDlg
{

public:
	ConnectModbus();
	~ConnectModbus();
	static DWORD WINAPI startClient(LPVOID lpParamter);

};

//ConnectModbus.cpp
#include "pch.h"
#include "ConnectModbus.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include <iostream>
#include "modbus/modbus.h"


using namespace std;

ConnectModbus::ConnectModbus()
{

}


ConnectModbus::~ConnectModbus()
{
}


DWORD __stdcall ConnectModbus::startClient(LPVOID lpParamter)
{
	const char* ip_address = "127.0.0.1";
	int MDport = 1234;
	int address = 5;
	int n = 1;

	uint16_t tab_reg[1] = { 0 };
	uint8_t M1[1] = { 0 };
	// 创建libmobus TCP实例
	modbus_t* pmbs_ctx = modbus_new_tcp(ip_address, MDport);
	modbus_set_debug(pmbs_ctx, 1);
	modbus_set_slave(pmbs_ctx, 1);	// 设置从机地址
	// 连接设备
	int nRet = modbus_connect(pmbs_ctx);
	// 连接失败
	if (-1 == nRet)
	{
		printf("connect failed:%s\n", modbus_strerror(errno));
		modbus_free(pmbs_ctx);

		return -1;
	}
	// 设置Modbus超时时间
	struct timeval tv;
	tv.tv_sec = 0;
	tv.tv_usec = 1000000;  //设置modbus超时时间为1000毫秒 
	modbus_set_response_timeout(pmbs_ctx, tv.tv_sec, tv.tv_usec);


	while (true)
	{
		printf("--------------------------------------------------\n");
		// 读取保持寄存器的值,起始地址为address,寄存器个数为n,读取到tab_reg数组中
		//int regs = modbus_read_registers(pmbs_ctx, address, n, tab_reg);
		//读取线圈状态
		int regs = modbus_read_bits(pmbs_ctx, address, n, M1);
		unsigned short  t = 1;
		if (M1[0]==TRUE)
		{

//写入需要执行的操作

			Sleep(1000);
		}
		else
		{
		}

	}

	return 0;
}

最后再对话框按钮上调用:

//CameraControlDlg.cpp
    const char* ip = "127.0.0.1";
	int port = 1234;
	int address = 5;
	int n=1;
	ConnectModbus a;
	HANDLE m_hand = CreateThread(NULL, 0, a.startClient, this, 0, NULL);
	CloseHandle(m_hand);

下面是一个使用QT读写Modbus协议的示例代码,包括了连接Modbus设备、读取和写入Modbus寄存器的功能: ```c++ #include "mainwindow.h" #include "ui_mainwindow.h" #include <QtSerialPort/QSerialPort> #include <QtSerialPort/QSerialPortInfo> #include <QModbusDataUnit> #include <QModbusTcpClient> #include <QModbusRtuSerialMaster> #include <QModbusTcpServer> #include <QThread> #include <QDebug> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); // 初始化Modbus设备连接 m_modbusDevice = nullptr; m_modbusClient = nullptr; m_modbusServer = nullptr; } MainWindow::~MainWindow() { // 断开Modbus设备连接 if (m_modbusClient) m_modbusClient->disconnectDevice(); if (m_modbusServer) m_modbusServer->disconnect(); delete ui; } void MainWindow::on_pushButton_Connect_clicked() { // 断开之前的Modbus设备连接 if (m_modbusClient) m_modbusClient->disconnectDevice(); if (m_modbusServer) m_modbusServer->disconnect(); // 初始化Modbus设备连接 if (ui->radioButton_TCP->isChecked()) { // 连接TCP Modbus设备 m_modbusClient = new QModbusTcpClient(this); m_modbusClient->setConnectionParameter(QModbusDevice::NetworkPortParameter, ui->lineEdit_TCP_Port->text().toInt()); m_modbusClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter, ui->lineEdit_TCP_IP->text()); m_modbusDevice = m_modbusClient; } else { // 连接串口 Modbus设备 m_modbusClient = new QModbusRtuSerialMaster(this); m_modbusClient->setConnectionParameter(QModbusDevice::SerialPortNameParameter, ui->comboBox_SerialPort->currentText()); m_modbusClient->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, ui->comboBox_BaudRate->currentText().toInt()); m_modbusClient->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, ui->comboBox_DataBits->currentText().toInt()); m_modbusClient->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, ui->comboBox_StopBits->currentText().toInt()); m_modbusClient->setConnectionParameter(QModbusDevice::SerialParityParameter, ui->comboBox_Parity->currentIndex()); m_modbusDevice = m_modbusClient; } // 连接Modbus设备 if (!m_modbusDevice->connectDevice()) { qDebug() << m_modbusDevice->errorString(); return; } // 显示连接状态 ui->label_Connected->setText("Connected"); } void MainWindow::on_pushButton_Disconnect_clicked() { // 断开Modbus设备连接 if (m_modbusClient) m_modbusClient->disconnectDevice(); if (m_modbusServer) m_modbusServer->disconnect(); // 显示连接状态 ui->label_Connected->setText("Disconnected"); } void MainWindow::on_pushButton_Read_clicked() { // 创建读取寄存器的数据单元 QModbusDataUnit readUnit(QModbusDataUnit::HoldingRegisters, ui->spinBox_ReadStartAddr->value(), ui->spinBox_ReadCount->value()); // 读取寄存器 if (auto *reply = m_modbusDevice->sendReadRequest(readUnit, ui->spinBox_SlaveID->value())) { // 等待读取完成 while (!reply->isFinished()) { QThread::usleep(100); } // 读取完成,显示读取结果 if (reply->error() == QModbusDevice::NoError) { const QModbusDataUnit unit = reply->result(); for (int i = 0; i < unit.valueCount(); i++) qDebug() << "Value[" << i << "]:" << unit.value(i); } else { qDebug() << "Read Error:" << reply->errorString(); } // 释放Modbus响应 reply->deleteLater(); } else { qDebug() << "Read Error:" << m_modbusDevice->errorString(); } } void MainWindow::on_pushButton_Write_clicked() { // 创建写入寄存器的数据单元 QModbusDataUnit writeUnit(QModbusDataUnit::HoldingRegisters, ui->spinBox_WriteStartAddr->value(), ui->spinBox_WriteCount->value()); // 设置写入寄存器的值 for (int i = 0; i < ui->spinBox_WriteCount->value(); i++) writeUnit.setValue(i, ui->lineEdit_WriteValues->text().split(',')[i].toInt()); // 写入寄存器 if (auto *reply = m_modbusDevice->sendWriteRequest(writeUnit, ui->spinBox_SlaveID->value())) { // 等待写入完成 while (!reply->isFinished()) { QThread::usleep(100); } // 写入完成,显示写入结果 if (reply->error() == QModbusDevice::NoError) { qDebug() << "Write Success"; } else { qDebug() << "Write Error:" << reply->errorString(); } // 释放Modbus响应 reply->deleteLater(); } else { qDebug() << "Write Error:" << m_modbusDevice->errorString(); } } ``` 这段代码中,我们使用了QT自带的QModbusTcpClient和QModbusRtuSerialMaster类实现了TCP和串口两种方式的Modbus设备连接,并使用QModbusDataUnit类读取和写入了Modbus寄存器。在实际使用中,需要根据具体的Modbus设备和通信协议进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值