提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
本章节是博主学习Modbus TCP所写的一篇文章
一、Modbus TCP是什么?
1.1.1 Modbus TCP介绍
Modbus TCP是Modbus的一个分支,主要用到网口通信的,在工业上也用的很频繁,我们公司最近的项目就是用的W5500+modbus TCP来和PC端的上位机通信和交互的。虽然这个项目不是我在写代码,但是我都学了Modbus RTU了,那我也抽空学习一下Modbus TCP吧。本次的Modbus TCP不是博主写的,是一个大佬开源的一个W5500写的一个Mobus TCP代码,我在这个基础上自己写了主机读从机多个数据,和主机写从机寄存器的函数。这个项目搞了一天,主要是一直ping不通,最后ping通了。
Modbus TCP 相较于 Mobus RTU是没有CRC16校验位的,而且还多了4个字节的事务协议。
1.1.2 报文格式
0x03 主机读从机寄存器
/*******************************************************************************
Modbus TCP
主机保持读从机 实物协议 字节长度 从机地址 功能码 起始地址 读取线圈个数
主机 05 95 00 00 00 06 01 03 00 00 00 01
实物协议 字节长度 从机地址 功能码 字节个数 上传数据
从机 05 95 00 00 00 05 01 03 02 00 04
0x03 读保持寄存器
********************************************************************************/
0x06 主机写从机寄存器
/*******************************************************************************
Modbus TCP
主机写单一从机 实物协议 字节长度 从机地址 功能码 寄存器地址 下发数据
主机 31 C9 00 00 00 06 01 06 00 00 00 20
实物协议 字节长度 从机地址 功能码 寄存器地址 下发数据
从机 31 C9 00 00 00 06 01 06 00 00 00 20
0x06 写单一寄存器
********************************************************************************/
总体来说还是很简单的
二、W5500配置
工程源码:添加链接描述,大家记得给博主点赞哈。
首先是配置
然后是查看你的IP地址、网关、子网掩码等
Win+R弹出运行框,然后输入cmd进入到
然后是 ipconfig/all可以查看IP地址等,这里我用的以太网.
然后可以自己静态分配地址 IPv4
然后就是修改代码
/*******************************************************************************
* 函数名 : Load_Net_Parameters
* 描述 : 装载网络参数
* 输入 : 无
* 输出 : 无
* 返回值 : 无
* 说明 : 网关、掩码、物理地址、本机IP地址、端口号、目的IP地址、目的端口号、端口工作模式
*******************************************************************************/
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]=0x08;//加载物理地址 ,这个可以和主机的不一样
Phy_Addr[1]=0x97;
Phy_Addr[2]=0x98;
Phy_Addr[3]=0xBE;
Phy_Addr[4]=0x2F;
Phy_Addr[5]=0x7F;
IP_Addr[0]=192;//加载本机IP地址
IP_Addr[1]=168;
IP_Addr[2]=1;
IP_Addr[3]=17;
S0_Port[0] = 0x13;//加载端口0的端口号5000
S0_Port[1] = 0x88;
S0_Mode=TCP_SERVER;//加载端口0的工作模式,TCP服务端模式
}
然后我们在cmd里面ping一下看通不通
输入 ping 自己的IP,我这里是 ping 192.168.1.17,下面是Ping成功的情况。
这个时候我们就可以用Modbus调试了。
三.读保持寄存器&&写单一寄存器函数
1.代码展示
/*******************************************************************************
* 函数名 : Process_Socket_Keep_Read_nData
* 描述 : W5500接收并发送接收到的多个数据
* 输入 : s:端口号
* 输出 : 无
* 返回值 : 无
* 说明 : 本过程先调用S_rx_process()从W5500的端口接收数据缓冲区读取数据,
* 然后将读取的数据从Rx_Buffer拷贝到Temp_Buffer缓冲区进行处理。
* 处理完毕,将数据从Temp_Buffer拷贝到Tx_Buffer缓冲区。调用S_tx_process()
* 发送数据。注意这里是发送多个数据(0x03),写一个数据是(0x06)
*******************************************************************************/
void Process_Socket_Keep_Read_nData(SOCKET s,uint8_t* Tx_Buff_datas){
uint16_t size;
uint8_t Tx_Buffer_CP[128];
uint8_t p=0;
size=Read_SOCK_Data_Buffer(s, Rx_Buffer);
/*******************************************************************************
Modbus TCP
主机保持读从机 实物协议 字节长度 从机地址 功能码 起始地址 读取线圈个数
主机 05 95 00 00 00 06 01 03 00 00 00 01
实物协议 字节长度 从机地址 功能码 字节个数 上传数据
从机 05 95 00 00 00 05 01 03 02 00 04
0x03 读保持寄存器
********************************************************************************/
if(Rx_Buffer[6]==0x01){//判读是否是该从机寄存器地址
if(Rx_Buffer[7]==0x03){//主机读取从机保持读寄存器
// printf("PC receive Data(0x03)=");
// for(int i=0;i<size;i++){
// printf("0x%X,",Rx_Buffer[i]);
// }
// printf("\r\n");
//判断发送的字节数量
uint16_t Begin_addr=Rx_Buffer[8]<<8;//读取起始地址高八位
Begin_addr=Rx_Buffer[9]; //读取起始地址低八位
uint16_t End_addr=Rx_Buffer[10]<<8;//读取结束地址高八位
End_addr=Rx_Buffer[11];//读取结束地址低八位
uint16_t RX_SUM=End_addr-Begin_addr;//主机读取多少个数据
uint16_t RX_SUM_size=RX_SUM*2;
//printf("PULL READ Data=%d\r\n",RX_SUM_size);
//判断事务协议后的字节数量
uint16_t start_size=3+RX_SUM_size;
//实物协议码
Tx_Buffer_CP[0]=Rx_Buffer[0];
Tx_Buffer_CP[1]=Rx_Buffer[1];
Tx_Buffer_CP[2]=Rx_Buffer[2];
Tx_Buffer_CP[3]=Rx_Buffer[3];
//下发长度
Tx_Buffer_CP[4]=start_size>>8;
Tx_Buffer_CP[5]=start_size;
//从机地址
Tx_Buffer_CP[6]=Rx_Buffer[6];
//功能码
Tx_Buffer_CP[7]=Rx_Buffer[7];
//发送的字节长度
Tx_Buffer_CP[8]=RX_SUM_size;
p=9;
for(int j=0;j<RX_SUM_size;j++){
if((p+j)%2==1){ //填充高8位
Tx_Buffer_CP[p+j]=Tx_Buff_datas[j];
}else{ //填充低8位
Tx_Buffer_CP[p+j]=Tx_Buff_datas[j];
}
}
memcpy(Tx_Buffer, Tx_Buffer_CP, p+RX_SUM_size);
//printf("size=%d\r\n",p+RX_SUM_size);
//发送响应报文
Write_SOCK_Data_Buffer(0, Tx_Buffer, p+RX_SUM_size);
}else if(Rx_Buffer[7]==0x06){//主机写从机单一寄存器
/*******************************************************************************
Modbus TCP
主机写单一从机 实物协议 字节长度 从机地址 功能码 寄存器地址 下发数据
主机 31 C9 00 00 00 06 01 06 00 00 00 20
实物协议 字节长度 从机地址 功能码 寄存器地址 下发数据
从机 31 C9 00 00 00 06 01 06 00 00 00 20
0x06 写单一寄存器
********************************************************************************/
//写地址
uint16_t Write_addr=Rx_Buffer[8]>>8;
Write_addr=Rx_Buffer[9];
//写数据
uint16_t Write_data=Rx_Buffer[10]>>8;
Write_data=Rx_Buffer[11];
printf("Write_addr=0x%x,Write_data=0x%x\r\n",Write_addr,Write_data);
printf("PC receive Data(0x06)=");
for(int w=0;w<size;w++){
printf("0x%X,",Rx_Buffer[w]);
}
printf("\r\n");
for(int i=0;i<size;i++){
Tx_Buffer[i]=Rx_Buffer[i];
}
printf("0x06_data_size=%d\r\n",size);
Write_SOCK_Data_Buffer(0, Tx_Buffer, size);
if(Write_addr==0x04){
if(Write_data==0x01){
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_SET);//控制LED灯
}else if(Write_data==0x02){
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_RESET);
}
}
}
}else{
printf("Not the address, but=0x%X,\r\n",Rx_Buffer[6]);
}
}
这里就介绍完了,最后效果展示
2.参考资料
W5500+STM32F103C8T6进行TCP通信(modbus)_junseven164的博客-CSDN博客文章来源:https://www.toymoban.com/news/detail-616176.html
总结
Modbus TCP使用还是非常好的,之前博主没有学Modbus的时候一直用的JSON格式来打包数据给上位机。现在掌握两种数据格式,美滋滋文章来源地址https://www.toymoban.com/news/detail-616176.html
到了这里,关于[STM32F103C8T6]W5500+Modbus TCP(HAL库)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!