1.modbus RTU
1.1 与modbus TCP的区别
在一般工业场景使用modbus RTU的场景还是更多一些,modbus RTU基于串行协议进行收发数据,包括RS232/485等工业总线协议。
与modbus TCP不同的是RTU没有报文头MBAP字段,保留从机地址,在尾部增加了两个CRC检验字节(CRC16),因为网络协议中自带校验,所以在 ModbusTCP协议中不需要使用CRC校验码。
RTU和TCP的总体使用方法基本一致,只是在创建modbus对象时有所不同,TCP需要传入网络socket信息;而RTU需要传入串口相关信息。
1.2 特点
Modbus RTU也是主从问答协议,由主机发起,一问一答
设置串口参数:
设置串口参数时要求:
波特率为9600 bit/s
8位数据位
1位停止位
无流控
2. 格式
ModbusRTU数据帧包含:从站地址码 功能码 数据 校验码
地址码:从机 ID
功能码:同 TCP
数据:起始地址 数量 数据
校验码:2个字节,对 地址码 功能码 数据进行校验,可以通过函数自动生成
3. 报文详解
以03 功能为例
主机--》从机
01 03 00 00 00 0184 0A
01:从机id
03:功能码
00 00:起始地址
00 01:数量
84 0A:CRC校验
从机---》主机
01 03 02 00 14 B4 44
01:从机id
03:功能码
02:字节计数
00 14:数据
B4 44:CRC校验
4. 步骤
步骤:
(1)打开串口文件 open
(2)初始化串口 uart_init
(3)实现功能,从机id 功能码 起始地址 数量
(4)传入数组,生成CRC校验码 GetCRC16
(5)将生成的CRC校验码放入数组,完成拼接
(6)向串口写入数组 write
(7)接收,读串口文件 read
(8)关闭文件描述符
在虚拟机端写代码实现串口的发送
// 从串口发送数据给从机
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "Crc_Calc.h"
int main(int argc, char const *argv[])
{
// 1.打开串口文件
int fd;
fd = open("/dev/ttyS1", O_RDWR);
if (fd < 0)
{
printf("open error");
return -1;
}
// 2.初始化串口
uart_init(fd);
// 3.实现03功能码的某一功能
// buf:01 03 00 00 00 01
uint8_t buf[12] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x01};
uint8_t buf1[12] = {0x01, 0x05, 0x00, 0x00, 0xFF, 0x00};
// 4.根据算法函数,传入数组生成校验码,16位,两个字节
uint16_t crc = GetCRC16(buf, 6);
uint16_t crc2 = GetCRC16(buf1, 6);
// 5.将生成的校验码放入数组,完成拼接
buf[6] = crc >> 8;
buf[7] = crc;
buf1[6] = crc2 >> 8;
buf1[7] = crc2;
// 6.发送---向串口文件中写数组
write(fd, buf, 8);
// 7.接收---读串口文件
uint8_t data[128];
read(fd, data, sizeof(data));
// 8.打印
for (int i = 0; i < data[2]; i++)
{
printf("%02x ", data[3 + i]);
}
printf("\n");
uint8_t data2[128];
write(fd, buf1, 8);
read(fd, data2, sizeof(data2));
for (int i = 0; i < data2[2]; i++)
{
printf("%02x ", data2[3 + i]);
}
printf("\n");
// 9.关闭文件描述符
close(fd);
return 0;
}