c语言modbus-rtu的代码
时间: 2023-09-02 22:08:36 浏览: 420
MODBUS通讯+C语言源代码.pdf
5星 · 资源好评率100%
下面是一个简单的C语言Modbus RTU通信的示例代码:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <termios.h>
#include <fcntl.h>
#define SLAVE_ADDR 0x01
#define FUNCTION_CODE_READ_HOLDING_REGISTERS 0x03
#define FUNCTION_CODE_WRITE_SINGLE_REGISTER 0x06
int open_serial_port(const char *port_name) {
int fd = open(port_name, O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1) {
printf("Failed to open serial port %s: %s\n", port_name, strerror(errno));
} else {
struct termios options;
tcgetattr(fd, &options);
// Set baud rate
cfsetispeed(&options, B9600);
cfsetospeed(&options, B9600);
// Set data bits, parity, and stop bits
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
// Enable receiver and ignore modem control lines
options.c_cflag |= CREAD | CLOCAL;
// Disable software flow control
options.c_iflag &= ~(IXON | IXOFF | IXANY);
// Set the new options for the port
tcsetattr(fd, TCSANOW, &options);
}
return fd;
}
void close_serial_port(int fd) {
close(fd);
}
unsigned short crc16(unsigned char *buf, int len) {
unsigned short crc = 0xFFFF;
for (int pos = 0; pos < len; pos++) {
crc ^= (unsigned short)buf[pos];
for (int i = 8; i != 0; i--) {
if ((crc & 0x0001) != 0) {
crc >>= 1;
crc ^= 0xA001;
} else {
crc >>= 1;
}
}
}
return crc;
}
int send_request(int fd, unsigned char *buf, int len) {
unsigned short crc = crc16(buf, len);
buf[len++] = crc & 0xFF;
buf[len++] = (crc >> 8) & 0xFF;
return write(fd, buf, len);
}
int receive_response(int fd, unsigned char *buf) {
int len = 0;
while (len < 3 || len < (buf[2] + 5)) {
int n = read(fd, &buf[len], 256);
if (n <= 0) {
return -1;
}
len += n;
}
if (buf[1] & 0x80) {
printf("Modbus exception %d\n", buf[2]);
return -1;
}
return len;
}
int read_holding_registers(int fd, unsigned short register_address, unsigned short num_registers, unsigned short *data) {
unsigned char buf[256];
int len = 0;
// Request
buf[len++] = SLAVE_ADDR;
buf[len++] = FUNCTION_CODE_READ_HOLDING_REGISTERS;
buf[len++] = (register_address >> 8) & 0xFF;
buf[len++] = register_address & 0xFF;
buf[len++] = (num_registers >> 8) & 0xFF;
buf[len++] = num_registers & 0xFF;
if (send_request(fd, buf, len) == -1) {
printf("Failed to send request: %s\n", strerror(errno));
return -1;
}
// Response
if (receive_response(fd, buf) == -1) {
printf("Failed to receive response: %s\n", strerror(errno));
return -1;
}
if (buf[2] != num_registers * 2) {
printf("Invalid response length\n");
return -1;
}
for (int i = 0; i < num_registers; i++) {
data[i] = (buf[3 + i * 2] << 8) | buf[4 + i * 2];
}
return 0;
}
int write_single_register(int fd, unsigned short register_address, unsigned short value) {
unsigned char buf[256];
int len = 0;
// Request
buf[len++] = SLAVE_ADDR;
buf[len++] = FUNCTION_CODE_WRITE_SINGLE_REGISTER;
buf[len++] = (register_address >> 8) & 0xFF;
buf[len++] = register_address & 0xFF;
buf[len++] = (value >> 8) & 0xFF;
buf[len++] = value & 0xFF;
if (send_request(fd, buf, len) == -1) {
printf("Failed to send request: %s\n", strerror(errno));
return -1;
}
// Response
if (receive_response(fd, buf) == -1) {
printf("Failed to receive response: %s\n", strerror(errno));
return -1;
}
if (buf[2] != value >> 8 || buf[3] != value & 0xFF) {
printf("Invalid response\n");
return -1;
}
return 0;
}
int main(int argc, char **argv) {
int fd = open_serial_port("/dev/ttyUSB0");
if (fd == -1) {
return -1;
}
unsigned short data[16];
if (read_holding_registers(fd, 0x0000, 16, data) == -1) {
close_serial_port(fd);
return -1;
}
for (int i = 0; i < 16; i++) {
printf("Register %d: %d\n", i, data[i]);
}
if (write_single_register(fd, 0x0000, 12345) == -1) {
close_serial_port(fd);
return -1;
}
close_serial_port(fd);
return 0;
}
```
这个示例代码包含了以下功能:
- 打开串口
- 发送读保持寄存器的请求并接收响应
- 发送写单个寄存器的请求并接收响应
- 计算CRC16校验和
你可以根据自己的需求修改代码。注意,该示例代码仅供参考,实际使用时需要根据具体情况进行修改和测试。
阅读全文