#include "mainwindow.h" #include "ui_mainwindow.h" #include #include #include #include #include "libmodbus/modbus.h" #define _DEBUG_VSPD_ #define TH08D_TEMPERATURE_EQUIPMENT_81_00_09 40000 #define TH08D_TEMPERATURE_EQUIPMENT_81_09_06 40009 // 处理数组的槽函数 void DecodeWorker::processArray(const QVector& array,int slave_id,int start_addr,int quantity,DeviceData* pData) { switch (start_addr) { case TH08D_TEMPERATURE_EQUIPMENT_81_00_09: { assert(pData->m_device_type == 81); TemperatureData* pTemperature = (TemperatureData*)pData; uint16_t value; int index = 0; pTemperature->m_device_online_state = array[index++]; //设备通讯状态 pTemperature->TempValue = (float)array[index++] * 1.0f / 10.f; //温度 pTemperature->HumidityValue = (float)array[index++] * 1.0f / 10.f; //湿度 pTemperature->DewPointValue = (float)array[index++] * 1.0f; //露点 value = array[index++]; //跳过温度偏移量 value = array[index++]; //跳过湿度偏移量 pTemperature->DO= array[index++]; //DO pTemperature->DI1 = array[index++]; //DI1 pTemperature->DI2 = array[index++]; //DI2 pTemperature->bDecodeAlarm = false; pTemperature->bDecodeTemp = true; } break; case TH08D_TEMPERATURE_EQUIPMENT_81_09_06: { assert(pData->m_device_type == 81); TemperatureData* pTemperature = (TemperatureData*)pData; pTemperature->bDecodeAlarm = true; pTemperature->bDecodeTemp = false; uint16_t value; int index = 0; float temp_threshold = (float)array[index++] * 1.0f / 10.f; //温度阈值 float temp_offset = (float)array[index++] * 1.0f / 10.f; //温控偏移量 value = array[index++]; //跳过设备状态 pTemperature->TempHighAlarm = array[index++]; //高温告警 pTemperature->HumidityHighAlarm = array[index++]; //高湿度告警 pTemperature->TempLowAlarm = array[index++]; //低温告警 } break; default: break; } //下面是模拟发送进度 //for (int i = 0; i < array.size(); ++i) //{ // qDebug() << "Worker处理索引:" << i << "值:" << array[i] // << "线程:" << QThread::currentThread(); // //QThread::msleep(100); // 模拟耗时处理 // emit progress(i); //} qDebug() << "Worker thread finished"; emit finished(); } MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) ,m_pModbus(nullptr) ,m_pSettings(nullptr) { ui->setupUi(this); m_version= "1.0.0"; m_modbus_type = 1; m_modbus_ip = "127.0.0.1"; m_modbus_port = 502; m_modbus_com = "COM1"; m_modbus_baund = 9600; m_modbus_data = 1; m_modbus_parity = 0; m_modbus_stop = 1; m_modbus_slave_id = 1; InitializeUI(); InitializeModbus(); } MainWindow::~MainWindow() { delete ui; if (m_pModbus) { modbus_close(m_pModbus); modbus_free(m_pModbus); m_pModbus = nullptr; } for (SlaveItem* ptr : m_SlaveData) { delete ptr; ptr = nullptr; } m_SlaveData.clear(); } void MainWindow::getConfiguration(QString iniFilePath) { m_pSettings = new QSettings(iniFilePath, QSettings::IniFormat); m_version = m_pSettings->value("version/ver").toString(); m_modbus_type = m_pSettings->value("modbus/type").toInt(); m_modbus_ip = m_pSettings->value("modbus/ip").toString(); m_modbus_port = m_pSettings->value("modbus/port").toInt(); m_modbus_com = m_pSettings->value("modbus/com").toString(); m_modbus_baund = m_pSettings->value("modbus/baund").toInt(); m_modbus_data = m_pSettings->value("modbus/data").toInt(); m_modbus_parity = m_pSettings->value("modbus/parity").toInt(); m_modbus_stop = m_pSettings->value("modbus/stop").toInt(); m_modbus_slave_id = m_pSettings->value("slaves/slave_id").toInt(); QString app = QString("slave_%1/function_code_counts").arg(m_modbus_slave_id); int functions_count = m_pSettings->value(app).toInt(); for(int i=0; ivalue(app2 + "/equipment_code").toInt(); equipmentCode = equipmentCode << 9; equipmentCode &= 0xFE00; // 二进制掩码: 1111 1110 0000 0000(保留高7位) QStringList sn_list = m_pSettings->value(app2 + "/serial_number").toString().split(":", Qt::SkipEmptyParts); QStringList quantity_list = m_pSettings->value(app2 + "/read_quantity").toString().split(":", Qt::SkipEmptyParts); assert(sn_list.size() == quantity_list.size()); int j = 0; foreach(const QString sn, sn_list) { SlaveItem* pSlaveData = new SlaveItem(); pSlaveData->id = m_modbus_slave_id; pSlaveData->function_code = m_pSettings->value(app2 + "/function_code").toInt(); pSlaveData->interval = m_pSettings->value(app2 + "/interval").toInt(); unsigned short serialNumber = sn.toInt(); serialNumber &= 0x01FF; // 二进制掩码: 0000 0001 1111 1111(保留低9位) // 组合操作:高7位左移9位,低9位直接填充 unsigned short address = pSlaveData->start_address = (equipmentCode ) | serialNumber; // 关键位操作 pSlaveData->start_address = address; pSlaveData->quantity = quantity_list.at(j).toInt(); m_SlaveData.push_back(pSlaveData); j++; } #else SlaveItem* pSlaveData = new SlaveItem(); pSlaveData->id = m_modbus_slave_id; pSlaveData->function_code = m_pSettings->value(app2 + "/function_code").toInt(); pSlaveData->interval = m_pSettings->value(app2 + "/interval").toInt(); pSlaveData->quantity = m_pSettings->value(app2 + "/quantity").toInt(); pSlaveData->start_address = m_pSettings->value(app2 + "/start_addr").toInt(); m_SlaveData.push_back(pSlaveData); #endif } } bool MainWindow::InitializeUI() { return false; } bool MainWindow::InitializeModbus() { QString appDir = QCoreApplication::applicationDirPath(); QString iniFilePath = appDir + QString::fromStdString("/emsshower.ini"); getConfiguration(iniFilePath); switch (m_modbus_type) { case 0: return InitializeTcp(); break; default: case 1: return InitializeRtu(); break; } } bool MainWindow::InitializeRtu() { if(m_pModbus) { modbus_close(m_pModbus); m_pModbus = nullptr; } std::string com = std::string("\\\\.\\") + m_modbus_com.toStdString(); m_pModbus = modbus_new_rtu(com.c_str(), m_modbus_baund, 'N', m_modbus_data, m_modbus_stop); int slave_id = m_modbus_slave_id; //modbus_set_debug(m_pModbus, true); modbus_set_slave(m_pModbus, slave_id); //设置modbus从机地址 modbus_rtu_set_serial_mode(m_pModbus, MODBUS_RTU_RS485); int rc = modbus_connect(m_pModbus); if (rc == -1) return false; struct timeval t; t.tv_sec=0; t.tv_usec=1000000; //设置modbus超时时间为1000毫秒 modbus_set_response_timeout(m_pModbus, t.tv_usec,t.tv_usec); return true; } bool MainWindow::InitializeTcp() { if(m_pModbus) { modbus_close(m_pModbus); m_pModbus = nullptr; } std::string ip = m_modbus_ip.toStdString(); int port = m_modbus_port; m_pModbus = modbus_new_tcp(ip.c_str(), port); //由于是tcp client连接,在同一个程序中相同的端口可以连接多次。 if (m_pModbus == nullptr) { return false; } int slave_id = m_modbus_slave_id; modbus_set_slave(m_pModbus, slave_id); //从机地址 int rc = modbus_connect(m_pModbus); if (rc == -1) return false; struct timeval t; t.tv_sec=0; t.tv_usec=1000000; //设置modbus超时时间为1000毫秒 modbus_set_response_timeout(m_pModbus, t.tv_usec,t.tv_usec); return true; } bool MainWindow::readRegister(int addr,int nb,uint16_t* dest) { for (auto it = m_SlaveData.begin(); it != m_SlaveData.end(); ++it) { SlaveItem* pItem = (SlaveItem*)(*it); uint16_t* tab_reg = new uint16_t[pItem->quantity]; int regs = modbus_read_registers(m_pModbus, pItem->start_address, pItem->quantity, tab_reg); QVector registers; for (int i = 0; i < regs; ++i) { registers.push_back(tab_reg[i]); } delete []tab_reg; DeviceData* pDevice = nullptr; if (pItem->start_address == TH08D_TEMPERATURE_EQUIPMENT_81_00_09 || pItem->start_address == TH08D_TEMPERATURE_EQUIPMENT_81_09_06) pDevice = new TemperatureData(); startAsyncProcess(registers,pItem->id,pItem->start_address, pItem->quantity, pDevice); if (pItem->start_address == TH08D_TEMPERATURE_EQUIPMENT_81_00_09 || pItem->start_address == TH08D_TEMPERATURE_EQUIPMENT_81_09_06) { TemperatureData* pData = (TemperatureData*)pDevice; assert(pData); if (pData->bDecodeTemp) { ui->txt_content_1->append(QString(tr("温度:%1\n湿度: %2\n露点: %3\n")).arg(pData->TempValue).arg(pData->HumidityValue).arg(pData->DewPointValue)); } if (pData->bDecodeAlarm) { ui->txt_content_1->append(QString(tr("高温告警:%1\n低温告警: %2\n湿度告警: %3\n")).arg(pData->TempHighAlarm).arg(pData->TempLowAlarm).arg(pData->HumidityHighAlarm)); } } qDebug() << "同步读取地址" << pItem->start_address; } return true; } void MainWindow::startAsyncProcess(const QVector& array,int slave_id,int start_addr,int quantity, DeviceData* pDevice) { QThread* thread = new QThread; DecodeWorker* worker = new DecodeWorker; worker->moveToThread(thread); worker->setParameters(array, slave_id, start_addr, quantity, pDevice); // 连接线程启动信号和槽函数 connect(this, &MainWindow::startProcessing, worker, &DecodeWorker::processArray); // 工作完成后退出线程 connect(worker, &DecodeWorker::finished, thread, &QThread::quit); connect(worker, &DecodeWorker::finished, worker, &DecodeWorker::deleteLater); connect(thread, &QThread::finished, thread, &QThread::deleteLater); //// 可选:连接进度信号更新UI //connect(worker, &DecodeWorker::progress, this, [](int index) //{ // qDebug() << "进度更新,当前处理到索引:" << index; //}); thread->start(); QEventLoop loop; QObject::connect(worker, &DecodeWorker::finished, &loop, &QEventLoop::quit); // 发射信号传递参数 emit startProcessing(array, slave_id, start_addr, quantity, pDevice); // 阻塞,等待线程结束 loop.exec(); qDebug() << "同步读取完成"; } void MainWindow::on_btn_read_register_clicked() { readRegister(0,0,0); }