需要开发一套接口,在 Linux 操作系统上,通过 moxa nport 串口服务器使用 Modbus 标准协议获取节点设备的数据信息。
硬件设备:
使用 NPort Administrator 软件将串口服务器设置为 TCP Server 模式,配置 IP 地址和端口号。
温湿度变送器官方说明手册:温湿度485带按键型说明书。
1. 连接串口服务器
int ModbusTcp::init(char *addr, int port)
{
/*检查参数*/
if (port <= 0 || port > 65535) {
cout << "Illegal parameters..." << endl;
return -2;
}
/*创建Socket*/
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockfd < 0) {
perror("socket()");
return -1;
}
/*与目标服务器建立连接*/
struct sockaddr_in raddr;
raddr.sin_family = AF_INET;
raddr.sin_port = htons(port);
if (inet_pton(AF_INET, addr, &raddr.sin_addr) != 1) {
cout << "Illegal parameters..." << endl;
return -2;
}
if (connect(sockfd, (struct sockaddr *)&raddr, sizeof(raddr)) <0) {
perror("connect()");
return -1;
}
return 0;
}
2. 发送采集数据命令
int ModbusTcp::sendCommand(unsigned char id, char *buf, int len)
{
if (NULL == buf) {
unsigned char msg[12];
/*报文信息*/
msg[0] = id; //从机id
msg[1] = 3; //功能码
msg[2] = 0x00; //寄存器地址
msg[3] = 0x00;
msg[4] = 0; //地址的长度
msg[5] = 2;
msg[6] = 0xC4;
msg[7] = 0x0B;
crc_16(msg, msg + 6, 6);
if (send(sockfd, msg, 8, 0) < 0) {
perror("send()");
return -1;
}
}
return 0;
}
读取指定 ID 的温湿度数据,参数 buf 为 NULL 表示读取温湿度数据,读取温湿度时不需要传入命令数据。(经询问设备厂家技术支持,除读取温湿度数据外,不支持其他命令)。
通过 Socket 发送报文数据,Modbus RTU 报文格式如下:
地址码 | 功能码 | 寄存器地址 | 寄存器数量 | 数据长度 | 正文 | CRC校验 |
---|---|---|---|---|---|---|
1Byte | 1Byte | 2Bytes | 2Bytes | 1Byte | - | 2Bytes |
其中 crc_16() 为 CRC 校验码计算函数,代码如下:
void crc_16(unsigned char *array, unsigned char *rcvbuf, unsigned int len)
{
unsigned int i, j, crc;
crc = 0xFFFF;
if (len <= 0) {
crc = 0;
}
else {
len--;
for (i = 0; i <= len; i++) {
crc = crc ^ (unsigned int)(array[i]);
for (j = 0; j <= 7; j++) {
if ((crc & 1) != 0)
crc = (crc >> 1) ^ 0xA001;
else
crc = crc >> 1;
}
}
}
rcvbuf[0] = (crc & 0x00ff);
rcvbuf[1] = (crc & 0xff00) >> 8;
}
3. 接收采集数据
int ModbusTcp::readResponse(char *buf, int size)
{
unsigned char msg[256];
int len, i;
len = recv(sockfd, msg, 256, 0);
if (len == -1) {
cout << "Read response error..." << endl;
return -1;
}
if (size < msg[2]) {
cout << "Illegal parameters..." << endl;
return -2;
}
for (i = 0; i < msg[2]; i++)
buf[i] = msg[i + 3];
return msg[2];
}
通过 Socket 接收节点设备回复的数据,并保存在 buf 中。接收的温湿度数据为 4 个字节,前两个字节为湿度,后两个字节为温度,对应的值除以 10 得到温湿度的值。需注意负数的值为补码形式。
4. 断开与串口服务器的连接
int ModbusTcp::exit()
{
close(sockfd);
return 0;
}
数据读取完毕后,断开与串口服务器的连接。
通过调用以上端口,可以从温湿度变送器中读取需要的温湿度数据。测试结果如下: