精华内容
下载资源
问答
  • 2022-02-22 15:55:51

    STM32驱动W5500连接腾讯云

    1.W5500简介

       W5500 是一款全硬件 TCP/IP 嵌入式以太网控制器,为嵌入式系统提供了更加简易的互联网连接方案。 W5500 集成了 TCP/IP 协议栈, 10/100M 以太网数据链路层(MAC)及物理层(PHY) ,使得用户使用单芯片就能够在他们的应用中拓展网络连接。
       久经市场考验的 WIZnet 全硬件 TCP/IP 协议栈支TCP,UDP,IPv4,ICMP,ARP,IGMP 以及 PPPoE 协议。 W5500 内嵌 32K 字节片上缓存以供以太网包处理。如果你使用 W5500,你只需要一些简单的 Socket 编程就能实现以太网应用。这将会比其他嵌入式以太网方案更加快捷、简便。用户可以同时使用 8 个硬件 Socket 独立通讯。
       W5500 提供了 SPI(外设串行接口)从而能够更加容易与外设 MCU 整合。而且,W5500 的使用了新的高效 SPI 协议支持 80MHz 速率,从而能够更好的实现高速网络通讯。为了减少系统能耗, W5500 提供了网络唤醒模式(WOL)及掉电模式供客户选择使用。

    2.W5500底层驱动编写与移植

    W5500底层底层驱动移植参考示例:https://blog.csdn.net/weixin_44453694/article/details/123066305
    STM32连接腾讯云参考示例:https://blog.csdn.net/weixin_44453694/article/details/116802776

    #include "stm32f10x.h"
    #include "usart.h"
    #include "timer.h"
    #include "aliyun_mqtt.h"
    
    /*w5500相关头文件*/
    #include "w5500api.h"
    #include "dhcp.h"
    #include "dns.h"
    #define SERVER_IP "LA57WTHWL6.iotcloud.tencentdevices.com"//服务器IP
    #define SERVER_PORT 1883 //端口号
    //客户端ID:{产品ID}{设备名}
    #define ClientID "LA57WTHWL6Smart_home"
    //用户名和密码可使用密码生成工具完成
    #define Username "LA57WTHWL2Smart_home;120310126;HK8V9;1635948714"
    #define Password "2a915cae4489b591ce556e71f4e9f1ka21c354a37d12fee7c46f56abee1f048a;hmacsha256"//密文 
    
    //订阅题:$thing/down/property/{ProductID}/{DeviceName} ---{ProductID}产品ID,{DeviceName}设备名
    #define SET_TOPIC  "$thing/down/property/Lb57WTHWL3/Smart_home"//订阅
    //发布主题:$thing/up/property/{ProductID}/{DeviceName}
    #define POST_TOPIC "$thing/up/property/Lb57WTHWL3/Smart_home"//发布
    
    char mqtt_message[200];//上报数据缓存区
    u8 rx_buff[200];
    void init_Net(void)
    {
    	u8 try_times=0;
    	init_W5500();/*W5500初始化*/
    	init_dhcp_client();//动态分配IP
    	while(check_DHCP_state(SOCK_DHCP)!=DHCP_RET_UPDATE)
      {
    			try_times++;
    			if(try_times==255)//超时 重启芯片
          {							
    				Reset_W5500();
    				init_dhcp_client();
    				try_times=0;
    			}
    			delay_ms(10);
    		}
        while(!set_Network());
      /*判断数据是否写入成功*/
      u8 ipaddr[4];//ip地址
      u8 subnet[4];//子网掩码
      u8 gateway[4];//网关
    	getSIPR (ipaddr);			
    	printf(" W5500 IP地址   : %d.%d.%d.%d\r\n", ipaddr[0],ipaddr[1],ipaddr[2],ipaddr[3]);
    	getSUBR(subnet);
    	printf(" W5500 子网掩码 : %d.%d.%d.%d\r\n", subnet[0],subnet[1],subnet[2],subnet[3]);
    	getGAR(gateway);
    	printf(" W5500 网关     : %d.%d.%d.%d\r\n", gateway[0],gateway[1],gateway[2],gateway[3]);  
    }
    /*连接服务器*/
    uint8 TCP_Connect(SOCKET Socket,uint8 *sip,uint16 sport,uint16 lport)
    {
      static uint8 CONNECT_FLAG = 0;
      switch(getSn_SR(Socket))
      {
        case SOCK_INIT:
    			 CONNECT_FLAG=connect(Socket,sip,sport);/*连接服务器*/
           break;
        case SOCK_CLOSE_WAIT:
          disconnect(Socket);
          close(Socket);
          break;
        case SOCK_CLOSED:
    			 CONNECT_FLAG=0;
    			 socket(Socket,Sn_MR_TCP,lport,Sn_MR_ND);
    			 break;
      }
      return CONNECT_FLAG;
    }
    int main()
    {
      u16 i=0;
      u8 stat=0;
      u16 time=0,cnt=0;
      float temp=10;
      u16 rlen;
      USART1_Init(115200);
      printf("W5500 SPI模拟时序寄存器版,连接腾讯云VER1.0 \r\n");
      init_Net();/*W5500硬件初始化,动态分配IP*/
      printf("W5500 硬件初始化成功\r\n");
      while(!do_dns((u8 *)SERVER_IP)){}/*域名解析*/
      while(1)
      {
        stat=TCP_Connect(MQTT_SOCK,NET_CONFIG.rip,1883,5500);/*连接服务器*/
        printf("stat=%d\r\n",stat);
        if(stat)break;
        delay_ms(1000);
      } 
      printf("腾讯物联网平台连接中....\n");
      while(1)
      {
        if(getSn_SR(MQTT_SOCK)==SOCK_ESTABLISHED)
        {
           if(getSn_IR(MQTT_SOCK)&Sn_IR_CON)
           {
             setSn_IR(MQTT_SOCK,Sn_IR_CON);
           }
           MQTT_Init();
           if(MQTT_Connect(ClientID,Username,Password)==0)
           {
              printf("腾讯云平台连接成功\r\n");
             break;
           }
        }
      }
      stat=MQTT_SubscribeTopic(SET_TOPIC,0,1);
      if(stat)printf("订阅失败\r\n"); 
      while(1)
      {
        /*接收数据*/
        rlen=getSn_RX_RSR(MQTT_SOCK);
        if(rlen>0)
        {
          rlen=recv(MQTT_SOCK,rx_buff,rlen);
          printf("len=%d\r\n",rlen);
          for(i=0;i<rlen;i++)
          {
            printf("%c",rx_buff[i]);
          }
        }
        delay_ms(1);
        time++;
        cnt++;
        if(time>=5000)
        {
          time=0;
          MQTT_SentHeart();//发送心跳包
        }
        if(cnt>=2000)
        {
          temp+=1.5;
          if(temp>=85)temp=-15;
          cnt=0;
          sprintf(mqtt_message,"{\"method\":\"report\",\"clientToken\":\"123\",\"params\":{\"LED1\":1,\"temp\":%.2f,\"L\":356}}",temp);//温度
          MQTT_PublishData(POST_TOPIC,mqtt_message,0);
        }    
      }
    }
    
    

    3.运行效果

    在这里插入图片描述

    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述
    参考示例:https://download.csdn.net/download/weixin_44453694/81893703

    更多相关内容
  • 实现基于STM32F405RGT6移植,UDP模式下通信正常,可用于应用开发
  • 电子-STM32F4w5500tcpservertcp标准modbus调通175121133.zip,单片机/嵌入式STM32-F3/F4/F7/H7
  • STM32F4系列W5500;(HAL库版本、W5500官网最新驱动)
  • 采用stm32f407+w5500模块,实现spi转以太网发送,实测可用.采用TIM2定时1ms发送一次数据
  • STM32F4+W5500DMA通信

    2019-12-16 11:01:38
    STM32F407通过SPI-DMA与W5500通信,循环扫描实现TCP服务器回环测试,W5500使用的是官方4.0库
  • STM32F4 W5500 利用SPI DMA以太网进行通讯 利用DMA提高CPU的处理速度 增大网络的吞吐量
  • stm32+w5500 W5500 Official Source W5500 Official Source
  • 基于STM32F4系列MCU利用W5500模块实现的DHCP、DNS以及网络授时功能(已验证)
  • stm32_w5500_dhcp http.rar

    2020-07-29 10:42:19
    stm32通过对w5500以太网模块寄存器的读写操作,实现stm32接入以太网的功能,代码里包括通过DHCP自动获取ip的功能
  • STM32+W5500 MQTT例程 附详细讲解

    热门讨论 2018-01-26 09:59:54
    通过一个实例,讲解了MQTT 在智能家居中的应用。硬件采用W5500EVB。
  • 首先我们下载FreeModbus源码,然后放到自己的工程中,新建一个MODBUS_TCP和PORT_TCP文件夹,然后将相关文件复制到里面,如下图所示: 然后修改porttcp中的代码: 首先定义一个数组用于接收数据: ...
  • STM32+W5500

    千次阅读 2021-12-25 19:51:37
    一、W5500简介 W5500 网络扩展板集成了一个硬件 TCP/IP 协议栈芯片 W5500 以及一个含有网络变压器的 RJ-45(HR911105A)。 其中,W5500 是一款全硬件 TCP/IP 嵌入式以太网控制器,为嵌入式系统提供了更加简易的...

    一、W5500简介

      W5500 网络扩展板集成了一个硬件 TCP/IP 协议栈芯片 W5500 以及一个含有网络变压器的 RJ-45(HR911105A)。 其中,W5500 是一款全硬件 TCP/IP 嵌入式以太网控制器,为嵌入式系统提供了更加简易的互联网连接方案, 使用硬件逻辑门电路实现 TCP/IP 协议栈的传输层及网络层(如:TCP, UDP, ICMP, IPv4, ARP, IGMP, PPPoE 等协议), 并集成了数据链路层,物理层,以及 32K 字节片上 RAM 作为数据收发缓存。使得上位机主控芯片, 只需承担TCP/IP 应用层控制信息的处理任务。从而大大节省了上位机对于数据复制、协议处理和中断处理等方面的工作量,提升了系统利用率及可靠性。

    详情:4. w5500模块 — [野火]STM32模块例程介绍 文档 (embedfire.com)

    二、厂家Demo演示

     

     

    二、STM32+W5500+modbus协议编程 

      下载工程文件并打开

    main.c

    int main(void)
    {
    	unsigned char i;
    
    	/* Initialize STM32F103 */
    	System_Initialization();//系统配置
    	SysTick_Init();//启动系统滴答定时器 SysTick
    
    	/* Config W5500 */
    	W5500_Configuration();//W5500配置
    	Delay_ms(200);//延时等待
    
    	/* Modbus-TCP Init */
        eMBTCPInit(MB_TCP_PORT_USE_DEFAULT); //端口依赖事件模块初始化
    	Delay_ms(200); //延时等待
    	
    	/* Enable Modbus-TCP Stack */    
        eMBEnable();//激活协议栈	
        
    
        printf("\r\nModbus-TCP Start!\r\n");
        printf("IP:192.168.1.128\r\n");
    
    
    	while(1)
    	{
    		
    		i=Read_SOCK_1_Byte(0,Sn_SR);  //读W5500状态
    		if(i==0)	  
    		{
    			do
    			{
    				Delay_ms(100);//延时等待
    			
    			}while(Socket_Listen(0)==FALSE);//设置“Socket n”为“TCP服务器模式”
    		}
    		else if(i==SOCK_ESTABLISHED)		 //建立TCP连接
    		{
    		eMBPoll();//启动modbus侦听
    		BSP_LED();//线圈控制LED灯
    		}
    				
    	}
    }
    

     W5500

    /* W5500 configuration */
    void W5500_Configuration()
    {
    	unsigned char array[6];
    
    	GPIO_SetBits(GPIO_W5500_RST_PORT, GPIO_W5500_RST_Pin);//上拉
    	Delay_ms(100);    /*delay 100ms 使用systick 1ms时基的延时*/
        //等待以太网链路
    	while((Read_1_Byte(PHYCFGR)&LINK)==0); 		/* Waiting for Ethernet Link */
    
    	Write_1_Byte(MR, RST);//写入W5500普通寄存器一个字节
    	Delay_ms(20);		/*delay 20ms */
    
    	/* Set Gateway IP as: 192.168.1.1 */
    	array[0]=192;
    	array[1]=168;
    	array[2]=1;
    	array[3]=1;
    	Write_Bytes(GAR, array, 4);//设置网关IP
    
    	/* Set Subnet Mask as: 255.255.255.0 */
    	array[0]=255;
    	array[1]=255;
    	array[2]=255;
    	array[3]=0;
    	Write_Bytes(SUBR, array, 4);//设置子网掩码
    
    	/* Set MAC Address as: 0x48,0x53,0x00,0x57,0x55,0x00 */
    	array[0]=0x48;
    	array[1]=0x53;
    	array[2]=0x00;
    	array[3]=0x57;
    	array[4]=0x55;
    	array[5]=0x00;
    	Write_Bytes(SHAR, array, 6);//设置MAC地址
    
    	/* Set W5500 IP as: 192.168.1.128 */
    	array[0]=192;
    	array[1]=168;
    	array[2]=1;
    	array[3]=128;
    	Write_Bytes(SIPR, array, 4);//设置W5500的IP地址
    }
    

    三、STM32+W5500的web服务

    打开工程文件

    mian.c

    int main(void)
    {
    	Systick_Init(72);//系统时钟初始化
    	GPIO_Configuration(); //GPIO configuration
    	USART1_Init(); //串口初始化:115200@8-n-1
    	printf("W5500 EVB initialization over.\r\n");
    	Reset_W5500();
    	WIZ_SPI_Init();//W5500相关引脚配置
    	printf("W5500 initialized!\r\n");
    	if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7))
    	{
    		DefaultSet();//出厂值
    	}
    	else
    	{
     		get_config();//read config data from flash
    	}
    	printf("Firmware ver%d.%d\r\n",ConfigMsg.sw_ver[0],ConfigMsg.sw_ver[1]);
    	if(ConfigMsg.debug==0) ConfigMsg.debug=1;
    
    	set_network();//配置网络信息
    	printf("Network is ready.\r\n");
    	while(1)
    	{
    		if(ConfigMsg.JTXD_Control == 0)
    		  	do_http();//开启http服务
    		else
    		  	JTXD_do_http();
    		if(reboot_flag)
    			NVIC_SystemReset();//发起系统复位请求复位单片机
    //        reboot();
            
    	}
    }
    
    

    W5500

    #include <stdio.h>
    #include <string.h>
    #include "config.h"
    #include "SPI2.h"
    #include "w5500.h"
    #include "socket.h"
    
    #ifdef __DEF_IINCHIP_PPP__
       #include "md5.h"
    #endif
    
    static uint8 I_STATUS[MAX_SOCK_NUM];
    static uint16 SSIZE[MAX_SOCK_NUM]; /**< Max Tx buffer size by each channel */
    static uint16 RSIZE[MAX_SOCK_NUM]; /**< Max Rx buffer size by each channel */
    
    uint8 getISR(uint8 s)
    {
      return I_STATUS[s];
    }
    void putISR(uint8 s, uint8 val)
    {
       I_STATUS[s] = val;
    }
    
    uint16 getIINCHIP_RxMAX(uint8 s)
    {
       return RSIZE[s];
    }
    uint16 getIINCHIP_TxMAX(uint8 s)
    {
       return SSIZE[s];
    }
    void IINCHIP_CSoff(void)
    {
      WIZ_CS(LOW);
    }
    void IINCHIP_CSon(void)
    {
       WIZ_CS(HIGH);
    }
    u8  IINCHIP_SpiSendData(uint8 dat)
    {
       return(SPI2_SendByte(dat));
    }
    
    void IINCHIP_WRITE( uint32 addrbsb,  uint8 data)
    {
       IINCHIP_ISR_DISABLE();                        // Interrupt Service Routine Disable
       IINCHIP_CSoff();                              // CS=0, SPI start
       IINCHIP_SpiSendData( (addrbsb & 0x00FF0000)>>16);// Address byte 1
       IINCHIP_SpiSendData( (addrbsb & 0x0000FF00)>> 8);// Address byte 2
       IINCHIP_SpiSendData( (addrbsb & 0x000000F8) + 4);    // Data write command and Write data length 1
       IINCHIP_SpiSendData(data);                    // Data write (write 1byte data)
       IINCHIP_CSon();                               // CS=1,  SPI end
       IINCHIP_ISR_ENABLE();                         // Interrupt Service Routine Enable
    }
    
    uint8 IINCHIP_READ(uint32 addrbsb)
    {
       uint8 data = 0;
       IINCHIP_ISR_DISABLE();                        // Interrupt Service Routine Disable
       IINCHIP_CSoff();                              // CS=0, SPI start
       IINCHIP_SpiSendData( (addrbsb & 0x00FF0000)>>16);// Address byte 1
       IINCHIP_SpiSendData( (addrbsb & 0x0000FF00)>> 8);// Address byte 2
       IINCHIP_SpiSendData( (addrbsb & 0x000000F8))    ;// Data read command and Read data length 1
       data = IINCHIP_SpiSendData(0x00);             // Data read (read 1byte data)
       IINCHIP_CSon();                               // CS=1,  SPI end
       IINCHIP_ISR_ENABLE();                         // Interrupt Service Routine Enable
       return data;    
    }
    
    uint16 wiz_write_buf(uint32 addrbsb,uint8* buf,uint16 len)
    {
       uint16 idx = 0;
       if(len == 0) printf("Unexpected2 length 0\r\n");
    
       IINCHIP_ISR_DISABLE();
       IINCHIP_CSoff();                              // CS=0, SPI start
       IINCHIP_SpiSendData( (addrbsb & 0x00FF0000)>>16);// Address byte 1
       IINCHIP_SpiSendData( (addrbsb & 0x0000FF00)>> 8);// Address byte 2
       IINCHIP_SpiSendData( (addrbsb & 0x000000F8) + 4);    // Data write command and Write data length 1
       for(idx = 0; idx < len; idx++)                // Write data in loop
       {
         IINCHIP_SpiSendData(buf[idx]);
       }
       IINCHIP_CSon();                               // CS=1, SPI end
       IINCHIP_ISR_ENABLE();                         // Interrupt Service Routine Enable    
    
       return len;  
    }
    
    uint16 wiz_read_buf(uint32 addrbsb, uint8* buf,uint16 len)
    {
      uint16 idx = 0;
      if(len == 0)
      {
        printf("Unexpected2 length 0\r\n");
      }
    
      IINCHIP_ISR_DISABLE();
      //SPI MODE I/F
      IINCHIP_CSoff();                                  // CS=0, SPI start
      IINCHIP_SpiSendData( (addrbsb & 0x00FF0000)>>16);// Address byte 1
      IINCHIP_SpiSendData( (addrbsb & 0x0000FF00)>> 8);// Address byte 2
      IINCHIP_SpiSendData( (addrbsb & 0x000000F8));    // Data write command and Write data length 1
      for(idx = 0; idx < len; idx++)                    // Write data in loop
      {
        buf[idx] = IINCHIP_SpiSendData(0x00);
      }
      IINCHIP_CSon();                                   // CS=1, SPI end
      IINCHIP_ISR_ENABLE();                             // Interrupt Service Routine Enable
      
      return len;
    }
    
    
    /**
    @brief  This function is for resetting of the iinchip. Initializes the iinchip to work in whether DIRECT or INDIRECT mode
    */
    void iinchip_init(void)
    {
      setMR( MR_RST );
    #ifdef __DEF_IINCHIP_DBG__
      printf("MR value is %02x \r\n",IINCHIP_READ_COMMON(MR));
    #endif
    }
    
    /**
    @brief  This function set the transmit & receive buffer size as per the channels is used
    Note for TMSR and RMSR bits are as follows\n
    bit 1-0 : memory size of channel #0 \n
    bit 3-2 : memory size of channel #1 \n
    bit 5-4 : memory size of channel #2 \n
    bit 7-6 : memory size of channel #3 \n
    bit 9-8 : memory size of channel #4 \n
    bit 11-10 : memory size of channel #5 \n
    bit 12-12 : memory size of channel #6 \n
    bit 15-14 : memory size of channel #7 \n
    Maximum memory size for Tx, Rx in the W5500 is 16K Bytes,\n
    In the range of 16KBytes, the memory size could be allocated dynamically by each channel.\n
    Be attentive to sum of memory size shouldn't exceed 8Kbytes\n
    and to data transmission and receiption from non-allocated channel may cause some problems.\n
    If the 16KBytes memory is already  assigned to centain channel, \n
    other 3 channels couldn't be used, for there's no available memory.\n
    If two 4KBytes memory are assigned to two each channels, \n
    other 2 channels couldn't be used, for there's no available memory.\n
    */
    void sysinit( uint8 * tx_size, uint8 * rx_size  )
    {
      int16 i;
      int16 ssum,rsum;
    #ifdef __DEF_IINCHIP_DBG__
      printf("sysinit()\r\n");
    #endif
      ssum = 0;
      rsum = 0;
    
      for (i = 0 ; i < MAX_SOCK_NUM; i++)       // Set the size, masking and base address of Tx & Rx memory by each channel
      {
              IINCHIP_WRITE( (Sn_TXMEM_SIZE(i)), tx_size[i]);
              IINCHIP_WRITE( (Sn_RXMEM_SIZE(i)), rx_size[i]);
              
    #ifdef __DEF_IINCHIP_DBG__
             printf("tx_size[%d]: %d, Sn_TXMEM_SIZE = %d\r\n",i, tx_size[i], IINCHIP_READ(Sn_TXMEM_SIZE(i)));
             printf("rx_size[%d]: %d, Sn_RXMEM_SIZE = %d\r\n",i, rx_size[i], IINCHIP_READ(Sn_RXMEM_SIZE(i)));
    #endif
        SSIZE[i] = (int16)(0);
        RSIZE[i] = (int16)(0);
    
    
        if (ssum <= 16384)
        {
             switch( tx_size[i] )
          {
          case 1:
            SSIZE[i] = (int16)(1024);
            break;
          case 2:
            SSIZE[i] = (int16)(2048);
            break;
          case 4:
            SSIZE[i] = (int16)(4096);
            break;
          case 8:
            SSIZE[i] = (int16)(8192);
            break;
          case 16:
            SSIZE[i] = (int16)(16384);
          break;
          default :
            RSIZE[i] = (int16)(2048);
            break;
          }
        }
    
       if (rsum <= 16384)
        {
             switch( rx_size[i] )
          {
          case 1:
            RSIZE[i] = (int16)(1024);
            break;
          case 2:
            RSIZE[i] = (int16)(2048);
            break;
          case 4:
            RSIZE[i] = (int16)(4096);
            break;
          case 8:
            RSIZE[i] = (int16)(8192);
            break;
          case 16:
            RSIZE[i] = (int16)(16384);
            break;
          default :
            RSIZE[i] = (int16)(2048);
            break;
          }
        }
        ssum += SSIZE[i];
        rsum += RSIZE[i];
    
      }
    }
    
    // added
    
    /**
    @brief  This function sets up gateway IP address.
    */
    void setGAR(
      uint8 * addr  /**< a pointer to a 4 -byte array responsible to set the Gateway IP address. */
      )
    {
        wiz_write_buf(GAR0, addr, 4);
    }
    void getGWIP(uint8 * addr)
    {
        wiz_read_buf(GAR0, addr, 4);
    }
    
    /**
    @brief  It sets up SubnetMask address
    */
    void setSUBR(uint8 * addr)
    {   
        wiz_write_buf(SUBR0, addr, 4);
    }
    /**
    @brief  This function sets up MAC address.
    */
    void setSHAR(
      uint8 * addr  /**< a pointer to a 6 -byte array responsible to set the MAC address. */
      )
    {
      wiz_write_buf(SHAR0, addr, 6);  
    }
    
    /**
    @brief  This function sets up Source IP address.
    */
    void setSIPR(
      uint8 * addr  /**< a pointer to a 4 -byte array responsible to set the Source IP address. */
      )
    {
        wiz_write_buf(SIPR0, addr, 4);  
    }
    
    /**
    @brief  This function sets up Source IP address.
    */
    void getGAR(uint8 * addr)
    {
        wiz_read_buf(GAR0, addr, 4);
    }
    void getSUBR(uint8 * addr)
    {
        wiz_read_buf(SUBR0, addr, 4);
    }
    void getSHAR(uint8 * addr)
    {
        wiz_read_buf(SHAR0, addr, 6);
    }
    void getSIPR(uint8 * addr)
    {
        wiz_read_buf(SIPR0, addr, 4);
    }
    
    void setMR(uint8 val)
    {
      IINCHIP_WRITE(MR,val);
    }
    
    /**
    @brief  This function gets Interrupt register in common register.
     */
    uint8 getIR( void )
    {
       return IINCHIP_READ(IR);
    }
    
    /**
    @brief  This function sets up Retransmission time.
    
    If there is no response from the peer or delay in response then retransmission
    will be there as per RTR (Retry Time-value Register)setting
    */
    void setRTR(uint16 timeout)
    {
      IINCHIP_WRITE(RTR0,(uint8)((timeout & 0xff00) >> 8));
      IINCHIP_WRITE(RTR1,(uint8)(timeout & 0x00ff));
    }
    
    /**
    @brief  This function set the number of Retransmission.
    
    If there is no response from the peer or delay in response then recorded time
    as per RTR & RCR register seeting then time out will occur.
    */
    void setRCR(uint8 retry)
    {
      IINCHIP_WRITE(WIZ_RCR,retry);
    }
    
    /**
    @brief  This function set the interrupt mask Enable/Disable appropriate Interrupt. ('1' : interrupt enable)
    
    If any bit in IMR is set as '0' then there is not interrupt signal though the bit is
    set in IR register.
    */
    void clearIR(uint8 mask)
    {
      IINCHIP_WRITE(IR, ~mask | getIR() ); // must be setted 0x10.
    }
    
    /**
    @brief  This sets the maximum segment size of TCP in Active Mode), while in Passive Mode this is set by peer
    */
    void setSn_MSS(SOCKET s, uint16 Sn_MSSR)
    {
      IINCHIP_WRITE( Sn_MSSR0(s), (uint8)((Sn_MSSR & 0xff00) >> 8));
      IINCHIP_WRITE( Sn_MSSR1(s), (uint8)(Sn_MSSR & 0x00ff));
    }
    
    void setSn_TTL(SOCKET s, uint8 ttl)
    {    
       IINCHIP_WRITE( Sn_TTL(s) , ttl);
    }
    
    
    
    /**
    @brief  get socket interrupt status
    
    These below functions are used to read the Interrupt & Soket Status register
    */
    uint8 getSn_IR(SOCKET s)
    {
       return IINCHIP_READ(Sn_IR(s));
    }
    
    
    /**
    @brief   get socket status
    */
    uint8 getSn_SR(SOCKET s)
    {
       return IINCHIP_READ(Sn_SR(s));
    }
    
    
    /**
    @brief  get socket TX free buf size
    
    This gives free buffer size of transmit buffer. This is the data size that user can transmit.
    User shuold check this value first and control the size of transmitting data
    */
    uint16 getSn_TX_FSR(SOCKET s)
    {
      uint16 val=0,val1=0;
      do
      {
        val1 = IINCHIP_READ(Sn_TX_FSR0(s));
        val1 = (val1 << 8) + IINCHIP_READ(Sn_TX_FSR1(s));
          if (val1 != 0)
        {
            val = IINCHIP_READ(Sn_TX_FSR0(s));
            val = (val << 8) + IINCHIP_READ(Sn_TX_FSR1(s));
        }
      } while (val != val1);
       return val;
    }
    
    
    /**
    @brief   get socket RX recv buf size
    
    This gives size of received data in receive buffer.
    */
    uint16 getSn_RX_RSR(SOCKET s)
    {
      uint16 val=0,val1=0;
      do
      {
        val1 = IINCHIP_READ(Sn_RX_RSR0(s));
        val1 = (val1 << 8) + IINCHIP_READ(Sn_RX_RSR1(s));
        if(val1 != 0)
        {
            val = IINCHIP_READ(Sn_RX_RSR0(s));
            val = (val << 8) + IINCHIP_READ(Sn_RX_RSR1(s));
        }
      } while (val != val1);
       return val;
    }
    
    
    /**
    @brief   This function is being called by send() and sendto() function also.
    
    This function read the Tx write pointer register and after copy the data in buffer update the Tx write pointer
    register. User should read upper byte first and lower byte later to get proper value.
    */
    void send_data_processing(SOCKET s, uint8 *data, uint16 len)
    {
      uint16 ptr =0;
      uint32 addrbsb =0;
      if(len == 0)
      {
        printf("CH: %d Unexpected1 length 0\r\n", s);
        return;
      }
    
     
      ptr = IINCHIP_READ( Sn_TX_WR0(s) );
      ptr = ((ptr & 0x00ff) << 8) + IINCHIP_READ(Sn_TX_WR1(s));
    
      addrbsb = (uint32)(ptr<<8) + (s<<5) + 0x10;
      wiz_write_buf(addrbsb, data, len);
      
      ptr += len;
      IINCHIP_WRITE( Sn_TX_WR0(s) ,(uint8)((ptr & 0xff00) >> 8));
      IINCHIP_WRITE( Sn_TX_WR1(s),(uint8)(ptr & 0x00ff));
    }
    
    
    /**
    @brief  This function is being called by recv() also.
    
    This function read the Rx read pointer register
    and after copy the data from receive buffer update the Rx write pointer register.
    User should read upper byte first and lower byte later to get proper value.
    */
    void recv_data_processing(SOCKET s, uint8 *data, uint16 len)
    {
      uint16 ptr = 0;
      uint32 addrbsb = 0;
      
      if(len == 0)
      {
        printf("CH: %d Unexpected2 length 0\r\n", s);
        return;
      }
    
      ptr = IINCHIP_READ( Sn_RX_RD0(s) );
      ptr = ((ptr & 0x00ff) << 8) + IINCHIP_READ( Sn_RX_RD1(s) );
    
      addrbsb = (uint32)(ptr<<8) + (s<<5) + 0x18;
      wiz_read_buf(addrbsb, data, len);
      ptr += len;
    
      IINCHIP_WRITE( Sn_RX_RD0(s), (uint8)((ptr & 0xff00) >> 8));
      IINCHIP_WRITE( Sn_RX_RD1(s), (uint8)(ptr & 0x00ff));
    }
    
    void setSn_IR(uint8 s, uint8 val)
    {
        IINCHIP_WRITE(Sn_IR(s), val);
    }
    
    
    
    
    
    #ifndef  _W5500_H_
    #define  _W5500_H_
    
    #include "Types.h"
    /**
     @brief Mode Register address
     * W5500 SPI Frame consists of 16bits Offset Address in Address Phase, 
     * 8bits Control Phase and N bytes Data Phase.
     * 0                8                16               24                   ~
     * |----------------|----------------|----------------|----------------------
     * |        16bit offset Address     | Control Bits   |  Data Phase
     *
     * The 8bits Control Phase is reconfigured with Block Select bits (BSB[4:0]), 
     * Read/Write Access Mode bit (RWB) and SPI Operation Mode (OM[1:0]). 
     * Block Select bits select a block as like common register, socket register, tx buffer and tx buffer.
     * Address value is defined as 16bit offset Address, BSB[4:0] and the three bits of zero-padding.(The RWB and OM [1:0] are '0 'padding)
     * Please, refer to W5500 datasheet for more detail about Memory Map.
     *
     */
    
    /**
     @brief Mode Register address
     */
    #define MR                          (0x000000)
    
    /**
     @brief Gateway IP Register address
     */
    #define GAR0                        (0x000100)
    #define GAR1                        (0x000200)
    #define GAR2                        (0x000300)
    #define GAR3                        (0x000400)
    /**
     @brief Subnet mask Register address
     */
    #define SUBR0                       (0x000500)
    #define SUBR1                       (0x000600)
    #define SUBR2                       (0x000700)
    #define SUBR3                       (0x000800)
    
    /**
     @brief Source MAC Register address
     */
    #define SHAR0                       (0x000900)
    #define SHAR1                       (0x000A00)
    #define SHAR2                       (0x000B00)
    #define SHAR3                       (0x000C00)
    #define SHAR4                       (0x000D00)
    #define SHAR5                       (0x000E00)
    /**
     @brief Source IP Register address
     */
    #define SIPR0                       (0x000F00)
    #define SIPR1                       (0x001000)
    #define SIPR2                       (0x001100)
    #define SIPR3                       (0x001200)
    /**
     @brief set Interrupt low level timer register address
     */
    #define INTLEVEL0                   (0x001300)
    #define INTLEVEL1                   (0x001400)
    /**
     @brief Interrupt Register
     */
    #define IR                          (0x001500)
    /**
     @brief Interrupt mask register
     */
    #define IMR                         (0x001600)
    /**
     @brief Socket Interrupt Register
     */
    #define SIR                         (0x001700) 
    /**
     @brief Socket Interrupt Mask Register
     */
    #define SIMR                        (0x001800)
    /**
     @brief Timeout register address( 1 is 100us )
     */
    #define RTR0                        (0x001900)
    #define RTR1                        (0x001A00)
    /**
     @brief Retry count reigster
     */
    #define WIZ_RCR                         (0x001B00)
    /**
     @briefPPP LCP Request Timer register  in PPPoE mode
     */
    #define PTIMER                      (0x001C00)
    /**
     @brief PPP LCP Magic number register  in PPPoE mode
     */
    #define PMAGIC                      (0x001D00)
    /**
     @brief PPP Destination MAC Register address
     */
    #define PDHAR0                      (0x001E00)
    #define PDHAR1                      (0x001F00)
    #define PDHAR2                      (0x002000)
    #define PDHAR3                      (0x002100)
    #define PDHAR4                      (0x002200)
    #define PDHAR5                      (0x002300)
    /**
     @brief PPP Session Identification Register
     */
    #define PSID0                       (0x002400)
    #define PSID1                       (0x002500)
    /**
     @brief PPP Maximum Segment Size(MSS) register
     */
    #define PMR0                        (0x002600)
    #define PMR1                        (0x002700)
    /**
     @brief Unreachable IP register address in UDP mode
     */
    #define UIPR0                       (0x002800)
    #define UIPR1                       (0x002900)
    #define UIPR2                       (0x002A00)
    #define UIPR3                       (0x002B00)
    /**
     @brief Unreachable Port register address in UDP mode
     */
    #define UPORT0                      (0x002C00)
    #define UPORT1                      (0x002D00)
    /**
     @brief PHY Configuration Register
     */
    #define PHYCFGR                      (0x002E00)
    /**
     @brief chip version register address
     */
    #define VERSIONR                    (0x003900)   
    
    
    
    /**
     @brief socket Mode register
     */
    #define Sn_MR(ch)                       (0x000008 + (ch<<5))
    
    /**
     @brief channel Sn_CR register
     */
    #define Sn_CR(ch)                       (0x000108 + (ch<<5))
    /**
     @brief channel interrupt register
     */
    #define Sn_IR(ch)                       (0x000208 + (ch<<5))
    /**
     @brief channel status register
     */
    #define Sn_SR(ch)                       (0x000308 + (ch<<5))
    /**
     @brief source port register
     */
    #define Sn_PORT0(ch)                    (0x000408 + (ch<<5))
    #define Sn_PORT1(ch)                    (0x000508 + (ch<<5))
    /**
     @brief Peer MAC register address
     */
    #define Sn_DHAR0(ch)                    (0x000608 + (ch<<5))
    #define Sn_DHAR1(ch)                    (0x000708 + (ch<<5))
    #define Sn_DHAR2(ch)                    (0x000808 + (ch<<5))
    #define Sn_DHAR3(ch)                    (0x000908 + (ch<<5))
    #define Sn_DHAR4(ch)                    (0x000A08 + (ch<<5))
    #define Sn_DHAR5(ch)                    (0x000B08 + (ch<<5))
    /**
     @brief Peer IP register address
     */
    #define Sn_DIPR0(ch)                    (0x000C08 + (ch<<5))
    #define Sn_DIPR1(ch)                    (0x000D08 + (ch<<5))
    #define Sn_DIPR2(ch)                    (0x000E08 + (ch<<5))
    #define Sn_DIPR3(ch)                    (0x000F08 + (ch<<5))
    /**
     @brief Peer port register address
     */
    #define Sn_DPORT0(ch)                   (0x001008 + (ch<<5))
    #define Sn_DPORT1(ch)                   (0x001108 + (ch<<5))
    /**
     @brief Maximum Segment Size(Sn_MSSR0) register address
     */
    #define Sn_MSSR0(ch)                    (0x001208 + (ch<<5))
    #define Sn_MSSR1(ch)                    (0x001308 + (ch<<5))
    /** 
     @brief IP Type of Service(TOS) Register 
     */
    #define Sn_TOS(ch)                      (0x001508 + (ch<<5))
    /**
     @brief IP Time to live(TTL) Register 
     */
    #define Sn_TTL(ch)                      (0x001608 + (ch<<5))
    /**
     @brief Receive memory size reigster
     */
    #define Sn_RXMEM_SIZE(ch)               (0x001E08 + (ch<<5))
    /**
     @brief Transmit memory size reigster
     */
    #define Sn_TXMEM_SIZE(ch)               (0x001F08 + (ch<<5))
    /**
     @brief Transmit free memory size register
     */
    #define Sn_TX_FSR0(ch)                  (0x002008 + (ch<<5))
    #define Sn_TX_FSR1(ch)                  (0x002108 + (ch<<5))
    /**
     @brief Transmit memory read pointer register address
     */
    #define Sn_TX_RD0(ch)                   (0x002208 + (ch<<5))
    #define Sn_TX_RD1(ch)                   (0x002308 + (ch<<5))
    /**
     @brief Transmit memory write pointer register address
     */
    #define Sn_TX_WR0(ch)                   (0x002408 + (ch<<5))
    #define Sn_TX_WR1(ch)                   (0x002508 + (ch<<5))
    /**
     @brief Received data size register
     */
    #define Sn_RX_RSR0(ch)                  (0x002608 + (ch<<5))
    #define Sn_RX_RSR1(ch)                  (0x002708 + (ch<<5))
    /**
     @brief Read point of Receive memory
     */
    #define Sn_RX_RD0(ch)                   (0x002808 + (ch<<5))
    #define Sn_RX_RD1(ch)                   (0x002908 + (ch<<5))
    /**
     @brief Write point of Receive memory
     */
    #define Sn_RX_WR0(ch)                   (0x002A08 + (ch<<5))
    #define Sn_RX_WR1(ch)                   (0x002B08 + (ch<<5))
    /**
     @brief socket interrupt mask register
     */
    #define Sn_IMR(ch)                      (0x002C08 + (ch<<5))
    /**
     @brief frag field value in IP header register
     */
    #define Sn_FRAG(ch)                     (0x002D08 + (ch<<5))
    /**
     @brief Keep Timer register
     */
    #define Sn_KPALVTR(ch)                  (0x002F08 + (ch<<5))
    
    /* MODE register values */
    #define MR_RST                       0x80 /**< reset */
    #define MR_WOL                       0x20 /**< Wake on Lan */
    #define MR_PB                        0x10 /**< ping block */
    #define MR_PPPOE                     0x08 /**< enable pppoe */
    #define MR_UDP_FARP                  0x02 /**< enbale FORCE ARP */
    
    
    /* IR register values */
    #define IR_CONFLICT                  0x80 /**< check ip confict */
    #define IR_UNREACH                   0x40 /**< get the destination unreachable message in UDP sending */
    #define IR_PPPoE                     0x20 /**< get the PPPoE close message */
    #define IR_MAGIC                     0x10 /**< get the magic packet interrupt */
    
    /* Sn_MR values */
    #define Sn_MR_CLOSE                  0x00     /**< unused socket */
    #define Sn_MR_TCP                    0x01     /**< TCP */
    #define Sn_MR_UDP                    0x02     /**< UDP */
    #define Sn_MR_IPRAW                  0x03      /**< IP LAYER RAW SOCK */
    #define Sn_MR_MACRAW                 0x04      /**< MAC LAYER RAW SOCK */
    #define Sn_MR_PPPOE                  0x05     /**< PPPoE */
    #define Sn_MR_UCASTB                 0x10     /**< Unicast Block in UDP Multicating*/
    #define Sn_MR_ND                     0x20     /**< No Delayed Ack(TCP) flag */
    #define Sn_MR_MC                     0x20     /**< Multicast IGMP (UDP) flag */
    #define Sn_MR_BCASTB                 0x40     /**< Broadcast blcok in UDP Multicating */
    #define Sn_MR_MULTI                  0x80     /**< support UDP Multicating */
    
     /* Sn_MR values on MACRAW MODE */
    #define Sn_MR_MIP6N                  0x10     /**< IPv6 packet Block */
    #define Sn_MR_MMB                    0x20     /**< IPv4 Multicasting Block */
    //#define Sn_MR_BCASTB                 0x40     /**< Broadcast blcok */
    #define Sn_MR_MFEN                   0x80     /**< support MAC filter enable */
    
    
    /* Sn_CR values */
    #define Sn_CR_OPEN                   0x01     /**< initialize or open socket */
    #define Sn_CR_LISTEN                 0x02     /**< wait connection request in tcp mode(Server mode) */
    #define Sn_CR_CONNECT                0x04     /**< send connection request in tcp mode(Client mode) */
    #define Sn_CR_DISCON                 0x08     /**< send closing reqeuset in tcp mode */
    #define Sn_CR_CLOSE                  0x10     /**< close socket */
    #define Sn_CR_SEND                   0x20     /**< update txbuf pointer, send data */
    #define Sn_CR_SEND_MAC               0x21     /**< send data with MAC address, so without ARP process */
    #define Sn_CR_SEND_KEEP              0x22     /**<  send keep alive message */
    #define Sn_CR_RECV                   0x40     /**< update rxbuf pointer, recv data */
    
    #ifdef __DEF_IINCHIP_PPP__
       #define Sn_CR_PCON                0x23      
       #define Sn_CR_PDISCON             0x24      
       #define Sn_CR_PCR                 0x25      
       #define Sn_CR_PCN                 0x26     
       #define Sn_CR_PCJ                 0x27     
    #endif
    
    /* Sn_IR values */
    #ifdef __DEF_IINCHIP_PPP__
       #define Sn_IR_PRECV               0x80     
       #define Sn_IR_PFAIL               0x40     
       #define Sn_IR_PNEXT               0x20     
    #endif
    
    #define Sn_IR_SEND_OK                0x10     /**< complete sending */
    #define Sn_IR_TIMEOUT                0x08     /**< assert timeout */
    #define Sn_IR_RECV                   0x04     /**< receiving data */
    #define Sn_IR_DISCON                 0x02     /**< closed socket */
    #define Sn_IR_CON                    0x01     /**< established connection */
    
    /* Sn_SR values */
    #define SOCK_CLOSED                  0x00     /**< closed */
    #define SOCK_INIT                    0x13     /**< init state */
    #define SOCK_LISTEN                  0x14     /**< listen state */
    #define SOCK_SYNSENT                 0x15     /**< connection state */
    #define SOCK_SYNRECV                 0x16     /**< connection state */
    #define SOCK_ESTABLISHED             0x17     /**< success to connect */
    #define SOCK_FIN_WAIT                0x18     /**< closing state */
    #define SOCK_CLOSING                 0x1A     /**< closing state */
    #define SOCK_TIME_WAIT               0x1B     /**< closing state */
    #define SOCK_CLOSE_WAIT              0x1C     /**< closing state */
    #define SOCK_LAST_ACK                0x1D     /**< closing state */
    #define SOCK_UDP                     0x22     /**< udp socket */
    #define SOCK_IPRAW                   0x32     /**< ip raw mode socket */
    #define SOCK_MACRAW                  0x42     /**< mac raw mode socket */
    #define SOCK_PPPOE                   0x5F     /**< pppoe socket */
    
    /* IP PROTOCOL */
    #define IPPROTO_IP                   0        /**< Dummy for IP */
    #define IPPROTO_ICMP                 1        /**< Control message protocol */
    #define IPPROTO_IGMP                 2        /**< Internet group management protocol */
    #define IPPROTO_GGP                  3        /**< Gateway^2 (deprecated) */
    #define IPPROTO_TCP                  6        /**< TCP */
    #define IPPROTO_PUP                  12       /**< PUP */
    #define IPPROTO_UDP                  17       /**< UDP */
    #define IPPROTO_IDP                  22       /**< XNS idp */
    #define IPPROTO_ND                   77       /**< UNOFFICIAL net disk protocol */
    #define IPPROTO_RAW                  255      /**< Raw IP packet */
    
    /*********************************************************
    * iinchip access function
    *********************************************************/
    void IINCHIP_WRITE( uint32 addrbsb,  uint8 data);
    uint8 IINCHIP_READ(uint32 addrbsb);
    uint16 wiz_write_buf(uint32 addrbsb,uint8* buf,uint16 len);
    uint16 wiz_read_buf(uint32 addrbsb, uint8* buf,uint16 len);
    
    
    void iinchip_init(void); // reset iinchip
    void sysinit(uint8 * tx_size, uint8 * rx_size); // setting tx/rx buf size
    uint8 getISR(uint8 s);
    void putISR(uint8 s, uint8 val);
    uint16 getIINCHIP_RxMAX(uint8 s);
    uint16 getIINCHIP_TxMAX(uint8 s);
    void setMR(uint8 val);
    void setRTR(uint16 timeout); // set retry duration for data transmission, connection, closing ...
    void setRCR(uint8 retry); // set retry count (above the value, assert timeout interrupt)
    void clearIR(uint8 mask); // clear interrupt
    uint8 getIR( void );
    void setSn_MSS(SOCKET s, uint16 Sn_MSSR); // set maximum segment size
    uint8 getSn_IR(SOCKET s); // get socket interrupt status
    uint8 getSn_SR(SOCKET s); // get socket status
    uint16 getSn_TX_FSR(SOCKET s); // get socket TX free buf size
    uint16 getSn_RX_RSR(SOCKET s); // get socket RX recv buf size
    uint8 getSn_SR(SOCKET s);
    void setSn_TTL(SOCKET s, uint8 ttl);
    void send_data_processing(SOCKET s, uint8 *wizdata, uint16 len);
    void recv_data_processing(SOCKET s, uint8 *wizdata, uint16 len);
    
    void setGAR(uint8 * addr); // set gateway address
    void setSUBR(uint8 * addr); // set subnet mask address
    void setSHAR(uint8 * addr); // set local MAC address
    void setSIPR(uint8 * addr); // set local IP address
    void getGAR(uint8 * addr);
    void getSUBR(uint8 * addr);
    void getSHAR(uint8 * addr);
    void getSIPR(uint8 * addr);
    
    void setSn_IR(uint8 s, uint8 val);
    /**
     @brief WIZCHIP_OFFSET_INC on IINCHIP_READ/WRITE
     * case1.
     *  IINCHIP_WRITE(RTR0,val);
     *  IINCHIP_WRITE(RTR1,val);
     * case1. 
     *  IINCHIP_WRITE(RTR0,val);
     *  IINCHIP_WRITE(WIZCHIP_OFFSET_INC(RTR0,1)); 
     */
    //#define WIZCHIP_OFFSET_INC(ADDR, N)    (ADDR + (N<<8)) //< Increase offset address
    
    #endif
    

    参考:(102条消息) STM32+W5500以太网模块_机智的橙子的博客-CSDN博客 

    展开全文
  • STM32 以太网W5500

    2021-11-16 12:49:35
    W5500 W5500 是一款全硬件 TCP/IP 嵌入式以太网控制器,为嵌入式系统提供了更加简易 的互联网连接方案。 W5500 集成了 TCP/IP 协议栈, 10/100M 以太网数据链路层(MAC)及物理层(PHY)W5500 内嵌 32K 字节片上缓存...

    W5500简介

    W5500 是一款全硬件 TCP/IP 嵌入式以太网控制器,为嵌入式系统提供了更加简易的互联网连接方案。

    特点:

    • 支持硬件 TCP/IP 协议: TCP, UDP, ICMP, IPv4, ARP, IGMP, PPPoE
    • 支持8个独立端口(Socket)同时通讯
    • 支持高速串行外设接口SPI( 80MHz 速率)
    • 内部32K字节收发缓存
    • LED状态显示
    • 支持掉电模式、网络唤醒

    以太网接入方案

    1、MAC+PHY方案
    MCU内部自带MAC,由于软件协议栈操作需要主控不断响应中断,极大程度上占用了MCU的资源。
    在这里插入图片描述
    优缺点:
    软件协议栈需要主控不断地响应中断,占用资源大,会影响通信质量
    代码量占用大,内存资源占用多;安全角度,容易收到攻击

    2、硬件协议方案
    用硬件化的逻辑门电路实现所有的处理TCP/IP协议的工作。MCU只需要处理面向用户的应用层数据即可,传输、网络、链路层以及物理层全部由外围硬件芯片完成。
    在这里插入图片描述
    优缺点:
    硬件协议栈,减少了单片机中断次数,通信速度快;
    代码量少,比软件协议栈安全;
    相比软件协议栈灵活性差,目前只支持8个socket

    引脚连接

    模块引脚说明单片机引脚
    CS片选引脚PB12
    CLKSPI时钟PB13
    MISO主输入从输出PB14
    MOSI主输出从输入PB15
    INT中断引脚PC6
    RST复位脚PC7
    GNDGND
    3V3电源3.3V供电3V3

    SPI读写访问

    W5500 的 SPI 数据帧包括了 16 位地址段的偏移地址, 8 位控制段和 N 字节数据段。
    在这里插入图片描述
    写访问
    在这里插入图片描述

    • 在 VDM (可变数据长度模式)模式下, SPI 数据帧的控制段:读写控制位(RWB)为‘1’,如果是读则为‘0’,工作模式位为’00’。
    • 此时外设主机在传输 SPI 数据帧之前,须拉低 SCSn 信号引脚。
    • 然后主机通过 MOSI 将 SPI 数据帧的所有位传输给 W5500 ,并在 SCLK 的下降沿同步。
    • 在完成 SPI 数据帧的传输后,主机拉高 SCSn 信号(低电平到高电平)。
    • 当 SCSn 保持低电平且数据段持续传输,即可实现连续数据写入。

    1 字节数据写访问示例

    Offset Address = 0x0018
    BSB[4:0] = ‘00000’
    RWB = ‘1’
    OM[1:0] = ‘00’
    1st Data = 0xAA

    在这里插入图片描述

    在传输 SPI 数据帧之前, 外设主机须拉低 SCSn,然后主机在时钟(SCLK)跳变时同步
    传输 1 位数据。在 SPI 数据帧传输完毕后,外设主机拉高 SCSn

    寄存器以及地址

    W5500 有 1 个通用寄存器,8 个 Socket 寄存器区,以及对应每个 Socket 的收/发缓存区。每个区域均通过 SPI 数据帧的区域选择位(BSB[4:0])来选取。
    每个 Socket 分配多大的收/发缓存,必须在 16 位的偏移地址范围内(从0x0000 到 0xFFFF)
    在这里插入图片描述
    以下对地址的一些理解
    在寄存器偏移计算的宏定义,采用宏定义方便计算socket n所使用的地址

    #define WIZCHIP_CREG_BLOCK          0x00 	//< Common register block
    #define WIZCHIP_SREG_BLOCK(N)       (1+4*N) //< Socket N register block
    #define WIZCHIP_TXBUF_BLOCK(N)      (2+4*N) //< Socket N Tx buffer address block
    #define WIZCHIP_RXBUF_BLOCK(N)      (3+4*N) //< Socket N Rx buffer address block
    

    手册中的地址与源码中地址理解
    手册中IP地址的定义
    在这里插入图片描述
    .h文件中的宏定义为

    #define SIPR0                       (0x000F00)
    #define SIPR1                       (0x001000)
    #define SIPR2                       (0x001100)
    #define SIPR3                       (0x001200)
    

    SPI读写操作中,地址操作,高位要偏移16,低要偏移8 ,这与地址的宏定义向左偏移8相符合。
    读写函数地址偏移如下:

       SPI_SendByte( (addrbsb & 0x00FF0000)>>16);//偏移16	
       SPI_SendByte( (addrbsb & 0x0000FF00)>> 8);//偏移8
    

    源码以及配置

    驱动源码

    文件说明
    W5500_conf.c主要配置W5500的MAC,IP地址,W5500基本的数据读写过程,服务设置函数等
    Socket.c设置socket的打开、关闭、以及接收数据、发送数据等
    w5500.c主要完成W5500的寄存器读写过程

    W5500的socket初始化过程
    1、基本配置

    • 模式寄存器(MR)
    • 中断屏蔽寄存器(IMR)
    • 重发时间寄存器(RTR)
    • 重发计数寄存器(RCR)

    2、网络设置

    • 网关地址寄存器(GAR)
    • 本机物理地址寄存器(SHAR)
    • 子网掩码寄存器(SUBR)
    • 本机IP地址寄存器

    3、端口设置,数据收发缓冲区
    W5500 有 1 个通用寄存器,8 个 Socket 寄存器区,以及对应每个 Socket 的收/发缓存区。每一个 Socket 的发送缓存区都在一个 16KB 的物理发送内存中,初始化分配为 2KB。每一个 Socket 的接收缓存区都在一个 16KB 的物理接收内存中,初始化分配为 2KB。

    4、应用层协议开发

    支撑协议:域名服务系统(DNS),简单网络管理协议(SNMP)
    应用协议:超文本传输协议(HTTP),简单邮件传输协议(SMTP),文件传输协议(FTP),简单文件传输协议(TFTP)和远程登录(Telnet)

    实现 TCP Server

    它使用 IP 作为网络层,提供全双工的和可靠交付的服务。TCP 建立通信的两端一端称为服务器端,另一端为客户端。

    reactor模式epoll
    多路复用 select poll epoll
    多进程,多线程方式

    三次握手过程

    详细了解三次握手请参考 深入源码了解三次握手
    TCP 协议通过三个报文段完成连接的建立,这个过程称为三次握手

    1,第一次握手:建立连接时,客户端发送 SYN 包(seq=j)到服务器,并进入SYN_SEND 状态,等待服务器确认。
    2,第二次握手:服务器收到 SYN 包,必须确认客户的 SYN(ack=j+1),同时自己也发送一个 SYN 包(seq=k),即 SYN+ACK 包,此时服务器进入 SYN_RECV状态。
    3,第三次握手:客户端收到服务器的 SYN+ACK 包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入 ESTABLISHED 状态,完成三次握手

    在这里插入图片描述

    SPI 配置

    数据传输SPI总线,CS片选引脚拉低,发送数据,拉高结束发送数据

    #define WIZ_SPIx_GPIO_PORT      GPIOB				      /* GPIO端口   */
    #define WIZ_SPIx_GPIO_CLK       RCC_APB2Periph_GPIOB	   /* GPIO时钟*/
    #define WIZ_SPIx                SPI2                   	   /*W5500所使用的SPI     */
    #define WIZ_SPIx_CLK_CMD        RCC_APB1PeriphClockCmd
    #define WIZ_SPIx_CLK            RCC_APB1Periph_SPI2    	   /* W5500所使用的SPI 时钟 */
    #define WIZ_SPIx_SCLK           GPIO_Pin_13			       /* W5500所使用的CLK      */
    #define WIZ_SPIx_MISO           GPIO_Pin_14				   /* W5500所使用的 MISO       */
    #define WIZ_SPIx_MOSI           GPIO_Pin_15			       /* W5500所使用的 MOSI     */
    
    void gpio_for_w5500_config(void)
    {
      SPI_InitTypeDef  SPI_InitStructure;
      GPIO_InitTypeDef GPIO_InitStructure;
      //开 RESET与片选引脚的时钟
      RCC_APB2PeriphClockCmd(WIZ_SPIx_RESET_CLK|WIZ_SPIx_INT_CLK, ENABLE);
      //开 CLK与片选引脚的时钟
      RCC_APB2PeriphClockCmd(WIZ_SPIx_GPIO_CLK|WIZ_SPIx_SCS_CLK, ENABLE);
    
      /*SPI Periph clock enable */
      WIZ_SPIx_CLK_CMD(WIZ_SPIx_CLK, ENABLE);
    
      /* Configure SCK */
      GPIO_InitStructure.GPIO_Pin = WIZ_SPIx_SCLK;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
      GPIO_Init(WIZ_SPIx_GPIO_PORT, &GPIO_InitStructure);
    
      /*Configure MISO */
      GPIO_InitStructure.GPIO_Pin = WIZ_SPIx_MISO;
      GPIO_Init(WIZ_SPIx_GPIO_PORT, &GPIO_InitStructure);
    
      /*Configure MOSI */
      GPIO_InitStructure.GPIO_Pin = WIZ_SPIx_MOSI;
      GPIO_Init(WIZ_SPIx_GPIO_PORT, &GPIO_InitStructure);
    
      /*Configure CS pin */
      GPIO_InitStructure.GPIO_Pin = WIZ_SPIx_SCS;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
      GPIO_Init(WIZ_SPIx_SCS_PORT, &GPIO_InitStructure);
    
      /* SPI1 configuration */
      SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
      SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
      SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
      SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
      SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
      SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
      SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
      SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
      SPI_InitStructure.SPI_CRCPolynomial = 7;
      SPI_Init(WIZ_SPIx, &SPI_InitStructure);
      SPI_Cmd(WIZ_SPIx, ENABLE);
    	
      /*复位引脚*/
      GPIO_InitStructure.GPIO_Pin = WIZ_RESET;					        
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		     
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;		     
      GPIO_Init(WIZ_SPIx_RESET_PORT, &GPIO_InitStructure);		 
      GPIO_SetBits(WIZ_SPIx_RESET_PORT, WIZ_RESET);		
      
      /*INT引脚*/	
      GPIO_InitStructure.GPIO_Pin = WIZ_INT;						       
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		     
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;				     
      GPIO_Init(WIZ_SPIx_INT_PORT, &GPIO_InitStructure);			 
    }
    

    SPI写函数

    uint8_t SPI_SendByte(uint8_t byte)
    {
      /* 检测数据寄存器状态*/
      while (SPI_I2S_GetFlagStatus(WIZ_SPIx, SPI_I2S_FLAG_TXE) == RESET);
      /* 发送数据 */
      SPI_I2S_SendData(WIZ_SPIx, byte);
      /* 等待接收一个字节 */
      while (SPI_I2S_GetFlagStatus(WIZ_SPIx, SPI_I2S_FLAG_RXNE) == RESET);
      /*返回从SPI上接收到的一个字节 */
      return SPI_I2S_ReceiveData(WIZ_SPIx);
    }
    

    SPI 片选

    void wiz_cs(uint8_t val)
    {
    	if (val == LOW) 
    	{
    	  GPIO_ResetBits(WIZ_SPIx_SCS_PORT, WIZ_SPIx_SCS); 
    	}
    	else if (val == HIGH)
    	{
    	  GPIO_SetBits(WIZ_SPIx_SCS_PORT, WIZ_SPIx_SCS); 
    	}
    }
    void iinchip_csoff(void)
    {
    	wiz_cs(LOW);
    }
    void iinchip_cson(void)
    {	
       wiz_cs(HIGH);
    }
    /*写*/
    void IINCHIP_WRITE( uint32 addrbsb,  uint8 data)
    {
       iinchip_csoff();                              	
       SPI_SendByte( (addrbsb & 0x00FF0000)>>16);//偏移16	
       SPI_SendByte( (addrbsb & 0x0000FF00)>> 8);//偏移8
       SPI_SendByte( (addrbsb & 0x000000F8) + 4);  
       SPI_SendByte(data);                   
       iinchip_cson();                            
    }
    /*读*/
    uint8 IINCHIP_READ(uint32 addrbsb)
    {
       uint8 data = 0;
       iinchip_csoff();                            
       SPI_SendByte( (addrbsb & 0x00FF0000)>>16);
       SPI_SendByte( (addrbsb & 0x0000FF00)>> 8);
       SPI_SendByte( (addrbsb & 0x000000F8))    ;
       data = SPI_SendByte(0x00);            
       iinchip_cson();                               
       return data;    
    }
    

    读写数据

    uint16 wiz_write_buf(uint32 addrbsb,uint8* buf,uint16 len)
    {
       uint16 idx = 0;
       if(len == 0) 
       		printf("Unexpected2 length 0\r\n");
       iinchip_csoff();                               
       SPI_SendByte( (addrbsb & 0x00FF0000)>>16);
       SPI_SendByte( (addrbsb & 0x0000FF00)>> 8);
       SPI_SendByte( (addrbsb & 0x000000F8) + 4); 
       for(idx = 0; idx < len; idx++)
       {
         SPI_SendByte(buf[idx]);
       }
       iinchip_cson();                           
       return len;  
    }
    
    uint16 wiz_read_buf(uint32 addrbsb, uint8* buf,uint16 len)
    {
      uint16 idx = 0;
      if(len == 0)
        printf("Unexpected2 length 0\r\n");
        
      iinchip_csoff();                                
      SPI_SendByte( (addrbsb & 0x00FF0000)>>16);
      SPI_SendByte( (addrbsb & 0x0000FF00)>> 8);
      SPI_SendByte( (addrbsb & 0x000000F8));    
      for(idx = 0; idx < len; idx++)                   
      {
        buf[idx] = SPI_SendByte(0x00);
      }
      iinchip_cson();                                  
      return len;
    }
    

    网络相关函数

    配置MAC地址

    #define SHAR0                       (0x000900)//寄存器地址查看手册
    
    void setSHAR(uint8 * addr)
    {
      wiz_write_buf(SHAR0, addr, 6);  
    }
    
    void set_w5500_mac(void)
    {
    	memcpy(ConfigMsg.mac, mac, 6);
    	setSHAR(ConfigMsg.mac);	/**/
    	memcpy(DHCP_GET.mac, mac, 6);
    }
    
    /**brief Subnet mask Register address*/
    #define SUBR0                       (0x000500)
    #define SUBR1                       (0x000600)
    #define SUBR2                       (0x000700)
    #define SUBR3                       (0x000800)
    /**brief Source MAC Register address*/
    #define SHAR0                       (0x000900)
    #define SHAR1                       (0x000A00)
    #define SHAR2                       (0x000B00)
    #define SHAR3                       (0x000C00)
    #define SHAR4                       (0x000D00)
    #define SHAR5                       (0x000E00)
    /**@brief Source IP Register address*/
    #define SIPR0                       (0x000F00)
    #define SIPR1                       (0x001000)
    #define SIPR2                       (0x001100)
    #define SIPR3                       (0x001200)
    //设置IP地址
    void set_w5500_ip(void)
    {	
    ···
    	setSUBR(ConfigMsg.sub);//配置子网掩码
    	setGAR(ConfigMsg.gw);//配置网关
    	setSIPR(ConfigMsg.lip);//配置IP
    	···
    }
    

    主循环

    void do_tcp_server(void)
    {	
    	uint16 len=0;  
    	switch(getSn_SR(SOCK_TCPS))	/*获取socket状态*/
    	{
    		case SOCK_CLOSED:/*关闭状态*/
    			socket(SOCK_TCPS ,Sn_MR_TCP,local_port,Sn_MR_ND);	   /*创建SOCKET*/
    		  break;     
    		case SOCK_INIT:/*socket已初始化状态*/
    			listen(SOCK_TCPS);	/*建立监听*/
    		  break;
    		case SOCK_ESTABLISHED:	/*建立连接状态*/
    			if(getSn_IR(SOCK_TCPS) & Sn_IR_CON)
    			{
    				setSn_IR(SOCK_TCPS, Sn_IR_CON);		 /*清除接收中断*/
    			}
    			len=getSn_RX_RSR(SOCK_TCPS);/*接收数据长度*/
    			if(len>0)
    			{
    				recv(SOCK_TCPS,buff,len);	/*接收来自client数据*/
    				buff[len]=0x00;
    				printf("%s\r\n",buff);
    				send(SOCK_TCPS,buff,len)/*向client发送数据*/
    		  }
    		  break;
    		case SOCK_CLOSE_WAIT:/*关闭状态*/
    			close(SOCK_TCPS);
    		  break;
    	}
    }
    

    主函数下,子函数的实现

    uint8 socket(SOCKET s, uint8 protocol, uint16 port, uint8 flag)
    {
       uint8 ret;
       if (
            ((protocol&0x0F) == Sn_MR_TCP)    || ((protocol&0x0F) == Sn_MR_UDP)    ||
            ((protocol&0x0F) == Sn_MR_IPRAW)  || ((protocol&0x0F) == Sn_MR_MACRAW) ||
            ((protocol&0x0F) == Sn_MR_PPPOE)
          )
       {
          close(s);
          //Socket n模式寄存器  0 0 0 1 写值  设置为TCP模式
          IINCHIP_WRITE(Sn_MR(s) ,protocol | flag);
          if (port != 0) {
          	 //写端口号
             IINCHIP_WRITE( Sn_PORT0(s) ,(uint8)((port & 0xff00) >> 8));
             IINCHIP_WRITE( Sn_PORT1(s) ,(uint8)(port & 0x00ff));
          } else {
             local_port++; // if don't set the source port, set local_port number.
             IINCHIP_WRITE(Sn_PORT0(s) ,(uint8)((local_port & 0xff00) >> 8));
             IINCHIP_WRITE(Sn_PORT1(s) ,(uint8)(local_port & 0x00ff));
          }
          //Socket n 配置寄存器  0x01 OPEN 打开
          IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_OPEN); 
          /* 等待命令处理*/
          while( IINCHIP_READ(Sn_CR(s)) );
          ret = 1;
       }
       else
       {
          ret = 0;
       }
       return ret;
    }
    
    uint8 listen(SOCKET s)
    {
       uint8 ret;
       //Socket n 状态寄存器   0x13 SOCK_INIT
       if (IINCHIP_READ( Sn_SR(s) ) == SOCK_INIT)
       {
          //Socket n 配置寄存器  0x02 LISTEN
          IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_LISTEN);
          /* 等待命令处理 */
          while( IINCHIP_READ(Sn_CR(s) ) );
          ret = 1;
       }
       else
       {
          ret = 0;
       }
       return ret;
    }
    
    uint8 connect(SOCKET s, uint8 * addr, uint16 port)
    {
        uint8 ret;
        if
            (
                ((addr[0] == 0xFF) && (addr[1] == 0xFF) && (addr[2] == 0xFF) && (addr[3] == 0xFF)) ||
                ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) ||
                (port == 0x00)
            )
        {
          ret = 0;
        }
        else
        {
            ret = 1;
            // 设置目的 IP
            IINCHIP_WRITE( Sn_DIPR0(s), addr[0]);
            IINCHIP_WRITE( Sn_DIPR1(s), addr[1]);
            IINCHIP_WRITE( Sn_DIPR2(s), addr[2]);
            IINCHIP_WRITE( Sn_DIPR3(s), addr[3]);
            //端口
            IINCHIP_WRITE( Sn_DPORT0(s), (uint8)((port & 0xff00) >> 8));
            IINCHIP_WRITE( Sn_DPORT1(s), (uint8)(port & 0x00ff));
            //设置状态 connect
            IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_CONNECT);
            /* 等待命令处理完成 */
            while ( IINCHIP_READ(Sn_CR(s) ) ) ;
    
            while ( IINCHIP_READ(Sn_SR(s)) != SOCK_SYNSENT )
            {
                //获取状态寄存器 0x17 SOCK_ESTABLISHED
                if(IINCHIP_READ(Sn_SR(s)) == SOCK_ESTABLISHED)
                {
                    break;
                }
                //只读 超时
                if (getSn_IR(s) & Sn_IR_TIMEOUT)
                {
                    IINCHIP_WRITE(Sn_IR(s), (Sn_IR_TIMEOUT));  // clear TIMEOUT Interrupt
                    ret = 0;
                    break;
                }
            }
        }
       return ret;
    }
    
    uint16 send(SOCKET s, const uint8 * buf, uint16 len)
    {
      uint8 status=0;
      uint16 ret=0;
      uint16 freesize=0;
    
      if (len > getIINCHIP_TxMAX(s)) 
      	ret = getIINCHIP_TxMAX(s); // 检查不超过最大值
      else ret = len;
    
      // if freebuf is available, start.
      do
      {
        //get socket TX free buf size
        freesize = getSn_TX_FSR(s);
        status = IINCHIP_READ(Sn_SR(s));
        if ((status != SOCK_ESTABLISHED) && (status != SOCK_CLOSE_WAIT))
        {
          ret = 0;
          break;
        }
      } while (freesize < ret);
      
      // copy data
      send_data_processing(s, (uint8 *)buf, ret);
      IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_SEND);
      /* 等待处理 */
      while( IINCHIP_READ(Sn_CR(s) ) );
    
      while ( (IINCHIP_READ(Sn_IR(s) ) & Sn_IR_SEND_OK) != Sn_IR_SEND_OK )
      {
        status = IINCHIP_READ(Sn_SR(s));
        if ((status != SOCK_ESTABLISHED) && (status != SOCK_CLOSE_WAIT) )
        {
          printf("SEND_OK Problem!!\r\n");
          close(s);
          return 0;
        }
      }
      IINCHIP_WRITE( Sn_IR(s) , Sn_IR_SEND_OK);
    
    #ifdef __DEF_IINCHIP_INT__
       putISR(s, getISR(s) & (~Sn_IR_SEND_OK));
    #else
       IINCHIP_WRITE( Sn_IR(s) , Sn_IR_SEND_OK);
    #endif
    
       return ret;
    }
    
    void send_data_processing(SOCKET s, uint8 *data, uint16 len)
    {
      uint16 ptr =0;
      uint32 addrbsb =0;
      if(len == 0)
      {
        printf("CH: %d Unexpected1 length 0\r\n", s);
        return;
      }
      //获取要写数据的地址,存器的值,表示数据在0-FFFF里存到了多少数
      ptr = IINCHIP_READ( Sn_TX_WR0(s) );
      ptr = ((ptr & 0x00ff) << 8) + IINCHIP_READ(Sn_TX_WR1(s));
    
      addrbsb = (uint32)(ptr<<8) + (s<<5) + 0x10;//数据帧控制位00010 0 00
      wiz_write_buf(addrbsb, data, len);
      
      ptr += len;记录发送缓存区已经写到了多少,存在发送写指针寄存器中
      IINCHIP_WRITE( Sn_TX_WR0(s) ,(uint8)((ptr & 0xff00) >> 8));
      IINCHIP_WRITE( Sn_TX_WR1(s),(uint8)(ptr & 0x00ff));
    }
    
    展开全文
  • stm32操作系统的学习操作,大家可以参考学习,STM32F4x7+freertos+lwip+ssl+MQTT-(MDK5)稳定可靠+W5500 MQTT例程和说明+LWIP+UCOSIII+UCOSII
  • stm32_IAP远程升级程序_STM32+W5500+IAP,现在项目正在使用,基于http的get和post两种模式。
  • STM32+W5500网络通信

    2021-12-28 19:51:24
    文章目录一、W5500模块二、 modbus协议三、从机代码 一、W5500模块 (一)W5500以太网模块介绍 D-W5500 EVB以太网模块是一款基于WIZnet W5500芯片的以太网模块,且性价比高的以太网模块。W5500是一款全硬件TCP/IP...

    一、W5500模块

    (一)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的电压,方便用户在不同的单片机系统中使用。
    (二)模块排针功能表
    在这里插入图片描述

    线路接法
    PA3 -> W5500_RST
    PA4 -> W5500_SCS
    PA5 -> W5500_SCK
    PA6 -> W5500_MISO
    PA7 -> W5500_MOSI

    二、 modbus协议

    (一)modbus协议原理
    Modbus协议是一种已广泛应用于当今工业控制领域的通用通讯协议。通过此协议,控制器相互之间、或控制器经由网络(如以太网)可以和其它设备之间进行通信。Modbus协议使用的是主从通讯技术,即由主设备主动查询和操作从设备。一般将主控设备方所使用的协议称为Modbus Master,从设备方使用的协议称为Modbus Slave。典型的主设备包括工控机和工业控制器等;典型的从设备如PLC可编程控制器等。
    Modbus的工作方式是请求/应答,每次通讯都是主站先发送指令,可以是广播,或是向特定从站的单播;从站响应指令,并按要求应答,或者报告异常。当主站不发送请求时,从站不会自己发出数据,从站和从站之间不能直接通讯。

    Modbus协议是应用层(协议层)报文传输协议,它定义了一个与物理层无关的协议数据单元(PDU),即PDU=功能码+数据域,功能码1byte,数据域不确定。

    Modbus协议能够应用在不同类型的总线或网络。对应不同的总线或网络,Modbus协议引入一些附加域映射成应用数据单元(ADU),即ADU=附加域+PDU,例如modbus tcp/ip------ ADU=MBAP+ADU。
    (二)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 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连接,地址就是代码里所写的,比如我是192.168.1.199在这里插入图片描述
    ,端口为5000,有个前提,要通信得先把前面的客户端例子调通,也就是需要修改适配器
    在这里插入图片描述
    在这里插入图片描述
    效果:
    在这里插入图片描述
    参考文献:https://blog.csdn.net/junseven164/article/details/122148326?spm=1001.2014.3001.5501

    展开全文
  • 经过这几天的学习与调试,终于在STM32F103VCT6+W5500(SPI1)+Freemodbus 平台上,实现Modbus-TCP协议的功能。其实很简单,只要熟悉Modbus-RTU通讯,明白Modbus帧的结构等,Modbus-TCP只是在原来的帧结构上加个头,去...
  • 硬件是STM32+W5500 ,使用http通信协议时间iap OTA 空中升级,文档讲的比较详细,也是我见过的比较好以及比较详细的IAP讲解了。我这边顺便说说为什么要用http 通信协议,因为http通讯协议协议头里面有个body 长度...
  • 嵌入式微操作系统学习,STM32+W5500 MQTT例程和说明+F407探索者+LWIP+UCOSIII+UCOSII
  • stm32操作系统的学习操作,大家可以参考学习,STM32F4x7+freertos+lwip+ssl+MQTT-(MDK5)稳定可靠+W5500 MQTT例程和说明+LWIP+UCOSIII+UCOSII
  • 单个电路板2片W5500的驱动代码,基于WIZnet官方驱动修改,包括spi总线初始化和w5500驱动;经实测,2片w5500可同时工作,同时作为tcpclient,同时作为tcpserver,一个client和一个server的情况下都可以正常运行,并且...
  • 基于STM32+W5500, 移植Ethernet文件并基于NTP实现RTC对时更新,USART可实现DMA 接收任意长度数据
  • stm32模拟spi控制w5500

    2018-10-06 16:09:50
    stm32模拟spi控制w5500实现客户端模式,芯片spi借口有别的用途,通过软件模拟spi与w5500通信 stm32模拟spi控制w5500实现客户端模式,芯片spi借口有别的用途,通过软件模拟spi与w5500通信 stm32模拟spi控制w5500...
  • 基于STM32F407下的阿里云MQTT开发,使用的是W5500 SPI通信方式,代码可以直接使用,阿里Iot平台需要修改下三元组。
  • 目录一、W5500及modbus二、代码实现1.初始化网络2.响应函数3.main函数循环三、通信结果链接 一、W5500及modbus W5500 芯片是一款集成全硬件 TCP/IP 协议栈的嵌入式以太网控制器,同时也是一颗工业级以太网控制芯片...

空空如也

空空如也

1 2 3 4 5 ... 7
收藏数 135
精华内容 54
关键字:

stm32f4 w5500