单片机控制RTL8019网卡芯片实现TCP/IP协议栈是一件非常有
意思的实验。我尝试使用专门针对8位单片机设计的uIP6.0在版主
的mcu51-63K仿真器移植成功,下面介绍一下移植过程。
在KELI中创建一个uip的工程,将相关的文件加入。参考
slipdev.c,我编写RTL8019的驱动接口,在文件ethrdev.c中提
供三个函数接口:
a:void ethrdev_init() 初始化网卡芯片,使网卡进入服务状态;
b:u16_t ethrdev_read() 读新的以太数据包,如果没有新数据返回0;
c:void ethrdev_send() 发送以太数据包到网络中。
修改main.c的main()函数
/*------------------------------------------------------------------------------
-----*/
void
main(void)
{
u8_t i;
u16_t start;
uip_init();
httpd_init();
ethrdev_init();
putstr("8051 TCP/IP stack and web server running/n");
init_int();
start = 0;
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 = ethrdev_read();
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();
ethrdev_send();
}
}
/* Call the ARP timer function every 10 seconds. */
if(++numClicks == 20)
{
uip_arp_timer();
numClicks = 0;
}
}else
{
if(BUF->type == htons(UIP_ETHTYPE_IP))
{
uip_arp_ipin();
uip_len -= sizeof(struct uip_eth_hdr);
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();
slipdev_send();
}
} else if(BUF->type == htons(UIP_ETHTYPE_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)
{
ethrdev_send();
}
}
}
}
}
由于RTL8019网卡的读入数据包前4个字节不是真正的以太包数据,
在ethrdev_read()函数中要特别注意,可以先读出前18个字节,校验
成功后再将剩余的数据读出。
需要修改文件uipopt.h中UIP_LLH_LEN为14
/* UIP_LLH_LEN: The link level header length; this is the offset into
the uip_buf where the IP header can be found. For Ethernet, this
should be set to 14. For SLIP, this should be set to 0. */
#define UIP_LLH_LEN 14
同时定义字节序为BIG_ENDIAN方式
#ifndef BYTE_ORDER
#define BYTE_ORDER BIG_ENDIAN
#endif /* BYTE_ORDER */
在函数ethrdev_init()初始化RTL8019的物理地址
需要使用uIP定义的物理地址。也可以使用从网卡读出的
物理地址,但要更新uIP的结构ethaddr,否则物理地址
会判断不一致。
上述修改完毕,编译并下载到mcu51-63K仿真器中,在PC上运行
ping 192.168.0.1 -t
你会看到有回应,说明ICMP OK。然后在你的IE中输入
http://192.168.0.1/ 你可看到web网页。简直不敢令人相信,
你只需花不到几个小时就实现了在单片机上移植运行一个Web Server。
TODo:
为了方便没有RTL8019网卡的环境也能实现TCP/IP协议栈,我正
在移植SLIP部分的代码。通过SLIP协议,可以在串口线上承载IP包,
从而不需要网卡也可以实现TCP/IP协议栈。现在我需要先实现通
过I/O线模拟一个串口(mcu51-63K仿真器的串口需要用作下载),
如果那位大侠已经在实现了模拟串口功能,希望共享一份,这样可以
大大加快移植进度。