使用libmodbus库实现。GitHub - stephane/libmodbus: A Modbus library for Linux, Mac OS, FreeBSD and Windows
编译后得到:modbus.lib和modbus.dll
包含文件:
modbus.h
modbus-rtu.h
modbus-tcp.h
modbus-version.h
使用说明:
初始化与释放:
/*
以TCP的方式创建libmobus实例
char *ip:连接的IP地址
int port: 连接的IP端口
*/
modbus_t *modbus_new_tcp(const char *ip, int port);
/*
以串口的方式创建libmobus实例
onst char *device:连接的串口号,类似是这样'\\\\.\\COM10'
int baud: 波特率
char parity:奇偶校验
int data_bit:数据位
int stop_bit:停止位
*/
modbus_t *modbus_new_rtu(const char *device, int baud, char parity, int data_bit, int stop_bit);
/*
释放libmodbus实例,使用完libmodbus需要释放掉
modbus_t *ctx:libmodbus实例
*/
void modbus_free(modbus_t *ctx);
读取:
/*
读取线圈状态,可读取多个连续线圈的状态
modbus_t *ctx:Modbus实例
int addr: 线圈地址
int nb:读取线圈的个数
uint8_t *dest: 传出的状态值
*/
int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
/*
读取输入状态,可读取多个连续输入的状态
modbus_t *ctx:Modbus实例
int addr:输入地址
int nb:读取输入的个数
uint8_t *dest:传出的状态值
*/
int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
/*
读取输入寄存器的值,可读取多个连续输入输入寄存器
modbus_t *ctx:Modbus实例
int addr:输入地址
int nb:读取输入寄存器的个数
uint8_t *dest:传出的寄存器值
*/
int modbus_read_input_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
/*
读取保持寄存器的值,可读取多个连续输入保持寄存器
modbus_t *ctx:Modbus实例
int addr:输入地址
int nb:读取保持寄存器的个数
uint8_t *dest:传出的寄存器值
*/
int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
写入:
/*
写入单个线圈的状态
modbus_t *ctx:Modbus实例
int addr:线圈地址
int status:线圈状态
*/
int modbus_write_bit(modbus_t *ctx, int addr, int status);
/*
写入多个连续线圈的状态
modbus_t *ctx:Modbus实例
int addr:线圈地址
int nb:线圈个数
const uint8_t *src:多个线圈状态
*/
int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *src);
/*
写入单个寄存器
modbus_t *ctx:Modbus实例
int addr:寄存器地址
int value:寄存器的值
*/
int modbus_write_register(modbus_t *ctx, int addr, int value);
/*
写入多个连续寄存器
int addr:寄存器地址
int nb:寄存器的个数
const uint16_t *src:多个寄存器的值
*/
int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src);
float浮点数转换:
float modbus_get_float(const uint16_t *src);
void modbus_set_float(float f, uint16_t *dest)
模拟通信:使用Modbus Slave和Modbus Poll 序列号:5455415451475662
Modbus Poll是服务端
Modbus Slave是客户端
01:线圈状态 可用上文中modbus_read_bits读取状态数据。
03:保持寄存器状态 可用上文 modbus_read_registers读取数据。
代码实现:
通信功能不能对程序阻塞,所以需要通过创建线程来实现。
//ConnectModbus.h
#include "CameraControlDlg.h"
class ConnectModbus : public CCameraControlDlg
{
public:
ConnectModbus();
~ConnectModbus();
static DWORD WINAPI startClient(LPVOID lpParamter);
};
//ConnectModbus.cpp
#include "pch.h"
#include "ConnectModbus.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include <iostream>
#include "modbus/modbus.h"
using namespace std;
ConnectModbus::ConnectModbus()
{
}
ConnectModbus::~ConnectModbus()
{
}
DWORD __stdcall ConnectModbus::startClient(LPVOID lpParamter)
{
const char* ip_address = "127.0.0.1";
int MDport = 1234;
int address = 5;
int n = 1;
uint16_t tab_reg[1] = { 0 };
uint8_t M1[1] = { 0 };
// 创建libmobus TCP实例
modbus_t* pmbs_ctx = modbus_new_tcp(ip_address, MDport);
modbus_set_debug(pmbs_ctx, 1);
modbus_set_slave(pmbs_ctx, 1); // 设置从机地址
// 连接设备
int nRet = modbus_connect(pmbs_ctx);
// 连接失败
if (-1 == nRet)
{
printf("connect failed:%s\n", modbus_strerror(errno));
modbus_free(pmbs_ctx);
return -1;
}
// 设置Modbus超时时间
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 1000000; //设置modbus超时时间为1000毫秒
modbus_set_response_timeout(pmbs_ctx, tv.tv_sec, tv.tv_usec);
while (true)
{
printf("--------------------------------------------------\n");
// 读取保持寄存器的值,起始地址为address,寄存器个数为n,读取到tab_reg数组中
//int regs = modbus_read_registers(pmbs_ctx, address, n, tab_reg);
//读取线圈状态
int regs = modbus_read_bits(pmbs_ctx, address, n, M1);
unsigned short t = 1;
if (M1[0]==TRUE)
{
//写入需要执行的操作
Sleep(1000);
}
else
{
}
}
return 0;
}
最后再对话框按钮上调用:
//CameraControlDlg.cpp
const char* ip = "127.0.0.1";
int port = 1234;
int address = 5;
int n=1;
ConnectModbus a;
HANDLE m_hand = CreateThread(NULL, 0, a.startClient, this, 0, NULL);
CloseHandle(m_hand);