本系统默认采用modbus协议,支持串口和网络rtu模式,后期还会引入其他通信协议比如mqtt等,可以在端口管理中下拉选择通信协议即可。
地址 | 功能码 | 寄存器地址 | 寄存器个数 | CRC校验 |
01 | 03 | 00 00 | 00 04 | 44 09 |
地址 | 功能码 | 长度 | 数据位1 | 数据位2 | 数据位3 | 数据位4 | CRC校验 |
01 | 03 | 08 | 00 00 | 00 00 | 00 00 | 00 00 | 95 D7 |
设备型号 | 长度 | 说明 |
FC1003-1 | 01 | |
FC1003-8 | 08 | |
FC1003-16 | 08 08 | 相当与两台FC1003-8,设备地址不同。 |
FC1003显示板 | 40 | 长度根据所接设备数量不同需要调整,最大为64个。 |
FC1003底板 | 04 | |
FT2104P | 01 | |
SAMS-4128 | 08 |
提示说明
示例数据1
示例数据2
示例数据3
void DeviceClient::readValue()
{
//还没有连接上或者地址为空则不需要处理
int addrCount = addrs.count();
if (!isOk || addrCount == 0) {
return;
}
//优先执行命令
if (doAddrs.count() > 0) {
QString type = doTypes.takeFirst();
quint8 addr = doAddrs.takeFirst();
QByteArray body = doBodys.takeFirst();
writeData(type, addr, body);
//额外执行的命令可能比较多导致设备离线,这里需要更新所有设备的时间
for (int i = 0; i < addrs.count(); ++i) {
times[i] = QDateTime::currentDateTime();
}
return;
}
//暂停不需要轮询,更新最后的消息时间,不然时间久了会判断离线
if (pause) {
for (int i = 0; i < addrs.count(); ++i) {
times[i] = QDateTime::currentDateTime();
}
return;
}
//如果没有一个在线的设备则不需要处理
bool existLive = false;
for (int i = 0; i < addrCount; ++i) {
if (onlines.at(i)) {
existLive = true;
break;
}
}
if (!existLive) {
emit receiveInfo(portName, 255, "没有一个在线设备,跳过遍历");
return;
}
//如果已经到了末尾则重新开始
if (currentIndex == addrCount) {
currentIndex = 0;
}
//跳过离线的设备,加速读取,递归
if (!onlines.at(currentIndex)) {
currentIndex++;
readValue();
return;
}
readValue(addrs.at(currentIndex));
currentIndex++;
}
void DeviceClient::checkValue()
{
if (!isOk) {
return;
}
QMutexLocker locker(&mutex);
readData();
//至少要多少个字节,保证下面取数据不出错
int size = buffer.size();
if (size < 5) {
return;
}
//01 03 08 00 00 00 00 00 00 00 00 95 D7
//01 03 08 00 14 03 12 00 00 00 00 79 E6
//取出首字节,判断是否为当前地址集合中的地址
quint8 addr = buffer.at(0);
quint8 cmd = buffer.at(1);
quint8 len = buffer.at(2);
//如果是错误码则直接解析错误信息
QList cmds;
cmds << 0x03 << 0x04 << 0x06;
if (!cmds.contains(cmd)) {
emit receiveError(portName, addr, QString("数据出错: %1").arg(QUIHelper::byteArrayToHexStr(buffer)));
buffer.clear();
return;
}
//如果数据过长则丢弃当前数据包,不然一旦产生了错误的数据会一直累积
if (size > 517) {
emit receiveError(portName, addr, QString("数据出错: %1").arg(QUIHelper::byteArrayToHexStr(buffer)));
buffer.clear();
return;
}
//后面的数据长度必须大于等于长度数据位表示的长度
if ((cmd == 0x03 || cmd == 0x04 || cmd == 0x06) && size < len + 5) {
emit receiveError(portName, addr, QString("数据不全,等待完整数据再解析: %1").arg(QUIHelper::byteArrayToHexStr(buffer)));
return;
}
//放在这里发出去数据是准确的完整的
emit receiveData(portName, addr, buffer);
//过滤不存在的地址,防止索引越界
int index = addrs.indexOf(addr);
if (index < 0) {
emit receiveError(portName, addr, "地址出错: 当前地址不在设定的地址集合中");
buffer.clear();
return;
}
//来过消息的设备,立马更新最后的消息时间,以及判断设备上线
times[index] = QDateTime::currentDateTime();
if (!onlines.at(index)) {
onlines[index] = true;
emit receiveOnline(portName, addr, true);
emit receiveInfo(portName, addr, "设备上线");
}
//根据不同的cmd+不同的命令类型,取出对应的数据内容
if (cmd == 0x03) {
QString info;
if (currentType == "查询浓度值") {
QList values;
//每个探测器状态1个寄存器=2字节
for (int i = 3; i < size - 2; i = i + 2) {
values << (float)QUIHelper::byteToUShort(buffer.mid(i, 2));
}
QStringList list;
foreach (quint16 value, values) {
list << QString::number(value);
}
info = QString("%1返回: %2").arg(currentType).arg(list.join(" "));
emit receiveValue(portName, addr, values);
}
//发送对应的文字解析
if (!info.isEmpty()) {
emit receiveInfo(portName, addr, info);
}
} else if (cmd == 0x04) {
} else if (cmd == 0x06) {
}
//重新赋值
buffer.clear();
}
留言与评论(共有 0 条评论) “” |