STM32无操作系统UDP

核心芯片使用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地址,连接时端口号应保持一致

猜你喜欢

转载自blog.csdn.net/qq_37016048/article/details/89206271