文章目录[隐藏]
一、W5500以太网模块介绍
Niren_W5500模块是一款基于WIZnet W5500芯片的以太网模块,是泥人电子继 Niren_W5100模块后设计的一块性能更好、性价比更高的以太网模块。模块集成硬件化TCP/IP协议:内部32K字节存储器作TX/RX
缓存:支持10/100Mbps的传输速率;支持8个独立端口同时运行;同时模块还支持3.3V或5V电源供电,5V供电时还可以输出3.3V电源,方便用户在不同的单片机系统中使用;模块与单片机系统的通讯方式是简单、方便的SPI通信。
二、modbus通信
- 当设备设置为使用ASCII(美国信息交换标准代码)模式在MODBUS串行线上进行通信时,消息中的每个8位字节将作为两个ASCII4位字符发送。当物理通信链路或设备的功能不允许符合RTU计时器管理要求时,使用此模式。
所以此模式的效率不如RTU,因为每个字节需要两个字符。示例:字节0x7D编码为两个字符:0x35和0x42(在ASCII表中为0x37=‘7’,而0x44 =‘D’)。 - Modbus RTU是一种紧凑的,采用二进制表示数据的方式;因为使用二进制编码和CRC错误检查的结合使得Modbus RTU适用于工业应用,因为它比ASCII字符的替代方案更有效地传输。 在Modbus RTU与ASCII之间进行选择时,如果考虑性能,则RTU是首选。
- Modbus TCP 是在TCP/IP网络上运行的Modbus的实现,旨在允许Modbus ASCII / RTU协议在基于TCP /IP的网络上传输。Modbus / TCP将Modbus消息嵌入TCP /IP帧内。尽管实现起来非常简单,但是与网络相关的特性增加了一些挑战。例如,由于Modbus主机期望并要求在一定时间范围内对其轮询做出响应,因此必须考虑TCP/ IP网络的不确定性(和其他方面)。 Modbus ASCII和Modbus TCP之间的主要区别在于,Modbus ASCII所需的LRC错误检查由IP层执行。
三、从机代码
void Load_Net_Parameters(void)
{
Gateway_IP[0] = 192;//加载网关参数
Gateway_IP[1] = 168;
Gateway_IP[2] = 0;
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]=0;
IP_Addr[3]=199;
S0_Port[0] = 0x13;//加载端口0的端口号5000
S0_Port[1] = 0x88;
S0_Mode=TCP_SERVER;//加载端口0的工作模式,TCP服务端模式
}
- 简单响应函数,这里需要在开始定义一个全局变量data,每次调用都会使data++,而返回的数据就是把data置于数据位,值通过tcp回传回去,能在modbus poll里看到这个值
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++;
}
- 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读取设置
-
读取效果
四、总结
有的人天生就是主角,只能说,大佬确实强啊
参考链接
https://blog.csdn.net/junseven164/article/details/122148326
https://blog.csdn.net/qq_45659777/article/details/121952778
版权声明:本文为CSDN博主「羚漆」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zero_zero_seven/article/details/122203016
一、w5500资料
- w5500的资料就放在下面了,单纯的客户端和其他模式上面有教程
https://www.aliyundrive.com/s/enPnnZgNtpE
二、modbus通信
-
Modbus RTU通信时使用的数据帧结构如下图,而Moubus TCP通信的数据帧和这个稍微不一样,没有crc检验,因为tcp本就是一种可靠传输协议
-
这里是Modbus TCP数据帧
-
公共功能码定义
三、从机代码
- 关键代码,这里需要在开始定义一个全局变量data,每次调用都会使data++,而返回的数据就是把data置于数据位,值通过tcp回传回去,能在modbus poll里看到这个值
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++;
}
- 代码下载链接
https://gitee.com/zxsjunqi/keilcode/tree/master/Modbus_TCP-main/Modbus_TCP-main
- Modbus Poll读取设置
- 这里是通过TCP连接,地址就是代码里所写的,比如我是192.168.201.68,端口为5000,有个前提,要通信得先把前面的客户端例子调通,也就是需要修改适配器
- 读取效果
四、总结
modbus tcp通信原理基本清楚了,但在代码实现的时候却很犹豫,不知道拿什么来接收并应答,直到看到同学的博客之后,突然就明白了,大佬是真的强啊。
五、参考
STM32F103基于W5500实现Modbus简单TCP通信
Modbus TCP通信概述
版权声明:本文为CSDN博主「伊始不觉」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/junseven164/article/details/122148326
一、w5500
D-W5500 EVB以太网模块是一款基于WIZnet W5500芯片的以太网模块,且性价比高的以太网模块。W5500是一款全硬件TCP/IP嵌入式以太网控制器,为嵌入式系统提供了更加建议的互联网连接方案。
W5500固化了TCP/IP协议栈,10/100Mbps以太网数据链路层(MAC)及物理层(PHY),使得用户使用单芯片就能够在他们的应用中拓展网络连接。内嵌32K字节片上缓存以供以太网处理,并且可以同时使用8个硬件Socket独立通讯;SPI(外设船型接口)从而能够更加容易与外设MCU整合,并且W5500使用了高效SPI协议支持80MHz,从而实现高速网络通讯。
模块还支持3.3V或者5V电源供电,当5V供电时还可以输出3.3V的电压,方便用户在不同的单片机系统中使用。
二、modbus通信
1.Modbus三种通讯方式
Modbus有下列三种通信方式:
(1)、以太网:对应的通信模式是Modbus TCP/IP
(2)、异步串行传输(各种介质如有线RS-232-/422/485/;光纤、无线等):对应的通信模式是Modbus RTU或Modbus ASCII
(3)、高速令牌传递网络:对应的通信模式是Modbus PLUS
Modbus RTU和Modbus ASCII协议应用于串口链接(RS232、RS485、RS422),Modbus tcp/ip协议应用于以太网链接。
2.在Modbus网络上传输
标准的Modbus口是使用RS-232C兼容串行接口,它定义了连接口的针脚、电缆、信号位、传输波特率、奇偶校验。控制器能直接或经由Modem组网。
控制器通信使用主/从技术,即仅一设备(主设备)能初始化传输(查询)。其它设备(从设备)根据主设备查询提供的数据作出相应反应。
典型的主设备:主机和可编程仪表。
典型的从设备:可编程控制器。
主设备可单独和从设备通信,也能以广播方式和所有从设备通信。如果单独通信,从设备返回一消息作为回应,如果是以广播方式查询的,则不作任何回应。
Modbus协议建立了主设备查询的格式:设备(或广播)地址、功能代码、所有要发送的数据、一错误检测域。
从设备回应消息也由Modbus协议构成,包括确认要行动的域、任何要返回的数据、和一错误检测域。如果在消息接收过程中发生一错误,或从设备不能执行其命令,从设备将建立一错误消息并把它作为回应发送出去。
3.以太网(modbus tcp/ip)
对于Modbus TCP而言,主站通常称为Client,从站称为Server;而对于Modbus RTU和Modbus ASCII来说,主站是Master,从站是Slave。
ModbusTCP的数据帧可分为两部分:ADU=MBAP+PDU = MBAP + 功能码 + 数据域,MBAP 7byte,功能码1byte,数据域不确定,由具体功能决定。
三、代码实现
(一)初始化从机网络
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服务端模式
(二)响应函数
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++;
}
(三)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);
}
四、结果
五、总结
本次实验用了Mudbus协议栈实现了简单的TCP通信。
六、参考资料
W5500+STM32F103C8T6进行TCP通信(modbus)_junseven164的博客-CSDN博客
版权声明:本文为CSDN博主「枫叶的鱼」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/w798214705/article/details/122201346
一、w5500资料
- w5500的资料就放在下面了,单纯的客户端和其他模式上面有教程
https://www.aliyundrive.com/s/enPnnZgNtpE
二、modbus通信
-
Modbus RTU通信时使用的数据帧结构如下图,而Moubus TCP通信的数据帧和这个稍微不一样,没有crc检验,因为tcp本就是一种可靠传输协议
-
这里是Modbus TCP数据帧
-
公共功能码定义
三、从机代码
- 关键代码,这里需要在开始定义一个全局变量data,每次调用都会使data++,而返回的数据就是把data置于数据位,值通过tcp回传回去,能在modbus poll里看到这个值
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++;
}
- 代码下载链接
https://gitee.com/zxsjunqi/keilcode/tree/master/Modbus_TCP-main/Modbus_TCP-main
- Modbus Poll读取设置
- 这里是通过TCP连接,地址就是代码里所写的,比如我是192.168.201.68,端口为5000,有个前提,要通信得先把前面的客户端例子调通,也就是需要修改适配器
- 读取效果
四、总结
modbus tcp通信原理基本清楚了,但在代码实现的时候却很犹豫,不知道拿什么来接收并应答,直到看到同学的博客之后,突然就明白了,大佬是真的强啊。
五、参考
STM32F103基于W5500实现Modbus简单TCP通信
Modbus TCP通信概述
版权声明:本文为CSDN博主「伊始不觉」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/junseven164/article/details/122148326
一、w5500
D-W5500 EVB以太网模块是一款基于WIZnet W5500芯片的以太网模块,且性价比高的以太网模块。W5500是一款全硬件TCP/IP嵌入式以太网控制器,为嵌入式系统提供了更加建议的互联网连接方案。
W5500固化了TCP/IP协议栈,10/100Mbps以太网数据链路层(MAC)及物理层(PHY),使得用户使用单芯片就能够在他们的应用中拓展网络连接。内嵌32K字节片上缓存以供以太网处理,并且可以同时使用8个硬件Socket独立通讯;SPI(外设船型接口)从而能够更加容易与外设MCU整合,并且W5500使用了高效SPI协议支持80MHz,从而实现高速网络通讯。
模块还支持3.3V或者5V电源供电,当5V供电时还可以输出3.3V的电压,方便用户在不同的单片机系统中使用。
二、modbus通信
1.Modbus三种通讯方式
Modbus有下列三种通信方式:
(1)、以太网:对应的通信模式是Modbus TCP/IP
(2)、异步串行传输(各种介质如有线RS-232-/422/485/;光纤、无线等):对应的通信模式是Modbus RTU或Modbus ASCII
(3)、高速令牌传递网络:对应的通信模式是Modbus PLUS
Modbus RTU和Modbus ASCII协议应用于串口链接(RS232、RS485、RS422),Modbus tcp/ip协议应用于以太网链接。
2.在Modbus网络上传输
标准的Modbus口是使用RS-232C兼容串行接口,它定义了连接口的针脚、电缆、信号位、传输波特率、奇偶校验。控制器能直接或经由Modem组网。
控制器通信使用主/从技术,即仅一设备(主设备)能初始化传输(查询)。其它设备(从设备)根据主设备查询提供的数据作出相应反应。
典型的主设备:主机和可编程仪表。
典型的从设备:可编程控制器。
主设备可单独和从设备通信,也能以广播方式和所有从设备通信。如果单独通信,从设备返回一消息作为回应,如果是以广播方式查询的,则不作任何回应。
Modbus协议建立了主设备查询的格式:设备(或广播)地址、功能代码、所有要发送的数据、一错误检测域。
从设备回应消息也由Modbus协议构成,包括确认要行动的域、任何要返回的数据、和一错误检测域。如果在消息接收过程中发生一错误,或从设备不能执行其命令,从设备将建立一错误消息并把它作为回应发送出去。
3.以太网(modbus tcp/ip)
对于Modbus TCP而言,主站通常称为Client,从站称为Server;而对于Modbus RTU和Modbus ASCII来说,主站是Master,从站是Slave。
ModbusTCP的数据帧可分为两部分:ADU=MBAP+PDU = MBAP + 功能码 + 数据域,MBAP 7byte,功能码1byte,数据域不确定,由具体功能决定。
三、代码实现
(一)初始化从机网络
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服务端模式
(二)响应函数
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++;
}
(三)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);
}
四、结果
五、总结
本次实验用了Mudbus协议栈实现了简单的TCP通信。
六、参考资料
W5500+STM32F103C8T6进行TCP通信(modbus)_junseven164的博客-CSDN博客
版权声明:本文为CSDN博主「枫叶的鱼」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/w798214705/article/details/122201346
暂无评论