基于ARM开发,对接modbus-rtu设备读取数据
modbus说明
Modbus协议有三类,分别是:Modbus-RTU、Modbus-ASCII、Modbus-TCP。一般来说,一个设备只有其中的一种协议,而且Modbus规定,Modbus-RTU是设备必须支持的协议,也是默认选项。所以大多数设备都采用了Modbus-RTU协议通信。本次就拿modbus-rtu设备来读取下。
读取命令
地址 | 功能码 | 读取寄存器Hi | 读取寄存器Lo | 读取长度Hi | 读取数据长度Lo | 校验CRC16 Hi | 校验CRC16 Lo |
---|---|---|---|---|---|---|---|
01 | 03 | 00 | 00 | 00 | 02 | C4 | 0B |
反馈命令
地址 | 功能码 | 数据长度 | 寄存器内容数据1Hi | 寄存器内容数据1Lo | 寄存器内容数据2Hi | 寄存器内容数据2Lo | 校验CRC16 Hi | 校验CRC16 Lo |
---|---|---|---|---|---|---|---|---|
01 | 03 | 04 | 00 | EA | 01 | C8 | BD | C1 |
功能码说明
以下模拟温湿度设备报文数据
温度 寄存器 0000 系数0.1
湿度 寄存器 0001 系数0.1
[2024-03-20 08:35:11.883]# SEND HEX> 01 03 00 00 00 02 C4 0B
[2024-03-20 08:35:11.889]# RECV HEX> 01 03 04 00 EA 01 C8 DB C1
温度(0000)-> 00 EA --> 234 * 0.1(系数) = 23.4
湿度(0001)-> 01 C8 --> 456 * 0.1(系数) = 45.6
#include "../CommunicationLibrary/CommunicationLibrary.h"
void NeInitNetCommLib()
{
#ifdef WIN32
WSADATA wd;
WSAStartup(MAKEWORD(2, 2), &wd);
#else
signal(SIGPIPE, SIG_IGN);
signal(SIGABRT, SIG_IGN);
signal(SIGFPE, SIG_IGN);
signal(SIGILL, SIG_IGN);
signal(SIGSEGV, SIG_IGN);
signal(SIGTERM, SIG_IGN);
#endif
}
//CRC校验
unsigned short CRC16(unsigned char *Msg, unsigned short len)
{
unsigned short CRC = 0xffff;
unsigned short i, temp;
while (len--)
{
CRC = CRC ^ (*Msg++);
for (i = 0; i < 8; i++)
{
if (CRC & 0x0001)
CRC = (CRC >> 1) ^ 0xa001;
else
CRC >>= 1;
}
}
temp = CRC & 0xff;
CRC = ((CRC >> 8) & 0xff) + (temp << 8);
return(CRC);
}
void printf_hex(BYTE * buf, const int len) {
for (int i = 0; i < len; i++) {
printf("%02X ", buf[i]);
}
printf("\n");
}
void modbus_wsd(CommunicationLibrary::SocketTcpClient * m_tcp_cli) {
BYTE nSendBuf[10] = { 0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00 };
BYTE Frame[256] = { 0 };
unsigned short CRC;
int nUnitNo = 1;
int nRecve = 0;
int nSend = 8; //modbus tcp nsend=12; modbus rtu nsend=8;
nSendBuf[0] = (BYTE)nUnitNo;//设备地址
CRC = CRC16(nSendBuf, 6); // CRC验证
nSendBuf[6] = (BYTE)((CRC >> 8) & 0x00FF); // 高位在前
nSendBuf[7] = (BYTE)(CRC & 0x00FF); // 低位在后
nRecve = nSendBuf[5] * 2 + 5; //一个寄存器 数据接收2bye
printf_hex(nSendBuf, 8);
int len = CommunicationLibrary::send_data(m_tcp_cli, (const char *)nSendBuf, nSend, CommunicationLibrary::TCPCLIENT);
if (len == nSend) {
if (CommunicationLibrary::select_data(m_tcp_cli, CommunicationLibrary::TCPCLIENT)) {
int recve_len = CommunicationLibrary::recv_data(m_tcp_cli, (char *)Frame, nRecve, CommunicationLibrary::TCPCLIENT);
printf_hex(Frame, recve_len);
if (recve_len == nRecve) { //解析温湿度数据
unsigned short temp = 0, temp1 = 0;
temp = Frame[3];
temp = (temp << 8) + Frame[3 + 1];
temp1 = Frame[5];
temp1 = (temp1 << 8) + Frame[5 + 1];
printf("温度:%0.2f\n", (float)temp / 10);
printf("湿度:%0.2f\n", (float)temp1 / 10);
}
}
}
}
int main()
{
NeInitNetCommLib();
CommunicationLibrary::SocketTcpClient * m_tcp_cli = new CommunicationLibrary::SocketTcpClient("127.0.0.1", 1001, 5, 3);
m_tcp_cli->connect_ser();
modbus_wsd(m_tcp_cli);
getchar();
delete m_tcp_cli;
}