们该干嘛呢?让我们进入第三步吧!
Step3:
诚如移植要点三所述:网络处理函数netconfig.c(与对应的netconfig.h)。主要是初始化lwip协议栈、以及做一些系统时钟中断等处理。这一句将enc28j6与lwip连接起来:netif_add(&enc28j60, &ipaddr, &netmask, &gw, NULL, ðernetif_init, ðernet_input); ethernetif_init, ethernet_input是lwip协议中neif与外设接口的函数。 这部分的函数比较固定,在此附上源码:(节选)
/****************************************************
* 函数名:LWIP_Init
* 描述:初始化LWIP协议栈,主要是把enc28j60与LWIP连接起来。 包括IP、MAC地址,接口函数 * 输入:无 * 输出 : 无
****************************************************/ void LwIP_Init(void) {
struct ip_addr ipaddr; struct ip_addr netmask; struct ip_addr gw;
/* Initializes the dynamic memory heap defined by MEM_SIZE.*/
/*内存堆的初始化函数,主要是告知内存堆的起止地址,以及初始化空闲列表, 由lwip初始化时自己调用,该接口为内部私有接口,不对用户层开放*/ mem_init();/*初始化由MEM_SIZE定义的动态内存堆*/
/*内存池的初始化,主要是为每种内存池建立链表memp_tab,其链表是逆序的, 此外,如果有统计功能使能的话,也把记录了各种内存池的数目。*/ memp_init();/*初始化由MEMP_NUM_x定义的内存池.*/ lwip_init();
IP4_ADDR(&ipaddr, 192, 168, 1, 18); IP4_ADDR(&netmask, 255, 255, 255, 0); IP4_ADDR(&gw, 192, 168, 1, 1);
/*初始化enc28j60与LWIP的接口,参数为网络接口结构体、ip地址、 子网掩码、网关、网卡信息指针、初始化函数、输入函数*/
/* 传入两个函数的指针,这样的话,函数才能访问得到这两个函数呢 */
netif_add(&enc28j60, &ipaddr, &netmask, &gw, NULL, ðernetif_init, ðernet_input);
/*把enc28j60设置为默认网卡 .*/ netif_set_default(&enc28j60);
netif_set_up(&enc28j60); //使能enc28j60接口 }
/**************************************************** * 函数名:LwIP_Periodic_Handle
* 描述:lwip协议栈要求周期调用一些函数,LwIP的周期性任务 tcp_tmr etharp_tmr dhcp_fine_tmr dhcp_coarse_tmr * 输入:无 * 输出 : 无
****************************************************/ void LwIP_Periodic_Handle(__IO uint32_t localtime) { if(localtime - INPUT_Timer >= INPUT_TMR_INTERVAL) {
/*一旦网卡接收到数据,应调用ethernetif_input函数 调用该函数让数据进入LwIP协议栈。*/ ethernetif_input(&enc28j60); //轮询是否接收到数据 }
/* TCP定时处理 every 250 ms */
if (localtime - TCPTimer >= TCP_TMR_INTERVAL) {
TCPTimer = localtime;
tcp_tmr(); //每250ms调用一次 }
/* ARP定时处理 every 5s */
if (localtime - ARPTimer >= ARP_TMR_INTERVAL) {
ARPTimer = localtime;
etharp_tmr(); //每5s调用一次 } }
Step4:
在对以上程序进行编译及移植后,其中 netif_add(&enc28j60, &ipaddr, &netmask, &gw, NULL, ðernetif_init, ðernet_input);是一条非常重要的语句。ethernetif_init,是网卡初始化函数,其由lwip协议栈已经完全编好,代码如下: err_t ethernetif_init( struct netif *netif ) {
struct ethernetif *ethernetif; ethernetif = mem_malloc( sizeof(struct ethernetif) ); if( ethernetif == NULL ) { LWIP_DEBUGF( NETIF_DEBUG, (\ return ERR_MEM; } netif->state = ethernetif; netif->name[0] = IFNAME0; netif->name[1] = IFNAME1; netif->output = etharp_output;
}
netif->linkoutput = low_level_output;
ethernetif->ethaddr = ( struct eth_addr * ) &( netif->hwaddr[0] ); low_level_init( netif );
return ERR_OK;
但以上程序不是最底层的,low_level_init、low_level_output才是底层的驱动函数,lwip只提供了一个模板,需要读者自己去完善。
/*-----------------------------------------------------------*/ static void low_level_init( struct netif *netif ) { /* set MAC hardware address length */ netif->hwaddr_len = 6; /* set MAC hardware address */ /* MAC地址 */ netif->hwaddr[0] = macaddress[0]; netif->hwaddr[1] = macaddress[1]; netif->hwaddr[2] = macaddress[2]; netif->hwaddr[3] = macaddress[3]; netif->hwaddr[4] = macaddress[4]; netif->hwaddr[5] = macaddress[5]; /* 最大传输单元 */ netif->mtu = netifMTU; netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; enc28j60Init(netif->hwaddr); //初始化enc28j60 enc28j60clkout(1); // change clkout from 6.25MHz to 12.5MHz }
/**********************************************
* low_level_output(): Should do the actual transmission of the packet. The * packet is contained in the pbuf that is passed to the function. This pbuf * might be chained.
pbuf结构为一个链表,第一个pbuf结构体中的tot_len字段代表整个以太网数据包的大小 ***********************************************/
static err_t low_level_output( struct netif *netif, struct pbuf *p ) /*底层发送数据函数*/ {
struct pbuf *q; int i = 0;
err_t xReturn = ERR_OK; /* Parameter not used. */
for(q = p; q != NULL; q = q->next) {
/* Send the data from the pbuf to the interface, one pbuf at a
time. The size of the data in each pbuf is kept in the ->len variable. */
memcpy(&Tx_Data_Buf[i], (u8_t*)q->payload, q->len); //这里的(u8_t*)q->payload仅仅是进行强制转换,没有什么特别的意思,其实也是地址 i = i + q->len; }
//注意这里是放到数组里慢慢发的 enc28j60PacketSend(i,Tx_Data_Buf); //发送数据包 return xReturn; } 结束语
好了,对以上文件进行正确编写,并配置正确的路径之后,大体上就完成了lwip的协议移植了,是不是很简单!只要细心,肯定会移植成功的!建议读者结合野火的以太网程序看!!!!
参考:STM32参考手册中文
ENC28J60中文网络芯片资料 零死角玩转STM32-V2
百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说综合文库LWIP移植说明及程序分析(2)在线全文阅读。
相关推荐: