OpenEdv-开源电子网

 找回密码
 立即注册

扫一扫,访问微社区

正点原子全套STM32开发资料,上千讲STM32视频教程,RT1052教程免费下载啦...
查看: 430|回复: 1

W7500 M0+MAC+TCP/IP 以太网单芯片方案 W7500EVB用户手册连载(17)--网络片

[复制链接]

  离线 

28

主题

77

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
229
金钱
229
注册时间
2018-2-23
在线时间
24 小时
发表于 2018-3-16 17:05:27 | 显示全部楼层 |阅读模式
本帖最后由 WSGustin 于 2018-3-20 16:05 编辑

W7500(W7500P)芯片简介:
W7500 芯片为工业级以太网单芯片解决方案, 集成 ARM Cortex-M0,128KB Flash 及全硬件TCP/IP 核(和W5500、W5100内核一致),特别适用于物联网领域。 使用 W7500EVB, 让您轻松完成原型开发。

全硬件TCP/IP核的最大优点是他在执行联网操作时不需要占用MCU的运行资源,大大增加了MCU的工作效率。

DHCP协议是TCP/IP协议簇中的一种,具体功能为DHCP客户端向DHCP服务器发送自动获取IP请求,DHCP服务器为DNCP客户端自动分配IP地址、网关、DNS服务器地址等信息。本例程就是W7500EVB以DHCP客户端的角色,向DHCP服务器发送自动获取IP信息的请求并最终成功自动获取IP信息。使用前,我们先了解下DHCP协议。


想了解更多关于WIZnet W7500更多信息,或者有技术问题请联系我们:gustin@wisioe.com
深圳炜世科技—WIZnet官方代理商,全程技术支持,价格绝对优势!
电话:0755-86568556
邮箱:support@wisioe.com
回复

使用道具 举报

  离线 

28

主题

77

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
229
金钱
229
注册时间
2018-2-23
在线时间
24 小时
 楼主| 发表于 2018-3-16 17:07:46 | 显示全部楼层
第十八章 DHCP18.1 DHCP例程概述
       DHCP协议是TCP/IP协议簇中的一种,具体功能为DHCP客户端向DHCP服务器发送自动获取IP请求,DHCP服务器为DNCP客户端自动分配IP地址、网关、DNS服务器地址等信息。
       本例程就是W7500EVB以DHCP客户端的角色,向DHCP服务器发送自动获取IP信息的请求并最终成功自动获取IP信息。使用前,我们先了解下DHCP协议。
18.2 DHCP协议简介
       在常见的小型网络中,网络管理员都是采用手工分配IP地址的方法。但在中、大型网络中,手动分配IP地址的方法就不太实际了。为了避免多台机器分配IP的困扰,引出了一种高效的IP地址分配方法即:DHCP自动分配IP地址。
       在日常生活中,家庭无线路由器都内嵌了DHCP服务器。因此,当PC或智能手机通过路由器联网的时候,无需我们手工输入IP地址、网关、子网掩码和DNS服务器IP地址等网络参数。PC或智能手机都可以通过路由器自动获得这些必要的网络配置信息。这里的PC或智能手机在联网时都会先执行DHCP客户端线程和DHCP服务器通信。
       DHCP是Dynamic Host Configuration Protocol的缩写,它是TCP/IP协议簇中的一种,使用UDP协议进行数据报传递,端口号是67。DHCP协议采用客户端/服务器模型,主机地址的动态分配任务由网络主机驱动。当DHCP服务器接收到来自网络主机申请地址的信息时,才会向网络主机发送相关的地址配置等信息,以实现网络主机地址信息的动态配置。通常被应用在大型的局域网络环境中,主要作用是集中的管理、分配IP地址,使网络环境中的主机动态的获得IP地址、网关地址、DNS服务器地址等信息,并能够提升地址的使用率。
       使用DHCP时必须在网络上有一台DHCP服务器,而其他机器执行DHCP客户端。当DHCP客户端程序发出一个信息,请求一个动态的IP地址时,DHCP服务器会根据目前已经配置的地址,提供一个可供使用的IP地址和子网掩码给客户端。这些被分配的IP地址都是DHCP服务器预先保留的一个由多个地址组成的地址集,并且它们一般是一段连续的地址。
       DHCP使服务器能够动态地为网络中的其他服务器提供IP地址,通过使用DHCP,就可以不给Intranet网中除DHCP、DNS和WINS服务器外的任何服务器设置和维护静态IP地址。使用DHCP可以大大简化配置客户机的TCP/IP的工作,尤其是当某些TCP/IP参数改变时,如网络的大规模重建而引起的IP地址和子网掩码的更改。
       DHCPRelay也叫做DHCP中继代理。DHCP中继代理,就是在DHCP服务器和客户端之间转发DHCP数据包。当DHCP客户端与服务器不在同一个子网上,就必须有DHCP中继代理来转发DHCP请求和应答消息。DHCP中继代理的数据转发,与通常路由转发是不同的,通常的路由转发相对来说是透明传输的,设备一般不会修改IP包内容。而DHCP中继代理接收到DHCP消息后,重新生成一个DHCP消息,然后转发出去。在DHCP客户端看来,DHCP中继代理就像DHCP服务器;在DHCP服务器看来,DHCP中继代理就像DHCP客户端。
18.3 DHCP工作流程
       首先,DHCP客户端发送DHCPDISCOVER消息(IP地址租用申请),这个消息通过广播方式发出,所有网络中的DHCP服务器都将接收到这个消息。
       随后,网络中的DHCP服务器会回应一个DHCPOFFER消息(IP地址租用提供),由于这个时候客户端还没有网络地址,所以DHCPOFFER也是通过广播的方式发送出去的。需要注意的是,由于网络中可能存在不止一台的DHCP服务器,所以,如果不考虑网络丢包的话,客户端将接收到不止一条的DHCPOFFER消息。那么客户端会选择它接收到的第一条DHCPOFFER作为获取配置的服务器。
       然后,向该服务器发送DHCPREQUEST消息。虽然这个时候客户端已经明确知道选择的DHCP服务器的地址所在,但仍将采用广播的方式发送DHCPREQUEST消息,这样做不仅可以通知选中的服务器向客户端分配IP地址,同时也可以通知其他没有选中的DHCP服务器不需要再响应它的请求。在DHCPREQUEST消息中将包含客户端申请的IP地址。
       最后,DHCP服务器将回送DHCPACK的响应消息来通知客户端可以使用该IP地址,该确认里面包含了分配的IP地址和该地址的一个稳定期限的租约(默认是8天),并同时更新DHCP数据库。
       当租约过了一半时(即4天),客户端将和设置它的TCP/IP配置的DHCP服务器更新租约。当租约过了85.7%时,如果客户端仍然无法与当初的DHCP服务器联系上,他将与其他DHCP服务器通信,如果网络中再没有任何DHCP服务器在运行时,该客户端停止使用该IP地址,并重新发送一个DHCPDISCOVER消息,再一次重复整个过程。
       DHCP工作时要求客户机和服务器进行交互,由客户端通过广播向服务器发起申请IP地址的请求,然后由服务器分配一个IP地址以及其他的TCP/IP设置信息。DHCPACK整个工作过程如图18.3.1所示,可以分为以下步骤:
1.JPG
图18.3.1 DHCP工作过程
(1)IP地址租用申请(DHCPDISCOVER):DHCP客户机通过UDP68端口发送DHCPDISCOVER广播信息来查找DHCP服务器。网络上每一台安装了TCP/IP协议的主机都会接收到这种广播信息,但只有DHCP服务器才会做出响应。DHCP客户机发送的DHCPDISCOVER数据包的源地址是0.0.0.0,目标地址是255.255.255.255。
(2)IP地址租用提供(DHCPOFFER):当网络中的DHCP服务器接收到DHCPDISCOVER广播时,将确定是否可以用自己的数据库来为该请求提供服务。如果可以为该请求提供服务,DHCP服务器就从尚未出租的IP地址范围中选择最前面的空置IP,连同其他TCP/IP设定,通过UDP67端口以单播DHCPOFFER的形式为客户端提供信息。可能有多台DHCP服务器收到DHCPDISCOVER广播,并且向DHCP客户端响应DHCPOFFER。客户接收到的DHCPOFFER数据包中包含客户的MAC地址,后面跟着服务器能提供的IP地址、子网掩码、租约期限以及DHCP服务器的IP地址。
(3)IP地址租用选择(DHCPREQUEST):DHCP客户端通常是接收第一个收到的DHCPOFFER所提供的信息,并且会向网络发送一个DHCPREQUEST广播风暴,告诉所有DHCP服务器它将接收哪一台服务器提供的IP地址。
(4)IP地址租用确认(DHCPACK):当DHCP服务器收到DHCPREQUEST信息之后,便向DHCP客户端发送一个单播的DHCPACK信息,以确认IP租约的正式生效。然后DHCP客户端便将其TCP/IP协议与网卡绑定。
18.4 DHCP例程解析
       在本演示程序中,W7500EVB充当DHCP客户端的角色,DHCP服务器则是我们连接的路由器。现在绝大多数路由器都能够实现DHCP服务器的功能。W7500EVB发送广播封包并接收路由器的IP地址分配,完成了完整的DHCP工作过程。
       主程序初始化单片机和W7500EVB,在主循环里面则是主要运行do_dhcp()函数。main.c程序中调用了dhcp.c的DHCP执行函数。这些函数完成DHCP协议的组包及对接收到的数据包的解析。在初始化DHCP客户端的函数中,因为DHCP服务器端监听了UDP的67端口,DHCP客户端需要打开本地68端口同服务器通信。因为IP地址等网络参数由DHCP服务器分配,在进入主循环之前,初始化过程不执行set_W7500_ip()函数。除此之外,初始化函数与Network install例程基本一样,在此就不多讲解。
       主要分析DHCP执行函数do_dhcp():
[AppleScript] 纯文本查看 复制代码
1.      void do_dhcp(void)
2.      {
3.        uint8_t tmp[8];
4.        uint32_t my_dhcp_retry = 0;
5.        switch(DHCP_run())          //判断DHCP运行状态
6.        {
7.        case DHCP_IP_ASSIGN:           //首次分配IP地址状态
8.        case DHCP_IP_CHANGED:              //从DHCP服务器获取新的IP地址状态
9.            toggle = 1;
10.         if(toggle)
11.         {
12.           toggle = 0;
13.           close(SOCK_TCPS);
14.         }
15.     break;
16.     case DHCP_IP_LEASED:           //成功租赁到IP地址状态
17.         if(toggle)
18.         {
19.           set_w7500_ip();            //设置IP地址
20.           toggle = 0;
21.         } 
22.     break;
23.     case DHCP_FAILED:         //DHCP 获取失败
24.         my_dhcp_retry++;
25.         if(my_dhcp_retry > MY_MAX_DHCP_RETRY)
26.         {
27.           #if DEBUG_MODE != DEBUG_NO
28.           printf(">> DHCP %d Failed\r\n",my_dhcp_retry);
29.           #endif
30.           my_dhcp_retry = 0;
31.          DHCP_stop();                  // if restart, recall DHCP_init()
32.        }
33.    break;
34.    default:
35.    break;
36.    }
37.  }
       第5行获取DHCP的状态,其实就是通过DHCP_run函数取得W7500EVB动态获取IP过程中返回的状态值。第5行到第36行其实就是一个状态机模式,DHCP的状态分为:DHCP_IP_ASSIGN首次分配IP地址状态、DHCP_IP_CHANGED从DHCP服务器获取新的IP地址状态、DHCP_IP_LEASED成功租赁到IP地址状态、DHCP_FAILED DHCP 获取失败转态,共4个状态。通过switch语句完成对所有状态的处理。第19行将获取的IP地址通过set_w7500_ip()函数写入W7500EVB。
       DHCP_run();函数实现了W7500EVB作为DHCP客户端的详细工作过程,由于程序篇幅比较大,此处仅摘录讲解(部分程序删除,请对照源程序)。
[AppleScript] 纯文本查看 复制代码
1.      uint8_t DHCP_run(void)
2.      {
3.        uint8_t  type;
4.        uint8_t  ret;
5.        uint8_t  i;
6.        if(dhcp_state == STATE_DHCP_STOP) return DHCP_STOPPED;
7.        if(getSn_SR(DHCP_SOCKET) != SOCK_UDP)         //开启UDP模式
8.          socket(DHCP_SOCKET, Sn_MR_UDP, DHCP_CLIENT_PORT, 0x00);
9.        ret = DHCP_RUNNING;
10.     type = parseDHCPMSG();
11.     
12.     switch ( dhcp_state )
13.     {
14.       case STATE_DHCP_INIT :                              //DHCP初始化状态
15.         for (i = 0; i < 4; i++) DHCP_allocated_ip[i] = 0;
16.         send_DHCP_DISCOVER();                       //发送DISCOVER包
17.         dhcp_state = STATE_DHCP_DISCOVER;
18.         break;
19.       case STATE_DHCP_DISCOVER :                //DISCOVER状态
20.         if (type == DHCP_OFFER)
21.         {
22.           #ifdef _DHCP_DEBUG_
23.           printf("> Receive DHCP_OFFER\r\n");
24.           #endif
25.           for (i = 0; i < 4; i++)
26.           {
27.               DHCP_allocated_ip[i] = pDHCPMSG->yiaddr[i];
28.           }
29.           send_DHCP_REQUEST();
30.           dhcp_state = STATE_DHCP_REQUEST;
31.         } else ret = check_DHCP_timeout();
32.           break;
33.        
34.      case STATE_DHCP_REQUEST :                   //REQUET请求状态
35.        if (type == DHCP_ACK)                          //DHCP请求响应成功
36.        {
37.          #ifdef _DHCP_DEBUG_
38.          printf("> Receive DHCP_ACK\r\n");
39.          #endif
40.          printf("> Receive !!!\r\n");
41.          
42.          if (check_DHCP_leasedIP())                //IP地址租赁成功
43.          {
44.            // Network info assignment from DHCP
45.            dhcp_ip_assign();                      //从DHCP服务器分配IP地址
46.            reset_DHCP_timeout();                            //复位超时时间
47.            dhcp_state = STATE_DHCP_LEASED;
48.          }
49.          else
50.          {
51.            // IP address conflict occurred
52.            reset_DHCP_timeout();                            //复位超时时间
53.            dhcp_ip_conflict();                            //判断iP地址是否冲突
54.              dhcp_state = STATE_DHCP_INIT;
55.          }
56.        }
57.        else if (type == DHCP_NAK)                  //DHCP请求响应不成功
58.        {
59.          #ifdef _DHCP_DEBUG_
60.          printf("> Receive DHCP_NACK\r\n");
61.          #endif
62.          reset_DHCP_timeout();                        //复位超时时间
63.          dhcp_state = STATE_DHCP_DISCOVER;
64.        }
65.        else ret = check_DHCP_timeout();                  //判断请求是否超时
66.      break;
67.      case STATE_DHCP_LEASED :                     //IP地址租赁状态
68.        ret = DHCP_IP_LEASED;
69.        if ((dhcp_lease_time != INFINITE_LEASETIME) && ((dhcp_lease_time/2) < dhcp_tick_1s))
70.        {                 
71.          #ifdef _DHCP_DEBUG_
72.          printf("> Maintains the IP address \r\n");
73.          #endif
74.          type = 0;
75.          for (i = 0; i < 4; i++)
76.          {
77.            OLD_allocated_ip[i] = DHCP_allocated_ip[i];   //保存得到的IP地址
78.          }
79.          DHCP_XID++;
80.          send_DHCP_REQUEST();                             //发送请求
81.          reset_DHCP_timeout();
82.          dhcp_state = STATE_DHCP_REREQUEST;
83.        }
84.      break;
85.      case STATE_DHCP_REREQUEST : //重新发送请求,判断IP地址是否成功分配 87.   ret = DHCP_IP_LEASED;
88.        if (type == DHCP_ACK)                   //重传请求应答成功
89.        {
90.          dhcp_retry_count = 0;
91.          if (OLD_allocated_ip[0] != DHCP_allocated_ip[0] ||
92.              OLD_allocated_ip[1] != DHCP_allocated_ip[1] ||
93.              OLD_allocated_ip[2] != DHCP_allocated_ip[2] ||
94.              OLD_allocated_ip[3] != DHCP_allocated_ip[3])
95.          {
96.            ret = DHCP_IP_CHANGED;
97.            dhcp_ip_update();
98.            #ifdef _DHCP_DEBUG_
99.            printf(">IP changed.\r\n");
100.           #endif
101.         }
102.         #ifdef _DHCP_DEBUG_
103.         else printf(">IP is continued.\r\n");
104.         #endif                                      
105.         reset_DHCP_timeout();
106.         dhcp_state = STATE_DHCP_LEASED;
107.       }
108.       else if (type == DHCP_NAK)          //重传请求应答不成功
109.       {
110.         #ifdef _DHCP_DEBUG_
111.         printf("> Receive DHCP_NACK, Failed to maintain ip\r\n");
112.         #endif
113.         reset_DHCP_timeout();                //复位超时时间
114.         dhcp_state = STATE_DHCP_DISCOVER;
115.       } else ret = check_DHCP_timeout();
116.       break;
117.     default :
118.       break;
119.   }
120.   return ret;
121. }
       DHCP协议客户端也是一个状态机的实现,它的工作过程是这样的:W7500作为客户端初始化时,我们设定DHCP的状态为STATE_DHCP_READY,首先如果现在DHCP socket处于打开状态,我们解析获得的数据包类型,并存入变量Type中;如果现在DHCP socket处于关闭状态,我们初始化DHCP socket并开启一个端口,端口号为了方便辨识,我们命名为DHCP_CLIENT_PORT,即68,协议类型为UDP协议。之后就开始了我们的状态机模式。
       7~8行判断SOCKET如果关闭,初始化DHCP客户端,打开端口。第10行是解析DHCP服务器的应答信息。第16行就是发送DISCOVER 封包,然后客户端就跳转到STATE_DHCP_DISCOVER状态。第19行,当处于DISCOVER状态时,如果接收到Offer封包,客户端就会发送REQUEST封包,然后进入STATE_DHCP_REQUEST状态,如果没有接收到,就检查时间是否超时,跳出循环。第34行,当处于REQUEST状态时,如果接收到ACK封包,确认是不是自己的IP地址,如果确认是IP租约,就跳转到IP租约(租约时间由路由器自动分配,或设置)绑定状态,返回DHCP的IP更新的状态值,并把获得的IP地址等信息写入单片机程序的变量中,并给W7500配置。然后打印串口信息出来,我们就能看到我们所获得的信息;如果和先前的IP租约不一致或者接收到NAK封包,返回到READY状态,并返回IP地址冲突的值。这就是DHCP中一个典型的获取IP的流程。
       此外,DHCP还有对网络参数的分配的管理。也就是状态机中的“续租”处理部分。第67行,当处于绑定IP地址的状态时,如果租约时间超过一半,第77行会把现在客户端的IP地址copy到原来的IP地址处,并再次发送REQUEST封包进入STATE_DHCP_REREQUEST状态,跳出循环,相当于发出一个“续租”的请求。第86行,当处于REREQUEST状态时,我们分以下情况:当接收到ACK封包的情况下,如果IP地址与原来的不同,则IP地址更新,返回IP更新的状态值;如果相同则完成IP续租的过程,仍然使用原来的IP地址。
       至此,DHCP例程代码解析就结束了。将DHCP例程编译烧录后打印串口信息结果如图18.4.1。
2.JPG
图18.4.1 DHCP例程打印结果
    打印串口信息显示已获取IP地址,我们尝试PC机能否Ping通W7500EVB。结果如图18.4.2,成功Ping通W7500EVB,至此证明W7500EVB自动获取IP地址配置成功,已与PC机接入同一网络中。
3.JPG
图18.4.2 Ping结果



回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则




关闭

正点原子双11大促销上一条 /1 下一条

正点原子公众号

QQ|联系我们|手机版|官方淘宝店|微信公众平台|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2018-11-13 02:02

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表
/* */