zoukankan      html  css  js  c++  java
  • Qt-Libmodbus

    一、介绍

      libmodbus是一个快速且可移植的Modbus库,支持传统的RS-232、RS-422、RS-485和以太网设备。

      A Modbus library for Linux, Mac OS X, FreeBSD, QNX and Win32.

      libmodbus is a free software library to send/receive data according to the Modbus protocol. This library is written in C and supports RTU (serial) and TCP (Ethernet) communications.The license of libmodbus is LGPL v2.1+ and the licence of programs in the tests directory is BSD 3-clause.

    二、下载及安装

      下载地址:https://libmodbus.org/

       安装:

    1 //进入解压目录
    2 cd libmodbus-3.1.6
    3 //配置编译选项(以ARM为例,--build为系统构架 --host为编译对应系统工具链,--prefix为输出目录,选项均是可选的)
    4 ./configure --build=i686 --host=arm-linux --enable-static --prefix=[install path]/
    5 //编译安装
    6 make && make install

    三、示例

      1、RTU slave

      笔者在使用的时候发现串口接收函数在未接收到数据时会阻塞,如果同时使用TCP通讯建议放在两个不同的线程中。使用的时候只需创建一个此线程的对象,初始化完成后打开线程即可。

      rtucomthread.cpp文件的内容:

      1 #include "rtucommthread.h"
      2 
      3 #include <sys/ioctl.h>
      4 #include <unistd.h>
      5 #include <netinet/in.h>
      6 #include <arpa/inet.h>
      7 #include <fcntl.h>
      8 
      9 uint16_t data_buff[256] = {1};
     10 
     11 RtuCommThread::RtuCommThread(QObject *parent) :
     12     QThread(parent),
     13     ctx_rtu(NULL),
     14     mb_mapping(NULL)
     15 {
     16     Baud[0] = 115200;           //波特率
     17     Baud[1] = 19200;
     18     Baud[2] = 9600;
     19     Baud[3] = 4800;
     20     Baud[4] = 2400;
     21 
     22     Parity[0] = 'N';            //校验
     23     Parity[1] = 'O';
     24     Parity[2] = 'E';
     25 
     26     DataBits[0] = 7;            //数据位
     27     DataBits[1] = 8;
     28 
     29     StopBit[0] = 1;             //停止位
     30     StopBit[1] = 2;
     31 
     32     /* 分配寄存器位的数组大小为125 */
     33     mb_mapping = modbus_mapping_new(0, 0, MODBUS_MAX_READ_REGISTERS, 0);
     34 }
     35 
     36 RtuCommThread::~RtuCommThread()
     37 {
     38     /* 释放分配的数组单元 */
     39     modbus_mapping_free(mb_mapping);
     40 
     41     modbus_close(ctx_rtu);
     42     modbus_free(ctx_rtu);
     43     mb_mapping = NULL;
     44     ctx_rtu = NULL;
     45 }
     46 
     47 /*******************************************************************************************
     48 * 函数名称:run()
     49 * 功能描述:线程执行函数
     50 * 输入参数:无
     51 * 返回参数:无
     52 * 创建者:
     53 * 创建日期:2020.3.23
     54 *******************************************************************************************/
     55 void RtuCommThread::run()
     56 {
     57     int rc;
     58     int offset;
     59     uint16_t data;
     60 
     61     while(1)
     62     {
     63         /* 接收请求 */
     64         rc = modbus_receive(ctx_rtu, query);
     65         if(rc == -1)
     66         {
     67             msleep(100);
     68             continue;
     69         }
     70         /* 得到头文件的长度 */
     71         offset = modbus_get_header_length(ctx_rtu);
     72         switch(query[offset])
     73         {
     74             case 0x03:      /* 读保持寄存器 */
     75                 /* 如果接收到请求,将要发送的数据放入mb_mapping寄存器表中*/
     76                 for(quint8 i = 0; i < 10; i++)
     77                 {
     78                     mb_mapping->tab_registers[i] = data_buff[i];
     79                 }
     80                 /* 响应 */
     81                 modbus_reply(ctx_rtu, query, rc, mb_mapping);
     82                 break;
     83             case 0x06:      /* 写单个寄存器 */
     84                 /* 响应 */
     85                 modbus_reply(ctx_rtu, query, rc, mb_mapping);
     86                 data = mb_mapping->tab_registers[(query[offset + 1] << 8) + query[offset + 2]];
     87                 data_buff[(query[offset + 1] << 8) + query[offset + 2]] = data;
     88                 break;
     89             case 0x10:      /* 写多个寄存器 */
     90                 /* 响应 */
     91                 modbus_reply(ctx_rtu, query, rc, mb_mapping);
     92                 for(int i = 0; i < 10; i++)
     93                 {
     94                    data_buff[i] = mb_mapping->tab_registers[i];
     95                 }
     96                 break;
     97             default:
     98                 break;
     99         }
    100     }
    101 }
    102 
    103 /*******************************************************************************************
    104 * 函数名称:modbus_rtu_init()
    105 * 功能描述:modbus_rtu初始化函数
    106 * 输入参数:无
    107 * 返回参数:无
    108 * 创建者:
    109 * 创建日期:2020.3.23
    110 *******************************************************************************************/
    111 void RtuCommThread::modbus_rtu_init()
    112 {
    113     if(ctx_rtu != NULL)
    114     {
    115         modbus_close(ctx_rtu);
    116         modbus_free(ctx_rtu);
    117         ctx_rtu = NULL;
    118     }
    119     120     slave    = 1;
    121     baud     = Baud[0];
    122     parity   = Parity[0];
    123     data_bit = DataBits[0];
    124     stop_bit = StopBit[0];
    125 
    126 127 /* create a libmodbus context for RTU */ 128 ctx_rtu = modbus_new_rtu("/dev/ttySP2", baud, parity, data_bit, stop_bit); 129 /* set slave number in the context */ 130 modbus_set_slave(ctx_rtu, slave); 131 /* establish a Modbus connection */ 132 modbus_connect(ctx_rtu); 133 }

      rtucomthread.h文件中的内容:

     1 #ifndef RTUCOMMTHREAD_H
     2 #define RTUCOMMTHREAD_H
     3 
     4 #include <QThread>
     5 #include "libmodbus/include/modbus/modbus.h"
     6 
     7 class RtuCommThread : public QThread
     8 {
     9     Q_OBJECT
    10 public:
    11     explicit RtuCommThread(QObject *parent = 0);
    12     ~RtuCommThread();
    13 
    14 public:
    15     void modbus_rtu_init();
    16 
    17 private:
    18     modbus_t *ctx_rtu;
    19     int  Baud[5];
    20     char Parity[2];
    21     int  DataBits[2];
    22     int  StopBit[2];
    23 
    24     int  slave;         //设备地址
    25     int  baud;          //波特率
    26     char parity;        //校验
    27     int  data_bit;      //数据位
    28     int  stop_bit;      //停止位
    29 
    30     modbus_mapping_t *mb_mapping;
    31     uint8_t query[MODBUS_RTU_MAX_ADU_LENGTH];
    32 
    33     void run();
    34 
    35     
    36 signals:
    37     
    38 public slots:
    39     
    40 };
    41 
    42 #endif // RTUCOMMTHREAD_H

      2、TCP slave

      使用的时候只需创建一个此线程的对象,初始化完成后打开线程即可。

      支持断线重连。

      tcpcomthread.cpp文件中的内容:

      1 #include "tcpcommthread.h"
      2 
      3 #include <sys/ioctl.h>
      4 #include <unistd.h>
      5 #include <netinet/in.h>
      6 #include <arpa/inet.h>
      7 #include <fcntl.h>
      8 
      9 uint16_t data_buff[256] = {1};
     10 
     11 TcpCommThread::TcpCommThread(QObject *parent) :
     12     QThread(parent),
     13     ctx_tcp(NULL),
     14     server_socket(-1),
     15     client_Socket(-1)
     16 {
     17     tv.tv_sec = 0;
     18     tv.tv_usec = 1*1000*1000;
     19 
     20     /* 分配寄存器位的数组大小为125 */
     21     mb_mapping = modbus_mapping_new(0, 0, MODBUS_MAX_READ_REGISTERS, 0);
     22 }
     23 
     24 TcpCommThread::~TcpCommThread()
     25 {
     26     /* 释放分配的数组单元 */
     27     modbus_mapping_free(mb_mapping);
     28 
     29     modbus_close(ctx_tcp);
     30     modbus_free(ctx_tcp);
     31     mb_mapping = NULL;
     32     ctx_tcp = NULL;
     33 }
     34 
     35 /*******************************************************************************************
     36 * 函数名称:run()
     37 * 功能描述:线程执行函数
     38 * 输入参数:无
     39 * 返回参数:无
     40 * 创建者:
     41 * 创建日期:2020.3.23
     42 *******************************************************************************************/
     43 void TcpCommThread::run()
     44 {
     45     int rc;
     46     int offset;
     47     uint16_t data;
     48 
     49     while(1)
     50     {
     51         while(client_Socket == -1)
     52         {
     53             /* 清空refset */
     54             FD_ZERO(&refset);
     55             FD_ZERO(&wrfset);
     56             /* 将套节字加入refset中 */
     57             FD_SET(server_socket, &refset);
     58             FD_SET(server_socket, &wrfset);
     59             /* 从refset查找就绪态的fd,最后一个参数是阻塞时长 */
     60             rc = select(server_socket+1, &refset, &wrfset, NULL, &tv);
     61             if(rc < 0)
     62             {
     63                 /* select超时返回0, 错误返回-1,查询到fd的总数 */
     64                 continue;
     65             }
     66             if(rc > 0)
     67             {
     68                 /* 判断server_socket是否在读就绪态 */
     69                 if(FD_ISSET(server_socket, &refset) || FD_ISSET(server_socket, &wrfset))
     70                 {
     71                     /*accept a new connection on a TCP Modbus socket (IPv4)*/
     72                     client_Socket = modbus_tcp_accept(ctx_tcp, &server_socket);
     73                 }
     74             }
     75         }
     76 
     77         /* 接收请求 */
     78         rc = modbus_receive(ctx_tcp, query);
     79         if(rc == -1)
     80         {
     81             msleep(100);
     82             client_Socket = -1;
     83             continue;
     84         }
     85         /* 得到头文件的长度 */
     86         offset = modbus_get_header_length(ctx_tcp);
     87         switch(query[offset])
     88         {
     89             case 0x03:      /* 读保持寄存器 */
     90                 /* 如果接收到请求,将要发送的数据放入mb_mapping寄存器表中*/
     91                 for(quint8 i = 0; i < 10; i++)
     92                 {
     93                     mb_mapping->tab_registers[i] = data_buff[i];
     94                 }
     95                 /* 响应 */
     96                 modbus_reply(ctx_tcp, query, rc, mb_mapping);
     97                 break;
     98             case 0x06:      /* 写单个寄存器 */
     99                 /* 响应 */
    100                 modbus_reply(ctx_tcp, query, rc, mb_mapping);
    101                 data = mb_mapping->tab_registers[(query[offset + 1] << 8) + query[offset + 2]];
    102                 data_buff[(query[offset + 1] << 8) + query[offset + 2]] = data;
    103                 break;
    104             case 0x10:      /* 写多个寄存器 */
    105                 /* 响应 */
    106                 modbus_reply(ctx_tcp, query, rc, mb_mapping);
    107                 for(int i = 0; i < 10; i++)
    108                 {
    109                    data_buff[i] = mb_mapping->tab_registers[i];
    110                 }
    111                 break;
    112             default:
    113                 break;
    114         }
    115     }
    116 }
    117 
    118 /*******************************************************************************************
    119 * 函数名称:modbus_tcp_init()
    120 * 功能描述:modbus_tcp初始化
    121 * 输入参数:无
    122 * 返回参数:无
    123 * 创建者:
    124 * 创建日期:2020.3.23
    125 *******************************************************************************************/
    126 void TcpCommThread::modbus_tcp_init()
    127 {
    128     QString str = "wr ifconfig eth0 192.168.1.136";
    129 
    130     if(ctx_tcp != NULL)
    131     {
    132         if(server_socket != -1)
    133         {
    134             shutdown(server_socket, SHUT_RDWR);
    135         }
    136         modbus_close(ctx_tcp);
    137         modbus_free(ctx_tcp);
    138         ctx_tcp = NULL;
    139     }
    140 
    141     142     port     = 502;
    143     ip.sprintf("%d.%d.%d.%d",
    144                192,
    145                168,
    146                1,
    147                178);
    148 149 
    150     /* 设置CPU的IP地址 */
    151     str.sprintf("wr ifconfig eth0 %s",ip.toLatin1().data());
    152     system(str.toLatin1().data());
    153     sleep(1);
    154 
    155     /* To listen any addresses on port 502 */
    156     ctx_tcp = modbus_new_tcp(NULL, port);
    157     /* create and listen a TCP Modbus socket */
    158     server_socket = modbus_tcp_listen(ctx_tcp, MODBUS_TCP_CONNECT_MAX);
    159     client_Socket = -1;
    160 }

      tcpcomthread.h文件中的内容:

     1 #ifndef TCPCOMMTHREAD_H
     2 #define TCPCOMMTHREAD_H
     3 
     4 #include <QThread>
     5 #include "libmodbus/include/modbus/modbus.h"
     6 #include <sys/socket.h>
     7 
     8 class TcpCommThread : public QThread
     9 {
    10 #define MODBUS_TCP_CONNECT_MAX  1
    11 #define COMM_TYPE_PROFIBUS      0
    12 #define COMM_TYPE_MODBUS_TCP    1
    13 
    14     Q_OBJECT
    15 public:
    16     explicit TcpCommThread(QObject *parent = 0);
    17     ~TcpCommThread();
    18 
    19 public:
    20     void modbus_tcp_init();
    21 
    22 private:
    23     modbus_t *ctx_tcp;
    24     modbus_mapping_t *mb_mapping;
    25     uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];
    26     int server_socket;
    27     int client_Socket;
    28     fd_set refset;
    29     fd_set wrfset;
    30 
    31     struct timeval tv;
    32 
    33     QString ip;         //ip
    34     int     port;       //端口号
    35 
    36     void run();
    37     
    38 signals:
    39     
    40 public slots:
    41     
    42 };
    43 
    44 #endif // TCPCOMMTHREAD_H

    end

  • 相关阅读:
    ubuntu18.04安装ssh服务
    跳转
    【WinForm】—窗体之间传值的几种方式
    使用jQuery完成复选框的全选和全不选
    VS2015下载安装随笔记录
    关于c#数据类型,类型转换,变量,常量,转义符。
    浅谈表单同步提交和异步提交
    form表单提交和跳转
    2019年8月19日矩阵
    C# WinForm快捷键设置技巧
  • 原文地址:https://www.cnblogs.com/wenhao-Web/p/13230122.html
Copyright © 2011-2022 走看看