modbus学习第5天

今天用Qt实现一个可以通过modbus对线圈寄存器--读写单个寄存器和多个寄存器,离散寄存器--读单个和多个寄存器,保持寄存器--读写单个寄存器和多个寄存器,输入寄存器--读单个和多个寄存器的功能,大概是这么个效果,ui设计好了
image

用单例模式设计了一个ModbusMaster的类用于连接从站设备以及对从站设备的读写,防止ui更新和读取数据冲突造成卡顿,用了多线程,今天完成了主站设备和从站设备的连接,明天再完成主站设备对从站设备的读写,整个小程序功能比较单一就不用git管理了

点击查看代码

点击查看代码
#include "ModbusMaster.h"
Q_GLOBAL_STATIC(ModbusMaster, theInstance);
ModbusMaster::ModbusMaster(QObject *parent)
	: QObject(parent), m_isConnect(false), m_modbusCtx(nullptr)
{
}

ModbusMaster::~ModbusMaster()
{
	this->disconnectSlave();
	if (m_modbusCtx != nullptr) 
	{
		modbus_free(m_modbusCtx);
		m_modbusCtx = nullptr;
	}
}
//获取单例对象
ModbusMaster * ModbusMaster::getInstance()
{
	return theInstance;
}
//初始化RTU
bool ModbusMaster::initRtu(const QString & portName, int baudRate, char parity, int dataBits, int stopBits)
{
	QMutexLocker locker(&this->m_mutex);
	if (this->m_modbusCtx != nullptr)
	{
		modbus_free(this->m_modbusCtx);
		this->m_modbusCtx = nullptr;
	}
	//创建modbus的RTU
	this->m_modbusCtx = modbus_new_rtu(portName.toLocal8Bit().data(), baudRate, parity, dataBits, stopBits);
	if (this->m_modbusCtx == nullptr)
	{
		QMessageBox::information(nullptr, QString::fromLocal8Bit("提示"), QString::fromLocal8Bit("初始化RTU失败"));
		return false;
	}
	modbus_set_response_timeout(this->m_modbusCtx, 3, 0);//设置超时3s
	QMessageBox::information(nullptr, QString::fromLocal8Bit("提示"), QString::fromLocal8Bit("初始化RTU成功"));
	return true;
}
//连接串口
bool ModbusMaster::connectSlave()
{
	QMutexLocker locker(&this->m_mutex);
	if (this->m_modbusCtx == nullptr)
	{
		QMessageBox::information(nullptr, QString::fromLocal8Bit("提示"), QString::fromLocal8Bit("未初始化RTU"));
		return false;
	}
	if (this->m_isConnect)
	{
		qDebug() << "已连接从站,不需要再次连接";
		return true;
	}
	int ret = modbus_connect(this->m_modbusCtx);//串口打开了,没有被占用
	if (ret == -1)
	{
		QMessageBox::information(nullptr, QString::fromLocal8Bit("提示"), QString::fromLocal8Bit("串口打开失败"));
		return false;
	}
	this->m_isConnect = true;
	return true;
}
//设置从站地址
void ModbusMaster::setSlaveId(int slaveId)
{
	QMutexLocker locker(&this->m_mutex);
	if (this->m_modbusCtx != nullptr)
	{
		modbus_set_slave(this->m_modbusCtx, slaveId);
		qDebug() << "从站地址为" << slaveId;
		uint16_t testData[1] = { 0 };
		// 读地址0的保持寄存器(功能码03),需和从站模拟器配置的地址匹配
		int readRet = modbus_read_registers(m_modbusCtx, 0, 1, testData);
		if (readRet == -1)
		{
			QString errMsg = QString::fromLocal8Bit("串口已打开,但从站(ID=%1)无响应:%2")
				.arg(slaveId).arg(modbus_strerror(errno));
			QMessageBox::warning(nullptr, QString::fromLocal8Bit("提示"), errMsg);
			// 串口已打开,需关闭
			modbus_close(this->m_modbusCtx);
			this->m_isConnect = false;
			return;
		}
	}
	else
	{
		QMessageBox::information(nullptr, QString::fromLocal8Bit("提示"), QString::fromLocal8Bit("未初始化RTU"));
	}
}
//断开连接
void ModbusMaster::disconnectSlave()
{
	QMutexLocker locker(&this->m_mutex);
	if ((this->m_modbusCtx == nullptr) && this->m_isConnect)
	{
		QMessageBox::information(nullptr, QString::fromLocal8Bit("提示"), 
			QString::fromLocal8Bit("初始化失败,无法断开连接"));
		return;
	}
	modbus_close(this->m_modbusCtx);
	this->m_isConnect = false;
	QMessageBox::information(nullptr, QString::fromLocal8Bit("提示"),
		QString::fromLocal8Bit("已断开"));
}
明天中午还约了个面试……赶快结束吧,让我考研上岸,再找个好实习
posted @ 2026-02-05 20:29  dd_l  阅读(4)  评论(0)    收藏  举报