ENC28J60 + 入門UIP + STM32 實現ICMP(ping通MCU)操作使用記錄


上次介紹了ENC28J60在STM32上怎么寫好第一個Hello World,這次在上次修改好驅動的基礎上,使用UIP實現ARP包響應,ICMP響應(ping通MCU)

UIPgitee下載地址: https://gitee.com/jinling_gitee/uip.git   github地址: https://github.com/adamdunkels/uip

下載后,項目路徑如下:

 

我們需要使用的文件主要是uip文件夾下的文件,和unix下的uip-conf.h(UIP配置項)和tapdev.h(底層SPI基礎讀寫實現)頭文件

在STM32中使用UIP時,由於UIP不是專門針對STM32設計的,所以需要修改一些東西才能正常使用:

1. 修改unix/uip-conf.h文件,這是UIP對用戶開放的一些配置文件

2. main.c中聲明UIP_APPCALL、uip_log回調函數,這是UIP提供的回調函數,為保證程序盡量簡單,本次ping沒有用到,暫時為空函數

3. 實現tapdev.h頭文件下聲明的tapdev_init  ENC28J60初始化、tapdev_read  讀一包數據、tapdev_send  發送一包數據函數

修改uip-conf.h

對uip-conf.h做一些修改,才能正常使用:

1. 注釋webserver.h引入頭文件

 

 

實現UIP_APPCALL、uip_log函數

這兩個函數是UIP的回調函數,本次目的只為使用UIP ping通MCU,所以實現為空函數:

在main.c中聲明了兩個函數,分別對應UIP_APPCALL和uip_log,和timer.c中調用的clock_time

....
//UIP_APPCALL
void main_appcall(){
    
}
//UIP_APPCALL
void main_uiplog(char* msg) {
    
}
int clock_time(){
    
}

.....

回到uip-conf.h,聲明UIP_APPCALL和uip_log實現函數為main_appcall和main_uiplog:

#define UIP_APPCALL main_appcall
#define uip_log main_uiplog

clock_time函數,已在clock.h中聲明,只不過沒有實現而已,所以此處不用重復聲明

uipopt.h中聲明uip_tcp_appstate_t appstate類型

在uipopt.h 503行位置,有已注釋掉的uip_tcp_appstate_t聲明,把此處打開:

 

 

 或者去uip.h中注釋掉使用uip_tcp_appstate_t位置:

實現tapdev_init、tapdev_read、tapdev_send函數

新建tapdev.c,實現如下:

#include <tapdev.h>
#include "enc28j60.h"//ENC28J60驅動
#include <uip.h>

//引用外部文件uip.c中聲明的uip_ethaddr
extern struct uip_eth_addr uip_ethaddr;
//網卡地址
unsigned char my_mac[6] = {0x29, 0x7C, 0x07, 0x37, 0x24, 0x63};
void tapdev_init(void) {
    enc28j60_init(my_mac);
    for (int i = 0; i < 6; i++)
    {
     uip_ethaddr.addr[i] = my_mac[i];
    }
}
//讀取一包數據
unsigned int tapdev_read(void){
    enc28j60_packet_receive(uip_buf, MAX_FRAMELEN);
}
//發送一包數據
void tapdev_send(void) {
    enc28j60_packet_send(uip_buf, MAX_FRAMELEN);
}

把UIP相關文件放在一起

最后把上述提到的unix/uip-conf.h、unix/tapdev.h放到UIP文件夾中,通過IDE(如keil5)設置頭文件路徑為UIP文件夾,添加如下圖紅框中的.c文件

keil5 添加下圖紅框中的.c文件

 

 

 對於keil5 IDE來說,需要修改每個.c文件的引入頭文件,把""改為<>,例如:

 

最后,編譯成功,就可以進行下一步操作了。

main.c實現arp響應和icmp響應

在此之前,需要保證添加以上文件后,可以正常編譯通過:

首先在mainc.c中聲明UIP的UIP_BUF:

這個UIP_BUF主要用來在接收到數據后,判斷協議類型,源、目標MAC地址

#define UIP_BUF ((struct uip_eth_hdr *)&uip_buf[0])

處理ICMP請求操作:

處理ping請求過來的包

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */
  

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_SPI1_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
    //初始化前等待一些時間
    for(int i = 0;i < 20;i++) {
        //enc28j60PhyWrite(PHLCON,0x7a4);    
        HAL_Delay(500);
        print("begin init enc28j60...");
    }
    tapdev_init();//初始化enc28j60
    print("init enc28j60 success!");
    //初始化UIP
    uip_init();
    uip_ipaddr_t ipaddr;
    uip_ipaddr(ipaddr, 192, 168, 1, 8);//MCU IP地址
    uip_sethostaddr(ipaddr);
    uip_ipaddr(ipaddr, 192, 168, 1, 1);//網關,電腦和MCU經過路由器時使用
    uip_setdraddr(ipaddr);
    uip_ipaddr(ipaddr, 255, 255, 252, 0);//子網掩碼
    uip_setnetmask(ipaddr);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
        //嘗試讀取一包數據
        uip_len = tapdev_read();
        if(uip_len == 0){
            //沒有讀到數據
            continue;
        }
        //是否是ARP請求
        if(UIP_BUF->type == htons(UIP_ETHTYPE_ARP)) {
            //拼裝ARP響應請求
            uip_arp_arpin();
            if(uip_len>0){
                //響應ARP請求發送數據
                tapdev_send();
            }
        }
        //是否是IPV4
        if(UIP_BUF->type == htons(UIP_ETHTYPE_IP)) {
       //ping過來時,會進入此判斷 uip_arp_ipin();
//UIP解析數據 uip_input(); if(uip_len > 0){ //必須調用,不然會出現ping不通情況,用抓包工具看,顯示收到數據包checksum bad 校驗和失敗 uip_arp_out(); tapdev_send(); } } /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ }

電腦端鏈接MCU后,需要打開網絡設備器,設置為使用下面IP:

 

 

 

最后附上成功ping通MCU設備Keil5項目供參考:https://wwb.lanzouw.com/itg8Ly0k6id 密碼:5nhb


免責聲明!

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



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