目录
一、问题概述
二、解决思路
三、代码实现
1.创建任务
2.UDP广播接收
一、问题概述
以前一直用RS232串口修改设备配置信息,但是现场施工人员的232线太细,经常容易断掉,这次准备用网口去修改,遇到了一个问题,那就是网口还需要TCP传输数据,网口的ip是根据现场分配的,所以你可能修改了网口ip以后,如果下一次去维护却忘了设置的这个ip是什么,这就很尴尬了。所以,如何通过网络搜寻到自己的STM32设备,就非常重要了。
二、解决思路
起初,琢磨的是用扫描ip的软件来扫到自己的设备,后来发现这个方法不太可行,因为扫一次费的时间太长了,而且只能扫到指定的网段,我要知道设备的ip还用扫吗,所以,这个方案pass掉了。
后来,在网上搜寻到的答案是用arp-a命令,这个命令可以查询看本地局域网中的所有与本机通信的监控设备IP地址、mac地址等,我们stm32设备的mac地址是自己设置的,能看出来哪个是自己的设备,但是这个功能不是很有实时性,有时候设备关了很久还在这显示,所以这个方法也不太靠谱。
最后,感觉最近用有人的小软件,搜索他们自己的设备嘎嘎快,几乎就是秒搜到,然后根据他们的说明文档和交互信息,了解到了一个新思路,UDP广播,什么是UDP广播呢,我认为就是主机像0.0.0.0到255.255.255.255所有的设备同时发送一个UDP,咱们自己的设备接收到UDP指令以后,可以顺便将自己的ip地址以及mac地址等基本信息一并传回来,这样就可以快速找到自己的设备了,因为第一次获取到了设备的mac地址,所以后面再发送UDP广播的时候只要带上mac地址就知道我们要修改哪个设备,哪个设备就进行相应的调整。
UDP广播可以用Packet Sender这个软件去发送,注意发送UDP广播的电脑如果装着虚拟机呢,需要在设备管理器里面禁用对应的网络适配器,否则UDP广播很有可能发送不出来。
三、代码实现
代码方面这里只写UDP广播接收这一部分,如果再想跑一个TCP,可以再另跑一个任务就行了,一个设备可以同时跑多个TCP或者UDP任务。
1.创建任务
#define UDP_PRIO 6
//任务堆栈大小
#define UDP_STK_SIZE 300
//任务控制块
OS_TCB UdpTaskTCB;
//任务堆栈
CPU_STK UDP_TASK_STK[UDP_STK_SIZE];
#define RCV_BUFFER_LEN 1024
unsigned char rec_buffer[RCV_BUFFER_LEN]={"\n"};
unsigned char rec_buffer1[RCV_BUFFER_LEN]={"0X00,0x14,0x97,0x0F,0x1D,0xEA\n"};
#define IP_addr_serv (192,168,1,255)
#define ADD_TO_INT(d ,c ,b , a) (((unsigned long)((a) & 0xff) << 24) | ((unsigned long)((b) & 0xff) << 16) | ((unsigned long)((c) & 0xff) << 8) | (unsigned long)((d) & 0xff))
//创建UDP线程
//返回值:0 UDP创建成功
// 其他 UDP创建失败
u8 udp_demo_init(void)
{
OS_ERR err;
CPU_SR_ALLOC();
OS_CRITICAL_ENTER();//进入临界区
//创建UDP任务
OSTaskCreate((OS_TCB * )&UdpTaskTCB,
(CPU_CHAR * )"udp task",
(OS_TASK_PTR )udp_thread,
(void * )0,
(OS_PRIO )UDP_PRIO,
(CPU_STK * )&UDP_TASK_STK[0],
(CPU_STK_SIZE)UDP_STK_SIZE/10,
(CPU_STK_SIZE)UDP_STK_SIZE,
(OS_MSG_QTY )0,
(OS_TICK )0,
(void * )0,
(OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
(OS_ERR * )&err);
OS_CRITICAL_EXIT(); //退出临界区
return err;
}
2.UDP广播接收
void udp_thread(void *arg)
{
OS_ERR err;
int s, ei, temp;
struct sockaddr_in serv, cli;
int len;
unsigned char optval = 1;
socklen_t client_addr_len=sizeof(struct sockaddr);//必须初始化,否则无法接收
memset(&serv, 0, sizeof(struct sockaddr_in));
serv.sin_family = AF_INET;
serv.sin_port = htons(1500); //本地端口
serv.sin_addr.s_addr = 0;
s = socket(AF_INET, SOCK_DGRAM , 0);
setsockopt(s,SOL_SOCKET,SO_BROADCAST,( void *)&optval,sizeof(optval));
ei = bind(s, (struct sockaddr*)&serv, sizeof(struct sockaddr_in));
while (1)
{
/* */
len = recvfrom( s, rec_buffer, RCV_BUFFER_LEN , 0,(struct sockaddr *) & cli, &client_addr_len );
if(len > 0)
{
len = sendto(s , rec_buffer1 , strlen(rec_buffer1) , 0 ,
(struct sockaddr*)&cli , sizeof(cli));
}
OSTimeDlyHMSM(0,0,0,5,OS_OPT_TIME_HMSM_STRICT,&err);
}
}
指定接收UDP广播端口为1500,可以在 if(len > 0) {}里面打断点,接收到了就会进入断点。
希望这篇文章对您扫到自己的物联网设备有所帮助。