一、Modbus/TCP协议
功能码 | 作用 |
---|---|
01 | 读取线圈状态 |
02 | 读取输入状态 |
03 | 读取保持寄存器 |
04 | 读取输入寄存器 |
05 | 强置单线圈 |
06 | 预置单寄存器 |
07 | 读取异常状态 |
08 | 回送诊断校验 |
09 | 编程(只用于484) |
0A | 控询 |
0B | 读取事件计数 |
0C | 读取通信事件记录 |
0D | 编程(184/384/484/584等) |
0E | 探寻 |
0F | 强置多线圈 |
10 | 预置多线圈 |
11 | 报告多寄存器 |
12 | 可使主机模拟编程功能 |
13 | 重置通信链路 |
14 | 读取通用参数 |
15 | 写入通用参数 |
16 | 屏蔽写寄存器 |
17 | 读/写多个寄存器 |
1.查询报文
00 6D 00 00 00 06 01 03 00 00 00 01
00 6D 查询编号
00 00 协议
00 06 数据包长度
01 设备编号
03 功能码
00 00 起始地址
00 01 查询寄存器个数
2.响应报文
00 6D 00 00 00 05 01 03 02 00 17
00 6D 查询编号
00 00 协议
00 05 数据包长度
01 设备地址
03 功能码
02 数据长度
00 17 数据值
二、从机代码
1.初始化从机网络
void Load_Net_Parameters(void)
{
Gateway_IP[0] = 192;//加载网关参数
Gateway_IP[1] = 168;
Gateway_IP[2] = 1;
Gateway_IP[3] = 1;
Sub_Mask[0]=255;//加载子网掩码
Sub_Mask[1]=255;
Sub_Mask[2]=255;
Sub_Mask[3]=0;
Phy_Addr[0]=0x0c;//加载物理地址
Phy_Addr[1]=0x29;
Phy_Addr[2]=0xab;
Phy_Addr[3]=0x7c;
Phy_Addr[4]=0x00;
Phy_Addr[5]=0x01;
IP_Addr[0]=192;//加载本机IP地址
IP_Addr[1]=168;
IP_Addr[2]=1;
IP_Addr[3]=199;
S0_Port[0] = 0x13;//加载端口0的端口号5000
S0_Port[1] = 0x88;
S0_Mode=TCP_SERVER;//加载端口0的工作模式,TCP服务端模式
}
2.简单响应函数
返回一个全局变量data,并且每次响应后自增1。
void Process_Socket_Data(SOCKET s)
{
int len;
unsigned char msg[11]={0x00,0x00,0x00 ,0x00, 0x00, 0x05, 0x01, 0x03, 0x02, 0x00, 0x70};
len=sizeof(msg);
unsigned short size;
size=Read_SOCK_Data_Buffer(s, Rx_Buffer);
memcpy(Tx_Buffer, Rx_Buffer, size);
//打印查询报文
for (int j=0;j<size;j++){
printf("0x%02X ",Tx_Buffer[j]);
}
//写响应报文
//检验码
msg[0]=Tx_Buffer[0];
msg[1]=Tx_Buffer[1];
//协议
msg[2]=0x00;
msg[3]=0x00;
//数据包长度
msg[4]=0x00;
msg[5]=0x05;
//设备编号
msg[6]=Tx_Buffer[6];
//功能码
msg[7]=Tx_Buffer[7];
//数据长度
msg[8]=0x02;
//低八位
msg[10]=data&0XFF;
//高八位
msg[9]=data>>8;
memcpy(Tx_Buffer, msg, len);
//发送响应报文
Write_SOCK_Data_Buffer(0, Tx_Buffer, len);
data++;
}
3.main函数循环等待连接
while (1)
{
W5500_Socket_Set();//W5500端口初始化配置
W5500_Interrupt_Process();//W5500中断处理程序框架
if((S0_Data & S_RECEIVE) == S_RECEIVE)//如果Socket0接收到数据
{
S0_Data&=~S_RECEIVE;
Process_Socket_Data(0);//W5500接收并发送接收到的数据
}
//从机状态标志
HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);
}
三、效果
使用modbus poll建立连接
设置id、地址、读取位数
使用TCP/IP建立连接,设置地址、端口。
效果
可以看到可以成功读取到data的值
四、总结
这次实验只是简单的读取了一个寄存器的值,多个寄存器思路类似。
五、源码
https://github.com/TangtangSix/Modbus_TCP
版权声明:本文为CSDN博主「醉意丶千层梦」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_47281915/article/details/121927294
一、Modbus/TCP协议
1.功能码
2.查询报文和相应报文
查询报文:
00 6D 00 00 00 06 01 03 00 00 00 01
00 6D 查询编号
00 00 协议
00 06 数据包长度
01 设备编号
03 功能码
00 00 起始地址
00 01 查询寄存器个数
响应报文:
00 6D 00 00 00 05 01 03 02 00 17
00 6D 查询编号
00 00 协议
00 05 数据包长度
01 设备地址
03 功能码
02 数据长度
00 17 数据值
二.从机代码
1.初始化从机网络
void Load_Net_Parameters(void)
{
Gateway_IP[0] = 192;//加载网关参数
Gateway_IP[1] = 168;
Gateway_IP[2] = 1;
Gateway_IP[3] = 1;
Sub_Mask[0]=255;//加载子网掩码
Sub_Mask[1]=255;
Sub_Mask[2]=255;
Sub_Mask[3]=0;
Phy_Addr[0]=0x0c;//加载物理地址
Phy_Addr[1]=0x29;
Phy_Addr[2]=0xab;
Phy_Addr[3]=0x7c;
Phy_Addr[4]=0x00;
Phy_Addr[5]=0x01;
IP_Addr[0]=192;//加载本机IP地址
IP_Addr[1]=168;
IP_Addr[2]=1;
IP_Addr[3]=199;
S0_Port[0] = 0x13;//加载端口0的端口号5000
S0_Port[1] = 0x88;
S0_Mode=TCP_SERVER;//加载端口0的工作模式,TCP服务端模式
}
2.简单响应函数
void Process_Socket_Data(SOCKET s)
{
int len;
unsigned char msg[11]={0x00,0x00,0x00 ,0x00, 0x00, 0x05, 0x01, 0x03, 0x02, 0x00, 0x70};
len=sizeof(msg);
unsigned short size;
size=Read_SOCK_Data_Buffer(s, Rx_Buffer);
memcpy(Tx_Buffer, Rx_Buffer, size);
//打印查询报文
for (int j=0;j<size;j++){
printf("0x%02X ",Tx_Buffer[j]);
}
//写响应报文
//检验码
msg[0]=Tx_Buffer[0];
msg[1]=Tx_Buffer[1];
//协议
msg[2]=0x00;
msg[3]=0x00;
//数据包长度
msg[4]=0x00;
msg[5]=0x05;
//设备编号
msg[6]=Tx_Buffer[6];
//功能码
msg[7]=Tx_Buffer[7];
//数据长度
msg[8]=0x02;
//低八位
msg[10]=data&0XFF;
//高八位
msg[9]=data>>8;
memcpy(Tx_Buffer, msg, len);
//发送响应报文
Write_SOCK_Data_Buffer(0, Tx_Buffer, len);
data++;
}
3.main函数循环等待连接
while (1)
{
W5500_Socket_Set();//W5500端口初始化配置
W5500_Interrupt_Process();//W5500中断处理程序框架
if((S0_Data & S_RECEIVE) == S_RECEIVE)//如果Socket0接收到数据
{
S0_Data&=~S_RECEIVE;
Process_Socket_Data(0);//W5500接收并发送接收到的数据
}
//从机状态标志
HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);
}
三.结果
1.使用modbus poll建立连接
设置id、地址、读取位数
2.使用TCP/IP建立连接,设置地址、端口。
3.效果
可以看到可以成功读取到data的值
四.总结
此次实验我们简单的读取了一个寄存器的值,同样方式在多个寄存器同样适用。
五.参考文献
https://blog.csdn.net/qq_47281915/article/details/121927294?spm=1001.2014.3001.5501.
版权声明:本文为CSDN博主「SomyloveLI」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/louderIII/article/details/122146208
一,目的
掌握W5500网络模块的特点,参考模块厂商配套资料,完成TCP数据通信、DHCP自动获取IP的程序设计。在此基础上,实现应用层modbus、httpd(web服务)协议编程。
二,代码
1,初始化从机网络
void Load_Net_Parameters(void)
{
Gateway_IP[0] = 10;//加载网关参数
Gateway_IP[1] = 60;
Gateway_IP[2] = 255;
Gateway_IP[3] = 254;
Sub_Mask[0]=255;//加载子网掩码
Sub_Mask[1]=255;
Sub_Mask[2]=255;
Sub_Mask[3]=0;
Phy_Addr[0]=0x0c;//加载物理地址
Phy_Addr[1]=0x29;
Phy_Addr[2]=0xab;
Phy_Addr[3]=0x7c;
Phy_Addr[4]=0x00;
Phy_Addr[5]=0x01;
IP_Addr[0]=10;//加载本机IP地址
IP_Addr[1]=60;
IP_Addr[2]=237;
IP_Addr[3]=75;
S0_Port[0] = 0x13;//加载端口0的端口号5000
S0_Port[1] = 0x88;
// S0_DIP[0]=192;//加载端口0的目的IP地址
// S0_DIP[1]=168;
// S0_DIP[2]=1;
// S0_DIP[3]=190;
//
// S0_DPort[0] = 0x17;//加载端口0的目的端口号6000
// S0_DPort[1] = 0x70;
S0_Mode=TCP_SERVER;//加载端口0的工作模式,TCP服务端模式
}
2,响应函数
void Process_Socket_Data(SOCKET s)
{
int len;
unsigned char msg[11]={0x00,0x00,0x00 ,0x00, 0x00, 0x05, 0x01, 0x03, 0x02, 0x00, 0x70};
len=sizeof(msg);
unsigned short size;
size=Read_SOCK_Data_Buffer(s, Rx_Buffer);
memcpy(Tx_Buffer, Rx_Buffer, size);
//打印查询报文
for (int j=0;j<size;j++){
printf("0x%02X ",Tx_Buffer[j]);
}
//写响应报文
//检验码
msg[0]=Tx_Buffer[0];
msg[1]=Tx_Buffer[1];
//协议
msg[2]=0x00;
msg[3]=0x00;
//数据包长度
msg[4]=0x00;
msg[5]=0x05;
//设备编号
msg[6]=Tx_Buffer[6];
//功能码
msg[7]=Tx_Buffer[7];
//数据长度
msg[8]=0x02;
//低八位
msg[10]=data&0XFF;
//高八位
msg[9]=data>>8;
memcpy(Tx_Buffer, msg, len);
//发送响应报文
Write_SOCK_Data_Buffer(0, Tx_Buffer, len);
data++;
}
然后使用modbus poll建立连接
再使用TCP/IP建立连接,设置地址、端口。
可以看到可以成功读取到data的值
三,总结
泪目了,完全不会,照着别人的依葫芦画瓢勉强做了出来。到时候再仔细想想原理吧
四,参考
https://blog.csdn.net/qq_47281915/article/details/121927294?spm=1001.2014.3001.5501
版权声明:本文为CSDN博主「可小阿木」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_53329531/article/details/122193956
暂无评论