基于Modbus/TCP的西门子1200PLC和STM32通信

1.前言
对于工控而言,有时候会需要和单片机进行通信,最近就测试了一下市面上常见的西门子PLC和STM32F103VET6的单片机进行通信。
2.硬件架构
STM32+W5500+ModbusTCP+西门子1200PLC 中间需要交换机来互联网口
首先通信是要基于协议的,对于单片机和PLC而言之间的通信协议可以有很多,串口232,485,ModbusRTU/TCP等等。现在工控都是组网时代了,ModbusTCP作为一款开源的协议资料也很多便于第三方移植。
PLC端现在大多数支持网口,西门子1200,1500系列PLC自带网口,支持Modbus协议,通信起来也方便一些。
单片机端选择需要带网口,我用的是野火指南者开发板,本身自己没有带网口,但是现在以太网模块很多,这里选择W5500的以太网模块来实现组网。W5500可以实现基于硬件的TCP/IP协议,可以避免解析复杂的TCP/IP协议,例程也多方便移植。其实本质就是基于W5500模块的ModbusTCP移植。这部分有很多参考资料,主要参考这篇文章,十分感谢https://blog.csdn.net/jordan20052009/article/details/46967451?ops_request_misc=%25257B%252522request%25255Fid%252522%25253A%252522160744407419726891153872%252522%25252C%252522scm%252522%25253A%25252220140713.130102334.pc%25255Fall.%252522%25257D&request_id=160744407419726891153872&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_v2~rank_v29-25-46967451.pc_search_result_cache&utm_term=freemodbus%20tcp
3.移植分析
需要理解Modbus协议的相关内容,W5500的使用,PLC端主站的建立。
其实分3大块:
1.Modbus协议源码移植
2.W5500TCP/IP移植
3.PLC端主站代码的编写
熟悉PLC的朋友应该知道,第3点其实不难,而且是在PLC里面写跟单片机其实没有太大关系,实际上在单片机跑通之后,就可以用Modbus scan32一类的工具去测试连接了,只要调试助手能读取成功就证明单片机端代码没有问题。
那就只剩下第1,2点。我是这么做的,先单独完成Modbus RTU的移植,这样可以方便了解Modbus协议的工作原理,再单独完成W5500TCP/IP的协议移植这样可以理解W5500的使用方法,最后再两者结合,就可以实现。不了解的同学可以尝试分步实现。一定要理解Modbus 因为我们就是在W5500的函数基础上添加Modbus内容。TCP/IP实现底层的收发,Modbus再对其进行处理。
4.移植流程
1.W5500可以直接参考官方的例程,下面是main函数

在这里插入代码片int main( void )
{
  eMBErrorCode    eStatus;                    
  systick_init(72);                     // 初始化滴答定时器
  USART1_Config();                      // 初始化USART1:115200@8-N-1 
  reset_break_gpio_init();              // 复位与中断管脚初始化
  spi_gpio_init();                      // SPI管脚初始化
  spiinitailize();                      // SPI配置初始化
  printf("\r\n 炜世科技--WIZnet W5500官方代理商。全程技术支持,价格优势大!\r\n\r\n");
  reset_w5500();                        // w5500硬件复位 
  PHY_check();                          // 网线检测程序
  set_w5500_mac();                      // 设置w5500MAC地址
  set_w5500_netinfo();                  // 设置w5500网络参数
  socket_buf_init(txsize, rxsize);      // 初始化4个Socket的发送接收缓存大小
  printf("\r\n W5500为TCP Server,建立侦听。等待PC作为TCP Client建立连接。\r\n");
  printf(" TCP Server IP:%d.%d.%d.%d。\r\n",remote_ip[0],remote_ip[1],remote_ip[2],remote_ip[3]);
  printf(" TCP Server Port:%d。\r\n",remote_port);
  printf(" 正常现象:连接成功,TCP Client发送数据给W5500,W5500将返回对应数据。\r\n");
  eStatus = eMBTCPInit( 2 );           //Modbus相关TCP初始化
  eStatus =eMBEnable();                //Modbus协议栈使能	
    while(1)
    {	
    modbus_tcps();                       //主函数
    }	
}

这其实是官方的例程,Modbus是后添加的,while中的循环函数我也进行了修改,是跟Modbus相关的。其实执行到最后一条Prtinf语句后,W5500就已经配置完成了,已经可以ping通了,这就可以证明W5500运转正常了,之后再去做下一步动作。官方的例程基本不需要修改,拿来直接用就可以,只是SPI部分的硬件接线要根据自己实际板子来修改部分代码。关于W5500可以参考官网的教程和网络资料也比较多,这里不多说。说一下IP地址

/*MAC地址首字节必须为偶数
  如果多块w5500网络适配板在同一现场工作,请使用不同的MAC地址
*/
uint8 mac[6]={0x00,0x08,0xdc,0x11,0x11,0x11};

/*定义默认IP信息*/
uint8 local_ip[4] = {192,168,1,8};                        // 定义w5500默认IP地址
uint8 subnet[4] = {255,255,255,0};                          // 定义w5500默认子网掩码
uint8 gateway[4] = {192,168,1,1};                           // 定义w5500默认网关
uint8 dns_server[4] = {114,114,114,114};                    // 定义w5500默认DNS

uint16 local_port = 502;                                   // 定义本地端口

注意单片机IP要和本地PLC在同一网段。端口号要和PLC端一致,常用502.
mac地址如果是多设备注意不要重复。下面是while中的函数。和RTU不同,TCP是一直处在监听状态,一旦建立了连接就会一直查询,检测到数据长度ucTCPRequestLen>0就开始接受数据,接受到数据之后,再驱动empoll函数即可 进入到Modbus的内部处理流程,处理完了再通过send函数发送出去。Send和recv都是W5500的库函数。

void modbus_tcps(void)
{  
  uint16 len=0;  
  switch(getSn_SR(SOCK_TCPS))                             // 获取socket的状态
  {
    case SOCK_CLOSED:                                     // socket处于关闭状态
      socket(SOCK_TCPS ,Sn_MR_TCP,local_port,Sn_MR_ND);   // 打开socket
      break;     
    
    case SOCK_INIT:                                       // socket已初始化状态
      listen(SOCK_TCPS);                                  // socket建立监听
      break;
    
    case SOCK_ESTABLISHED:                                // socket处于连接建立状态
    
      if(getSn_IR(SOCK_TCPS) & Sn_IR_CON)
      {
        setSn_IR(SOCK_TCPS, Sn_IR_CON);                   // 清除接收中断标志位
      }
      ucTCPRequestLen=getSn_RX_RSR(SOCK_TCPS);                        // 定义len为已接收数据的长度
      if(ucTCPRequestLen>0)
      {
				 recv(SOCK_TCPS,ucTCPRequestFrame, ucTCPRequestLen); //W5500接收数据
         xMBPortEventPost(EV_FRAME_RECEIVED);  //发送EV_FRAME_RECEIVED事件,以驱动eMBpoll()函数中的状态机
         eMBPoll();   //处理EV_FRAME_RECEIVED事件
         eMBPoll();   //处理EV_EXECUTE事件
         if(bFrameSent)  
           {  
              bFrameSent = FALSE;  //W5500发送Modbus应答数据包                               
              send(SOCK_TCPS,ucTCPResponseFrame,ucTCPResponseLen);
           }													
      }
      break;
    
    case SOCK_CLOSE_WAIT:                                 // socket处于等待关闭状态
			disconnect(SOCK_TCPS);                              // 断开当前TCP连接
      close(SOCK_TCPS);                                   // 关闭当前所使用socket
      break;
  }
}

其实如果完全不了解Modbus协议的话,移植起来还是比较困难,建议一定要了解一些之后再移植,可以先做ModbusRTU的移植。

  • 5
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值