Qtmodbus使⽤详解
⽬录
⼀、Modbus协议通信过程
Modbus能实现的功能较多,理解了如下2个操作,基本算掌握了Modbus 80%的使⽤了。在此基础上,能很快扩展到其他功能使⽤上。
这个功能的⽬的是:实现主机对从机 寄存器 的写⼊操作。 注意:是 主机 对 从机
说明:假如从机地址是 1,那么单⽚机接收到这串数据,根据CRC16进⾏校验判断数据是否正确,如果数据⽆误,就改变⾃⼰寄存器的值。 成都江汉路然后从机原封不动返回这句话,告诉主机通讯成功
*****下⾯⽤ 串⼝调试助⼿XCOM V2.0作为主机,Modbus Slave软件作为从机 ,通过串⼝数据监视软件AccessPort 捕获通讯中的数据,过程如下: 如下图所⽰,发送数据01 06 00 04 00 07 89 C9,接收到从机返回数据01 06 00 04 00 07 89 C9。说明通讯成功。
从串⼝数据监视软件AccessPort⾥也可以看出,如下图中红⾊框中所⽰,
对主机⽽⾔,发送01 06 00 04 00 07 89 C9后,接收了01 06 00 04 00 07 89 C9;
对从机⽽⾔,接收01 06 00 04 00 07 89 C9后,发送了01 06 00 04 00 07 89 C9。
1.2 主机对从机读数据操作(0x03)
这个功能的⽬的是:实现主机对从机 寄存器 的值的读操作。
注意:是 主机 对 从机
说明:假如从机地址是 1,那么单⽚机接收到这串数据,根据CRC16进⾏校验判断数据是否正确,如果数据⽆误,就发送相应的寄存器的值给主机
注意:这⾥的数据字节个数,在主机下发数据那⾥可以变更,单位是不同的——对主机端,⼀个数据个数对应从机端两个字节的数据。
*****下⾯⽤ 串⼝调试助⼿XCOM V2.0作为主机,Modbus Slave软件作为从机 ,通过串⼝数据监视软件AccessPort 捕获通讯中的数据,过程如下:
湖南同志
如下图所⽰,串⼝调试助⼿作为主机发送01 03 00 00 00 0A C5 CD,Modbus Slave作为从机,接收到主机的读信息后,发送01 03 14 78 67 00 00 00 05 00 00 00 00 00 00 00 06 00 00 00 00 00 08 80 AC作为回应。
主机端要求从从机0x01的寄存器0x0000开始读取10个数据;从机端接收到命令后,从寄存器0x0000,读取10个数据共20个字节,发送给主机。
从串⼝数据监视软件AccessPort⾥也可以看出,如下图中红⾊框中所⽰,
对主机⽽⾔,发送01 03 00 00 00 0A C5 CD后,接收了01 03 14 78 67 00 00 00 05 00 00 00 00 00 00 00 06 00 00 00 00 00 08 80 AC;
对从机⽽⾔,接收01 03 00 00 00 0A C5 CD后,发送了01 03 14 78 67 00 00 00 05 00 00 00 00 00 00 00 06 00 00 00 00 00 08 80 AC。
1.3 Modbus的CRC校验
Modbus的CRC校验使⽤的是CRC16,输出两个字节校验结果。这个过程了解即可,Qt⾃带算CRC的
算法。
CRC16校验的查表法 C++算法如下:
//CRC16校验算法系数表
uchar auchCRCHi[]=
{
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
赵总理0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
三士道0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40
};
uchar auchCRCLo[] =
{
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE,
0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7
A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, 0x40
};
//查表法:Modbus的16位CRC校验
uint ModbusTool::N_CRC16(uchar *updata,uint len)
{
uchar uchCRCHi=0xff;
uchar uchCRCLo=0xff;
uint uindex;
浦东实践的现实意义
while(len–)
{
uindex=uchCRCHi^*updata++;
uchCRCHi=uchCRCLo^auchCRCHi[uindex];
uchCRCLo=auchCRCLo[uindex];
}
return (uchCRCHi<<8|uchCRCLo);
}
⼆、在Qt中使⽤QModbus读写数据
我的软件环境作为参考,win7,win10下都可以。
2.1 部署准备——头⽂件中(.h)
天然气工业投稿需要包含如下头⽂件和QModbus类,⾄于定义Modbus对象,可以在头⽂件中,也可以在cpp中。
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <QModbusDataUnit>
class QModbusClient;
class QModbusReply;
//类中定义,我的类名叫ModbusTool
private:
QModbusClient *modbustoolDevice;//Modbus对象
private slots:
void readReady();//读下位机寄存器数据回调函数
public:
void write2client(unsigned int regStartAddr,unsigned int number);//上位机向下位机的某个寄存器写⼊数据void readfromclient(unsigned int startAddress,int number);//从指定下位机寄存器处读取数据
2.2 部署准备——cpp⽂件中
定义modbus串⼝的打开和关闭函数
//当然,相应的.cpp和.h⽂件需要对应起来哈,别傻傻的不同的.h和.cpp中写⼊代码了