通过nport串口服务器读取Modbus协议设备信息

1、功能需求

  需要开发一套接口,在 Linux 操作系统上,通过 moxa nport 串口服务器使用 Modbus 标准协议获取节点设备的数据信息。
  
  硬件设备:

  • MOXA NPort 5130 串口服务器
  • 建大仁科温湿度变送器 485 型

2、串口服务器配置

  使用 NPort Administrator 软件将串口服务器设置为 TCP Server 模式,配置 IP 地址和端口号。


通过nport串口服务器读取Modbus协议设备信息_第1张图片

  
  将串口服务器的串口波特率设置为4800kbps(温湿度变送器默认值)。

3、获取温湿度数据

  温湿度变送器官方说明手册:温湿度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;
}

  数据读取完毕后,断开与串口服务器的连接。
  
  通过调用以上端口,可以从温湿度变送器中读取需要的温湿度数据。测试结果如下:


通过nport串口服务器读取Modbus协议设备信息_第2张图片

你可能感兴趣的:(Linux)