一:概念可参考
https://blog.csdn.net/sgmcumt/article/details/87435191
二:仿真工具下载
https://modbustools.com/download.html
使用以及注册什么的,这个大家可以百度或者去b站上面搜索一下相应的视频即可。
三:例程参考
提供了两个例程供大家参考,一个是主站,这个相当于socket编程里面的客户端,另一个是从站,这个相当于服务端。

从站的话,这里是使用了libmodbus库,具体的版本以及下载方法。
(1)3.1.6接口说明
https://libmodbus.org/docs/v3.1.6/
(2)下载
https://www.libmodbus.org/download/

安装方法:
(a)先解压,用tar -zxvf + 文件包名
(b)执行./configure
这个命令其实就是在运行一些脚本,安装和系统匹配的一些东西,
©sudo make 进行编译
(d)sudo make install 安装
安装的意思就是把编译好的东西拷贝一份到系统的某个具体的目录下,这个可以参考Makefile文件看看到底做了什么。

从站:

#include "ModbusTcpMaster.h"
int main(int argc, char **argv)
{/*创建一个ModbusTCP 对象*/ModbusTcpMaster mb = ModbusTcpMaster("127.0.0.1", 502);/*设置从站地址*/mb.modbus_set_slave_id(1);/*对从站发起连接*/mb.modbus_connect();/*读线圈(function code 0x01)*/bool read_coil; /*tab_bits可读写*/mb.modbus_read_coils(0, 1, &read_coil);/*读输入位(discrete input function code 0x02)*/bool read_bits; /*tab_input_bits只读*/mb.modbus_read_input_bits(0, 1, &read_bits);/*读保持寄存器(function code 0x03)*/uint16_t read_holding_regs[1]; /*tab_registers可读写*/mb.modbus_read_holding_registers(0, 1, read_holding_regs);/*读输入寄存器(function code 0x04)*/uint16_t read_input_regs[1]; /*tab_input_registers只读*/mb.modbus_read_input_registers(0, 1, read_input_regs);/*写单线圈(function code 0x05)*/mb.modbus_write_coil(0, true);/*tab_bits可读写*//*写单寄存器(function code 0x06)*/mb.modbus_write_register(0, 123);/*tab_registers可读写*//*写多线圈(function code 0x0F)*/bool write_cols[4] = {true, true, true, true};/*tab_bits可读写*/mb.modbus_write_coils(0, 4, write_cols);/*写多寄存器(function code 0x10)*/uint16_t write_regs[4] = {123, 123, 123};/*tab_registers可读写*/mb.modbus_write_registers(0, 4, write_regs);/*关闭连接以及释放内存*/mb.modbus_close();return 0;
}
/*g++ ModbusTcpMaster.cpp main.cpp --std=c++11 -o ModbusTcpMaster
事务 长度  地址 code 起始高 起始低 数量高 数量低
0x00000000 0x0006 0x01 0x03 0x00 0x6B 0x00 0x02uint8_t d1 = 0x01;uint8_t d2 = 0x02;uint16_t wd = ((uint16_t)d2 << 8) | d1;d1 d2 d3 ... dn-1 ... dnuint16_t d1 = 0x01;uint16_t d2 = 0x02;uint32_t wd = ((uint16_t)d2 << 16) | d1;d1 d2 d3 ... dn-1 ... dn
*/
#include "ModbusTcpMaster.h"
/**************************************************************** @file       ModbusTcpMaster.cpp* @brief      Constructor* @author     seer-txj* @version    v1* @return     null* @date       2021/10/3**************************************************************/
ModbusTcpMaster::ModbusTcpMaster(std::string host, uint16_t port = 502)
{HOST = host;        /*Host IP*/PORT = port;        /*Host PORT(default 502)*/_slaveid = 1;_msg_id = 1;_connected = false;err = false;err_no = 0;error_msg = "";
}
/**************************************************************** @file       ModbusTcpMaster.cpp* @brief      Set the slave address* @author     seer-txj* @version    v1* @return     null* @date       2021/10/3**************************************************************/
void ModbusTcpMaster::modbus_set_slave_id(int id)
{_slaveid = id;
}
/**************************************************************** @file       ModbusTcpMaster.cpp* @brief      Connect from the station* @author     seer-txj* @version    v1* @return     null* @date       2021/10/3**************************************************************/
bool ModbusTcpMaster::modbus_connect()
{if(HOST.empty() || PORT == 0){LOG("Missing Host and Port\n");return false;}else{LOG("Found Proper Host %s and Port %d\n", HOST.c_str(), PORT);}#ifdef _WIN32if (WSAStartup(0x0202, &wsadata)){return false;}
#endif_socket = socket(AF_INET, SOCK_STREAM, 0);if (!X_ISVALIDSOCKET(_socket)){LOG("Error Opening Socket\n");
#ifdef _WIN32WSACleanup();
#endifreturn false;}else{LOG("Socket Opened Successfully\n");}#ifdef WIN32const DWORD timeout = 20;
#elsestruct timeval timeout{};/*after 20 seconds connect() will timeout*/timeout.tv_sec = 20;timeout.tv_usec = 0;
#endif/*设置套接字属性以及填充结构体*/setsockopt(_socket, SOL_SOCKET, SO_SNDTIMEO, (const char *)&timeout, sizeof(timeout));setsockopt(_socket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout));_server.sin_family = AF_INET;_server.sin_addr.s_addr = inet_addr(HOST.c_str());_server.sin_port = htons(PORT);if(!X_ISCONNECTSUCCEED(connect(_socket, (SOCKADDR *)&_server, sizeof(_server)))){LOG("Connection Error\n");
#ifdef _WIN32WSACleanup();
#endifreturn false;}LOG("Connected\n");_connected = true;return true;
}
/**************************************************************** @file       ModbusTcpMaster.cpp* @brief      close Connect* @author     seer-txj* @version    v1* @return     null* @date       2021/10/3**************************************************************/
void ModbusTcpMaster::modbus_close() const
{X_CLOSE_SOCKET(_socket);
#ifdef _WIN32WSACleanup();
#endifLOG("Socket Closed\n");
}
/**************************************************************** @file       ModbusTcpMaster.cpp* @brief      Modbus Request Builder* @param      to_send   Message Buffer to Be Sent* @param      address   Reference Address* @param      func      Modbus Functional Code* @author     seer-txj* @version    v1* @return     null* @date       2021/10/3**************************************************************/
void ModbusTcpMaster::modbus_build_request(uint8_t *to_send, uint16_t address, int func) const
{to_send[0] = (uint8_t)(_msg_id >> 8u);to_send[1] = (uint8_t)(_msg_id & 0x00FFu);to_send[2] = 0;to_send[3] = 0;to_send[4] = 0;to_send[6] = (uint8_t)_slaveid;to_send[7] = (uint8_t)func;to_send[8] = (uint8_t)(address >> 8u);to_send[9] = (uint8_t)(address & 0x00FFu);
}
/**************************************************************** @file       ModbusTcpMaster.cpp* @brief      Write Request Builder and Sender* @param      address   Reference Address* @param      amount    Amount of data to be Written* @param      func      Modbus Functional Code* @param      value     Data to Be Written* @author     seer-txj* @version    v1* @return     null* @date       2021/10/3**************************************************************/
int ModbusTcpMaster::modbus_write(uint16_t address, uint16_t amount, int func, const uint16_t *value)
{int status = 0;uint8_t *to_send = nullptr;if(func == WRITE_COIL || func == WRITE_REG){to_send = new uint8_t[12];modbus_build_request(to_send, address, func);to_send[5] = 6;to_send[10] = (uint8_t)(value[0] >> 8u);to_send[11] = (uint8_t)(value[0] & 0x00FFu);status = modbus_send(to_send, 12);}else if(func == WRITE_REGS){to_send = new uint8_t[13 + 2 * amount];modbus_build_request(to_send, address, func);to_send[5] = (uint8_t)(7 + 2 * amount);to_send[10] = (uint8_t)(amount >> 8u);to_send[11] = (uint8_t)(amount & 0x00FFu);to_send[12] = (uint8_t)(2 * amount);for (int i = 0; i < amount; i++){to_send[13 + 2 * i] = (uint8_t)(value[i] >> 8u);to_send[14 + 2 * i] = (uint8_t)(value[i] & 0x00FFu);}status = modbus_send(to_send, 13 + 2 * amount);}else if(func == WRITE_COILS){to_send = new uint8_t[14 + (amount - 1) / 8];modbus_build_request(to_send, address, func);to_send[5] = (uint8_t)(7 + (amount + 7) / 8);to_send[10] = (uint8_t)(amount >> 8u);to_send[11] = (uint8_t)(amount & 0x00FFu);to_send[12] = (uint8_t)((amount + 7) / 8);for(int i = 0; i < (amount + 7) / 8; i++)to_send[13 + i] = 0; /*init needed before summing*/for(int i = 0; i < amount; i++){to_send[13 + i / 8] += (uint8_t)(value[i] << (i % 8u));}status = modbus_send(to_send, 14 + (amount - 1) / 8);}delete[] to_send;return status;
}
/**************************************************************** @file       ModbusTcpMaster.cpp* @brief      Read Request Builder and Sender* @param      address   Reference Address* @param      amount    Amount of data to be Written* @param      func      Modbus Functional Code* @author     seer-txj* @version    v1* @return     null* @date       2021/10/3**************************************************************/
int ModbusTcpMaster::modbus_read(uint16_t address, uint16_t amount, int func)
{uint8_t to_send[12];modbus_build_request(to_send, address, func);to_send[5] = 6;to_send[10] = (uint8_t)(amount >> 8u);to_send[11] = (uint8_t)(amount & 0x00FFu);return modbus_send(to_send, 12);
}
/**************************************************************** @file       ModbusTcpMaster.cpp* @brief      Read Holding Registers / MODBUS FUNCTION 0x03* @param      address   Reference Address* @param      amount    Amount of Registers to Read* @param      buffer     Buffer to Store Data Read from Registers* @author     seer-txj* @version    v1* @return     null* @date       2021/10/3**************************************************************/
int ModbusTcpMaster::modbus_read_holding_registers(uint16_t address, uint16_t amount, uint16_t *buffer)
{if(_connected){modbus_read(address, amount, READ_REGS);uint8_t to_rec[MAX_MSG_LENGTH];ssize_t k = modbus_receive(to_rec);if(k == -1){set_bad_con();return BAD_CON;}modbuserror_handle(to_rec, READ_REGS);if (err)return err_no;for (auto i = 0; i < amount; i++){buffer[i] = ((uint16_t)to_rec[9u + 2u * i]) << 8u;buffer[i] += (uint16_t)to_rec[10u + 2u * i];}return 0;}else{set_bad_con();return BAD_CON;}
}
/**************************************************************** @file       ModbusTcpMaster.cpp* @brief      Read Input Registers / MODBUS FUNCTION 0x04* @param      address   Reference Address* @param      amount    Amount of Registers to Read* @param      buffer    Buffer to Store Data Read from Registers* @author     seer-txj* @version    v1* @return     null* @date       2021/10/3**************************************************************/
int ModbusTcpMaster::modbus_read_input_registers(uint16_t address, uint16_t amount, uint16_t *buffer)
{if(_connected){modbus_read(address, amount, READ_INPUT_REGS);uint8_t to_rec[MAX_MSG_LENGTH];ssize_t k = modbus_receive(to_rec);if(k == -1){set_bad_con();return BAD_CON;}modbuserror_handle(to_rec, READ_INPUT_REGS);if(err)return err_no;for(auto i = 0; i < amount; i++){buffer[i] = ((uint16_t)to_rec[9u + 2u * i]) << 8u;buffer[i] += (uint16_t)to_rec[10u + 2u * i];}return 0;}else{set_bad_con();return BAD_CON;}
}
/**************************************************************** @file       ModbusTcpMaster.cpp* @brief      Read Coils / MODBUS FUNCTION 0x01* @param      address   Reference Address* @param      amount    Amount of Coils to Read* @param      buffer    Buffer to Store Data Read from Coils* @author     seer-txj* @version    v1* @return     null* @date       2021/10/3**************************************************************/
int ModbusTcpMaster::modbus_read_coils(uint16_t address, uint16_t amount, bool *buffer)
{if(_connected){if(amount > 2040){set_bad_input();return EX_BAD_DATA;}modbus_read(address, amount, READ_COILS);uint8_t to_rec[MAX_MSG_LENGTH];ssize_t k = modbus_receive(to_rec);if(k == -1){set_bad_con();return BAD_CON;}modbuserror_handle(to_rec, READ_COILS);if(err)return err_no;for(auto i = 0; i < amount; i++){buffer[i] = (bool)((to_rec[9u + i / 8u] >> (i % 8u)) & 1u);}return 0;}else{set_bad_con();return BAD_CON;}
}
/**************************************************************** @file       ModbusTcpMaster.cpp* @brief      Read Input Bits(Discrete Data) / MODBUS FUNCTION 0x02* @param      address   Reference Address* @param      amount    Amount of Bits to Read* @param      buffer    Buffer to store Data Read from Input Bits* @author     seer-txj* @version    v1* @return     null* @date       2021/10/3**************************************************************/
int ModbusTcpMaster::modbus_read_input_bits(uint16_t address, uint16_t amount, bool *buffer)
{if(_connected){if(amount > 2040){set_bad_input();return EX_BAD_DATA;}modbus_read(address, amount, READ_INPUT_BITS);uint8_t to_rec[MAX_MSG_LENGTH];ssize_t k = modbus_receive(to_rec);if(k == -1){set_bad_con();return BAD_CON;}if(err)return err_no;for(auto i = 0; i < amount; i++){buffer[i] = (bool)((to_rec[9u + i / 8u] >> (i % 8u)) & 1u);}modbuserror_handle(to_rec, READ_INPUT_BITS);return 0;}else{return BAD_CON;}
}
/**************************************************************** @file       ModbusTcpMaster.cpp* @brief      Write Single Coils / MODBUS FUNCTION 0x05* @param      address    Reference Address* @param      to_write   Value to be Written to Coil* @author     seer-txj* @version    v1* @return     0/bad* @date       2021/10/3**************************************************************/
int ModbusTcpMaster::modbus_write_coil(uint16_t address, const bool &to_write)
{if(_connected){int value = to_write * 0xFF00;modbus_write(address, 1, WRITE_COIL, (uint16_t *)&value);uint8_t to_rec[MAX_MSG_LENGTH];ssize_t k = modbus_receive(to_rec);if(k == -1){set_bad_con();return BAD_CON;}modbuserror_handle(to_rec, WRITE_COIL);if (err)return err_no;return 0;}else{set_bad_con();return BAD_CON;}
}
/**************************************************************** @file       ModbusTcpMaster.cpp* @brief      Write Single Register / MODBUS FUNCTION 0x06* @param      address   Reference Address* @param      value     Value to Be Written to Register* @author     seer-txj* @version    v1* @return     0/bad* @date       2021/10/3**************************************************************/
int ModbusTcpMaster::modbus_write_register(uint16_t address, const uint16_t &value)
{if(_connected){modbus_write(address, 1, WRITE_REG, &value);uint8_t to_rec[MAX_MSG_LENGTH];ssize_t k = modbus_receive(to_rec);if(k == -1){set_bad_con();return BAD_CON;}modbuserror_handle(to_rec, WRITE_COIL);if (err)return err_no;return 0;}else{set_bad_con();return BAD_CON;}
}
/**************************************************************** @file       ModbusTcpMaster.cpp* @brief      Write Multiple Coils / MODBUS FUNCTION 0x0F* @param      address  Reference Address* @param      amount   Amount of Coils to Write* @param      value    Values to Be Written to Coils* @author     seer-txj* @version    v1* @return     0/bad* @date       2021/10/3**************************************************************/
int ModbusTcpMaster::modbus_write_coils(uint16_t address, uint16_t amount, const bool *value)
{if(_connected){uint16_t *temp = new uint16_t[amount];for(int i = 0; i < amount; i++){temp[i] = (uint16_t)value[i];}modbus_write(address, amount, WRITE_COILS, temp);delete[] temp;uint8_t to_rec[MAX_MSG_LENGTH];ssize_t k = modbus_receive(to_rec);if(k == -1){set_bad_con();return BAD_CON;}modbuserror_handle(to_rec, WRITE_COILS);if(err)return err_no;return 0;}else{set_bad_con();return BAD_CON;}
}
/**************************************************************** @file       ModbusTcpMaster.cpp* @brief      Write Multiple Registers / MODBUS FUNCION 0x10* @param      address Reference Address* @param      amount  Amount of Value to Write* @param      value   Values to Be Written to the Registers* @author     seer-txj* @version    v1* @return     0/bad* @date       2021/10/3**************************************************************/
int ModbusTcpMaster::modbus_write_registers(uint16_t address, uint16_t amount, const uint16_t *value)
{if(_connected){modbus_write(address, amount, WRITE_REGS, value);uint8_t to_rec[MAX_MSG_LENGTH];ssize_t k = modbus_receive(to_rec);if(k == -1){set_bad_con();return BAD_CON;}modbuserror_handle(to_rec, WRITE_REGS);if(err)return err_no;return 0;}else{set_bad_con();return BAD_CON;}
}
/**************************************************************** @file       ModbusTcpMaster.cpp* @brief      Data Sender* @param      to_send Request to Be Sent to Server* @param      length  Length of the Request* @author     seer-txj* @version    v1* @return     Size of the request* @date       2021/10/3**************************************************************/
ssize_t ModbusTcpMaster::modbus_send(uint8_t *to_send, size_t length)
{_msg_id++;return send(_socket, (const char *)to_send, (size_t)length, 0);
}
/**************************************************************** @file       ModbusTcpMaster.cpp* @brief      Data Receiver* @param      buffer Buffer to Store the Data Retrieved* @author     seer-txj* @version    v1* @return     Size of Incoming Data* @date       2021/10/3**************************************************************/
ssize_t ModbusTcpMaster::modbus_receive(uint8_t *buffer) const
{return recv(_socket, (char *)buffer, 1024, 0);
}
/**************************************************************** @file       ModbusTcpMaster.cpp* @brief      Error Code Handler* @param      msg   Message Received from the Server* @param      func  Modbus Functional Code* @author     seer-txj* @version    v1* @return     null* @date       2021/10/3**************************************************************/
void ModbusTcpMaster::modbuserror_handle(const uint8_t *msg, int func)
{err = false;error_msg = "NO ERR";if(msg[7] == func + 0x80){err = true;switch (msg[8]){case EX_ILLEGAL_FUNCTION:error_msg = "1 Illegal Function";break;case EX_ILLEGAL_ADDRESS:error_msg = "2 Illegal Address";break;case EX_ILLEGAL_VALUE:error_msg = "3 Illegal Value";break;case EX_SERVER_FAILURE:error_msg = "4 Server Failure";break;case EX_ACKNOWLEDGE:error_msg = "5 Acknowledge";break;case EX_SERVER_BUSY:error_msg = "6 Server Busy";break;case EX_NEGATIVE_ACK:error_msg = "7 Negative Acknowledge";break;case EX_MEM_PARITY_PROB:error_msg = "8 Memory Parity Problem";break;case EX_GATEWAY_PROBLEMP:error_msg = "10 Gateway Path Unavailable";break;case EX_GATEWYA_PROBLEMF:error_msg = "11 Gateway Target Device Failed to Respond";break;default:error_msg = "UNK";break;}}
}
/**************************************************************** @file       ModbusTcpMaster.cpp* @brief      Error Code type* @author     seer-txj* @version    v1* @return     null* @date       2021/10/3**************************************************************/
void ModbusTcpMaster::set_bad_con()
{err = true;error_msg = "BAD CONNECTION";
}
/**************************************************************** @file       ModbusTcpMaster.cpp* @brief      input Error* @author     seer-txj* @version    v1* @return     null* @date       2021/10/3**************************************************************/
void ModbusTcpMaster::set_bad_input()
{err = true;error_msg = "BAD FUNCTION INPUT";
}
#ifndef MODBUSTCP_H
#define MODBUSTCP_H#include <cstring>
#include <stdint.h>
#include <string>
#include <iostream>
#include <thread>
using namespace std;
#define ENABLE_MODBUSTCP_LOGGING debuglog/*调试输出*/
#ifdef ENABLE_MODBUSTCP_LOGGING
#include <cstdio>
#define LOG(fmt, ...) printf("[ModbusTcp_DebugLog]" fmt, ##__VA_ARGS__)
#else
#define LOG(...) (void)0
#endif/*如果是windows平台则要加载相应的静态库和头文件*/
#ifdef _WIN32
#define _WINSOCK_DEPRECATED_NO_WARNINGS#include <winsock2.h>
#pragma comment(lib, "Ws2_32.lib")
using X_SOCKET = SOCKET;
using ssize_t = int;#define X_ISVALIDSOCKET(s) ((s) != INVALID_SOCKET)
#define X_CLOSE_SOCKET(s) closesocket(s)
#define X_ISCONNECTSUCCEED(s) ((s) != SOCKET_ERROR)/*linux平台*/
#else
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
using X_SOCKET = int;#define X_ISVALIDSOCKET(s) ((s) >= 0)
#define X_CLOSE_SOCKET(s) close(s)
#define X_ISCONNECTSUCCEED(s) ((s) >= 0)
#endif
/*类型重定义*/
using SOCKADDR = struct sockaddr;
using SOCKADDR_IN = struct sockaddr_in;#define    MAX_MSG_LENGTH    260
#define    BAD_CON           -1/*功能码*/
#define    READ_COILS         0x01      //读线圈
#define    READ_INPUT_BITS    0x02      //读离散输入状态
#define    READ_REGS          0x03      //读保持寄存器
#define    READ_INPUT_REGS    0x04      //读输入寄存器
#define    WRITE_COIL         0x05      //写线圈状态
#define    WRITE_REG          0x06      //写单个保持寄存器
#define    WRITE_COILS        0x0F      //写多个线圈
#define    WRITE_REGS         0x10      //写多个保持寄存器/*异常码*/
#define    EX_ILLEGAL_FUNCTION    0x01    //Function Code not Supported
#define    EX_ILLEGAL_ADDRESS     0x02    //Output Address not exists
#define    EX_ILLEGAL_VALUE       0x03    //Output Value not in Range
#define    EX_SERVER_FAILURE      0x04    //Slave Deive Fails to process request
#define    EX_ACKNOWLEDGE         0x05    //Service Need Long Time to Execute
#define    EX_SERVER_BUSY         0x06    //Server Was Unable to Accept MB Request PDU
#define    EX_NEGATIVE_ACK        0x07
#define    EX_MEM_PARITY_PROB     0x08
#define    EX_GATEWAY_PROBLEMP    0x0A    //Gateway Path not Available
#define    EX_GATEWYA_PROBLEMF    0x0B    //Target Device Failed to Response
#define    EX_BAD_DATA            0XFF    //Bad Data lenght or Address/*定义一个ModbusTcp功能的类*/
class ModbusTcpMaster
{public:bool err{};int err_no{};std::string error_msg;ModbusTcpMaster(std::string host, uint16_t port);~ModbusTcpMaster() = default;
public:bool modbus_connect();void modbus_close() const;void modbus_set_slave_id(int id);int modbus_read_coils(uint16_t address, uint16_t amount, bool *buffer);int modbus_read_input_bits(uint16_t address, uint16_t amount, bool *buffer);int modbus_read_holding_registers(uint16_t address, uint16_t amount, uint16_t *buffer);int modbus_read_input_registers(uint16_t address, uint16_t amount, uint16_t *buffer);int modbus_write_coil(uint16_t address, const bool &to_write);int modbus_write_register(uint16_t address, const uint16_t &value);int modbus_write_coils(uint16_t address, uint16_t amount, const bool *value);int modbus_write_registers(uint16_t address, uint16_t amount, const uint16_t *value);
private:bool _connected{};uint16_t PORT{};uint32_t _msg_id{};int _slaveid{};std::string HOST;X_SOCKET _socket{};SOCKADDR_IN _server{};
#ifdef _WIN32WSADATA wsadata;
#endifinline void set_bad_con();inline void set_bad_input();inline ssize_t modbus_receive(uint8_t *buffer) const;void modbuserror_handle(const uint8_t *msg, int func);inline ssize_t modbus_send(uint8_t *to_send, size_t length);int modbus_read(uint16_t address, uint16_t amount, int func);int modbus_write(uint16_t address, uint16_t amount, int func, const uint16_t *value);inline void modbus_build_request(uint8_t *to_send, uint16_t address, int func) const;
};#endif

主站:

#include "ModbusTcpSlave.h"
void modbusRunner(ModbusTcpSlave *server)
{server->initModbus(502, true);server->recieveMessages();
}
ModbusTcpSlave modSer;
int main()
{std::thread modSerThread(modbusRunner, &modSer);modSerThread.join();std::cout << "Running? " << modSer.isRunning() << std::endl;return 0;
}/*g++ -g -Wall -pthread -libmodbus ModbusTcpSlave.cpp main.cpp --std=c++11 -o ModbusTcpSlave
使用小于1024的端口时,需要以管理员权限启动,sudo ./ModbusTcpSlave*/
#include "ModbusTcpSlave.h"
/**************************************************************** @file       ModbusTcpSlave.cpp* @author     seer-txj* @brief      Constructor* @version    v1* @return     null* @date       2021/10/6**************************************************************/
ModbusTcpSlave::ModbusTcpSlave()
{m_initialized = false;mapping = modbus_mapping_new(m_numBits, m_numInputBits, m_numRegisters, m_numInputRegisters);
}
/**************************************************************** @file       ModbusTcpSlave.cpp* @author     seer-txj* @brief      Destructor* @version    v1* @return     null* @date       2021/10/6**************************************************************/
ModbusTcpSlave::~ModbusTcpSlave()
{modbus_mapping_free(mapping);modbus_close(ctx);modbus_free(ctx);
}
/**************************************************************** @file       ModbusTcpSlave.cpp* @author     seer-txj* @brief      modbus initialization flag* @version    v1* @return     null* @date       2021/10/6**************************************************************/
bool ModbusTcpSlave::isRunning()
{return m_initialized;
}
/**************************************************************** @file       ModbusTcpSlave.cpp* @author     seer-txj* @brief      modbus initialization* @param      IP/PORT/debugflag* @version    v1* @return     null* @date       2021/10/6**************************************************************/
bool ModbusTcpSlave::initModbus(std::string Host_Ip = "127.0.0.1", int port = 502, bool debugging)
{ctx = modbus_new_tcp(Host_Ip.c_str(), port);modbus_set_debug(ctx, debugging);if(ctx == NULL){std::cerr << "There was an error allocating the modbus" << std::endl;throw -1;}/*int rc = modbus_set_slave(ctx, 1);if(rc == -1){fprintf(stderr,"无效的从站 ID\n");modbus_free(ctx);return -1;}*/m_modbusSocket  = modbus_tcp_listen(ctx, 1);/*设置线圈, 离散输入, 输入寄存器, 保持寄存器个数*/mapping = modbus_mapping_new(500, 500, 500, 500);m_initialized = true;return true;
}
/**************************************************************** @file       ModbusTcpSlave.cpp* @author     seer-txj* @brief      setRegisterValue* @param      registerNumber/Value* @version    v1* @return     null* @date       2021/10/6**************************************************************/
bool ModbusTcpSlave::setRegisterValue(int registerNumber, uint16_t Value)
{if(registerNumber > m_numRegisters){return false;}mapping->tab_registers[registerNumber] = Value;return true;
}
/**************************************************************** @file       ModbusTcpSlave.cpp* @author     seer-txj* @brief      getRegisterValue* @param      registerNumber* @version    v1* @return     null* @date       2021/10/6**************************************************************/
uint16_t ModbusTcpSlave::getRegisterValue(int registerNumber)
{if(!m_initialized){return -1;}std::mutex mappingLock;std::lock_guard<std::mutex> lock(mappingLock);uint16_t registerVal = mapping->tab_registers[registerNumber];return registerVal;
}
/**************************************************************** @file       ModbusTcpSlave.cpp* @author     seer-txj* @brief      getTab_Input_Bits* @param      NumBit* @version    v1* @return     null* @date       2021/10/9**************************************************************/
uint8_t ModbusTcpSlave::getTab_Input_Bits(int NumBit)
{if(!m_initialized){return -1;}std::mutex mappingLock;std::lock_guard<std::mutex> lock(mappingLock);uint8_t BitValue = mapping->tab_input_bits[NumBit];return BitValue;
}
/**************************************************************** @file       ModbusTcpSlave.cpp* @author     seer-txj* @brief      setTab_Input_Bits* @param      NumBit/Value* @version    v1* @return     null* @date       2021/10/9**************************************************************/
bool ModbusTcpSlave::setTab_Input_Bits(int NumBit, uint8_t Value)
{if(NumBit > m_numInputBits){return false;}mapping->tab_input_bits[NumBit] = Value;return true;
}
/**************************************************************** @file       ModbusTcpSlave.cpp* @author     seer-txj* @version    v1* @return     null* @date       2021/10/6**************************************************************/
void ModbusTcpSlave::recieveMessages()
{int ret;uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];modbus_tcp_accept(ctx, &m_modbusSocket);if(m_modbusSocket == -1){std::cerr << modbus_strerror(errno) << std::endl;}for(;;){ret = modbus_receive(ctx, query);if(ret == 0){m_errCount = 0;continue;} else if(ret > 0){m_errCount = 0;modbus_reply(ctx, query, sizeof(query), mapping);}else{modbus_set_error_recovery(ctx, MODBUS_ERROR_RECOVERY_LINK);modbus_close(ctx);modbus_tcp_accept(ctx, &m_modbusSocket);modbus_set_error_recovery(ctx, MODBUS_ERROR_RECOVERY_NONE);m_errCount++;}if(m_errCount > 5){m_initialized = false;break;}}
}
#ifndef MODBUSTCPSLAVE_H
#define MODBUSTCPSLAVE_H
#include <iostream>
#include <thread>
#include <stdlib.h>
#include <iostream>
#include <mutex>
#include <string>
#include <modbus.h>
//#include <modbus/modbus.h>
using namespace std;
/*如果是windows平台则要加载相应的静态库和头文件*/
#ifdef _WIN32
#define _WINSOCK_DEPRECATED_NO_WARNINGS
/*https://www.jianshu.com/p/074f93491201*/
#include <winsock2.h>
#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "modbus.lib")
/*linux平台*/
#else
#include <unistd.h>
#include <error.h>
#endif
class ModbusTcpSlave
{public:ModbusTcpSlave();~ModbusTcpSlave();
public:bool        isRunning();void        recieveMessages();bool        initModbus(std::string Host_Ip = "127.0.0.1", int port = 502, bool debugging);uint16_t    getRegisterValue(int registerNumber);bool        setRegisterValue(int registerNumber, uint16_t Value);uint8_t     getTab_Input_Bits(int NumBit);bool        setTab_Input_Bits(int NumBit, uint8_t Value);
private:modbus_t            *ctx;modbus_mapping_t    *mapping;bool        m_initialized;int         m_modbusSocket;int         m_port;int         m_errCount;/*Mapping*/int         m_numBits;int         m_numInputBits;int         m_numRegisters;int         m_numInputRegisters;
};
/*Annotation:
(1)https://www.jianshu.com/p/0ed380fa39eb
(2)typedef struct _modbus_mapping_t
{int nb_bits;                //线圈int start_bits;int nb_input_bits;          //离散输入int start_input_bits;int nb_input_registers;     //输入寄存器int start_input_registers;int nb_registers;           //保持寄存器int start_registers;uint8_t *tab_bits;uint8_t *tab_input_bits;uint16_t *tab_input_registers;uint16_t *tab_registers;
}modbus_mapping_t;*/
#endif //MODBUSTCPSLAVE_H

CmakeLists.txt:

#cmake_minimum_required(VERSION 3.5.2)
project(ModbusTcpSlave)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")INCLUDE(FindPkgConfig)
pkg_check_modules(MODBUS REQUIRED libmodbus)
include_directories(${MODBUS_INCLUDE_DIRS})
link_directories(${MODBUS_LIBRARY_DIRS})set(SOURCE_FILES main.cpp)
add_executable(ModbusTcpSlave ${SOURCE_FILES} ModbusTcpSlave.cpp ModbusTcpSlave.h)target_link_libraries(ModbusTcpSlave ${MODBUS_LIBRARIES} pthread)

深入浅出ModbusTcp相关推荐

  1. Python --深入浅出Apriori关联分析算法(二) Apriori关联规则实战

    上一篇我们讲了关联分析的几个概念,支持度,置信度,提升度.以及如何利用Apriori算法高效地根据物品的支持度找出所有物品的频繁项集. Python --深入浅出Apriori关联分析算法(一) 这次 ...

  2. MSDN Webcast“深入浅出ASP.NET AJAX系列”

    课程: ASP.NET AJAX深入浅出系列课程(1):ASP.NET AJAX 概述(3月13日):对于ASP.NET AJAX的大致功能进行概述和演示,通过简单的演示让听众了解到ASP.NET A ...

  3. 5.3Role和Claims授权「深入浅出ASP.NET Core系列」

    5.3Role和Claims授权「深入浅出ASP.NET Core系列」 原文:5.3Role和Claims授权「深入浅出ASP.NET Core系列」 希望给你3-5分钟的碎片化学习,可能是坐地铁. ...

  4. 深入浅出开源性能测试工具 Locust (使用篇 1)

    在<[LocustPlus序]漫谈服务端性能测试>中,我对服务端性能测试的基础概念和性能测试工具的基本原理进行了介绍,并且重点推荐了Locust这一款开源性能测试工具.然而,当前在网络上针 ...

  5. 《深入浅出iPhone/iPad开发(第2版)》——在Xcode中建立你的界面

    本节书摘来自异步社区<深入浅出iPhone/iPad开发(第2版)>一书中的在Xcode中建立你的界面,作者 [美]Dan Pilone , Tracey Pilone,更多章节内容可以访 ...

  6. 【组队学习】【35期】深入浅出Pytorch

    深入浅出Pytorch 航路开辟者:李嘉骐.牛志康.刘洋.陈安东 领航员:朱松青 航海士:管柯琴.宋泽山.林旭升 基本信息 开源内容:https://github.com/datawhalechina ...

  7. 深入浅出Pytorch:02 PyTorch基础知识

    深入浅出Pytorch 02 PyTorch基础知识 内容属性:深度学习(实践)专题 航路开辟者:李嘉骐.牛志康.刘洋.陈安东 领航员:叶志雄 航海士:李嘉骐.牛志康.刘洋.陈安东 开源内容:http ...

  8. 深入浅出Pytorch:01 课程大纲与PyTorch简介

    深入浅出Pytorch 01 课程大纲与PyTorch简介 内容属性:深度学习(实践)专题 航路开辟者:李嘉骐.牛志康.刘洋.陈安东 领航员:叶志雄 航海士:李嘉骐.牛志康.刘洋.陈安东 开源内容:h ...

  9. 今晚8点直播 | 深入浅出理解A3C强化学习

    强化学习是一种比较传统的人工智能手段,在近年来随着深度学习的发展,强化学习和深度学习逐渐结合在了一起.这种结合使得很多原来无法想象的工作有了可能,最令我们瞩目的莫过于AlphaGo战胜李世石,以及Op ...

最新文章

  1. usb-key登录windows+远程桌面
  2. Eclipse中使用SVN
  3. 测试两个主机之间的连通性_UCloud 全链路大规模网络连通性检测系统详解
  4. 项目经理升职了是啥_什么是升职率?
  5. pandas绘图_Pandas内置绘图方法(线型图、柱状图、密度图)
  6. 《可用性测试手册(第2版)》一第1章 什么造就了可用性1.1 “可用”究竟是什么...
  7. emacs VS vim 替换为回车符
  8. python的sorted函数和operator.itemgetter函数
  9. matlab离散信号z变换,离散信号与系统的Z变换分析
  10. 新买的华为Matebook,Office没激活,激活方法在这里!!!
  11. 百度网盘,到底限了谁的速?
  12. 若干物联网无线技术 - NB-IOT、LoRa、433、GPRS、2.4G、PKE近场通信,基础理论与开发点滴总结
  13. Go 限流器 limter
  14. 微信开发 ━━ 微信商户v3微信支付回调之php篇
  15. 龙腾世纪:起源–最后的古代墓碑和剑圣盔甲
  16. GraphX 在图数据库 Nebula Graph 的图计算实践
  17. Air724UG 4G LTE 模块AT指令连接服务器
  18. linux shell遍历多个数组
  19. Flutter 加载WebView(加载网页)
  20. 【CCF会议期刊推荐】CCF推荐国际学术期刊/会议(网络与信息安全)

热门文章

  1. All Attention You Need
  2. 【自然语言处理】【向量检索】面向开放域稠密检索的多视角文档表示学习
  3. 舔狗日记 API数据接口
  4. Qbao Network携手FinCredit Protocol启动大规模空投
  5. PB 饼状图制作过程
  6. 一览Polkadot平行链Moonbeam生态的应用
  7. Python相对引用报错ImportError: attempted relative import with no known parent package的处理方法
  8. 计算机音乐安顺学院教务网络管理系统,安顺学院教务网络管理系统jwxt.asu.edu.cn/jwweb/...
  9. DVDRW光驱无法读DVD刻录盘
  10. 长方形纸做容积最大的长方体_探究无盖长方体的最大容积