最近一段时间研究了一下以太网驱动,前前后后也花了好些时间,在这写下我的一点经验,希望对大家的开发有点帮助。
概述:既然是联网,那首先要知道的无非是四层网络协议,具体每层协议是什么,做哪些工作我就不赘述了,网上多得是这方面的介绍,还有ENC28J60这个以太网驱动芯片,同样不作解释,同理,其他人说得比我好多了,没必要再写,大多数的驱动拿过来改个接口就直接能用,简单方便。我就着重讲一下此硬件基础上移植uIP协议栈的过程和注意事项,给想学习这方面的人多一点参考。
首先要说一下:移植uIP一点也不麻烦,不要因为看到uIP中那么多的文件感觉超出了自己的驾驭能力,先告诉自己打个底,这很简单。还有一点就是:要相信这个协议栈,当得不到自己的预期结果时,可以看资料看官方文档看其他人的经验,千万不要随便修改协议内部的函数,协议栈的封装真的很好。下面进入做web客户端具体操作。
一、 前期准备:官网下载1.0源码,创建工程,在main函数外建3个文件夹,分别放uIP,ENC28J60以及web client的文件
二、做好ENC28J60的驱动,提供3个函数:enc28j60_init,enc28j60_send(len,package)和enc28j60_receive(maxlen,package);
三、取出main.c加入工程,ENC28J60文件夹中放入自己写的以太网驱动,uIP中需要放的文件有:timer.c tapdev.c uip.c uip_arp.c 及对应.h文件uip_arch.h uip_arch.h uip-conf.h uipopt.h。web client需要放入的有:resolv.c webclient.c webclient-strings.c uip_lib.c及对应.h文件
四、tapdev里函数:函数名不变以减少其他修改,这样写应该能看懂吧
void tapdev_init(void){enc28j60Init();}
unsigned int tapdev_read(void){return enc28j60PacketReceive(UIP_BUFSIZE, uip_buf);}
void tapdev_send(void){enc28j60PacketSend(uip_len, uip_buf);}
五、timer可以全删掉,用单片机的定时器中断,一个0.5秒一个10秒,替换掉主函数的这2处,没什么难度,不作解释。
else if(timer_expired(&periodic_timer)) { //0.5s是否到
timer_reset(&periodic_timer);
if(timer_expired(&arp_timer)) { //10s是否到
timer_reset(&arp_timer);
六、修改uip-conf.h文件
#define UIP_CONF_BYTE UIP_BIG_ENDIAN //单片机大端模式
#define UIP_CONF_LOGGING 0 //值改为0,功能用不着,关这个方便,不然报错
#define UIP_CONF_MAXCONNECTIONS 1 //原值为40,占空间太大,客户端为1就够了
#define UIP_CONF_MAXLISTENPORTS 0 //又不是服务器,不需要监听,0就行
#define UIP_CONF_UDP 1 //支持UDP还是需要的
七、修改uip_popt.h文件
#define UIP_FIXEDETHADDR 1 enc28j60,固定MAC地址
然后在uip.c中的代码#if UIP_FIXEDETHADDR后面添加:
#define UIP_ETHADDR0 0x44
#define UIP_ETHADDR1 0x33
#define UIP_ETHADDR2 0x4C
#define UIP_ETHADDR3 0x11
#define UIP_ETHADDR4 0x22
#define UIP_ETHADDR5 0x33
八、在main函数中,首先修改本设备信息
uip_ipaddr(ipaddr, 192,168,1,xxx);
uip_sethostaddr(ipaddr);
uip_ipaddr(ipaddr, 192,168,1,1);
uip_setdraddr(ipaddr);
uip_ipaddr(ipaddr, 255,255,255,0);
uip_setnetmask(ipaddr);
然后打开web client注释掉的部分
webclient_init();
resolv_init();
uip_ipaddr(ipaddr,192,168,1,1);
resolv_conf(ipaddr);
resolv_query("www.xxx.com");
九、修改main.c的resolv_found函数,差不多改成下面这样
void resolv_found(char *name, u16_t *ipaddr)
{
if(ipaddr != NULL)
{
webclient_get(“www.xxx.com”,80, “/xxx/xxx”);
}
}
www.xxx.com是网页服务器,80是网络端口,/xxx/xxx是网页目录
十:这个问题可能是我用的AS6.1编译器的问题,也提一下,在webclient.c里面。
关于报错:value required as increment operand
进入错误点++((char *)uip_appdata);
把这个拆分一下就行char* temp = (char *)uip_appdata;
Uip_appdata = ++temp;
到这里基本的连接就结束了,只要能进入webclient_connect()这个函数,恭喜你,联网已经OK了,数据处理找webclient_datahandler(char* data,u16_t len);完善看个人需求了,写得比较粗陋,大家将就着看吧。
再放个代码地址,感兴趣的去下吧,我加了些简单的注释http://download.youkuaiyun.com/detail/u011376744/7451509