20130408-[转]ENC28J60以太网之uIP协议

原文地址:http://blog.csdn.net/sun_rise2011/article/details/7555311

 

       广东省电子设计大赛准备的,智能家居网关,外围单片机通信数据需要使用TCP/IP通信,故采用ENC28J60模块。

       在嵌入式系统中,以太网控制器通常也是研究热点之一,MicroChip公司的ENC28J60在嵌入式系统中应用价值较高,该芯片集成了MAC控制器和PHY,使用SPI接口,适合在引脚资源比较紧张的嵌入式系统中加入以太网连接功能,本文主要介绍了MicroChip公司的ENC28J60控制器的初始化及其编程相关的注意和要点。

        uIP作为一种广泛使用的轻量级嵌入式TCP/IP协议栈,其UDP协议的实现还不够完善,目前最新的1.0版本中仅实现了UDP客户端,尚没有实现UDP服务端。为此,对其进行了以下三方面的改进:UDP服务端口的初始化;接收到UDP客户端数据包后的端口号判断及匹配;UDP服务端发送报文后目的端口的释放。

       硬件平台:STC12C60S2+ENC28J60

 

主函数main:在函数中,对于处理应用数据的用户,对 uIP 整个流程做一个了解即可,uIP 将处理后的结果全部
都回调到uip_appcall()函数统一处理,所以重点需要完成的工作全部在uip_appcall()函数中

  1. /*  
  2.  * Copyright (c) 2001-2003, Adam Dunkels.  
  3.  * All rights reserved.   
  4.  *  
  5.  * Redistribution and use in source and binary forms, with or without   
  6.  * modification, are permitted provided that the following conditions   
  7.  * are met:   
  8.  * 1. Redistributions of source code must retain the above copyright   
  9.  *    notice, this list of conditions and the following disclaimer.   
  10.  * 2. Redistributions in binary form must reproduce the above copyright   
  11.  *    notice, this list of conditions and the following disclaimer in the   
  12.  *    documentation and/or other materials provided with the distribution.   
  13.  * 3. The name of the author may not be used to endorse or promote  
  14.  *    products derived from this software without specific prior  
  15.  *    written permission.    
  16.  *  
  17.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS  
  18.  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED  
  19.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  
  20.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY  
  21.  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  
  22.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE  
  23.  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  
  24.  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
  25.  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING  
  26.  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS  
  27.  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.    
  28.  *  
  29.  * This file is part of the uIP TCP/IP stack.  
  30.  *  
  31.  * $Id: main.c,v 1.10.2.1 2003/10/04 22:54:17 adam Exp $  
  32.  *  
  33.  */  
  34. #include "uip.h"   
  35. #include "uip_arp.h"  
  36. #include "httpd.h"  
  37. //#include "telnet.h"  
  38. #include "mcu_uart.h"  
  39. #include "enc28j60.h"  
  40. #include "tcp_server.h"  
  41.   
  42. #define BUF ((struct uip_eth_hdr *)&uip_buf[0])  
  43.   
  44. #ifndef NULL  
  45. #define NULL (void *)0  
  46. #endif /* NULL */  
  47.   
  48. /*-----------------------------------------------------------------------------------*/  
  49. int  
  50. main(void)  
  51. {  
  52.     idata u8_t i, arptimer;  
  53.     idata u16_t j;  
  54.     init_uart();   //串口初始化  
  55.     printu("starting......\r\n");  
  56.     /* Initialize the device driver. */   
  57.     dev_init();    //网卡初始化  
  58.     uip_arp_init(); //ARP初始化  
  59.     /* Initialize the uIP TCP/IP stack. */  
  60.     uip_init();   //uIP协议初始化  
  61.     printu("uip\r\n");  
  62.     /* Initialize the HTTP server. */  
  63. //  httpd_init();  
  64.     tcp_server_init(); //用户自定义处,实现功能函数  
  65.       
  66.     arptimer = 0;  //ARP缓存表更新定时器  
  67.     printu("ok\r\n");  
  68.   while(1) {  
  69.     /* Let the tapdev network device driver read an entire IP packet  
  70.        into the uip_buf. If it must wait for more than 0.5 seconds, it  
  71.        will return with the return value 0. If so, we know that it is  
  72.        time to call upon the uip_periodic(). Otherwise, the tapdev has  
  73.        received an IP packet that is to be processed by uIP. */  
  74.     uip_len = dev_poll();  //查询网卡是否有包收到  
  75.     for(j=0;j<500;j++);     //延时,避免服务端应答过慢,造成不必要重发包  
  76. /*  
  77.     if(uip_len > 0)  
  78.     {  
  79.         printuf("--------------- uip_len = 0x%x", uip_len);  
  80.         printuf("%x ----------\r\n", uip_len);  
  81.         for(i=0;i<uip_len;i++)  
  82.         {  
  83.             printuf("%x ", uip_buf[i]);  
  84.             if((i+1)%16==0) printu("\r\n");           
  85.         }  
  86.         printu("\r\n");           
  87.     }  
  88. */  
  89.     if(uip_len == 0) {  
  90.       for(i = 0; i < UIP_CONNS; i++) {   //协议栈解析,组包,状态监测等  
  91.     uip_periodic(i);  
  92.     /* If the above function invocation resulted in data that  
  93.        should be sent out on the network, the global variable  
  94.        uip_len is set to a value > 0. */  
  95.     if(uip_len > 0) {  
  96.       uip_arp_out();            //有包需要发送  
  97.       dev_send();  
  98.     }  
  99.       }  
  100.   
  101. #if UIP_UDP  
  102.       for(i = 0; i < UIP_UDP_CONNS; i++) {  
  103.     uip_udp_periodic(i);  
  104.     /* If the above function invocation resulted in data that  
  105.        should be sent out on the network, the global variable  
  106.        uip_len is set to a value > 0. */  
  107.     if(uip_len > 0) {  
  108.       uip_arp_out();  
  109.       dev_send();  
  110.     }  
  111.       }  
  112. #endif /* UIP_UDP */  
  113.         
  114.       /* Call the ARP timer function every 10 seconds. */  
  115.       if(++arptimer == 20) {      
  116.     uip_arp_timer();       //更新ARP缓存  
  117.     arptimer = 0;  
  118.       }  
  119.         
  120.     } else {        //有包    处理IP包  
  121.       if(BUF->type == htons(UIP_ETHTYPE_IP)) {  
  122.     uip_arp_ipin();  
  123.     uip_input();  
  124.     /* If the above function invocation resulted in data that  
  125.        should be sent out on the network, the global variable  
  126.        uip_len is set to a value > 0. */  
  127.     if(uip_len > 0) {  
  128.       uip_arp_out();  
  129.       dev_send();  
  130.     }  
  131.       } else if(BUF->type == htons(UIP_ETHTYPE_ARP)) {       //处理ARP  
  132.     uip_arp_arpin();  
  133.     /* If the above function invocation resulted in data that  
  134.        should be sent out on the network, the global variable  
  135.        uip_len is set to a value > 0. */   
  136.     if(uip_len > 0) {      
  137.       dev_send();  
  138.     }  
  139.       }  
  140.     }  
  141.       
  142.   }  
  143.   return 0;  
  144. }  
  145. /*-----------------------------------------------------------------------------------*/  
  146. void  
  147. uip_log(char *m)  
  148. {  
  149. //  printf("uIP log message: %s\n", m);  
  150. }  
  151. /*-----------------------------------------------------------------------------------*/  
/*
 * Copyright (c) 2001-2003, Adam Dunkels.
 * All rights reserved. 
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions 
 * are met: 
 * 1. Redistributions of source code must retain the above copyright 
 *    notice, this list of conditions and the following disclaimer. 
 * 2. Redistributions in binary form must reproduce the above copyright 
 *    notice, this list of conditions and the following disclaimer in the 
 *    documentation and/or other materials provided with the distribution. 
 * 3. The name of the author may not be used to endorse or promote
 *    products derived from this software without specific prior
 *    written permission.  
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
 *
 * This file is part of the uIP TCP/IP stack.
 *
 * $Id: main.c,v 1.10.2.1 2003/10/04 22:54:17 adam Exp $
 *
 */
#include "uip.h" 
#include "uip_arp.h"
#include "httpd.h"
//#include "telnet.h"
#include "mcu_uart.h"
#include "enc28j60.h"
#include "tcp_server.h"

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

#ifndef NULL
#define NULL (void *)0
#endif /* NULL */

/*-----------------------------------------------------------------------------------*/
int
main(void)
{
	idata u8_t i, arptimer;
	idata u16_t j;
	init_uart();   //串口初始化
	printu("starting......\r\n");
	/* Initialize the device driver. */ 
	dev_init();	   //网卡初始化
	uip_arp_init();	//ARP初始化
	/* Initialize the uIP TCP/IP stack. */
	uip_init();	  //uIP协议初始化
	printu("uip\r\n");
	/* Initialize the HTTP server. */
//	httpd_init();
	tcp_server_init(); //用户自定义处,实现功能函数
	
	arptimer = 0;  //ARP缓存表更新定时器
	printu("ok\r\n");
  while(1) {
    /* Let the tapdev network device driver read an entire IP packet
       into the uip_buf. If it must wait for more than 0.5 seconds, it
       will return with the return value 0. If so, we know that it is
       time to call upon the uip_periodic(). Otherwise, the tapdev has
       received an IP packet that is to be processed by uIP. */
    uip_len = dev_poll();  //查询网卡是否有包收到
	for(j=0;j<500;j++);	   //延时,避免服务端应答过慢,造成不必要重发包
/*
	if(uip_len > 0)
	{
		printuf("--------------- uip_len = 0x%x", uip_len);
		printuf("%x ----------\r\n", uip_len);
		for(i=0;i<uip_len;i++)
		{
			printuf("%x ", uip_buf[i]);
			if((i+1)%16==0) printu("\r\n");			
		}
		printu("\r\n");			
	}
*/
    if(uip_len == 0) {
      for(i = 0; i < UIP_CONNS; i++) {	//协议栈解析,组包,状态监测等
	uip_periodic(i);
	/* If the above function invocation resulted in data that
	   should be sent out on the network, the global variable
	   uip_len is set to a value > 0. */
	if(uip_len > 0) {
	  uip_arp_out();			//有包需要发送
	  dev_send();
	}
      }

#if UIP_UDP
      for(i = 0; i < UIP_UDP_CONNS; i++) {
	uip_udp_periodic(i);
	/* If the above function invocation resulted in data that
	   should be sent out on the network, the global variable
	   uip_len is set to a value > 0. */
	if(uip_len > 0) {
	  uip_arp_out();
	  dev_send();
	}
      }
#endif /* UIP_UDP */
      
      /* Call the ARP timer function every 10 seconds. */
      if(++arptimer == 20) {	
	uip_arp_timer();	   //更新ARP缓存
	arptimer = 0;
      }
      
    } else {		//有包    处理IP包
      if(BUF->type == htons(UIP_ETHTYPE_IP)) {
	uip_arp_ipin();
	uip_input();
	/* If the above function invocation resulted in data that
	   should be sent out on the network, the global variable
	   uip_len is set to a value > 0. */
	if(uip_len > 0) {
	  uip_arp_out();
	  dev_send();
	}
      } else if(BUF->type == htons(UIP_ETHTYPE_ARP)) {		//处理ARP
	uip_arp_arpin();
	/* If the above function invocation resulted in data that
	   should be sent out on the network, the global variable
	   uip_len is set to a value > 0. */	
	if(uip_len > 0) {	
	  dev_send();
	}
      }
    }
    
  }
  return 0;
}
/*-----------------------------------------------------------------------------------*/
void
uip_log(char *m)
{
//  printf("uIP log message: %s\n", m);
}
/*-----------------------------------------------------------------------------------*/


在tcp_server_init(); //用户自定义处,实现功能函数中

  1. #include "example0.h"  
  2. #include "example1.h"  
  3. #include "tcp_server.h"  
  4. //#include "httpd.h"  
  5. #include "uip.h"  
  6. #include "mcu_uart.h"  
  7.   
  8.   
  9. void tcp_server_init(void)  //在应用程序函数中,依靠uIP事件检测函数来决定处理的方法,  
  10.                             //另外可以通过判断当前连接的端口号来区分处理不同的连接。  
  11. {  
  12.     httpd_init();  
  13.     example0_init();   //用户自定义函数,实现某些功能的,主要监听端口  
  14.     example1_init();   //  
  15. }  
  16.   
  17. void tcp_server_appcall(void)   
  18. {  
  19.     switch(uip_conn->lport)   
  20.     {  
  21.         case HTONS(80):  
  22.             httpd_appcall();break;  
  23.         case HTONS(8000):  
  24.             example0_app();break;  
  25.         case HTONS(8001):  
  26.             example1_app();break;  
  27.     }  
  28. }  
  29.                    
#include "example0.h"
#include "example1.h"
#include "tcp_server.h"
//#include "httpd.h"
#include "uip.h"
#include "mcu_uart.h"


void tcp_server_init(void) 	//在应用程序函数中,依靠uIP事件检测函数来决定处理的方法,
							//另外可以通过判断当前连接的端口号来区分处理不同的连接。
{
	httpd_init();
	example0_init();   //用户自定义函数,实现某些功能的,主要监听端口
	example1_init();   //
}

void tcp_server_appcall(void) 
{
	switch(uip_conn->lport) 
	{
		case HTONS(80):
			httpd_appcall();break;
		case HTONS(8000):
			example0_app();break;
		case HTONS(8001):
			example1_app();break;
	}
}
				 


如example0_init中

  1. void example0_init(void)   
  2. {  
  3.     uip_listen(HTONS(8000));  
  4. }  
void example0_init(void) 
{
	uip_listen(HTONS(8000));
}


 

究竟如何调用自己编写的函数呢?在uipopt.h中,可以修改IP地址,MAC,默认网关。实现的用户自定义的函数

 

  1. #define UIP_PINGADDRCONF 0  
  2.   
  3. #define UIP_IPADDR0     192 /**< The first octet of the IP address of  
  4.                    this uIP node, if UIP_FIXEDADDR is  
  5.                    1. \hideinitializer */  
  6. #define UIP_IPADDR1     168 /**< The second octet of the IP address of  
  7.                    this uIP node, if UIP_FIXEDADDR is  
  8.                    1. \hideinitializer */  
  9. #define UIP_IPADDR2     0   /**< The third octet of the IP address of  
  10.                    this uIP node, if UIP_FIXEDADDR is  
  11.                    1. \hideinitializer */  
  12. #define UIP_IPADDR3     44  /**< The fourth octet of the IP address of  
  13.                    this uIP node, if UIP_FIXEDADDR is  
  14.                    1. \hideinitializer */  
  15.   
  16. #define UIP_NETMASK0    255 /**< The first octet of the netmask of  
  17.                    this uIP node, if UIP_FIXEDADDR is  
  18.                    1. \hideinitializer */  
  19. #define UIP_NETMASK1    255 /**< The second octet of the netmask of  
  20.                    this uIP node, if UIP_FIXEDADDR is  
  21.                    1. \hideinitializer */  
  22. #define UIP_NETMASK2    255 /**< The third octet of the netmask of  
  23.                    this uIP node, if UIP_FIXEDADDR is  
  24.                    1. \hideinitializer */  
  25. #define UIP_NETMASK3    0   /**< The fourth octet of the netmask of  
  26.                    this uIP node, if UIP_FIXEDADDR is  
  27.                    1. \hideinitializer */  
  28.   
  29. #define UIP_DRIPADDR0   192 /**< The first octet of the IP address of  
  30.                    the default router, if UIP_FIXEDADDR is  
  31.                    1. \hideinitializer */  
  32. #define UIP_DRIPADDR1   168 /**< The second octet of the IP address of  
  33.                    the default router, if UIP_FIXEDADDR is  
  34.                    1. \hideinitializer */  
  35. #define UIP_DRIPADDR2   0   /**< The third octet of the IP address of  
  36.                    the default router, if UIP_FIXEDADDR is  
  37.                    1. \hideinitializer */  
  38. #define UIP_DRIPADDR3   1   /**< The fourth octet of the IP address of  
  39.                    the default router, if UIP_FIXEDADDR is  
  40.                    1. \hideinitializer */  
  41.   
  42. /**  
  43.  * Specifies if the uIP ARP module should be compiled with a fixed  
  44.  * Ethernet MAC address or not.  
  45.  *  
  46.  * If this configuration option is 0, the macro uip_setethaddr() can  
  47.  * be used to specify the Ethernet address at run-time.  
  48.  *  
  49.  * \hideinitializer  
  50.  */  
  51. #define UIP_FIXEDETHADDR 1  
  52.   
  53. #define UIP_ETHADDR0    0x12  /**< The first octet of the Ethernet  
  54.                  address if UIP_FIXEDETHADDR is  
  55.                  1. \hideinitializer */  
  56. #define UIP_ETHADDR1    0x34  /**< The second octet of the Ethernet  
  57.                  address if UIP_FIXEDETHADDR is  
  58.                  1. \hideinitializer */  
  59. #define UIP_ETHADDR2    0x56  /**< The third octet of the Ethernet  
  60.                  address if UIP_FIXEDETHADDR is  
  61.                  1. \hideinitializer */  
  62. #define UIP_ETHADDR3    0x78  /**< The fourth octet of the Ethernet  
  63.                  address if UIP_FIXEDETHADDR is  
  64.                  1. \hideinitializer */  
  65. #define UIP_ETHADDR4    0x90  /**< The fifth octet of the Ethernet  
  66.                  address if UIP_FIXEDETHADDR is  
  67.                  1. \hideinitializer */  
  68. #define UIP_ETHADDR5    0xAB  /**< The sixth octet of the Ethernet  
  69.                  address if UIP_FIXEDETHADDR is  
  70.                  1. \hideinitializer */  
#define UIP_PINGADDRCONF 0

#define UIP_IPADDR0     192 /**< The first octet of the IP address of
			       this uIP node, if UIP_FIXEDADDR is
			       1. \hideinitializer */
#define UIP_IPADDR1     168 /**< The second octet of the IP address of
			       this uIP node, if UIP_FIXEDADDR is
			       1. \hideinitializer */
#define UIP_IPADDR2     0   /**< The third octet of the IP address of
			       this uIP node, if UIP_FIXEDADDR is
			       1. \hideinitializer */
#define UIP_IPADDR3     44  /**< The fourth octet of the IP address of
			       this uIP node, if UIP_FIXEDADDR is
			       1. \hideinitializer */

#define UIP_NETMASK0    255 /**< The first octet of the netmask of
			       this uIP node, if UIP_FIXEDADDR is
			       1. \hideinitializer */
#define UIP_NETMASK1    255 /**< The second octet of the netmask of
			       this uIP node, if UIP_FIXEDADDR is
			       1. \hideinitializer */
#define UIP_NETMASK2    255 /**< The third octet of the netmask of
			       this uIP node, if UIP_FIXEDADDR is
			       1. \hideinitializer */
#define UIP_NETMASK3    0   /**< The fourth octet of the netmask of
			       this uIP node, if UIP_FIXEDADDR is
			       1. \hideinitializer */

#define UIP_DRIPADDR0   192 /**< The first octet of the IP address of
			       the default router, if UIP_FIXEDADDR is
			       1. \hideinitializer */
#define UIP_DRIPADDR1   168 /**< The second octet of the IP address of
			       the default router, if UIP_FIXEDADDR is
			       1. \hideinitializer */
#define UIP_DRIPADDR2   0   /**< The third octet of the IP address of
			       the default router, if UIP_FIXEDADDR is
			       1. \hideinitializer */
#define UIP_DRIPADDR3   1   /**< The fourth octet of the IP address of
			       the default router, if UIP_FIXEDADDR is
			       1. \hideinitializer */

/**
 * Specifies if the uIP ARP module should be compiled with a fixed
 * Ethernet MAC address or not.
 *
 * If this configuration option is 0, the macro uip_setethaddr() can
 * be used to specify the Ethernet address at run-time.
 *
 * \hideinitializer
 */
#define UIP_FIXEDETHADDR 1

#define UIP_ETHADDR0    0x12  /**< The first octet of the Ethernet
				 address if UIP_FIXEDETHADDR is
				 1. \hideinitializer */
#define UIP_ETHADDR1    0x34  /**< The second octet of the Ethernet
				 address if UIP_FIXEDETHADDR is
				 1. \hideinitializer */
#define UIP_ETHADDR2    0x56  /**< The third octet of the Ethernet
				 address if UIP_FIXEDETHADDR is
				 1. \hideinitializer */
#define UIP_ETHADDR3    0x78  /**< The fourth octet of the Ethernet
				 address if UIP_FIXEDETHADDR is
				 1. \hideinitializer */
#define UIP_ETHADDR4    0x90  /**< The fifth octet of the Ethernet
				 address if UIP_FIXEDETHADDR is
				 1. \hideinitializer */
#define UIP_ETHADDR5    0xAB  /**< The sixth octet of the Ethernet
				 address if UIP_FIXEDETHADDR is
				 1. \hideinitializer */
  1. /*为了将用户的应用程序挂接到uIP中,必须将宏UIP_APPCALL()定义成实际的应用  
  2.   程序函数名,这样每当某个uIP事件发生时,内核就会调用该应用程序进行处理*/  
  3. #define UIP_APPCALL     tcp_server_appcall//httpd_appcall  
  4. /*  
/*为了将用户的应用程序挂接到uIP中,必须将宏UIP_APPCALL()定义成实际的应用
  程序函数名,这样每当某个uIP事件发生时,内核就会调用该应用程序进行处理*/
#define UIP_APPCALL     tcp_server_appcall//httpd_appcall
/*


最后,如何进行测试呢:使用TCP/UDP 调试工具,上网下载的


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值