C++ modbus 开源代码(包含tcp,udp,rtu),既有master又有slave

modbus是一个比较简单的协议,在工业领域和嵌入式设备上使用非常多,得益于其协议的简单,得到了广泛的应用。

虽然此协议存在一些不足之处,比如一次传输的数据量有限,以偏移量定义变量,需要对应的点表才能解析等等,但不影响其使用的广泛。

各类Modbus协议的代码多如牛毛。在此推荐一个不错的Modbus c++代码,项目比较完整,跨平台支持比较好,既可以在Linux下编译,也可以在windows下运行。

代码地址:https://github.com/lyqdy/ymodbus

下载后在tests目录下有.sln,需要使用vs2015打开,用到一些c++11的特性。vs2013以后的估计都可以。

1. 直接编译会报一些头文件找不到,需要将 ../ , ../include 加入到头文件目录

2. 我用vs2019编译报不识别 std::placeholders  在报错的文件test_***.cpp 里面添加 #include <functional> 

3. 删除解决方案里的 linuxserlistener.cpp, 工程中用不到linux下面的文件

4. 报main函数重复,删除一个test_开头的文件   test_ymaster.cpp 或 test_yslave.cpp 。

5.ymblog.h  里面  #ifndef WIN32   改成  #ifndef _WIN32

基本上就可以编译成功了。

不想动手的可以到ymodbus在windows下的修改版,能够被vs2019编译通过。-交通文档类资源-CSDN下载

下载,我用的vs2019,不知vs2015能否打开。生成的时候选择生成 x86平台的。 

test中相当于将项目的使用已经说的比较清楚了。还是比较简单的。

class Player : public IPlayer

在Player类中写入相应的逻辑即可实现modbus功能,可以说对于我们的modbus是非常方便的了。

下面是一个基于C++Modbus RTU通信代码示例: ```cpp #include <iostream> #include <cstring> #include <cerrno> #include <cstdlib> #include <cstdio> #include <unistd.h> #include <fcntl.h> #include <termios.h> using namespace std; int open_port(const char* port) { int fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY); if (fd == -1) { perror("open_port: Unable to open serial port"); } else { fcntl(fd, F_SETFL, 0); } return (fd); } int set_port(int fd, int baud_rate, int data_bits, int stop_bits, char parity) { struct termios options; if (tcgetattr(fd, &options) == -1) { perror("set_port: Unable to get port settings"); return (-1); } cfsetispeed(&options, baud_rate); cfsetospeed(&options, baud_rate); options.c_cflag |= (CLOCAL | CREAD); options.c_cflag &= ~CSIZE; switch (data_bits) { case 5: options.c_cflag |= CS5; break; case 6: options.c_cflag |= CS6; break; case 7: options.c_cflag |= CS7; break; case 8: options.c_cflag |= CS8; break; default: fprintf(stderr, "Unsupported data size\n"); return (-1); } switch (parity) { case 'n': case 'N': options.c_cflag &= ~PARENB; options.c_iflag &= ~INPCK; break; case 'o': case 'O': options.c_cflag |= (PARODD | PARENB); options.c_iflag |= INPCK; break; case 'e': case 'E': options.c_cflag |= PARENB; options.c_cflag &= ~PARODD; options.c_iflag |= INPCK; break; default: fprintf(stderr, "Unsupported parity\n"); return (-1); } switch (stop_bits) { case 1: options.c_cflag &= ~CSTOPB; break; case 2: options.c_cflag |= CSTOPB; break; default: fprintf(stderr, "Unsupported stop bits\n"); return (-1); } options.c_cc[VTIME] = 0; options.c_cc[VMIN] = 1; tcflush(fd, TCIFLUSH); if (tcsetattr(fd, TCSANOW, &options) == -1) { perror("set_port: Unable to set port settings"); return (-1); } return (0); } int modbus_read_registers(int fd, unsigned char slave_addr, unsigned short start_addr, unsigned short count, unsigned short* values) { unsigned char buf[256]; int i, len; buf[0] = slave_addr; buf[1] = 0x03; buf[2] = start_addr >> 8; buf[3] = start_addr & 0xff; buf[4] = count >> 8; buf[5] = count & 0xff; len = 6; unsigned short crc = 0xFFFF; for (i = 0; i < len; i++) { crc ^= buf[i]; for (int j = 0; j < 8; j++) { if (crc & 1) { crc >>= 1; crc ^= 0xA001; } else { crc >>= 1; } } } buf[len++] = crc & 0xff; buf[len++] = crc >> 8; int n = write(fd, buf, len); if (n != len) { perror("modbus_read_registers: Unable to write to port"); return (-1); } usleep(10000); len = read(fd, buf, 256); if (len < 5) { perror("modbus_read_registers: Error reading from port"); return (-1); } crc = 0xFFFF; for (i = 0; i < len - 2; i++) { crc ^= buf[i]; for (int j = 0; j < 8; j++) { if (crc & 1) { crc >>= 1; crc ^= 0xA001; } else { crc >>= 1; } } } if (crc != (buf[len - 2] | (buf[len - 1] << 8))) { perror("modbus_read_registers: CRC error"); return (-1); } if (buf[1] & 0x80) { perror("modbus_read_registers: Exception response"); return (-1); } for (i = 0; i < count; i++) { values[i] = buf[3 + i * 2] << 8 | buf[4 + i * 2]; } return (0); } int main() { const char* port = "/dev/ttyUSB0"; int baud_rate = B9600; int data_bits = 8; int stop_bits = 1; char parity = 'N'; int fd = open_port(port); if (fd == -1) { return (EXIT_FAILURE); } if (set_port(fd, baud_rate, data_bits, stop_bits, parity) == -1) { return (EXIT_FAILURE); } unsigned short values[256]; if (modbus_read_registers(fd, 1, 0, 10, values) == -1) { return (EXIT_FAILURE); } for (int i = 0; i < 10; i++) { cout << values[i] << endl; } close(fd); return (EXIT_SUCCESS); } ``` 这个代码示例使用Linux系统提供的串口设备文件进行通信,并且实现了读取Modbus RTU从设备的寄存器的功能。需要注意的是,Modbus RTU通信需要进行CRC校验,这个代码示例中使用了一个CRC计算函数来实现校验。在实际使用中,你需要根据自己的具体需求进行修改。
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

路边闲人2

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值