ENC28J60+Uip TCP Server/Client



接了一個專案要利用網路互相傳資料,必需同時開發TCP Server/Client 兩端,在網路找了一些範例 同樣是利用 ENC28J60+Uip 來開發,開始找到同是SPI2 的範例,所以下列 1~6 是將 SPI2改為 SPI1所需注意的事項。但因為不是很了解 Uip TCP的應用,雖然改成 SPI1但仍無法完成通訊,在進一步研究 TCP 的通訊原理後發現在 IP應用上有問題,在修改 7, 8兩項後終於可以利用 TCP Server/Client 傳資料。( 我此處用的範例是 ALIENTEK MINISTM32 擴展實驗21 ENC28J60網路模組實驗)

1. SPI2 修改為SPI1

      由於範例程式用的是SPI2 原來引腳
      CS    INT    MISO   MOSI   SCK    RST
      PG8   PD2    PB14   PB15   PB13   PG6
      現在的引腳
      CS    INT    MISO   MOSI   SCK    RST
      PC4  PC1    PA6     PA7      PA5    
      所以必需修改為SPI1

2. 系統頻率 HSE12000000 SYSTEM CLOCK 72000000 HSE12000000,所以鎖頻 PLL=6

由於範例程式用的是25M或者是8M的石英振盪器,所以必需在stm32f10x_conf.h的程式庫中的HSE定義改為12000000
main() 中設定為 Stm32_Clock_Init(9)其中 9 為鎖頻 PLL 的倍數。因此這個參數應改為
Stm32_Clock_Init(6);  //System Clock 設定
由於我們的石英振盪器為12M ,而我們希望 SYSTEM CLOCK 72M HSE12M,所以鎖頻 PLL=6


3. SPI 初始化 SPI1 腳位定義需注意,尤其 CS腳位要宣告

      由於範例程式用的是SPI2 原來引腳
      CS    INT    MISO   MOSI   SCK    RST
      PG8   PD2    PB14   PB15   PB13   PG6
      現在的引腳
      CS    INT    MISO   MOSI   SCK    RST
      PC4  PC1    PA6     PA7      PA5    
       
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
          GPIO_Init(GPIOB, &GPIO_InitStructure);// GPIOB
          GPIO_SetBits(GPIOB,GPIO_Pin_4);
      ENC28J60.h   SPI 初始化 時注意 CS 腳位的PoutA(X) X的值需改變
      #define ENC28J60_CS         PGout(4)         //ENC28J60


      5. SPI 初始化 SPI1_SetSpeed

若原來為 SPI2_SetSpeed 請修改為SPI1_SetSpeed,且原為SPI2 改為SPI1

void SPI1_SetSpeed(u8 SpeedSet)
{
     ...
   SPI1->CR1 &= ~0x0030; 
          SPI1->CR1 |=  0x0008;     //====SPI SPPED 18MHZ
          SPI1->CR1|=1<<6;          //SPI ENABLE
      }



      6. ENC28J60.c delayms(1) 改為 10mS

ENC28J60_Write_Op(ENC28J60_SOFT_RESET,0,ENC28J60_SOFT_RESET);//
while(!(ENC28J60_Read(ESTAT)&ESTAT_CLKRDY)&&retry<500)
    {
            retry++;
            delay_ms(10);
    };
SPI GPIO的速度被降低為 10M 又分頻為8,所以等待時間加長。




7. 網路互連要注要對方為Server 時的IP 位置
tcp_client_demo.c 


void tcp_client_reconnect()
    {
          uip_ipaddr_t ipaddr;
          uip_ipaddr(&ipaddr,192,168,1,101);
 //設置IP192.168.1.101
          uip_connect(&ipaddr,htons(1400));
 //埠為1400
    }


注意雙方所連線的 IP及 Port 請參考下圖。









8. TCP服務 Server 的設定--1

      ========test.c  (client 部份)
      int main(void)
      {       
       ...
         uip_ipaddr(ipaddr, 192,168,1,16);  //設置本地設置IP位址
          uip_sethostaddr(ipaddr);                                           
          uip_ipaddr(ipaddr, 192,168,1,1);   //設置閘道IP位址(其實就是你路由器的IP地址)
          uip_setdraddr(ipaddr);                                          
          uip_ipaddr(ipaddr, 255,255,255,0);        //設置網路遮罩
          uip_setnetmask(ipaddr);
          uip_listen(HTONS(1200));                       //監聽1200,用於TCP Server
          //uip_listen(HTONS(80));                                //監聽80,用於Web Server
                //tcp_client_reconnect();                        //嘗試連接到TCP Server,用於TCP Client
          _Rxflag = 0;
          while (1)
          {...}
       ...
      }


8. 完成TCP服務 Server----2

      ========tcp_demo.c  (client 部份)
      //TCP應用介面函數(UIP_APPCALL)  ,  完成TCP服務(包括serverclient)HTTP服務
      void tcp_demo_appcall(void)
      {  
          switch(uip_conn->lport)//本地監聽埠801200
          {
                  case HTONS(80):
                          httpd_appcall();
                          break;
                  case HTONS(1200):
                                                  tcp_server_demo_appcall();
                          break;
                  default:                                             
                      break;
          }                  
          switch(uip_conn->rport) //遠端連接1400
          {
            case HTONS(1400):   //此處client1 400
          tcp_client_demo_appcall();
                 break;
              default:
                 break;
          }    
      }

留言

這個網誌中的熱門文章

STM32 I2C-EEPROM 的讀寫

如何提高STM32 ADC的精度