c语言modbus协议源码
时间: 2023-12-14 20:04:12 浏览: 80
FolderManager,c语言modbus协议源码,c语言程序
以下是一个简单的C语言modbus协议源码,可以实现modbus RTU通信:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#define MODBUS_RTU_SLAVEID 0x01
#define MODBUS_RTU_FUNCTION_READ 0x03
#define MODBUS_RTU_FUNCTION_WRITE 0x06
#define MODBUS_RTU_FUNCTION_WRITEMULTI 0x10
#define MODBUS_RTU_CRC_POLYNOMIAL 0xA001
unsigned short modbus_crc16(unsigned char *buf, int len)
{
unsigned short crc = 0xFFFF;
int i, j;
for (i = 0; i < len; i++) {
crc ^= buf[i];
for (j = 0; j < 8; j++) {
if (crc & 0x0001) {
crc >>= 1;
crc ^= MODBUS_RTU_CRC_POLYNOMIAL;
} else {
crc >>= 1;
}
}
}
return crc;
}
int modbus_send(int fd, unsigned char *buf, int len)
{
int n;
n = write(fd, buf, len);
if (n != len) {
return -1;
}
return 0;
}
int modbus_recv(int fd, unsigned char *buf, int len, int timeout)
{
int n, count = 0;
while (count < timeout) {
n = read(fd, buf, len);
if (n > 0) {
return n;
}
count++;
usleep(1000);
}
return -1;
}
int modbus_read(int fd, unsigned char *buf, int addr, int count)
{
unsigned char frame[8], resp[255];
int i, len;
frame[0] = MODBUS_RTU_SLAVEID;
frame[1] = MODBUS_RTU_FUNCTION_READ;
frame[2] = (addr >> 8) & 0xFF;
frame[3] = addr & 0xFF;
frame[4] = (count >> 8) & 0xFF;
frame[5] = count & 0xFF;
len = 6;
*(unsigned short *)(frame + len) = modbus_crc16(frame, len);
len += 2;
if (modbus_send(fd, frame, len) < 0) {
return -1;
}
len = modbus_recv(fd, resp, 255, 100);
if (len < 0) {
return -1;
}
if (len < 5) {
return -1;
}
if (resp[0] != MODBUS_RTU_SLAVEID) {
return -1;
}
if (resp[1] != MODBUS_RTU_FUNCTION_READ) {
return -1;
}
if (resp[2] != count * 2) {
return -1;
}
for (i = 0; i < count; i++) {
buf[i * 2] = resp[3 + i * 2];
buf[i * 2 + 1] = resp[4 + i * 2];
}
return count;
}
int modbus_write(int fd, unsigned char *buf, int addr, int value)
{
unsigned char frame[8], resp[8];
int len;
frame[0] = MODBUS_RTU_SLAVEID;
frame[1] = MODBUS_RTU_FUNCTION_WRITE;
frame[2] = (addr >> 8) & 0xFF;
frame[3] = addr & 0xFF;
frame[4] = (value >> 8) & 0xFF;
frame[5] = value & 0xFF;
len = 6;
*(unsigned short *)(frame + len) = modbus_crc16(frame, len);
len += 2;
if (modbus_send(fd, frame, len) < 0) {
return -1;
}
len = modbus_recv(fd, resp, 8, 100);
if (len < 0) {
return -1;
}
if (len < 5) {
return -1;
}
if (resp[0] != MODBUS_RTU_SLAVEID) {
return -1;
}
if (resp[1] != MODBUS_RTU_FUNCTION_WRITE) {
return -1;
}
if (resp[2] != (addr >> 8) & 0xFF || resp[3] != addr & 0xFF) {
return -1;
}
if (*(unsigned short *)(resp + 4) != *(unsigned short *)(frame + 4)) {
return -1;
}
return 0;
}
int modbus_writemulti(int fd, unsigned char *buf, int addr, int count, unsigned short *values)
{
unsigned char frame[255], resp[8];
int i, len;
frame[0] = MODBUS_RTU_SLAVEID;
frame[1] = MODBUS_RTU_FUNCTION_WRITEMULTI;
frame[2] = (addr >> 8) & 0xFF;
frame[3] = addr & 0xFF;
frame[4] = (count >> 8) & 0xFF;
frame[5] = count & 0xFF;
frame[6] = count * 2;
for (i = 0; i < count; i++) {
frame[7 + i * 2] = (values[i] >> 8) & 0xFF;
frame[8 + i * 2] = values[i] & 0xFF;
}
len = 7 + count * 2;
*(unsigned short *)(frame + len) = modbus_crc16(frame, len);
len += 2;
if (modbus_send(fd, frame, len) < 0) {
return -1;
}
len = modbus_recv(fd, resp, 8, 100);
if (len < 0) {
return -1;
}
if (len < 5) {
return -1;
}
if (resp[0] != MODBUS_RTU_SLAVEID) {
return -1;
}
if (resp[1] != MODBUS_RTU_FUNCTION_WRITEMULTI) {
return -1;
}
if (resp[2] != (addr >> 8) & 0xFF || resp[3] != addr & 0xFF) {
return -1;
}
if (*(unsigned short *)(resp + 4) != *(unsigned short *)(frame + 4)) {
return -1;
}
return 0;
}
int main()
{
int fd, ret, i;
unsigned char buf[256];
unsigned short values[16];
fd = open("/dev/ttyS0", O_RDWR);
if (fd < 0) {
printf("open error\n");
return -1;
}
struct termios options;
tcgetattr(fd, &options);
options.c_cflag |= B9600;
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
options.c_cc[VMIN] = 1;
options.c_cc[VTIME] = 0;
tcsetattr(fd, TCSANOW, &options);
ret = modbus_read(fd, buf, 0x1000, 16);
if (ret < 0) {
printf("read error\n");
return -1;
}
for (i = 0; i < ret; i++) {
values[i] = (buf[i * 2] << 8) | buf[i * 2 + 1];
}
values[0]++;
ret = modbus_write(fd, buf, 0x1000, values[0]);
if (ret < 0) {
printf("write error\n");
return -1;
}
for (i = 0; i < 16; i++) {
values[i] += i;
}
ret = modbus_writemulti(fd, buf, 0x1010, 16, values);
if (ret < 0) {
printf("write multi error\n");
return -1;
}
printf("success\n");
close(fd);
return 0;
}
```
该源码通过串口通信实现modbus RTU协议的读写操作,其中包括modbus CRC16校验的计算和使用。可以根据实际需求进行修改和扩展。
阅读全文