跳转至

ModbusTcp主站接口说明

一、使用示例

创建一条ModbusTcp主站通讯通道,在通道上创建1个站点,循环获取站点的值或写入站点的值

MTCP主站

#include "modbus_host/modbustcp_host_ch.h"
#include "modbus_host/modbus_host_dev.h"
#include <stdio.h>
#include <unistd.h>

void read_test(const char *name, ModbusHostDev *pdev, int code, int startaddr, int size)
{
    uint16_t data[1024] = { 0 };
    printf("%s, code=%d, addr=[%04X]%d, size=%d--------------------------------------------\r\n",
        name, code, startaddr, startaddr, size);
    pdev->GetCycleReadDataBlookValue((ModbusHost::ReadCode_E)code, startaddr, data, size);
    for(int i = 0; i < size; i++) {
        printf("%s, code=%d, addr=[%04X]%d, value=[%04X]%d\r\n",
            name, code, startaddr+i, startaddr+i, data[i], data[i]);
    }
}

int main(int argc, char *argv[])
{
    // 创建通道
    ModbusTcpHostCh *pch = new ModbusTcpHostCh("192.168.100.204", 502);
    pch->SetBitSingleMaxPoint(4);
    pch->SetRegSingleMaxPoint(6);
    printf("创建通讯通道 [%08X]\r\n", pch);
    // 创建设备1-PCS
    ModbusHostDev *pdev1 = new ModbusHostDev(pch, 1);
    pdev1->AddCycleReadDataBlock(ModbusHost::kReadCodeBits, 0x0000, 10);
    pdev1->AddCycleReadDataBlock(ModbusHost::kReadCodeBits, 0x1000, 10, 5000);
    pdev1->AddCycleReadDataBlock(ModbusHost::kReadCodeInputBits, 0x2000, 10, 5000);
    pdev1->AddCycleReadDataBlock(ModbusHost::kReadCodeHoldRegs, 0x3000, 10, 5000);
    pdev1->AddCycleReadDataBlock(ModbusHost::kReadCodeInputRegs, 0x4000, 12, 5000);
    printf("创建设备1 [%08X]\r\n", pdev1);
    // 启动通道
    pch->Run();
    printf("启动通讯通道\r\n");

    int bits[1024] = { 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 };
    int regs[1024] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
    int ret_write = 0;

    // 等待
    for(int i = 0; i < 1000; i++) {
        sleep(10);
        uint16_t data[1024];
        // 设备1读取测试 功能码01,起始地址0x0000,点数10
        int code = ModbusHost::kReadCodeBits;
        int startaddr = 0x0000;
        int size = 10;
        read_test("pdev1", pdev1, code, startaddr, size);

        // 设备1读取测试 功能码01,起始地址0x1000,点数10
        code = ModbusHost::kReadCodeBits;
        startaddr = 0x1000;
        size = 10;
        read_test("pdev1", pdev1, code, startaddr, size);

        // 设备1读取测试 功能码02,起始地址0x2000,点数10
        code = ModbusHost::kReadCodeInputBits;
        startaddr = 0x2000;
        size = 10;
        read_test("pdev1", pdev1, code, startaddr, size);

        // 设备1读取测试 功能码03,起始地址0x3000,点数10
        code = ModbusHost::kReadCodeHoldRegs;
        startaddr = 0x3000;
        size = 10;
        read_test("pdev1", pdev1, code, startaddr, size);

        // 设备1读取测试 功能码04,起始地址0x4000,点数12
        code = ModbusHost::kReadCodeInputRegs;
        startaddr = 0x4000;
        size = 12;
        read_test("pdev1", pdev1, code, startaddr, size);
        printf("[%s][%d][%s] i=%d\r\n", __FILE__, __LINE__, __FUNCTION__, i);

        // 设备1写入测试 功能码15,起始地址0x0000,点数10
        ret_write = pdev1->AddWriteDataBlock(ModbusHost::kWriteCodeBits, 0x0000, bits, 10);
        printf("[%s][%d][%s] ret_write=%d\r\n", __FILE__, __LINE__, __FUNCTION__, ret_write);

        // 设备1写入测试 功能码16,起始地址0x3000,点数10
        ret_write = pdev1->AddWriteDataBlock(ModbusHost::kWriteCodeHoldRegs, 0x3000, regs, 10);
        printf("[%s][%d][%s] ret_write=%d\r\n", __FILE__, __LINE__, __FUNCTION__, ret_write);

        // 获取设备1和设备2的超时状态
        printf("[%s][%d][%s] pdev1->GetTimeoutStatus()=%d\r\n",
            __FILE__, __LINE__, __FUNCTION__, pdev1->GetTimeoutStatus());
    }

    return 1;
}

二、ModbusHostCh类

ModbusHostCh类为ModbusRtuHostCh类、ModbusTcpHostCh类的基类,提供Modbus主站通道的通用属性

1. 构造函数

/**
 * @brief 构造函数
 *
 * @param
 */
ModbusHostCh();

2. 析构函数

/**
 * @brief 析构函数
 */
~ModbusHostCh();

3. 获取数据区指针

获取ModbusHost通道的数据区指针

/**
 * @brief 获取数据区指针
 *
 * 获取ModbusHost通道的数据区指针
 *
 * @param 无
 *
 * @return 数据区的指针
 */
ModbusHostData *GetDataArea();
  • 参数
  • 无;
  • 返回值
  • 数据区指针;

4. 获取通讯超时状态

/**
 * @brief 获取通讯超时状态
 *
 * @param slaveid 站地址
 *
 * @return 是否超时:1-超时;0-未超时;-1-站地址错误;
 */
 int GetTimeoutStatus(int slaveid);
  • 参数
  • slaveid 站地址;
  • 返回值
  • 是否超时:1-超时;0-未超时;-1-站地址错误;

5. 设置通讯超时时间

/**
 * @brief 设置通讯超时时间
 * 
 * @param sec  超时时间的秒数;
 * @param usec 超时时间的微秒数;
 * 
 * @return 无
 */
void SetResponseTimeout(long sec, long usec);
  • 参数
  • sec:超时时间的秒数;
  • usec:超时时间的微秒数;
  • 返回值

6. 设置Modbus通讯异常的判定次数

modbus帧通讯超时次数超过此值时,认为Modbus通讯异常

/**
 * @brief 设置Modbus通讯异常的判定次数
 *
 * Modbus帧通讯超时次数超过此值时,认为Modbus通讯异常
 *
 * @param count 次数;
 * 
 * @return 无
 */
void SetTimeoutMaxCount(uint32_t count);
  • 参数
  • count:次数;
  • 返回值

7. 轮询帧时间间隔 毫秒

/**
 * @brief 轮询帧时间间隔
 *
 * 每2帧通讯报文的之间的间隔时间
 *
 * @param ms 间隔时间,毫秒;
 * 
 * @return 无
 */
void SetPollFrameIntervalMs(uint32_t ms);
  • 参数
  • ms:每2帧通讯报文的间隔时间,毫秒;
  • 返回值

8. 轮询总时间间隔 毫秒

/**
 * @brief 轮询总时间间隔
 *
 * 所有帧通讯报文之间的间隔时间,即所有报文轮训一遍后等待一定时间后再进行下次轮训
 *
 * @param ms 所有帧通讯报文的间隔时间,毫秒;
 * 
 * @return 无
 */
void SetPollTotalIntervalMs(uint32_t ms);
  • 参数
  • ms:所有帧通讯报文的间隔时间,毫秒;
  • 返回值

9. 设置是否打印报文

/**
 * @brief 设置是否打印报文(通过printf输出到命令行中)
 * 
 * @param debug 是否开启,0-关闭;1-开启;
 * 
 * @return 无
 */
void SetPollTotalIntervalMs(int debug);
  • 参数
  • debug :是否开启,0-关闭;1-开启;
  • 返回值

10. 设置线圈单帧最大读点个数

/**
 * @brief 线圈单帧最大读点个数
 *
 * @param point 点数
 *
 * @return 无
 */
void SetBitSingleMaxPoint(int point);

11. 设置寄存器单帧最大读点个数

/**
 * @brief 寄存器单帧最大读点个数
 *
 * @param point 点数
 *
 * @return 无
 */
void SetRegSingleMaxPoint(int point);

12. 设置收发报文内容回调函数

/**
 * @brief 设置收发报文内容回调函数
 *
 * @param *s_callback 发送报文回调函数(参数,报文内容,报文长度);
 * @param *r_callback 接收报文回调函数(参数,报文内容,报文长度);
 * @param arg         回调参数;
 * 
 * @return 无
 */
void set_MessageCallback(
        void (*s_callback)(void *, const uint8_t *, int),
        void (*r_callback)(void *, const uint8_t *, int),
        void *arg = NULL);
  • 参数
  • *s_callback:发送报文回调函数(参数,报文内容,报文长度);
  • *r_callback:接收报文回调函数(参数,报文内容,报文长度);
  • arg:回调参数;
  • 返回值

13. 设置收发报文内容回调使能

/**
 * @brief 设置收发报文内容回调使能
 *
 * @param en 是否使能:0-未使能;1-使能;
 * 
 * @return 无
 */
void set_MessagrCallbackEn(int en);
  • 参数
  • en:是否使能:0-未使能;1-使能;
  • 返回值

14. 获取指定设备地址的通讯计数信息

/**
 * @brief 获取指定设备地址的通讯计数信息
 *
 * @param slave                 指定的Modbus设备站地址,1~255;
 * @param *total_recvok_count   输出参数,总接收成功(通讯正常)的帧数量
 * @param *total_recvfail_count 输出参数,总接收失败(通讯异常)的帧数量
 * @param *curr_timout_count    输出参数,当前接收成功(通讯正常)的帧数量
 * 
 * @return 是否获取成功:1-获取成功;-1-获取失败;
 */
int get_CommunicatCount(int slave,
        uint64_t *total_recvok_count, uint64_t *total_recvfail_count,
        uint64_t *curr_timout_count = NULL);
  • 参数
  • slave:指定的Modbus设备站地址,1~255;
  • *total_recvok_count:输出参数,总接收成功(通讯正常)的帧数量
  • *total_recvfail_count:输出参数,总接收失败(通讯异常)的帧数量
  • *curr_timout_count:输出参数,当前接收成功(通讯正常)的帧数量
  • 返回值
  • 是否获取成功:1-获取成功;-1-获取失败;

三、ModbusTcpHostCh类

ModbusTcpHostCh类,继承自ModbusHostCh类,用于创建ModbusTcp主站通讯通道

1. 构造函数

/**
 * @brief 构造函数
 *
 * @param *ipaddr IP地址,例"192.168.1.123";
 * @param port    端口号,一般为502;
 */
ModbusTcpHostCh(const char *ipaddr, int port = 502);
  • 参数
  • *ipaddr:IP地址,例"192.168.1.123";
  • port:端口号,一般为502;
  • 返回值
  • 返回值

2. 析构函数

/**
 * @brief 析构函数
 */
~ModbusTcpHostCh();

3. 启动函数

/**
 * @brief 启动函数
 *
 * 启动ModbusTcp主站读取数据
 *
 * @param 无
 *
 * @return 无
 */
void Run();
  • 参数
  • 返回值

4. 设置回调函数-重连回调

/**
 * @brief 设置回调函数-重连回调
 *
 * 当ModbusTcp发送连接断开自动进行重连时,会触发次回调函数
 *
 * @param fun 回调函数名;
 * @param arg 回调函数;
 * 
 * @return 无
 */
void SetFunReconnectCallback(fpReconnect_Callback fun, void *arg = NULL);

// 重连回调函数(参数,目标IP,目标端口,总重连次数,总重连成功次数,总重连失败次数, 当前失败次数)
typedef void (*fpReconnect_Callback)(void *arg,
    const char* ip, const int port, const int rcount, const int rsconut, const int rfcount, const int crfcount);
  • 参数
  • fun:回调函数名;
  • arg:回调参数;
  • 返回值

四、ModbusHostDev类

Modbus主站模式下的站点类

1. 构造函数

构造函数,用于创建主站模式下的站点

/**
 * @brief 构造函数
 *
 * @param pch ModbusHost通道
 * @param slave 站地址
 */
ModbusHostDev(ModbusHostCh *pch, int slave = 1);
  • 参数

  • pch: ModbusHost通道

  • slave:站地址;
  • 返回值

  • 返回值

2. 析构函数

/**
 * @brief 析构函数
 */
~ModbusHostDev();

3. 获取站点ID

/**
 * @brief 获取站点ID(站地址)
 *
 * @return 站地址
 */
int GetSlaveId();
  • 参数
  • 无;
  • 返回值
  • 站地址

4. 添加回读数据块

/**
 * @brief 添加循环回读数据块
 *
 * @param code      功能码;
 * @param startaddr 点的起始地址,一般为0~65535;
 * @param nb        点的个数;
 * @param cycle     该数据块通讯周期
 *
 * @return 是否添加成功:
 *          1 :添加成功;
 *          -1:站地址错误;
 *          -2:添加失败(数据越界);
 *          -3:添加失败(已存在冲突的数据块);
 */
int AddCycleReadDataBlock(ModbusHost::ReadCode_E code, int startaddr, int nb, int cycle = 1000);
  • 参数

  • code 功能码;

  • addr 点的起始地址,一般为0~65535;
  • nb 点的个数;
  • cycle 该数据块通讯周期
  • 返回值

  • 是否添加成功:1-添加成功;

    -1:站地址错误;
    
    -2:添加失败(数据越界);
    
    -3:添加失败(已存在冲突的数据块);
    

5. 获取回读数据区多个连续数据点的值

/**
 * @brief 获取回读数据区多个连续数据点的值
 *
 * 获取指定数据类型、多个连续点地址的值
 *
 * @param code      功能码;
 * @param startaddr 点的起始地址,一般为0~65535;
 * @param *point    返回参数,点的值;
 * @param nb        点的数量;
 *
 * @return 是否获取成功:1-获取成功;-1-返回参数为空;-2-未找到数据块;
 */
int GetCycleReadDataBlookValue(ModbusHost::ReadCode_E code, int startaddr, uint16_t *point, int nb = 1);
  • 参数

  • code 功能码;

  • addr 点的起始地址,一般为0~65535;
  • *value 返回参数,点的值;
  • nb 点的个数;
  • 返回值

  • 是否获取成功:1-获取成功;-1-返回参数为空;-2-未找到数据块;

6. 添加写数据块

/**
 * @brief 添加写数据块
 *
 * @param code      功能码;
 * @param startaddr 点的起始地址,一般为0~65535;
 * @param *value    点的值;
 * @param nb        点的个数;
 *
 * @return 是否添加成功:
 *          1 :添加成功;
 *          -1:站地址错误;
 *          -2:添加失败(数据越界);
 */
int AddWriteDataBlock(ModbusHost::WriteCode_E code, int startaddr, int *value, int nb = 1);
  • 参数

  • code 功能码;

  • startaddr 点的起始地址,一般为0~65535;

  • *value 点的值;
  • nb 点的个数;
  • 返回值

  • 是否添加成功:

    • 1 :添加成功;
    • -1:站地址错误;
    • -2:添加失败(数据越界);

7. 获取通讯超时状态

/**
 * @brief 获取通讯超时状态
 *
 * @return 通讯状态,0-未超时;1-超时;
 */
int GetCommTimeOutFlag();
  • 参数
  • 返回值
  • 通讯状态,0-未超时;1-超时;