原文地址: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()函数中
- /*
- * 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);
- }
- /*-----------------------------------------------------------------------------------*/
/*
* 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(); //用户自定义处,实现功能函数中
- #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;
- }
- }
#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中
- void example0_init(void)
- {
- uip_listen(HTONS(8000));
- }
void example0_init(void)
{
uip_listen(HTONS(8000));
}
究竟如何调用自己编写的函数呢?在uipopt.h中,可以修改IP地址,MAC,默认网关。实现的用户自定义的函数
- #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 */
#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 */
- /*为了将用户的应用程序挂接到uIP中,必须将宏UIP_APPCALL()定义成实际的应用
- 程序函数名,这样每当某个uIP事件发生时,内核就会调用该应用程序进行处理*/
- #define UIP_APPCALL tcp_server_appcall//httpd_appcall
- /*
/*为了将用户的应用程序挂接到uIP中,必须将宏UIP_APPCALL()定义成实际的应用
程序函数名,这样每当某个uIP事件发生时,内核就会调用该应用程序进行处理*/
#define UIP_APPCALL tcp_server_appcall//httpd_appcall
/*
最后,如何进行测试呢:使用TCP/UDP 调试工具,上网下载的