LWIP裸机环境下实现TCP与UDP通讯

时间:2022-12-16 23:48:26

前面移植了LWIP,并且简单的实用了DHCP的功能,今天来使用一下实际的数据通讯的功能

首先是实现TCP客户端,我先上代码

#ifndef __TCP_CLIENT_H_
#define __TCP_CLIENT_H_
#include "network.h" //连接状态
enum tcp_client_states
{
ES_NONE = ,
ES_RECEIVED, //接收到了数据
ES_CLOSING //连接关闭
}; //TCP服务器状态
struct tcp_client_state
{
u8_t state;
}; #define LWIP_CLIENT_BUF 200 //TCP链接缓存 extern u8 lwip_client_buf[LWIP_CLIENT_BUF]; //定义用来发送和接收数据的缓存 extern u8 lwip_tcp_client_flag; //用于定义lwip tcp client状态 //客户端成功连接到远程主机时调用
err_t Tcp_Client_Connect(void *arg,struct tcp_pcb *tpcb,err_t err); //连接轮询时将要调用的函数
err_t Tcp_Client_Poll(void *arg, struct tcp_pcb *tpcb); //用于连接远程主机
void Tcp_Client_Connect_Remotehost(void); //客户端接收到数据之后将要调用的函数
err_t Tcp_Client_Recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err); //关闭连接
void Tcp_Client_Close(struct tcp_pcb *tpcb, struct tcp_client_state* ts); //初始化TCP客户端
void Tcp_Client_Init(void); #endif
#include "tcp_client.h"

u8 lwip_tcp_client_flag;      //用于定义lwip tcp client状态

//定义一个TCP的协议控制块
struct tcp_pcb* tcp_client_pcb;
//链接的自动回应信息
static const char* respond = "tcp_client connect success\r\n"; u8 lwip_client_buf[LWIP_CLIENT_BUF]; //定义用来发送和接收数据的缓存 //客户端成功连接到远程主机时调用
err_t Tcp_Client_Connect(void *arg,struct tcp_pcb *tpcb,err_t err)
{
struct tcp_client_state* ts;
ts = arg;
ts->state = ES_RECEIVED; //可以开始接收数据了
lwip_tcp_client_flag |= LWIP_CONNECTED; //标记连接成功了
tcp_write(tpcb,respond,strlen(respond),); //回应信息
return ERR_OK;
} //连接轮询时将要调用的函数
err_t Tcp_Client_Poll(void *arg, struct tcp_pcb *tpcb)
{
err_t ret_err;
struct tcp_client_state* ts;
ts = arg;
// lwip_log("tcp_client_polling!\r\n");
if(ts!=NULL)//连接处于空闲可以发送数据
{
if((lwip_tcp_client_flag&LWIP_SEND_DATA)==LWIP_SEND_DATA)
{
tcp_write(tpcb,lwip_client_buf,strlen((char *)lwip_client_buf),);//发送数据
lwip_tcp_client_flag &=~LWIP_SEND_DATA; //清除发送数据的标志
}
}
else
{
tcp_abort(tpcb);
ret_err = ERR_ABRT;
}
return ret_err;
} //用于连接远程主机
void Tcp_Client_Connect_Remotehost(void)
{
//记住如果此处需要频繁重连的时候记得先关闭已经申请的tcb
//最好将tcb换成全局变量
// Tcp_Client_Close();
Tcp_Client_Init();
} //客户端接收到数据之后将要调用的函数
err_t Tcp_Client_Recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
err_t ret_err;
struct tcp_client_state* ts;
ts = arg; //TCP PCB状态
if(p==NULL)
{
ts->state = ES_CLOSING; //连接关闭了
Tcp_Client_Close(tpcb,ts);
lwip_tcp_client_flag &=~ LWIP_CONNECTED; //清除连接标志
}
else if(err!=ERR_OK)
{ //位置错误释放pbuf
if(p!=NULL)
{
pbuf_free(p);
}
ret_err = err; //得到错误
}
else if(ts->state==ES_RECEIVED)
{//连接收到了新的数据 // printf("服务器新接收的数据:%s\r\n",p->payload);
if((p->tot_len)>=LWIP_CLIENT_BUF)
{ //如果收的的数据大于缓存
((char*)p->payload)[] = ;
memcpy(lwip_client_buf,p->payload,);
}
else
{
memcpy(lwip_client_buf,p->payload,p->tot_len);
lwip_client_buf[p->tot_len] = ;
}
lwip_tcp_client_flag |= LWIP_NEW_DATA; //收到了新的数据
tcp_recved(tpcb, p->tot_len); //用于获取接收数据的长度, 表示可以获取更多的数据
pbuf_free(p); //释放内存
ret_err = ERR_OK;
}
else if(ts->state==ES_CLOSING)//服务器关闭了
{
tcp_recved(tpcb, p->tot_len); //远程端口关闭两次,垃圾数据
pbuf_free(p);
ret_err = ERR_OK;
}
else
{ //其他未知状态
tcp_recved(tpcb, p->tot_len);
pbuf_free(p);
ret_err = ERR_OK;
}
return ret_err; } //关闭连接
void Tcp_Client_Close(struct tcp_pcb *tpcb, struct tcp_client_state* ts)
{ tcp_arg(tcp_client_pcb, NULL);
tcp_recv(tcp_client_pcb, NULL);
tcp_poll(tcp_client_pcb, NULL, );
if(ts!=NULL)
{
mem_free(ts);
}
tcp_close(tpcb);
} //指定连接的客户端为1300端口
#define TCP_CLIENT_PORT 1300 //初始化TCP客户端
void Tcp_Client_Init(void)
{
struct tcp_client_state* ts;
ip_addr_t ipaddr;
IP4_ADDR(&ipaddr, , , , ); tcp_client_pcb = tcp_new(); //新建一个PCB
if(tcp_client_pcb!=NULL)
{
ts = mem_malloc(sizeof(struct tcp_client_state)); //申请内存
tcp_arg(tcp_client_pcb, ts); //将程序的协议控制块的状态传递给多有的回调函数
//设定TCP的回调函数
tcp_connect(tcp_client_pcb,&ipaddr,TCP_CLIENT_PORT,Tcp_Client_Connect);
tcp_recv(tcp_client_pcb, Tcp_Client_Recv); //指定连接接收到新的数据之后将要调用的回调函数
tcp_poll(tcp_client_pcb, Tcp_Client_Poll, ); //指定轮询时将要调用的回调函数
}
}

我们可以看到,在tcp客户端初始化的时候我们使用了回调函数技术将接收数据和轮询数据的函数添加到了网络的底层轮转中,还要指定链接的端口和ip,但是不需要指定本地端口
同时,我们还在在程序主循环中不停地处理网络事件(因为没有操作系统)

//LWIP查询
void LWIP_Polling(void)
{
if(timer_expired(&input_time,)) //接收包,周期处理函数
{
ethernetif_input(&enc28j60_netif);
}
if(timer_expired(&last_tcp_time,TCP_TMR_INTERVAL/CLOCKTICKS_PER_MS))//TCP处理定时器处理函数
{
tcp_tmr();
}
if(timer_expired(&last_arp_time,ARP_TMR_INTERVAL/CLOCKTICKS_PER_MS))//ARP处理定时器
{
etharp_tmr();
}
if(timer_expired(&last_ipreass_time,IP_TMR_INTERVAL/CLOCKTICKS_PER_MS))//IP重新组装定时器
{
ip_reass_tmr();
}
}

这样,完整的TCP通讯链路就能建成了,数据的使用这样

if((lwip_tcp_client_flag&LWIP_CONNECTED)==LWIP_CONNECTED)
{
LCD_ShowString(,,,,(u8*)"TCP CLIENT Connect ",LCD_BLACK);
if(keyValue == KEY_RIGHT)
{
t_client_cnt++;
sprintf((char*)lwip_client_buf,"tcp_client send %d\r\n",t_client_cnt);
LCD_ShowString(,,,,(u8*)lwip_client_buf,LCD_BLACK);//显示当前发送数据
lwip_tcp_client_flag |= LWIP_SEND_DATA; //标记有数据需要发送
keyValue = ;
}
}
else
{
// Tcp_Client_Connect_Remotehost();//没有连接上,此时处于TCP客户端模式,则尝试重新连接
} if((lwip_tcp_client_flag&LWIP_NEW_DATA)==LWIP_NEW_DATA)
{
LCD_ShowString(,,,,(u8*)lwip_client_buf,LCD_BLACK);
lwip_tcp_client_flag &=~LWIP_NEW_DATA; //清除接受数据的标志
}

同理,TCP服务器的流程也差不多,但是多了一个东西,tcp服务器要监听本地某一个特定端口,使用如下

#include "tcp_service.h"

struct tcp_pcb* tcp_server_pcb;//定义一个TCP的协议控制块

static const char* respond =  "tcp_service connect ok!\r\n";

u8 lwip_tcp_service_flag;      //用于定义lwip tcp client状态

u8 lwip_service_buf[LWIP_SERCER_BUF];        //定义用来发送和接收数据的缓存

//初始化LWIP服务器
void Init_TCP_Server(void)
{
err_t err; //LWIP错误信息
tcp_server_pcb = tcp_new(); //新建一个TCP协议控制块
if(tcp_server_pcb!=NULL)
{
err = tcp_bind(tcp_server_pcb,IP_ADDR_ANY,TCP_SERVER_PORT);//绑定本地所有IP地址和端口号 作为服务器不需要知道客户端的IP
if(err==ERR_OK)//成功绑定
{
tcp_server_pcb = tcp_listen(tcp_server_pcb); //开始监听端口
tcp_accept(tcp_server_pcb,Tcp_Server_Accept); //指定监听状态的连接联通之后将要调用的回调函数
}
} } //服务器连接成功后将要调用的函数
err_t Tcp_Server_Accept(void *arg, struct tcp_pcb *newpcb, err_t err)
{
err_t ret_err;
struct tcp_server_state* ts; ts = mem_malloc(sizeof(struct tcp_server_state)); //申请内存
if(ts!=NULL)
{
ts->state = ES_SERVER_RECEIVED; //可以接收数据了
lwip_tcp_service_flag |= LWIP_CONNECTED; //已经连接上了
tcp_write(newpcb,respond,strlen(respond),); //回应信息 tcp_arg(newpcb, ts); //将程序的协议控制块的状态传递给多有的回调函数 tcp_recv(newpcb, Tcp_Server_Recv); //指定连接接收到新的数据之后将要调用的回调函数
tcp_err(newpcb, Tcp_Server_Error); //指定连接出错将要调用的函数
tcp_poll(newpcb, Tcp_Server_Poll, ); //指定轮询时将要调用的回调函数
ret_err = ERR_OK;
}
else
{
ret_err = ERR_MEM;
}
return ret_err; } //连接轮询时将要调用的函数
err_t Tcp_Server_Poll(void *arg, struct tcp_pcb *tpcb)
{
err_t ret_err;
struct tcp_server_state* ts;
ts = arg;
if(ts!=NULL)
{ //连接处于空闲可以发送数据
if((lwip_tcp_service_flag&LWIP_SEND_DATA)==LWIP_SEND_DATA)
{
tcp_write(tpcb,lwip_service_buf,strlen((char *)lwip_service_buf),);//发送数据
lwip_tcp_service_flag &=~LWIP_SEND_DATA; //清除发送数据的标志
}
}
else
{
tcp_abort(tpcb);
ret_err = ERR_ABRT;
}
return ret_err;
} //服务器接收到数据之后将要调用的函数
err_t Tcp_Server_Recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
err_t ret_err;
struct tcp_server_state* ts; ts = arg; //TCP PCB状态
if(p==NULL)
{
ts->state = ES_SERVER_CLOSING; //连接关闭了
Tcp_Server_Close(tpcb,ts);
lwip_tcp_service_flag &=~ LWIP_CONNECTED; //清除连接标志
}
else if(err!=ERR_OK)
{ //未知错误,释放pbuf
if(p!=NULL)
{
pbuf_free(p);
}
ret_err = err; //得到错误
}
else if(ts->state==ES_SERVER_RECEIVED)
{//连接收到了新的数据
if((p->tot_len)>=LWIP_SERCER_BUF)
{ //如果收的的数据大于缓存
((char*)p->payload)[] = ;
memcpy(lwip_service_buf,p->payload,);
}
else
{
memcpy(lwip_service_buf,p->payload,p->tot_len);
lwip_service_buf[p->tot_len] = ;
} lwip_tcp_service_flag |= LWIP_NEW_DATA; //收到了新的数据 tcp_recved(tpcb, p->tot_len); //用于获取接收数据的长度, 通知LWIP已经读取了数据,可以获取更多的数据
pbuf_free(p); //释放内存
ret_err = ERR_OK;
}
else if(ts->state==ES_SERVER_CLOSING)
{ //服务器关闭了
tcp_recved(tpcb, p->tot_len); //远程端口关闭两次,垃圾数据
pbuf_free(p);
ret_err = ERR_OK;
}
else
{ //其他未知状态
tcp_recved(tpcb, p->tot_len);
pbuf_free(p);
ret_err = ERR_OK;
}
return ret_err; } //连接出错将要调用的函数
void Tcp_Server_Error(void *arg,err_t err)
{
struct tcp_server_state* ts;
ts = arg;
if(ts!=NULL)
{
mem_free(ts);
}
} //关闭连接
void Tcp_Server_Close(struct tcp_pcb *tpcb, struct tcp_server_state* ts)
{
if(ts!=NULL)
{
mem_free(ts);
}
tcp_close(tpcb);
}

可以看到上面的代码多了一个bind的过程

剩下的就是udp通讯了,在之前tcp的源码里面能看到,发送数据的时候不需要专门去做发送函数,指定一个标志位就行了,在轮转的时候程序会自动把数据发送出去,当使用UDP的时候就不行了,因为TCP是面向链接的,而UDP本身就是无连接的,UDP的是使用源码如下

#include "udp_send.h"

//该文件即可以接受也可以发送数据
//都是用1500端口进行操作 u8 lwip_udp_send_buf[LWIP_UDP_SEND_BUF]; //定义用来发送和接收数据的缓存
u8 lwip_udp_send_flag; //用于定义lwip tcp client状态 struct udp_pcb* udp_client_pcb;//定义一个UDP的协议控制块
struct pbuf * ubuf_client; //接收到数据包将要调用的函数
void udp_client_rev(void* arg,struct udp_pcb* upcb,struct pbuf* p,struct ip_addr*addr ,u16_t port)
{
if(p!=NULL)
{
if((p->tot_len)>=LWIP_UDP_SEND_BUF)
{ //如果收的的数据大于缓存
((char*)p->payload)[] = ;
memcpy(lwip_udp_send_buf,p->payload,);
}
else
{
memcpy(lwip_udp_send_buf,p->payload,p->tot_len);
lwip_udp_send_buf[p->tot_len] = ;
}
lwip_udp_send_flag |= LWIP_NEW_DATA; //收到了新的数据
pbuf_free(p);
}
} //发送数据
void udp_client_send_data(void)
{
err_t err;
if((lwip_udp_send_flag&LWIP_SEND_DATA)==LWIP_SEND_DATA)
{
ubuf_client = pbuf_alloc(PBUF_TRANSPORT, strlen((char *)lwip_udp_send_buf), PBUF_RAM); //为发送包分配内存
ubuf_client->payload = lwip_udp_send_buf;
err=udp_send(udp_client_pcb,ubuf_client);//发送数据
if(err!=ERR_OK)
{
//lwip_log("UDP SERVER发送数据失败!");
}
lwip_udp_send_flag &=~LWIP_SEND_DATA; //清除发送数据的标志
pbuf_free(ubuf_client);
}
} //初始化UDP客户端
void Init_UDP_Client(void)
{
//struct ip_addr* ipaddr;
ip_addr_t ipaddr;
IP4_ADDR(&ipaddr, , , , ); //设置本地ip地址
udp_client_pcb = udp_new(); //新建一个UDP协议控制块
if(udp_client_pcb!=NULL)
{
udp_bind(udp_client_pcb,IP_ADDR_ANY,UDP_CLIENT_PORT); //
udp_connect(udp_client_pcb,&ipaddr,UDP_CLIENT_PORT); //设置连接到远程主机
udp_recv(udp_client_pcb,udp_client_rev,NULL); //指定收到数据包时的回调函数
}
}

这是一个UDP的客户端,在初始化的时候指明了目的主机的地址和端口号,连接到目的主机上

  接下来是一个UDP的服务器

#include "udp_recv.h"

struct udp_pcb* udp_server_pcb;//定义一个UDP的协议控制块
struct pbuf * ubuf; u8 lwip_udp_recv_buf[LWIP_UDP_RECV_BUF]; //定义用来发送和接收数据的缓存
u8 lwip_udp_recv_flag; //用于定义lwip tcp client状态 //接收到数据包将要调用的函数
void Udp_Server_Recv(void* arg,struct udp_pcb* upcb,struct pbuf* p,struct ip_addr*addr ,u16_t port)
{
if(p!=NULL)
{
if((p->tot_len)>=LWIP_UDP_RECV_BUF)
{ //如果收的的数据大于缓存
((char*)p->payload)[] = ;
memcpy(lwip_udp_recv_buf,p->payload,);
}
else
{
memcpy(lwip_udp_recv_buf,p->payload,p->tot_len);
lwip_udp_recv_buf[p->tot_len] = ;
}
lwip_udp_recv_flag |= LWIP_NEW_DATA; //收到了新的数据
udp_server_pcb->remote_ip = *addr; //记录远程主机的IP和端口号
udp_server_pcb->remote_port = port;
pbuf_free(p);
}
} //发送数据
void Udp_Server_Send_Data(void)
{
err_t err;
if((lwip_udp_recv_flag&LWIP_SEND_DATA)==LWIP_SEND_DATA)
{
ubuf = pbuf_alloc(PBUF_TRANSPORT, strlen((char *)lwip_udp_recv_buf), PBUF_RAM);
ubuf->payload = lwip_udp_recv_buf;
err=udp_send(udp_server_pcb,ubuf);//发送数据
if(err!=ERR_OK)
{
//do something
}
lwip_udp_recv_flag &=~LWIP_SEND_DATA; //清除发送数据的标志
pbuf_free(ubuf);
}
} //初始化UDP服务器
void Init_UDP_Server(void)
{
udp_server_pcb = udp_new(); //新建一个UDP协议控制块
if(udp_server_pcb!=NULL)
{
udp_bind(udp_server_pcb,IP_ADDR_ANY,UDP_RECV_PORT); //监听一个UDP端口
udp_recv(udp_server_pcb,Udp_Server_Recv,NULL); //指定收到数据包时的回调函数
}
}

可以看到,UDP的服务器在使用的时候没有主动去连接那个IP,他只是自己绑定了自己的某个端口,算是客户端和服务器编程的两种差异

给一个使用文件

#include "mainInclude.h"

#include "lwip/init.h"
#include "lwip/ip.h"
#include "lwip/dhcp.h"
#include "lwip/tcp_impl.h"
#include "lwip/ip_frag.h"
#include "lwip/dns.h"
#include "netif/etharp.h"
#include "netif/ethernetif.h"
#include "arch/sys_arch.h" #define CLOCKTICKS_PER_MS 10 //定义时钟节拍 static ip_addr_t ipaddr, netmask, gw; //定义IP地址
struct netif enc28j60_netif; //定义网络接口
u32_t input_time;
u32_t last_arp_time;
u32_t last_tcp_time;
u32_t last_ipreass_time; u32_t last_dhcp_fine_time;
u32_t last_dhcp_coarse_time;
u32 dhcp_ip=; //LWIP查询
void LWIP_Polling(void)
{
if(timer_expired(&input_time,)) //接收包,周期处理函数
{
ethernetif_input(&enc28j60_netif);
}
if(timer_expired(&last_tcp_time,TCP_TMR_INTERVAL/CLOCKTICKS_PER_MS))//TCP处理定时器处理函数
{
tcp_tmr();
}
if(timer_expired(&last_arp_time,ARP_TMR_INTERVAL/CLOCKTICKS_PER_MS))//ARP处理定时器
{
etharp_tmr();
}
if(timer_expired(&last_ipreass_time,IP_TMR_INTERVAL/CLOCKTICKS_PER_MS))//IP重新组装定时器
{
ip_reass_tmr();
}
} int main(void)
{
u8 t_client_cnt = ;
u8 t_server_cnt = ;
u8 t_send_cnt = ;
u8 t_recv_cnt = ;
NVIC_Group_Init();//系统默认中断分组
Debug_Serial_Init();
Delay_Init();
Led_Init();
Key_Exti_Init();
LCD_Init();
LCD_Clear(LCD_BLACK); IP4_ADDR(&ipaddr, , , , ); //设置本地ip地址
IP4_ADDR(&gw, , , , ); //网关
IP4_ADDR(&netmask, , , , ); //子网掩码 //初始化LWIP定时器
init_lwip_timer();
//初始化LWIP协议栈,执行检查用户所有可配置的值,初始化所有的模块
lwip_init(); //添加网络接口
while((netif_add(&enc28j60_netif, &ipaddr, &netmask, &gw, NULL, &ethernetif_init, &ethernet_input)==NULL))
{
LCD_ShowString(,,,,(u8*)"ENC28J60 Init Failed ",LCD_BLACK);
Delay_Ms();
LCD_ShowString(,,,,(u8*)" ",LCD_BLACK);
Delay_Ms();
}
LCD_ShowString(,,,,(u8*)"ENC28J60 Init OK ",LCD_BLACK);
//注册默认的网络接口
netif_set_default(&enc28j60_netif);
//建立网络接口用于处理通信
netif_set_up(&enc28j60_netif); Tcp_Client_Init();//初始化tcp客户端 LCD_ShowString(,,,,(u8*)"TCP CLIENT INIT ",LCD_BLACK);
LCD_ShowString(,,,,(u8*)"TCP CLIENT Disconnect ",LCD_BLACK);
LCD_ShowString(,,,,(u8*)"RX: ",LCD_BLACK);
LCD_ShowString(,,,,(u8*)"TX: ",LCD_BLACK); Init_TCP_Server();
LCD_ShowString(,,,,(u8*)"TCP SERVER INIT ",LCD_BLACK);
LCD_ShowString(,,,,(u8*)"TCP SERVER Disconnect ",LCD_BLACK);
LCD_ShowString(,,,,(u8*)"RX: ",LCD_BLACK);
LCD_ShowString(,,,,(u8*)"TX: ",LCD_BLACK); Init_UDP_Client();
LCD_ShowString(,,,,(u8*)"UDP SEND INIT ",LCD_BLACK);
LCD_ShowString(,,,,(u8*)"RX: ",LCD_BLACK);
LCD_ShowString(,,,,(u8*)"TX: ",LCD_BLACK); Init_UDP_Server();//初始化UDP接收端
LCD_ShowString(,,,,(u8*)"UDP RECV INIT ",LCD_BLACK);
LCD_ShowString(,,,,(u8*)"RX: ",LCD_BLACK);
LCD_ShowString(,,,,(u8*)"TX: ",LCD_BLACK); while()
{
LWIP_Polling();
if((lwip_tcp_client_flag&LWIP_CONNECTED)==LWIP_CONNECTED)
{
LCD_ShowString(,,,,(u8*)"TCP CLIENT Connect ",LCD_BLACK);
if(keyValue == KEY_RIGHT)
{
t_client_cnt++;
sprintf((char*)lwip_client_buf,"tcp_client send %d\r\n",t_client_cnt);
LCD_ShowString(,,,,(u8*)lwip_client_buf,LCD_BLACK);//显示当前发送数据
lwip_tcp_client_flag |= LWIP_SEND_DATA; //标记有数据需要发送
keyValue = ;
}
}
else
{
// Tcp_Client_Connect_Remotehost();//没有连接上,此时处于TCP客户端模式,则尝试重新连接
} if((lwip_tcp_client_flag&LWIP_NEW_DATA)==LWIP_NEW_DATA)
{
LCD_ShowString(,,,,(u8*)lwip_client_buf,LCD_BLACK);
lwip_tcp_client_flag &=~LWIP_NEW_DATA; //清除接受数据的标志
} if((lwip_tcp_service_flag&LWIP_CONNECTED)==LWIP_CONNECTED)
{
LCD_ShowString(,,,,(u8*)"TCP SERVER Connect ",LCD_BLACK);
if(keyValue == KEY_LEFT)
{
t_server_cnt++;
sprintf((char*)lwip_service_buf,"tcp_service send %d\r\n",t_server_cnt);
LCD_ShowString(,,,,(u8*)lwip_service_buf,LCD_BLACK);//显示当前发送数据
lwip_tcp_service_flag |= LWIP_SEND_DATA; //标记有数据需要发送
keyValue = ;
}
}
if((lwip_tcp_service_flag&LWIP_NEW_DATA)==LWIP_NEW_DATA)
{
LCD_ShowString(,,,,(u8*)lwip_service_buf,LCD_BLACK);
lwip_tcp_service_flag &=~LWIP_NEW_DATA; //清除接受数据的标志
} if(keyValue == KEY_UP)
{
t_send_cnt++;
sprintf((char*)lwip_udp_send_buf,"udp_send send %d\r\n",t_send_cnt);
LCD_ShowString(,,,,(u8*)lwip_udp_send_buf,LCD_BLACK);//显示当前发送数据
lwip_udp_send_flag |= LWIP_SEND_DATA; //标记有数据需要发送
keyValue = ;
udp_client_send_data();
} if((lwip_udp_send_flag&LWIP_NEW_DATA)==LWIP_NEW_DATA)
{
LCD_ShowString(,,,,(u8*)lwip_udp_send_buf,LCD_BLACK);
lwip_udp_send_flag &=~LWIP_NEW_DATA; //清除接受数据的标志
} if(keyValue == KEY_DOWN)
{
t_recv_cnt++;
sprintf((char*)lwip_udp_recv_buf,"udp_recv send %d\r\n",t_send_cnt);
LCD_ShowString(,,,,(u8*)lwip_udp_recv_buf,LCD_BLACK);//显示当前发送数据
lwip_udp_recv_flag |= LWIP_SEND_DATA; //标记有数据需要发送
keyValue = ;
Udp_Server_Send_Data();
} if((lwip_udp_recv_flag&LWIP_NEW_DATA)==LWIP_NEW_DATA)
{
LCD_ShowString(,,,,(u8*)lwip_udp_recv_buf,LCD_BLACK);
lwip_udp_recv_flag &=~LWIP_NEW_DATA; //清除接受数据的标志
} Delay_Ms();
}
} void USB_LP_CAN1_RX0_IRQHandler(void)
{ } void USBWakeUp_IRQHandler(void)
{
// EXTI->PR|=1<<18;//清除USB唤醒中断挂起位
}

完整的工程路径如下

http://download.csdn.net/detail/dengrengong/8555627