modbus学习第6天

继续之前用Qt做的那个代替主站对从站的4大寄存器写入读取的程序,我总共封装了两个类,一个是ModbusPro(只是用来管理ui),一个是ModbusMaster(用来连接从站,写入,读取数据)
本来我是想着用多线程,主线程更新ui,子线程用来连接从站,然后后面越改bug越多,经常出现野指针的问题,我就放弃了,但还是采用了ModbusPro和ModbusMaster通过信号与槽连接,ModbusPro只负责ui的更新,ModbusMaster采用了懒汉模式,然后就是一些连接信号与槽的繁琐操作,整体比较简单
可能比较困难的部分是怎么将QString类型写入Modbus的寄存器,我是写入"1 1 0 0 1"这种类型,先把空格提出去,然后用QStringList保存,后转化为uint8_t *类型

点击查看代码
void ModbusMaster::toQStringList(uint8_t * bits, const QString & data)
{
	QRegularExpression temp("\\s+");
	QStringList tempList = data.split(temp, QString::SkipEmptyParts);
	for (int i = 0; i < tempList.size(); i++)
	{
		bits[i] = tempList[i].toInt();
	}
}
void ModbusMaster::slot_WBtn(int functionID, int addr, int text, int number, const QString&data)
{
	if (!this->m_isConnect || !this->m_modbusCtx) 
	{
		this->m_erromsg = QString::fromLocal8Bit("RTU未初始化或未连接串口");
		emit error_msg(this->m_erromsg);
		return;
	}
	int ret;//记录写寄存器的结果
	uint8_t* bits = new uint8_t[number]();
	uint16_t* bits_16 = new uint16_t[number]();
	switch (functionID)
	{
	case 5://线圈寄存器下写单个寄存器
		ret = modbus_write_bit(this->m_modbusCtx, addr, text);
		break;
	case 15://线圈寄存器下写多个寄存器
		this->toQStringList(bits, data);
		ret = modbus_write_bits(this->m_modbusCtx, addr, number, bits);
		delete[]bits;
		bits = nullptr;
		break;
	case 6://保持寄存器的写单个寄存器
		ret = modbus_write_register(this->m_modbusCtx, addr, text);
		break;
	case 16://保持寄存器的写多个寄存器
		this->toQStringList(bits_16, data);
		ret = modbus_write_registers(this->m_modbusCtx, addr, number, bits_16);
		delete[]bits_16;
		bits_16 = nullptr;
		break;
	default:
		this->m_erromsg = QString::fromLocal8Bit("写寄存器的功能码传入错误");
		emit error_msg(this->m_erromsg);
		break;
	}
	if (bits != nullptr)
		delete bits;
	if (bits_16 != nullptr)
		delete bits_16;
	if (ret > 0)
	{
		/*QMessageBox::information(nullptr, QString::fromLocal8Bit("写入成功"),
			QString::fromLocal8Bit("线圈地址:%1,写入的值:%2").arg(addr).arg(text));*/
		if (functionID == 5 || functionID == 6)
			this->m_erromsg = QString::fromLocal8Bit("写入成功,线圈地址:%1,写入的值:%2").arg(addr).arg(text);
		else
			this->m_erromsg = QString::fromLocal8Bit("写入成功,线圈地址:%1,写入的值:%2").arg(addr).arg(data);
		emit error_msg(this->m_erromsg);
	}
	else
	{
		/*QMessageBox::information(nullptr, QString::fromLocal8Bit("写入失败"),
			QString::fromLocal8Bit("线圈地址:%1,写入的值:%2,错误原因:%3").arg(addr).arg(text).arg(modbus_strerror(errno)));*/
		this->m_erromsg = QString::fromLocal8Bit("写入失败,线圈地址:%1,写入的值:%2").arg(addr).arg(text);
		emit error_msg(this->m_erromsg);
	}
}

对于如何把modbus寄存器中的数据读取出来,我们就准备一个uint8_t的数组就行,把数据读取到数组中,然后再一位一位的读取到QString中,因为读取其他寄存器的逻辑和线圈寄存器一样,我就偷个懒不写了
点击查看代码
void ModbusMaster::slot_RBtn(int functionID, int addr, int number)
{
	if (!this->m_isConnect || !this->m_modbusCtx)
	{
		this->m_erromsg = QString::fromLocal8Bit("RTU未初始化或未连接串口");
		emit error_msg(this->m_erromsg);
		return;
	}
	int ret;//记录读寄存器的结果
	uint8_t*bits = new uint8_t[number]();
	switch (functionID)
	{
	case 1://线圈寄存器单个或多个
		ret = modbus_read_bits(this->m_modbusCtx, addr, number, bits);
		break;
	case 2://离散状态寄存器
		break;
	case 3://保持寄存器
		break;
	case 4://输入寄存器
		break;
	default:
		this->m_erromsg = QString::fromLocal8Bit("读寄存器的功能码传入错误");
		emit error_msg(this->m_erromsg);
		break;
	}
	if (ret > 0)
	{
		QString data;
		for (int i = 0; i < number; ++i)
		{
			if (bits[i] == 1)
				data.append("1");
			else
				data.append("0");
		}
		emit Read_msg(functionID, data);//发送ui显示的信号
		delete bits;
	}
	else
	{
		delete bits;
		this->m_erromsg = QString::fromLocal8Bit("写入失败,线圈地址:%1,功能码:%2").arg(addr).arg(functionID);
		emit error_msg(this->m_erromsg);
	}
}
posted @ 2026-02-08 10:49  dd_l  阅读(3)  评论(0)    收藏  举报