STM32F412應用開發筆記之五:結合W5500實現以太網通訊


因實際使用需求我們測試一下網絡通訊,在NUCLEO-F412ZG測試板上沒有以太網部分,我們選擇外接一個W5500的實驗板。W5500支持SPI接口通訊,DC3.3V供源。而NUCLEO-F412ZG測試板已經將SPI1的各引腳SPI1_NSS(CN7_17)、SPI1_SCK(CN7_10)、SPI1_MISO(CN7_12)、SPI1_MOSI(CN7_14)引出到CN7,3.3VDC和GND也引導了CN8,可以方便的實現測試。如下圖紅框所示:

1、測試的准備工作

為了實現以太網通訊首先需要下載W5500的驅動源碼,可以到WIZnet的官網下載:http://www.iwiznet.cn/

目前最新版本為V1.1,我選用的是V1.03下載下來的壓縮包解壓后如下圖:

 

需要將ethernet文件夾拷貝到我們的項目目錄中:

 

並在IAR的項目下添加相關的文件和路徑,主要是socket.c、w5500.c、wizchip_.conf.c三個文件。這三個文件分別實現socket、硬件驅動及相關通訊配置功能,具體可以查看相應的源碼級手冊。

  

2、編寫測試代碼

在完成以上工作后就可以開始真正地移植工作了。具體步驟如下:

  • 硬件配置及初始化。
  • 以太網通訊配置的初始化。
  • 實現具體的通訊過程。

2.1、硬件的配置及初始化

由於W5500通過SPI接口與STM32通訊,所以硬件配置和初始化是非常簡單的,與W5500實際上沒有關系,使一些通用的操作。事實上就是STM32F412ZG的SPI接口初始化的過程,需要實現RCC、GPIO以及SPI的初始化就可以了。關於這部分可以查看ST的例程。

2.2、以太網通訊配置的初始化

以太網通訊配置的初始化主要有三個方面的內容:

  • 注冊TCP通訊相關的回調函數  RegisterFunction();
  • 初始化芯片參數  ChipParametersConfiguration();
  • 初始化網絡通訊參數  NetworkParameterConfiguration()

三個函數的具體實現內容如下:

//函數注冊,首先,應由用戶實現SPI注冊回調函數來訪問WIZCHIP

void RegisterFunction(void)

  //臨界區回調函數

  reg_wizchip_cris_cbfunc(SPI_CrisEnter, SPI_CrisExit);  //注冊臨界區函數

  //片選回調函數

#if   _WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_SPI_VDM_

  reg_wizchip_cs_cbfunc(SPI_CS_Select, SPI_CS_Deselect);//注冊SPI片選信號函數

#elif _WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_SPI_FDM_

  reg_wizchip_cs_cbfunc(SPI_CS_Select, SPI_CS_Deselect);  // CS必須為低電平.

#else

   #if (_WIZCHIP_IO_MODE_ & _WIZCHIP_IO_MODE_SIP_) != _WIZCHIP_IO_MODE_SIP_

      #error "Unknown _WIZCHIP_IO_MODE_"

   #else

      reg_wizchip_cs_cbfunc(wizchip_select, wizchip_deselect);

   #endif

#endif

  //SPI的讀寫回調函數

  reg_wizchip_spi_cbfunc(SPI_ReadByte, SPI_WriteByte);     //注冊讀寫函數

}

注冊函數實際上就是函數指針的調用,可參考C語言函數指針部分內容。對於以上注冊的函數,SPI_WriteByte需要說明一下,無論是用可函數還是直接操作寄存器,在寫完之后都需要再讀一下(紅色部分),否則就會在客戶端出現連接TCPServer超時的報警,沒明白什么原因。

//寫1字節數據到SPI總線

void SPI_WriteByte(uint8_t TxData)

{                       

//  while((SPI2->SR&SPI_I2S_FLAG_TXE)==0);        //等待發送區空              

//  SPI2->DR=TxData;                              //發送一個byte

//  while((SPI2->SR&SPI_I2S_FLAG_RXNE)==0);       //等待接收完一個byte 

//  SPI2->DR;

  while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);        //等待發送區空

  SPI_I2S_SendData(SPI2,TxData);                                        //發送一個byte

  while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_RXNE) == RESET);        //等待接收完一個byte

  SPI_I2S_ReceiveData(SPI2);                                            //返回接收的數據

}

 

 

//初始化芯片參數

void ChipParametersConfiguration(void)

{

  uint8_t tmp;

  uint8_t memsize[2][8] = {{2,2,2,2,2,2,2,2},{2,2,2,2,2,2,2,2}};

  //WIZCHIP SOCKET緩存區初始化

  if(ctlwizchip(CW_INIT_WIZCHIP,(void*)memsize) == -1){

    //printf("WIZCHIP Initialized fail.\r\n");

  while(1);

  }

 

  //PHY物理層連接狀態檢查

  do{

    if(ctlwizchip(CW_GET_PHYLINK, (void*)&tmp) == -1){

      //printf("Unknown PHY Link stauts.\r\n");

    }

  }while(tmp == PHY_LINK_OFF);

}

以上實現網絡物理層的配置。

//初始化WIZCHIP中的網絡參數信息

void NetworkParameterConfiguration(void)

{

  uint8_t tmpstr[6];

  ctlnetwork(CN_SET_NETINFO, (void*)&gWIZNETINFO);

  ctlnetwork(CN_GET_NETINFO, (void*)&gWIZNETINFO);

 

  ctlwizchip(CW_GET_ID,(void*)tmpstr);

}

 

其中gWIZNETINFO是一個wiz_NetInfo類型的結構體變量,該結構體在wizchip_conf.h中定義,用於設置mac地址、IP地址等網絡參數,具體如下:

typedef struct wiz_NetInfo_t

{

   uint8_t mac[6];  ///< Source Mac Address

   uint8_t ip[4];   ///< Source IP Address

   uint8_t sn[4];   ///< Subnet Mask

   uint8_t gw[4];   ///< Gateway IP Address

   uint8_t dns[4];  ///< DNS server IP Address

   dhcp_mode dhcp;  ///< 1 - Static, 2 - DHCP

}wiz_NetInfo;

至此網絡部分的初始化就已完成。

2.3、具體通訊過程的實現

經過前面的配置網絡已經可以ping通了,下面可以實現具體的應用。對於我這個項目就是可是實現Modbus TCP的編寫了。

編寫TCP Server,這部分有很多資料,直接附代碼:

//TCP服務器數據通訊

int32_t TCPServer(uint8_t sn, uint16_t port)

{

  int32_t ret;

  uint8_t socketStatus=getSn_SR(sn);

 

  switch(socketStatus)

  {

    case SOCK_ESTABLISHED :

      {

        if(getSn_IR(sn) & Sn_IR_CON)

        {

          setSn_IR(sn,Sn_IR_CON);

        }

        uint16_t size=0;

        if((size = getSn_RX_RSR(sn)) > 0)

        {

          if(size > DATA_BUFFER_SIZE)

          {

            size = DATA_BUFFER_SIZE;

          }

          uint8_t rxBuffer[DATA_BUFFER_SIZE];

          ret = recv(sn,rxBuffer,size);

          if(ret <= 0)

          {

            return ret;

          }

          //添加數據解析及響應的函數

          uint8_t txBuffer[DATA_BUFFER_SIZE];

          uint16_t length=ReceivedDataParsing(rxBuffer,txBuffer);

         

          uint16_t sentsize=0;

          while(length != sentsize)

          {

            ret = send(sn,txBuffer+sentsize,length-sentsize);

            if(ret < 0)

            {

              close(sn);

              return ret;

            }

            sentsize += ret; // 不用管SOCKERR_BUSY, 因為它是零.

          }

        }

        break;

      }

    case SOCK_CLOSE_WAIT :

      if((ret=disconnect(sn)) != SOCK_OK)

      {

        return ret;

      }

      break;

    case SOCK_INIT :

      if( (ret = listen(sn)) != SOCK_OK)

      {

        return ret;

      }

      break;

    case SOCK_CLOSED:

      if((ret=socket(sn,Sn_MR_TCP,port,0x00)) != sn)

      {

        return ret;

      }

      break;

    default:

      break;

  }

  return 1;

}

 

其中ReceivedDataParsing(rxBuffer,txBuffer)實現具體的應用協議,根據具體的需求而定,在此我們實現了簡單的Modbus TCP協議。

3、測試結果

完成編寫,調試無誤后,將程序下載到目標板,首先既然是以太網通訊,我們就在上位機上機簡單的網絡測試。在目標板上我們設定的IP地址為:192.168.1.100,在CMD中使用簡單的Ping命令測試如下:

 

由上圖可以看到,網路沒有問題。接下來我們用TCP&UDP測試工具進行進一步的測試,並使用Microsoft Network Monitor監視數據包。打開TCP&UDP測試工具,創建一個TCP客戶端,目標IP還是目標板IP,端口用502(我們在軟件中設定了)。

 

創建完成后,連接無誤,在發送欄中以16進制發送一條指令,可以看到下方的接收欄中收到數據。

 

我們再看看Microsoft Network Monitor中捕獲到的數據包核對一下數據是否正確。

 

由於我們實現了簡單的Modbus TCP協議,所以我們在使用ModScan32來測試一下通訊是否正確。首先啟動ModScan32,並做如下配置:

 

連接后數據顯示出來,持續更新一段時間后沒有問題。

 

同樣,我們再看看Microsoft Network Monitor中捕獲到的數據更新與ModScan32做一對比,數據包完整而且正確。

 

完成測試,通訊沒有問題STM32F412與W5500實現以太網通訊簡單方便。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM