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);
}
}
点击查看代码
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);
}
}
浙公网安备 33010602011771号