uip学习记录.docx
《uip学习记录.docx》由会员分享,可在线阅读,更多相关《uip学习记录.docx(16页珍藏版)》请在冰豆网上搜索。
![uip学习记录.docx](https://file1.bdocx.com/fileroot1/2023-1/8/a17b6f7b-2527-415e-a4ff-54086cbdd14a/a17b6f7b-2527-415e-a4ff-54086cbdd14a1.gif)
uip学习记录
1.要知道uip是TCP/IP协议族一种简化并实现的协议栈。
实现TCP/IP协议有uip还有lwip,这两种是比较常用的协议栈,在嵌入式应用中发挥了作用。
2.uip可以作为webclient向指定的网站提交数据,也可以作为一个webserver作为网页服务器,提供一个小型的动态页面访问功能。
3.uip用到的rom有6kb,而ram只有几百字节,相对于lwip更适合于非操作系统的单片机。
Uip的文件架构
学习uip需要知道uip协议里到底都有那些东东?
1uip_app;uip_lib,uip本身核心代码,uip底层驱动与以太网控制器模块有关,
Uip_app是uip的一些应用示例程序smtp,rsolve,dhcp,telnetd,以及webclient。
Lib里边是memb.c是分配内存的文件。
Uip里边有uip.ctimer.c因为要为TCP和ARP提供定时器服务,比如心跳包,刷新老化程序需要有定时器的配置。
如果使用ENC28U60,还需要ENC28U60.H
Uip的数据通过网卡Enc28j60从物理层剥离,所以需要先配置Uip和Enc28j60的数据交互。
这个部分在tapdev.c文件中:
tapdev_init():
网卡初始化函数,初始化网卡的工作模式。
tapdev_read(void):
读包函数。
将网卡收到的数据放入全局缓存区uip_buf中,返回包的长度,赋给uip_len。
voidtapdev_send(void):
发包函数。
将全局缓存区uip_buf里的数据(长度放在uip_len中)发送出去。
在uip1.0中,clock_archo。
C是用来管理时钟的。
├─appsapps目录下为uip提供的一些应用示例
│├─dhcpc
│├─hello-world
│├─resolv
│├─smtp
│├─telnetd
│├─webclient
│└─webserver
||___tcpclient
||___tcpcserver
│└─httpd-fs
├─docdoc下放置的为说明文档,程序中用不上
│└─html
├─liblib下为内存块管理函数源码
├─uipuip下为uip和核心实现源码
└─unixunix环境里的uip应用例子,可以参照这个例子实现应用
2
3
4
5
6
7
8
9
10
11
#include"clock-arch.h"
#include"stm32f10x.h"
extern__IOint32_tg_RunTime;
/*---------------------------------------------------------------------------*/
clock_time_t
clock_time(void)
{
returng_RunTime;
}
/*---------------------------------------------------------------------------*/
使用stm32滴答定时器中断代码:
User/stm32f10x_it.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
__IOint32_tg_RunTime=0;
voidSysTick_Handler(void)
{
staticuint8_ts_count=0;
if(++s_count>=10)
{
s_count=0;
g_RunTime++;/*全局运行时间每10ms增1*/
if(g_RunTime==0x80000000)
{
g_RunTime=0;
}
}
}
3.uipopt.h/uip-conf.h是配置文件,用来设置本地的IP地址、网关地址、MAC地址、全局缓冲区的大小、支持的最大连接数、侦听数、ARP表大小等。
可以根据需要配置。
#defineUIP_FIXEDADDR1
决定uIP是否使用一个固定的IP地址。
如果uIP使用一个固定的IP地址,应该置位(set)这些uipopt.h中的选项。
如果不的话,则应该使用宏uip_sethostaddr(),uip_setdraddr()和uip_setnetmask()。
#defineUIP_PINGADDRCONF0PingIP地址赋值。
#defineUIP_FIXEDETHADDR0指明uIPARP模块是否在编译时使用一个固定的以太网MAC地址。
#defineUIP_TTL255uIP发送的IPpackets的IPTTL(timetolive)。
#defineUIP_REASSEMBLY0uIP支持IPpackets的分片和重组。
#defineUIP_REASS_MAXAGE40一个IPfragment在被丢弃之前可以在重组缓冲区中存在的最大时间。
#defineUIP_UDP0是否编译UDP的开关。
#defineUIP_ACTIVE_OPEN1决定是否支持uIP打开一个连接。
#defineUIP_CONNS10同时可以打开的TCP连接的最大数目。
由于TCP连接是静态分配的,减小这个数目将占用更少的RAM。
每一个TCP连接需要大约30字节的内存。
#defineUIP_LISTENPORTS10同时监听的TCP端口的最大数目。
每一个TCP监听端口需要2个字节的内存。
#defineUIP_RECEIVE_WINDOW32768建议的接收窗口的大小。
如果应用程序处理到来的数据比较慢,那么应该设置的小一点(即,相对与uip_buf缓冲区的大小来说),相反如果应用程序处理数据很快,可以设置的大一点(32768字节)。
#defineUIP_URGDATA1决定是否支持TCPurgentdatanotification。
#defineUIP_RTO3Theinitialretransmissiontimeoutcountedintimerpulses.不要改变
#defineUIP_MAXRTX8在中止连接之前,应该重发一个段的最大次数。
不要改变
#defineUIP_TCP_MSS(UIP_BUFSIZE–UIP_LLH_LEN–40)TCP段的最大长度。
它不能大于UIP_BUFSIZE–UIP_LLH_LEN–40.
#defineUIP_TIME_WAIT_TIMEOUT120一个连接应该在TIME_WAIT状态等待多长。
不要改变
#defineUIP_ARPTAB_SIZE8ARP表的大小。
如果本地网络中有许多到这个uIP节点的连接,那么这个选项应该设置为一个比较大的值。
#defineUIP_BUFSIZE1500uIPpacket缓冲区不能小于60字节,但也不必大于1500字节。
#defineUIP_STATISTICS1决定是否支持统计数字。
统计数字对调试很有帮助,并展示给用户。
#defineUIP_LOGGING0输出uIP登陆信息。
#defineUIP_LLH_LEN14链接层头部长度。
对于SLIP,应该设置成0。
uip-conf.h中增加几个主要结构体定义,不include任何应用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#defineUIP_CONF_LOGGING0//loggingoff
typedefintuip_tcp_appstate_t;//出错可注释
typedefintuip_udp_appstate_t;//出错可注释
/*#include"smtp.h"*/
/*#include"hello-world.h"*/
/*#include"telnetd.h"*/
/*#include"webserver.h"*/
/*#include"dhcpc.h"*/
/*#include"resolv.h"*/
/*#include"webclient.h"*/
#include"app_call.h"//加入一个Uip的数据接口文件
uIP在接受到底层传来的数据包后,调用UIP_APPCALL(),将数据送到上层应用程序处理。
User/app_call.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include"stm32f10x.h"
#ifndefUIP_APPCALL
#defineUIP_APPCALLUip_Appcall
#endif
#ifndefUIP_UDP_APPCALL
#defineUIP_UDP_APPCALLUdp_Appcall
#endif
voidUip_Appcall(void);
voidUdp_Appcall(void);
voidUip_Appcall(void)
{
}
voidUdp_Appcall(void)
{
}
4.加入uIP的的主循环代码架构
User/main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
1
#include"stm32f10x.h"
#include"stdio.h"
#include"string.h"
#include"uip.h"
#include"uip_arp.h"
#include"tapdev.h"
#include"timer.h"
#include"ENC28J60.h"
#include"SPI.h"
#definePRINTF_ON1
#defineBUF((structuip_eth_hdr*)&uip_buf[0])
#ifndefNULL
#defineNULL(void*)0
#endif/*NULL*/
staticunsignedcharmymac[6]={0x04,0x02,0x35,0x00,0x00,0x01};
voidRCC_Configuration(void);
voidGPIO_Configuration(void);
voidUSART_Configuration(void);
intmain(void)
{
inti;
uip_ipaddr_tipaddr;
structtimerperiodic_timer,arp_timer;
RCC_Configuration();
GPIO_Configuration();
USART_Configuration();
SPInet_Init();
timer_set(&periodic_timer,CLOCK_SECOND/2);
timer_set(&arp_timer,CLOCK_SECOND*10);
SysTick_Config(72000);//配置滴答计时器
//以太网控制器驱动初始化
tapdev_init(mymac);
//Uip协议栈初始化
uip_init();
uip_ipaddr(ipaddr,192,168,1,15);//配置Ip
uip_sethostaddr(ipaddr);
uip_ipaddr(ipaddr,192,168,1,1);//配置网关
uip_setdraddr(ipaddr);
uip_ipaddr(ipaddr,255,255,255,0);//配置子网掩码
uip_setnetmask(ipaddr);
while
(1){
uip_len=tapdev_read();//从网卡读取数据
if(uip_len>0)
{//如果数据存在则按协议处理
if(BUF->type==htons(UIP_ETHTYPE_IP)){//如果收到的是IP数据,调用uip_input()处理
uip_arp_ipin();
uip_input();
/*Iftheabovefunctioninvocationresultedindatathat
shouldbesentoutonthenetwork,theglobalvariableuip_lenissettoavalue>0.*/
if(uip_len>0)
{
uip_arp_out();
tapdev_send();
}
}elseif(BUF->type==htons(UIP_ETHTYPE_ARP)){//如果收到的是ARP数据,调用uip_arp_arpin处理
uip_arp_arpin();
/*Iftheabovefunctioninvocationresultedindatathat
shouldbesentoutonthenetwork,theglobalvariableuip_lenissettoavalue>0.*/
if(uip_len>0)
{
tapdev_send();
}
}
}elseif(timer_expired(&periodic_timer)){//查看0.5s是否到了,调用uip_periodic处理TCP超时程序
timer_reset(&periodic_timer);
for(i=0;iuip_periodic(i);
/*Iftheabovefunctioninvocationresultedindatathat
shouldbesentoutonthenetwork,theglobalvariableuip_lenissettoavalue>0.*/
if(uip_len>0)
{
uip_arp_out();
tapdev_send();
}
}
for(i=0;i{
uip_udp_periodic(i);//处理udp超时程序
/*Iftheabovefunctioninvocationresultedindatathat
shouldbesentoutonthenetwork,theglobalvariableuip_lenissettoavalue>0.*/
if(uip_len>0)
{
uip_arp_out();
tapdev_send();
}
}
/*CalltheARPtimerfunctionevery10seconds.*///10s到了就处理ARP
if(timer_expired(&arp_timer))
{
timer_reset(&arp_timer);
uip_arp_timer();
}
}
}
}
/*******************************Stm32Set***************************************/
voidGPIO_Configuration(void)
{
GPIO_InitTypeDefGPIO_InitStructure;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
voidRCC_Configuration(void)
{
/*定义枚举类型变量HSEStartUpStatus*/
ErrorStatusHSEStartUpStatus;
/*复位系统时钟设置*/
RCC_DeInit();
/*开启HSE*/
RCC_HSEConfig(RCC_HSE_ON);
/*等待HSE起振并稳定*/
HSEStartUpStatus=RCC_WaitForHSEStartUp();
/*判断HSE起是否振成功,是则进入if()内部*/
if(HSEStartUpStatus==SUCCESS)
{
/*选择HCLK(AHB)时钟源为SYSCLK1分频*/
RCC_HCLKConfig(RCC_SYSCLK_Div1);
/*选择PCLK2时钟源为HCLK(AHB)1分频*/
RCC_PCLK2Config(RCC_HCLK_Div1);
/*选择PCLK1时钟源为HCLK(AHB)2分频*/
RCC_PCLK1Config(RCC_HCLK_Div2);
/*设置FLASH延时周期数为2*/
FLASH_SetLatency(FLASH_Latency_2);
/*使能FLASH预取缓存*/
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
/*选择锁相环(PLL)时钟源为HSE1分频,倍频数为9,则PLL输出频率为8MHz*9=72MHz*/
RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);
/*使能PLL*/
RCC_PLLCmd(ENABLE);
/*等待PLL输出稳定*/
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET);
/*选择SYSCLK时钟源为PLL*/
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
/*等待PLL成为SYSCLK时钟源*/
while(RCC_GetSYSCLKSource()!
=0x08);
}
/*打开APB2总线上的GPIOA时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);
}
voidUSART_Configuration(void)
{
USART_InitTypeDefUSART_InitStructure;
USART_ClockInitTypeDefUSART_ClockInitStructure;
USART_ClockInitStructure.USART_Clock=USART_Clock_Disable;
USART_ClockInitStructure.USART_CPOL=USART_CPOL_Low;
USART_ClockInitStructure.USART_CPHA=USART_CPHA_2Edge;
USART_ClockInitStructure.USART_LastBit=USART_LastBit_Disable;
USART_ClockInit(USART1,&USART_ClockInitStructure);
USART_InitStructure.USART_BaudRate=9600;
USART_InitStructure.USART_WordLength=USART_WordLength_8b;
USART_InitStructure.USART_StopBits=USART_StopBits_1;
USART_InitStructure.USART_Parity=USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
USART_Init(USART1,&USART_InitStructure);
USART_Cmd(USART1,ENABLE);
}
#ifPRINTF_ON
intfputc(intch,FILE*f)
{
USART_SendData(USART1,(u8)ch);
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
returnc