zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    JVM调试常用命令——jmap、jstat(2)
    JVM调试常用命令——jps、(1)
    线程基础:多任务处理(18)——MESI协议以及带来的问题:volatile关键字
    线程基础:多任务处理(18)——MESI协议以及带来的问题:伪共享
    网络穿透与音视频技术(5)——NAT映射检测和常见网络穿越方法论(NAT检测实践2)
    网络穿透与音视频技术(4)——NAT映射检测和常见网络穿越方法论(NAT检测实践1)
    网络穿透与音视频技术(3)——NAT映射检测和常见网络穿越方法论(NAT检测)
    网络穿透与音视频技术(2)——NAT的概念及工作模式(下)
    成功解决JSP和Servlet的中文乱码问题
    bootstrap心得
  • 原文地址:https://www.cnblogs.com/GengMingYan/p/15734623.html
Copyright © 2011-2022 走看看