1.主/从角色划分:
1.概念
①Coil和Register
Modbus中定义的两种数据类型。Coil是位(bit)变量;Register是整型(Word,即16-bit)变量。
②Slave和Master与Server和Client
同一种设备在不同领域的不同叫法。
Slave: 工业自动化用语;响应请求;
Master:工业自动化用语;发送请求;
Server:IT用语;响应请求;
Client:IT用语;发送请求;
在Modbus中,Slave和Server意思相同,Master和Client意思相同。
2.Modbus数据模型
Modbus中,数据可以分为两大类,分别为Coil和Register,每一种数据,根据读写方式的不同,又可细分为两种(只读,读写)。
Modbus四种数据类型:
Discretes Input 位变量 只读
Coils 位变量 读写
Input Registers 16-bit整型 只读
Holding Registers 16-bit整型 读写
通常,在Slave端中,定义四张表来实现四种数据。
3.Modbus地址范围对应表
设备地址 Modbus地址 描述 功能 R/W
1~10000 address-1 Coils(Output) 0 R/W
10001~20000 address-10001 Discrete Inputs 01 R
30001~40000 address-30001 Input Registers 04 R
40001~50000 address-40001 Holding Registers 03 R/W
4.Modbus变量地址
映射地址 Function Code 地址类型 R/W 描述
0xxxx 01,05,15 Coil R/W -
1xxxx 02 离散输入 R -
2xxxx 03,04,06,16 浮点寄存器 R/W 两个连续16-bit寄存器表示一个浮点数(IEEE754)
3xxxx 04 输入寄存器 R 每个寄存器表示一个16-bit无符号整数(0~65535)
4xxxx 03,06,16 保持寄存器 R/W -
5xxxx 03,04,06,16 ASCII字符 R/W 每个寄存器表示两个ASCII字符
5. rtu与tcp的相互转化:
将Modbus RTU改写成Modbus TCP/IP形式。
Modbus RTU:01 03 01 8E 00 04 25 DE
Modbus TCP/IP:00 00 00 00 00 06 01 03 01 8E 00 04
两者含义是一样的,就是从地址码为01的模块的0x018E寄存器地址开始读4个寄存器。
6. rtu master 通讯demo:
#define MODBUS_DEV_NAME "/dev/ttyUSB0"
modbus_t *ctx =NULL;
printf("==liuxd==main enter,%s,115200\n",MODBUS_DEV_NAME);
// 以串口的方式创建libmobus实例,并设置参数
ctx = modbus_new_rtu(MODBUS_DEV_NAME, 115200, 'N', 8, 1);
if (ctx == NULL) //使用UART4,对应的设备描述符为ttymxc3
{
fprintf(stderr, "Unable to allocate libmodbus contex\n");
return -1;
}
struct timeval response_timeout;
response_timeout.tv_sec = 10;
response_timeout.tv_usec = 0;
modbus_set_response_timeout(ctx,response_timeout.tv_sec,response_timeout.tv_usec);
// 使用RS485时需考虑设置串口模式、RTS引脚等
// modbus_rtu_set_serial_mode(MODBUS_RTU_RS485); //设置串口模式
modbus_set_debug(ctx, 1); //设置1可看到调试信息
modbus_set_slave(ctx, 1); //设置slave ID
if (modbus_connect(ctx) == -1) //等待连接设备
{
fprintf(stderr, "Connection failed:%s\n", modbus_strerror(errno));
return -1;
}
int i,rc;
uint16_t tab_reg[64] = {0}; //定义存放数据的数组
printf("==liuxd== enter while==\n");
while (1)
{
printf("\n----------------\n");
//读取保持寄存器的值,可读取多个连续输入保持寄存器
rc = modbus_read_registers(ctx, 0, 10, tab_reg);
if (rc == -1)
{
fprintf(stderr,"liuxd modbus_read_registers=%s\n", modbus_strerror(errno));
return -1;
}
for (i=0; i<10; i++)
{
printf("reg[%d] = %d(0x%x)\n", i, tab_reg[i], tab_reg[i]);
}
usleep(5000000);
}
printf("==liuxd== exit while==\n");
modbus_close(ctx); //关闭modbus连接
modbus_free(ctx); //释放modbus资源,使用完libmodbus需要释放掉
return 0;
}