核心芯片使用STM32F407,以太网芯片使用LAN8720,开发环境基于LWIP无操作系统移植。代码参考正点原子。
1、主要使用函数:
//创建一个协议控制块
struct udp_pcb *udp_new(void)
//UDP客户端连接到指定IP地址和端口号的服务器
err_t udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
//绑定本地IP地址与端口号
err_t udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
//注册回调函数
void udp_recv(struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg)
//udp发送数据
err_t udp_send(struct udp_pcb *pcb, struct pbuf *p)
//udp数据打包
err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)
//LWIP轮询任务
void lwip_periodic_handle()
//断开UDP连接
void udp_disconnect(struct udp_pcb *pcb)
//删除UDP
void udp_remove(struct udp_pcb *pcb)
2、自写udp.c文件
(1)全局变量以及头文件包含
#include "lwip_comm.h"
#include "lwip/pbuf.h"
#include "lwip/udp.h"
#define UDP_DEMO_RX_BUFSIZE 2000 //定义udp最大接收数据长度
#define UDP_DEMO_PORT 8001 //定义udp连接的端口
u8 udp_recvbuf[UDP_DEMO_RX_BUFSIZE];
struct udp_pcb *udppcb;
uint8_t sendbuf[40]={'0'};
u8 udp_flag;
1)lwip_comm.h是在移植lwip时写创建的,主要用到了其中的ip地址以及lwip_periodic_handle()函数
2)udp_flag是全局状态标记变量。bit6:0,没有收到数据;1,收到数据了.。bit5:0,没有连接上;1,连接上了.
(2)udp初始化
uint8_t udp_config(void)
{
err_t err;
struct ip_addr rmtipaddr; //远端ip地址
udppcb=udp_new();
if(udppcb)//创建成功
{
//远端IP设置
IP4_ADDR(&rmtipaddr,lwipdev.remoteip[0],lwipdev.remoteip[1],lwipdev.remoteip[2],lwipdev.remoteip[3]);
err=udp_connect(udppcb,&rmtipaddr,UDP_DEMO_PORT);
if(err==ERR_OK)
{
err=udp_bind(udppcb,IP_ADDR_ANY,UDP_DEMO_PORT);
if(err==ERR_OK)
{
udp_recv(udppcb,udp_recive_data,NULL);//注册接受回调函数
udp_flag |= 1<<5;//标记已经连接上
}else return 1;
}else return 1;
}else return 1;
return 0;
}
(3)udp回调接受函数
void udp_recive_data(void *arg,struct udp_pcb *upcb,struct pbuf *p,struct ip_addr *addr,u16_t port)
{
u32 data_len = 0;
struct pbuf *q;
if(p!=NULL) //接收到不为空的数据时
{
memset(udp_recvbuf,0,UDP_DEMO_RX_BUFSIZE); //数据接收缓冲区清零
for(q=p;q!=NULL;q=q->next) //遍历完整个pbuf链表
{
//判断要拷贝到UDP_DEMO_RX_BUFSIZE中的数据是否大于UDP_DEMO_RX_BUFSIZE的剩余空间,如果大于
//的话就只拷贝UDP_DEMO_RX_BUFSIZE中剩余长度的数据,否则的话就拷贝所有的数据
if(q->len > (UDP_DEMO_RX_BUFSIZE-data_len))
memcpy(udp_recvbuf+data_len,q->payload,(UDP_DEMO_RX_BUFSIZE-data_len));//拷贝数据
else
memcpy(udp_recvbuf+data_len,q->payload,q->len);
data_len += q->len;
if(data_len > UDP_DEMO_RX_BUFSIZE)
break; //超出TCP客户端接收数组,跳出
}
udp_flag|=1<<6; //标记接收到数据了
pbuf_free(p);//释放内存
}
else
{
udp_disconnect(upcb);
udp_flag &= ~(1<<5); //标记连接断开
}
}
(4)接受数据处理函数
通过接受回调函数将接受到的数据存放在udp_recvbuf[]数组中,在下列函数中进行数据处理。该函数需要轮训
void udp_recive_handle(void)
{
if(udp_flag&1<<6)//是否收到数据?
{
//数据处理
udp_flag&=~(1<<6);//标记数据已经被处理了.
lwip_periodic_handle();
}
}
(5)发送数据函数
void udp_send_data(uint8_t *data)
{
struct pbuf *ptr;
ptr=pbuf_alloc(PBUF_TRANSPORT,strlen((char*)data),PBUF_POOL); //申请内存
if(ptr)
{
pbuf_take(ptr,(char*)data,strlen((char*)data)); //将发送的数据打包进pbuf结构中
udp_send(udppcb,ptr); //udp发送数据
pbuf_free(ptr);//释放内存
}
}
(6)关闭udp连接
//关闭UDP连接
void udp_connection_close(struct udp_pcb *upcb)
{
udp_disconnect(upcb);
udp_remove(upcb);
udp_flag &= ~(1<<5); //标记连接断开
}
udp整体流程较为清晰且比较简单主函数不再展示,回调函数是个关键。远端ip为上位机ip地址,连接时端口号应保持一致