当前位置: 首页 > news >正文

STM32 LWIP UDP 一对一 一对多发送

STM32 LWIP UDP通信

  • 前言
  • 设置 IP 地址
  • UDP函数配置
  • 实验结果
    • 单播发送,一对一发送
    • 广播发送,一对多发送
  • 可能遇到的问题
  • 总结

前言

之前没有接触过网络的通信,工作需要 UDP 接收和发送通信,在网上没有找到一对一、一对多的相关例程;于是在技术总监对我的指导,用正点原子板子给的例程是从官方的程序修改的,实现了Lwip UDP通信一对一、一对多的发送程序,可以随便指定发送ip地址、发送端口号,以及发送十六进制或是 ASCII码都可以,本人测试STM32F1系列和F4系列都没问题,十分的方便。

设置 IP 地址

  1. 假设设置STM32单片机IP为:192.168.1.130
	lwipx->ip[0]=192;	lwipx->ip[1]=168;lwipx->ip[2]=1;lwipx->ip[3]=130;
  1. 假设设置我的电脑的IP为:192.168.1.36

在这里插入图片描述

UDP函数配置

  1. STM32单片机上电不需要每次手动按键调节设置远端IP地址(ip地址、端口号)
//	udp_demo_set_remoteip();//先选择IPLCD_Clear(WHITE);	//清屏POINT_COLOR=RED; 	//红色字体LCD_ShowString(30,30,200,16,16,"WARSHIP STM32F103");LCD_ShowString(30,50,200,16,16,"UDP Test");LCD_ShowString(30,70,200,16,16,"ATOM@ALIENTEK");  LCD_ShowString(30,90,200,16,16,"KEY0:Send data");  LCD_ShowString(30,110,200,16,16,"KEY_UP:Quit"); LCD_ShowString(30,130,200,16,16,"KEY1:Connect");tbuf=mymalloc(SRAMIN,200);	//申请内存if(tbuf==NULL)return ;		//内存申请失败了,直接退出sprintf((char*)tbuf,"Local IP:%d.%d.%d.%d",lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]);//服务器IPLCD_ShowString(30,150,210,16,16,tbuf);sprintf((char*)tbuf,"Local Port:%d",UDP_DEMO_PORT);//服务器端口号LCD_ShowString(30,170,210,16,16,tbuf);
//	sprintf((char*)tbuf,"Remote IP:%d.%d.%d.%d",lwipdev.remoteip[0],lwipdev.remoteip[1],lwipdev.remoteip[2],lwipdev.remoteip[3]);//远端IP
//	LCD_ShowString(30,170,210,16,16,tbuf);  
//	sprintf((char*)tbuf,"Remote Port:%d",UDP_DEMO_PORT);//客户端端口号
//	LCD_ShowString(30,190,210,16,16,tbuf);POINT_COLOR=BLUE;LCD_ShowString(30,210,210,16,16,"STATUS:Disconnected"); 
  1. UDP客户端连接不需要指定IP地址和端口号的服务器
	udppcb=udp_new();if(udppcb)//创建成功{ IP4_ADDR(&rmtipaddr,lwipdev.remoteip[0],lwipdev.remoteip[1],lwipdev.remoteip[2],lwipdev.remoteip[3]);err=udp_bind(udppcb,IP_ADDR_ANY,UDP_DEMO_PORT);//绑定本地IP地址与端口号if(err==ERR_OK)	//绑定完成{udp_recv(udppcb,udp_demo_recv,NULL);//注册接收回调函数 LCD_ShowString(30,210,210,16,16,"STATUS:Connected   ");//标记连接上了(UDP是非可靠连接,这里仅仅表示本地UDP已经准备好)udp_demo_flag |= 1<<5;			//标记已经连接上POINT_COLOR=RED;LCD_ShowString(30,230,lcddev.width-30,lcddev.height-190,16,"Receive Data:");//提示消息		POINT_COLOR=BLUE;//蓝色字体}else res=1;	}else res=1;
  1. UDP回调函数
void udp_demo_recv(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_demo_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_demo_recvbuf+data_len,q->payload,(UDP_DEMO_RX_BUFSIZE-data_len));//拷贝数据else memcpy(udp_demo_recvbuf+data_len,q->payload,q->len);data_len += q->len;  	if(data_len > UDP_DEMO_RX_BUFSIZE) break; //超出TCP客户端接收数组,跳出	}upcb->remote_ip=*addr; 				//记录远程主机的IP地址upcb->remote_port=port;  			//记录远程主机的端口号lwipdev.remoteip[0]=upcb->remote_ip.addr&0xff; 		//IADDR4lwipdev.remoteip[1]=(upcb->remote_ip.addr>>8)&0xff; //IADDR3lwipdev.remoteip[2]=(upcb->remote_ip.addr>>16)&0xff;//IADDR2lwipdev.remoteip[3]=(upcb->remote_ip.addr>>24)&0xff;//IADDR1 udp_demo_flag|=1<<6;	//标记接收到数据了pbuf_free(p);//释放内存}else{udp_disconnect(upcb); LCD_Clear(WHITE);			//清屏POINT_COLOR = RED;LCD_ShowString(30,30,200,16,16,"WARSHIP STM32F103");LCD_ShowString(30,50,200,16,16,"UDP Test");LCD_ShowString(30,70,200,16,16,"ATOM@ALIENTEK");POINT_COLOR=BLUE;LCD_ShowString(30,90,200,16,16,"Connect break!");  LCD_ShowString(30,110,200,16,16,"KEY1:Connect");udp_demo_flag &= ~(1<<5);	//标记连接断开} 
}

实验结果

单播发送,一对一发送

	if(key == KEY0_PRES)//KEY0按下了,发送数据{u8 remote_add[4] = {192,168,1,36};	//发送对端的ip地址u8 send_str_data[] = "hello word!";	//要发送的信息Unicast_Send(remote_add,send_str_data,0,8089);//单播发送}

我按键按下KEY0_PRES按了三次发送,单播发送的端口号为8089,用 Wireshark 抓包
在这里插入图片描述
也可以用网络调试助手查看是否收到STM32发来的数据,刚刚前面说过我设置自己的电脑ip:192.168.1.36,电脑本机端口号设置和STM32单片机发送数据端口号一致才能收到数据
在这里插入图片描述

广播发送,一对多发送

	if(key == KEY2_PRES)//KEY2按下了,发送数据{u8 send_data[8] = {0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8};	//要发送的信息Broadcast_Send(send_data,8,8080);//广播发送}

我按键按下KEY2_PRES按了两次发送,广播发送的端口号为8080,用 Wireshark 抓包
在这里插入图片描述
也可以用网络调试助手查看是否收到STM32发来的数据,电脑本机端口号端口号设置和STM32单片机发送数据端口号一致才能收到数据,因为我刚刚设置STM32广播发送的端口号是8080,所以本地端口号8089是不会收到数据的,重新打开一个网络调试助手(端口号设置为8080),此时就可以正常收到数据了
在这里插入图片描述
接收是正常的我就不演示了,没有 TFT显示屏 可以使用串口来查看单片机是否收到别的单片机发来的数据

		if(udp_demo_flag&1<<6)//是否收到数据?{LCD_Fill(30,250,lcddev.width-1,lcddev.height-1,WHITE);//清上一次数据LCD_ShowString(30,250,lcddev.width-30,lcddev.height-230,16,udp_demo_recvbuf);//显示接收到的数据			printf("接收到数据:%s\r\n",udp_demo_recvbuf);udp_demo_flag&=~(1<<6);//标记数据已经被处理了.} 

可能遇到的问题

  1. 移植不成功:不会将F1例程移植到F4板子上之类的问题
  2. 移植不会修改程序
  3. 没有设置自己的电脑ip地址
  4. 程序、STM32单片机、网线都没有问题,但电脑没有收到包,此时检查电脑的防火墙
  5. 端口号不一致也收不到包的 (这一点很重要),端口号要一致才能收发数据
  6. 其它等等问题

总结

本人也花了大量时间去研究,如需要源码支付30元,提供技术服务,加企鹅号:970484728,加企鹅时备注STM32 UDP,不需要源码的也不强求;记录下自己的学习过程,我只是刚入门的新手,知道有许多会的大佬,不喜勿喷!欢迎各位小伙伴一起前来讨论。

http://www.lryc.cn/news/106730.html

相关文章:

  • 【有趣的设计模式】23 种设计模式详解和场景分析
  • 【数据结构与算法】TypeScript 实现图结构
  • 《golang设计模式》第一部分·创建型模式-04-抽象工厂模式(Abstract Factory)
  • 改进粒子群算法优化BP神经网络---回归+分类两种案例
  • VSCode和QT联合开发
  • YOLO5-1 使用YOLO5检测 水面漂浮物记录
  • MongoDB教程-7
  • Redisson提供优秀的并发控制机制
  • Linux: 设置qmake的Qt版本
  • 使用LLM插件从命令行访问Llama 2
  • gateway过滤器没生效,特殊原因
  • 长相思追剧小游戏
  • leetcode做题笔记51
  • Windows同时安装两个版本的JDK并随时切换,以JDK6和JDK8为例,并解决相关存在的问题(亲测有效)
  • 【ChatGPT辅助学Rust | 基础系列 | Cargo工具】Cargo介绍及使用
  • 全面了解CPU Profiler:解读CPU性能分析工具的核心功能与用法
  • rust format!如何转义{},输出{}?
  • 真人AI写真的制作方法-文生图换脸
  • vscode如何包含第三方库
  • 【Docker】Docker安装Consul
  • 《吐血整理》进阶系列教程-拿捏Fiddler抓包教程(20)-Fiddler精选插件扩展安装让你的Fiddler开挂到你怀疑人生
  • 计算机top命令
  • DevExpress WPF Tree List组件,让数据可视化程度更高!(二)
  • lc1074.元素和为目标值的子矩阵数量
  • elementUi el-radio神奇的:label与label不能设置默认值
  • git仓库清理
  • 从0到1开发go-tcp框架【3-读写协程分离、引入消息队列、进入连接管理器、引入连接属性】【基础篇完结】
  • python-爬虫作业
  • vue3+ts+pinia整合websocket
  • 【微信小程序】保存多张图片到本地相册