STM32移植uIP

STM32移植uIP文件说明 这是 uIP1 0 源码文件 apps 是作者写好的应用程序 demo doc 是一些文档 lib 里面只有一个文件是内存申请与释放函数的接口 uip 是 tcp ip 的协议栈了 unix 是与外部的接口 我们移植也主要去改这些文件 说一下一眼看不出作用的文件 lc h lc addrlabels h lc switch h psock c ps

文件说明:



STM32移植uIP



STM32移植uIP

  • 这是uIP1.0源码文件,apps是作者写好的应用程序demo,doc是一些文档,lib里面只有一个文件是内存申请与释放函数的接口,uip是tcp/ip的协议栈了,unix是与外部的接口,我们移植也主要去改这些文件。
STM32移植uIP



STM32移植uIP

  • 说一下一眼看不出作用的文件。lc.h、lc-addrlabels.h、lc-switch.h、psock.c、psock.h和pt.h这些是一个模拟线程的轻量级库protothreads。uip_arp.c地址解析协议的接口。uip-fw.c是多重网络转发数据包的借口(没用到)。uiplib.c里只有一个函数uiplib_ipaddrconv:把ip地址转换成字符格式(没用到)。uip-neighbor.c可能是存储网络上一下ip与mac(网络邻居?没用到)。uip-split.c拆包发送的借口,tcp/ip协议规定包的长度不能超过1500个字节,否则需要拆包发送(没用到)。
STM32移植uIP



STM32移植uIP

  • clock-arch.c里面只有一个函数clock_time。main函数自己重写吧。tapdev.c是与硬件网络模块的接口。uip-conf.h是一些配置。
  • 为什么我觉得uip比RL_TCPnet移植更麻烦?就是因为uip的文件关系有点乱,而且一些数据类型需要重定义,甚至还需要改动库文件里的,可能RL_TCPnet是因为Keil公司专门写了用于M3内核的库才没有这么些问题吧。下面是简单的头文件包含关系,在移植的时候需要注意。
STM32移植uIP



STM32移植uIP





移植:

  • 因为只做udp、tcp(客户端与服务器)和http,所以添加这些文件就够了。工程结构如下图。uip_user.c是自己写的应用函数。
STM32移植uIP



STM32移植uIP
  • 我用的网络模块是enc28j60。网络上有很多该模块的驱动,只要改一下spi管脚配置就行。
  • tapdev.c就是uip与硬件的接口函数了。具体见下。
void tapdev_init(unsigned char *my_mac) { int i; /*初始化 enc28j60*/ enc28j60Init(my_mac); for (i = 0; i < 6; i++) { uip_ethaddr.addr[i] = my_mac[i]; } } /*---------------------------------------------------------------------------*/ / * 名 称:uint16_t tapdev_read(void) * 功 能: * 入口参数:读取一包数据 * 出口参数: 如果一个数据包收到返回数据包长度,以字节为单位,否则为零。 * 说 明: * 调用方法: / unsigned int tapdev_read(void) { return enc28j60PacketReceive(1500,uip_buf); } / * 名 称:void tapdev_send(void) * 功 能: * 入口参数:发送一包数据 * 出口参数: * 说 明: * 调用方法: / void tapdev_send(void) { enc28j60PacketSend(uip_len,uip_buf); }





  • uip-conf.h是配置文件,关闭日志输出:#define UIP_CONF_LOGGING         0。打开udp连接:#define UIP_CONF_UDP             1。只留下#include webserver.h(里面有个http回调函数,不过最好在之前自己写回调函数,因为还要做tcp的其他连接)。ps.实际的配置文件是uipopth.h,不过那里面的一般不用改。
/* 定义应用程序回调函数 */ #ifndef UIP_APPCALL #define UIP_APPCALL tcp_appcall #endif #define UIP_UDP_APPCALL udp_appcall //uip-tcp的总回调函数 void tcp_appcall(void) { if(uip_conn->lport == HTONS(80)) { httpd_appcall();//指向了http.c的httpd_appcall()回调函数。 } if(uip_conn->lport == HTONS(LocalPort)) { tcp_server_appcall(); } if(uip_conn->rport == HTONS(RemotePort)) { tcp_client_appcall(); } }





  • clock-arch.h中只有一个函数clock_time()。uip这个协议栈需要时间轮询函数,在clock-arch.h中定义#define CLOCK_CONF_SECOND 100,也就是100毫秒。由于我是用的ucos-ii,所以就写在系统时间钩子函数(在os_cpu_c.c里),如果没有用的话,也只需要另开一个定时器就可以了。
volatile INT32U uIP_time = 0; #if (OS_CPU_HOOKS_EN > 0) && (OS_TIME_TICK_HOOK_EN > 0) void OSTimeTickHook (void) { #if OS_APP_HOOKS_EN > 0 App_TimeTickHook(); #endif static INT8U s_count = 0; if (++s_count >= 10) { s_count = 0; uIP_time++; /* 全局运行时间每10ms增1 */ if (uIP_time == 0x) { uIP_time = 0; } } #if OS_TMR_EN > 0 OSTmrCtr++; if (OSTmrCtr >= (OS_TICKS_PER_SEC / OS_TMR_CFG_TICKS_PER_SEC)) { OSTmrCtr = 0; OSTmrSignal(); } #endif } #endif





  • uip_user.c是自己写的一些应用函数
extern u16 LocalPort; //本地端口 extern u16 RemotePort; //远端端口 extern u8 RemoteIP[4]; //远端ip extern u8 enc_send_buf[256]; //发送数据最大字节256 extern u8 enc_send_size; //需要发送的字节数 void Net_Init(void); //网络初始化 void Udp_Init(void); //udp初始化 void Tcp_Init(void); //tcp初始化 void tcp_appcall(void); //tcp总回调函数 void udp_appcall(void); //udp总回调函数 void Uip_Proc(void); //uip的处理函数(需要循环调用) void tcp_server_appcall(void); //tcp作为服务器时的回调函数 void tcp_client_appcall(void); //tcp作为客户端时的回调函数 void tcp_newdata(void); //tcp接收函数 void tcp_senddata(void); //tcp发送函数 void udp_newdata(void); //udp接收函数 void udp_senddata(void); //udp发送函数





  • 到此,uip的移植基本上差不多了。只需要再修改一些小错误:比如,数据类型的重定义,删除一些打印函数,tcp_udp_appstate_t(用户自定义类型)的重定义在http.c里面有了,如果不需要用到作者的一些应用函数可以直接定义成int,同样uip_udp_appstate_t(用户自定义类型)也可以直接定义为int,当然也可以定义成数组,把数据的指针和长度放里面。
  • pt.h中115行中把PT_YIELD_FLAG定义为volatile可变的,可以减少好的警告信息。
  • psock.c中164行,添加一行uip_flags &= ~UIP_ACKDATA。还有一个udp连接bug在uip.c里,具体可见奋斗板。
static char data_acked(register struct psock *s) { if(s->state == STATE_DATA_SENT && uip_acked()) { uip_flags &= ~UIP_ACKDATA; if(s->sendlen > uip_mss()) { s->sendlen -= uip_mss(); s->sendptr += uip_mss(); } else { s->sendptr += s->sendlen; s->sendlen = 0; } s->state = STATE_ACKED; return 1; } return 0; }



应用:



  • uip初始化要设置网络基本信息和轮询时间。
void Net_Init(void) { uip_ipaddr_t ipaddr; unsigned char mymac[6] = {0x04, 0x02, 0x35, 0x00, 0x00, 0x01}; //MAC地址 tapdev_init(mymac); //ENC28J60初始化 uip_init(); //UIP协议栈初始化 uip_ipaddr(ipaddr, 172, 72, 100, 212); //设置IP地址 uip_sethostaddr(ipaddr); uip_ipaddr(ipaddr, 172, 72, 101, 1); //设置默认路由器IP地址 uip_setdraddr(ipaddr); uip_ipaddr(ipaddr, 255, 255, 252, 0); //设置网络掩码 uip_setnetmask(ipaddr); timer_set(&periodic_timer, CLOCK_SECOND / 2); timer_set(&arp_timer, CLOCK_SECOND * 10); //设置轮询时间 }

  • udp的初始化连接注意一下绑定本地ip。tcp服务器端只需要监听某个端口(80是http服务端口)。tcp客户端需要建立连接。
//建立UDP连接初始化* void Udp_Init(void) { uip_ipaddr_t ipaddr;//定义IP类型变量 uip_ipaddr(ipaddr, RemoteIP[0], RemoteIP[1], RemoteIP[2], RemoteIP[3]); //远端IP if(my_udp_conn != NULL) { uip_udp_remove(my_udp_conn);//如果连接已经建立,则删除之 } my_udp_conn = uip_udp_new(&ipaddr, HTONS(RemotePort));//建立到远程端口 if(my_udp_conn != NULL) { uip_udp_bind(my_udp_conn, HTONS(LocalPort));//绑定本地端口 } } //作为tcp客户端初始化 void Tcp_Init(void) { uip_ipaddr_t ipaddr;//定义IP类型变量 uip_ipaddr(ipaddr, RemoteIP[0], RemoteIP[1], RemoteIP[2], RemoteIP[3]); //远程IP my_tcp_conn = uip_connect(&ipaddr, HTONS(RemotePort));//建立到远程端口 }

  • 还有一个问题是:作为tcp客户端的时候,pc机使用网络调试助手,如果在连接后再点断开的话就重连不上。 PC机断开连接后,那个端口先是timeout然后应该就删除了,断开后会进入2次uip_closed(),所以判断一下重新连接(会分配新的端口)。如果在程序运行开始但是PC机并没有打开连接的话,会一直进入uip_aborted(),在里面设置重新连接,这样会直到PC机打开。
 if(uip_closed()) { tcp_server_flag++; if(tcp_server_flag == 2) { uip_ipaddr_t ipaddr;//定义IP类型变量 uip_ipaddr(ipaddr, RemoteIP[0], RemoteIP[1], RemoteIP[2], RemoteIP[3]); //远程IP my_tcp_conn = uip_connect(&ipaddr, HTONS(RemotePort));//建立到远程端口 tcp_server_flag = 0; } } if( uip_aborted()) { uip_ipaddr_t ipaddr;//定义IP类型变量 uip_ipaddr(ipaddr, RemoteIP[0], RemoteIP[1], RemoteIP[2], RemoteIP[3]); //远程IP my_tcp_conn = uip_connect(&ipaddr, HTONS(RemotePort)); //建立到远程端口 }
  • 有关http的应用请见下一篇。ps.uip1.0的smtp好像不完整,请参照0.9版。


下载:


  • uip1.0英文使用指南下载,请点击。
  • stm32移植uip1.0工程源码下载,请点击。如果使用HG 只要clone https:///zouw96/uip_http





版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/178308.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月26日 下午5:34
下一篇 2026年3月26日 下午5:34


相关推荐

  • C++标准输入输出流_seekg函数详解

    C++标准输入输出流_seekg函数详解对文件输入输出流的操作函数主要有1/seekg()和tellg() //对输入流的操作(也就是读)2/seekp()和tellp() //对输出流的操作(也就是写) 1.seekg()是对输入文件定位,它有两个参数:第一个参数是偏移量,第二个参数是基地址。对于第一个参数,可以是正负数值,正的表示向后偏移,负的表示向前偏移。而第二个参数可以是:   ios::beg

    2022年5月24日
    54
  • var let和const的区别_JavaScript let

    var let和const的区别_JavaScript let1.let命令基本语法ES6新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。{leta=1varb=2console

    2022年7月31日
    9
  • 说明子网和子网掩码的概念_子网掩码和子网地址

    说明子网和子网掩码的概念_子网掩码和子网地址一个IP(v4)地址如:210.52.207.2,是一个4字节(共32bit)的数字,被分为4段,每段8位,段与段之间用‘.’分隔。每段所能表示的十进制数最大不超过255。IP

    2022年8月1日
    9
  • JS截取字符串 3种方法

    JS截取字符串 3种方法1 String 定义了 3 个字符串截取的原型方法 String 类型的截取字符串方法字符串方法说明 slice 抽取一个子串 substring 返回字符串的一个子串 substr 抽取一个子串 1 1 截取指定长度字符串 substr 方法能够根据指定长度来截取子字符串 它包含两个参数 第一个参数表示准备截取的子字符串起始下标 第二个参数表示截取的长度 示例 1 在下面示例中使用 lastIndexOf 获取字符串的最后一个点号的下标位

    2026年3月18日
    2
  • rabbitMQ-kafka+mq作用目的

    rabbitMQ-kafka+mq作用目的目录 rocketMq 架构 mq 作用消息幂等性判断 mq 消息积压 mq 消息过期 rabbitMq 优点缺点消息重复消费丢失数据 1 生产者丢数据 rabbitMqkafk mq 丢数据 rabbitMqkafk 消费者丢数据 rabbitMqKafk 顺序消费 rabbitMqkafk 架构 NameServer 是一个几乎无状态节点 可集群部署 在消息队列 RocketMQ 版中提供命名服务

    2025年8月5日
    6
  • nmap命令的详解

    nmap命令的详解使用-sP参数对对应主机段的主机发送ICMP报文,可以查询到哪些主机是存活的。[root@localhost~]#nmap-sP192.168.8.0/24StartingNmap6.40(http://nmap.org)at2018-07-1014:32CSTNmapscanreportfor192.168.8.0Hostisup(0….

    2022年5月8日
    51

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号