0
本帖最后由 黑皮男 于 2016-12-12 19:31 编辑
不知不觉都试用了这么久,发到了第六弹,只可惜发的质量都不怎么样,基本都是贴代码。不管那么多了,这次是移植了LWIP,简单测试了一下ping,最长时间7ms,最短时间4ms,时间是有那么点长哈,之前在F407上外接phy的网返时间基本都是1ms,这差别是有那么点大。不管时间长短,功能是实现了。
在工程中添加lwip库,本人用的是IAR,工程目录如下。keil能用,不过还是习惯用IAR,后续打算迁移到eclipse上,毕竟keil和IAR目前用的都是破解版的,对于一个爱折腾的人来说,还是要折腾一下,毕竟之前也用过eclipse玩过java,用着还是不错的。闲话少说,网络相关的代码都在lwip这个group里。
首先是介绍初始化代码,又是粘贴party,哎,没办法。理论性的东西自己还在摸索。
- void net_init(void){
- struct ip_addr ipaddr, netmask, gw;
- UINT8_T tm;
- lwip_init();//lwip协议栈初始化
- #if LWIP_DHCP==1//是否启用DHCP功能自动获取IP,这个需要接到路由上,直接和电脑连接需要使用固定ip
- IP4_ADDR(&gw, 0, 0, 0, 0);
- IP4_ADDR(&ipaddr, 0, 0, 0, 0);
- IP4_ADDR(&netmask, 0, 0, 0, 0);
- #else
- IP4_ADDR(&gw, 192, 168, 0, 1);
- IP4_ADDR(&ipaddr, 192, 168, 0, 105);
- IP4_ADDR(&netmask, 255, 255, 255, 0);
- #endif
- netif_add(&dm_netif, &ipaddr, &netmask, &gw, NULL, ethernetif_init, ethernet_input);
- netif_set_default(&dm_netif);
- netif_set_up(&dm_netif);
- #if LWIP_DHCP==1
- dhcp_start(&dm_netif);
- tm = 50;
- while(tm!=0){
- dhcp_fine_tmr();
- delay_ms(200);
- tm--;
- }
- if(dm_netif.dhcp!=NULL&&(dm_netif.dhcp->offered_ip_addr.addr!=0)&&(dm_netif.dhcp->offered_sn_mask.addr!=0)&&(dm_netif.dhcp->offered_gw_addr.addr!=0)){
- netif_set_addr(&dm_netif, &(dm_netif.dhcp->offered_ip_addr), &(dm_netif.dhcp->offered_sn_mask), &(dm_netif.dhcp->offered_gw_addr));
- netif_set_up(&dm_netif);
- }else{
- IP4_ADDR(&gw, 192, 168, 0, 1);
- IP4_ADDR(&ipaddr, 192, 168, 0, 105);
- IP4_ADDR(&netmask, 255, 255, 255, 0);
- netif_set_addr(&dm_netif, &ipaddr, &netmask, &gw);
- netif_set_up(&dm_netif);
- }
- dhcp_stop(&dm_netif);
- #endif
- }
复制代码
接下来是网络任务函数,net_task,调用 sch_add(net_task, 0, 250)把任务添加到调度器中,250ms循环一下,这样就OK了,用命令行ping一下,大功告成。其中net_task主要是定时更新lwip相关的时钟。其代码如下
- UINT16_T arp_tmr = 5000;
- void net_task(void){
- if(sch_autodec(&arp_tmr)){//这个函数是每运行一次就回把arp_timr的值减少net_task的周期,直到为0或小于net_task的周期,并返回1;
- arp_tmr = 5000;
- etharp_tmr();
- }
- tcp_tmr();
- }
复制代码
呵呵,太陋了,是不是有点敷衍。移植lwip主要是要实现底层的接口,网卡初始化,数据包收发,都在ethernetif.c这个文件中实现。主要是处理数据包的收发。关于这几个函数的具体实现,请参看附件。移植这事很多帖子都讲烂了,这里说说自己在移植过程中的一点收获。最重要的接口移植都在ethernetif.c这个文件中,此外移植的过程中有一些小细节,就是都文件的加载。也许大神看着会觉得这个很简单,但是就是这个头文件的路径问题,在我第一次移植的过程中成了拦路虎。主要是lwip头文件包含使用了相对路径。所以包含路径时一定要包含相对路径的最顶层路径。一般都要包含以lwip为名字的文件夹所在路径。例如包含ipv4相关api的头文件,其路径如下,则应该包含$PROJ_DIR$..lwipincludeipv4.
下面是全部lwip应该包含的头文件,这里是IAR工程的路径包含。
- $PROJ_DIR$..lwipinclude
- $PROJ_DIR$..lwiparch
- $PROJ_DIR$..lwipincludeipv4
- $PROJ_DIR$..lwipapi
- $PROJ_DIR$..lwip
复制代码
工程建立相关的内存介绍完了,接下来介绍一下tcp,udp相关的应用。主要就是通过TCP和udp跟电脑之间进行数据收发。这里仅仅介绍一下tcp server,tcp client和udp基本都差不多。
tcp server需要先于tcp client建立,待server建立完成后,client才能连接server,并进行数据 通信。首先进行初始化
- void tcpserver_init(void){
- struct tcp_PCB *pcb;
- pcb = tcp_new();
- tcp_bind(pcb, IP_ADDR_ANY, 8080);//这里是8080接口,为了做webserver才设定的,其实也可以改为其他的端口号,
- pcb = tcp_listen(pcb);
- tcp_accept(pcb, tcpserver_accept);//设置建立连接时的回掉函数。作用就是当建立连接后设置接收数据回掉函数
- }
复制代码
tcpserver_accept函数内容如下
- static err_t tcpserver_accept(void *arg, struct tcp_pcb * pcb, err_t err){
- tcp_setprio(pcb, TCP_PRIO_MIN);
-
- tcp_recv(pcb, tcpserver_recv);//建立接收回掉函数
- return ERR_OK;
- }
复制代码
下面看看数据接收部分,主要就是把接收到的数据回传给客户端。
- static err_t tcpserver_recv(void *arg, struct tcp_pcb * pcb, struct pbuf *p, err_t err){
- if(p!=NULL){
- tcp_recved(pcb, p->tot_len);
- tcp_write(pcb, p->payload, p->len, 1);
- pbuf_free(p);
- }
- else if(err==ERR_OK){
- return tcp_close(pcb);
- }
- return ERR_OK;
- }
复制代码
下面是数据收发,但是有个问题,字符串中间不能有标点,现在还不知道原因,各位大神如果知道原因给点指点,但是这个我用F407解析命令时倒没有这个问题,中间有空格也没问题。
|
|