单片机udp能通 ping udp 端口一定能通吗

自制安卓WiFi控制器原理解析|我爱单片机 - 数码之家
查看完整版本: [--
&Pages: ( 2 total )
赞助商链接
&&&&&&&& 首先写这篇帖子不是说一个能用安卓手机wifi控制的东西有什么价值或值不值,而是将原理、程序等各部分简单介绍下,可以用在其它很多东西上。之前为找相关资料走了很多弯路,在此分享自己当时做这个的一些知识,希望对他人有所帮助。&&&&&&&& 总的就三样东西:1.受控部分的硬件。2.受控部分的程序(不局限于单片机类型)。3.Android部分程序。●硬件部分&&&&&& 本质上主要有三种东西:通讯模块、数据处理及控制(单片机)、执行部分(继电器、晶闸管)。&&&&&& 数字通讯小模块有很多,如:NRF2401、HC-05(蓝牙)、ESP8266 wifi模块等,在此用的是ESP8266,因为其是价格低廉的wifi模块,操作它容易,稳定性满足日常要求,所以选它;&&&&&& 数据处理,最简单的就是单片机了,不管事何种单片机,只要有串口,且速度不要太低就能满足ESP8266的操作,其余就是算法,原理不变,用在什么单片机上都是可行的。&&&&&& 执行部分,那就要看要控制什么东西,有何特殊要求,最常见的就是继电器作常开节点控制,但继电器吸合时需要持续通电保持,对于省电有要求则需考虑其他办法。其实固态继电器是个很好的东西,就是贵了点,下面以光耦+晶闸管作为执行部分举例。&&&&&& 下面是去年搞得一个东西,实质不是为遥控风扇,只是为验证wifi控制的整个系统。原帖实物可参看:[attachment=7224404]如上图,前2部分不变,后一部分改变即可实现控制不同要求的东西,此处用光耦+晶闸管,第一是为静音,第二是为降低控制部分的功耗。由于单片机与ESP8266就2根通讯线(TXD、RXD),在此也无需说明了,当然也可用SPI控制它,此外ESP8266还可给用户直接对其进行编程,这样就可以直接省去 上图的单片机部分,但需用官方提供的SDK,没用过所以目前也不会。&&&&&&下图为控制部分(执行部分)实际电路图:[attachment=7224405]PORTD5为单片机IO的PD5,上图为高档位的控制,其余几个档位同理。注意上图驱动方法不适用于51单片机无推挽输出的IO(STC89C52等无,STC12C5A IO有推挽输出),不然光耦不能很好导通。&&&&&& 硬件就这么简单,最多再找个手机充电器提供5V电源(注意ESPV供电,用个ASM即可),整个硬件就完成了。其实硬件不是关键,软件部分才是核心,要控制什么东西,怎么控制,都需在软件中考虑。下面先说下单片机软件部分。 ●单片机软件部分&&&&&& 把源代码放出来就算开源,但是很多时候看别人的代码还真不知如何下手,一个因字数多,另一个因字数多没心思看,在此写出程序的主体流程及注意的关键点,分享程序的思路,同时以备日久忘记了程序的主要思路。&&&&&& 总的来说,数据从串口中得到,再逐个数据分析解释,确认无误后就执行,简单理解就是接到上级通知,提取通知里要办的事,接着着手去做。串口基本每个单片机都有了(就算没有,都可以直接软件模拟串口),虽然整个流程很简单,但过程中总会遇到些麻烦。程序用AVR stdio6写的,其它单片机或编译器注意改串口初始化及中断服务程序等。下面分3块来说:一、串口数据接收&&&&&& 考虑到串口数据的接收及处理需要一定时间,响应速度不能慢但是又不能丢掉发来的指令,所以设置了一个串口数据缓冲区和一个待处理数据区,由于串口数据缓冲区有时接收的数量太多了(列出当前所有可用wifi时),设置的字符串数组就一定得够长,由于单片机内部寄存器数量的限制,是不可能设置那么长的,于是将数据缓冲区和待处理数据区合并到一个数组里,前270字节是数据缓冲区,后面全部是待处理区,数据接收完毕后将数据全部复制到待处理区。当数据缓冲过长则将占用待处理数据区(不使用待处理区,缓冲区同时作为待处理区,取消待处理区后将不再复制数据到原来的待处理区),直接在缓冲区内处理,再来新指令将暂时不理。当然一般情况下是没有这么多数据的。&&&&&& 与ESP8266对接时,判断何时指令接收完毕是不能单单以0x0D 0x0A(换行)来判断,不同情况、不同指令会有不同的行数,故不能一概而论,其实最简单办法就是等待一小段时间看是否有新串口数据进入,无则认为接收完了,或者针对每种情况、每种指令写不同的结束识别,或者以单向控制(只管往ESP8266写命令,不去管其返回何值)。[attachment=7224406]//串口接收中断//Len串口数据长度 rbuffer缓冲数组 Receive标志寄存器 T2_period定时器已定时时长,即定时多少个周期ISR ( SIG_UART_RECV ){&&&&&&&&&&&&&&&&UCSRB&=~ ( 1&&RXCIE );&&&&&&//关接受结束中断使能&&&&&&&&value=UDR;&&&& ///注意串口数据每次必须读取否则会导致程序出错&&&&&&&&if(Len&Receive_length*2)rbuffer[Len++]=&&&&&&&& if( !(Receive&0x02)){Receive|=0x02;}&& //进入定时器检测结束&&&&&&&&T2_period=0;//TCNT2=0;&&&&&&&&UCSRB|= ( 1&&RXCIE );&&&&&&&&&&&&&&&&&&&&&&&& // 开接受结束中断使能}/*************************************功&&能:定时器2比较中断,为判断串口数据是否接收完*备&&注:中断服务程序&& period 10ms*Judge_End判断多少周期后无数据认为接收完*************************************/SIGNAL(SIG_OUTPUT_COMPARE2){&&&&&&&&int i=0;&&&&&&&& wdt_reset();&&&&&& //喂狗指令;每次唤醒后喂狗&&&&&&&&&&&&&&&&if(WaitTime){WaitTime++;&&&&&&&&}&&&&&&&&if(Receive&0x02){&&&&&&&&T2_period++;&&&&&&&&if(T2_period&Judge_End){T2_period=0; &&&&&&&&&&&&&&&&Receive &= 0xFD;//关闭识别&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&rbuffer[Len]=0;&&&&&&&&&&&&&&&&if((Receive & 0x04)==0){//读取了才填充,数据处理后会将bit2置0&&&&&&&&&&&&&&&&Len1=L&&&&&&&&&&&&&&&&if(Len&Receive_length)Len=0;&&&&&&&&&&&&&&&&//将rsbuffer-&com_data&& 注意Len1 超范围访问&&&&&&&&&&&&&&&&if(Len1&=Receive_length)//在没有超出缓冲区长度时才复制数据&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&&&&&while(i&Len1)&&&&&&&&&&&&&&&&&&&&&&&&{rbuffer[i+Receive_length]=rbuffer[i];i++; }&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&else {Len1=0; }&& //丢弃此包&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&Receive |= 0x04;//数据准备好标记,主程序可以处理数据了&&&&&&&&}}&&&&&&&&TIFR |= 0x80;//清定时器2标志位} 二、ESP8266控制部分&&&&&&&&当初选择ESP8266 wifi模块,主要是因为它有很多先天优势,第一现在安卓手机很多,第二数据通讯方便,理论可接N个节点(ESP8266可自建AP,软件上在个节点转发数据,故可组网数量&255个),第三更可以介入家用路由器通过互联网控制(由于需申请官方账号且控制都是设定的,不好改,在此就不说它),当然最主要一点就是模块便宜。&&&&&&&&但是使用wifi模块还是必须知道wifi建立、通讯的流程,不然没法用好它。其实在官方的模块指令介绍也写的很详细,下面把主要的几点写下:wifi模块的STA、AP模式使用、TCP/UDP传输方式使用,另外说下透传模式(实质就是变成一个无线串口)。&&&&&&&&首先STA模式是接入到别人的无线热点里(或无线路由器),AP则是自身变成一个无线热点,别人接进来,最大可接5个。ESP8266两个模式可并存或只用一种模式,AP模式下很费电,注意ESP8266内部无路由功能(不用指望它能代替路由器提供上网)。[attachment=7224407]&&&&&& AP模式开启只需发送AT+CWMODE=2即可(AT+CWMODE=3表示AP、STA模式同时开),此时接入到此AP的手机或wifi模块之间是不能互相访问的,也就是相互间收发不了数据,所以这个AP模式也只能开个热点让其它设备接入进来,所有的通讯只能是建AP的这个wifi模块与接入到它的wifi设备间,若要实现更自由的网络通讯要么就搞个路由器别用这个AP,或者自己在软件里加数据转发部分;&&&&&& STA模式只需发送AT+CWMODE=1即可开启,此时需考虑此模块接入到那个wifi信号(SSID)那,若不明确则可以进行搜索(AT+CWLAP即可列出当前全部可用的wifi),此时收到串口数据会很大(wifi信号多的话约有600多字节),单片机串口数据处理需注意,通过串口发送”AT+CWJAP=SSID号,密码”即可加入,此时一般等20s左右会有回复,成功则收到OK,失败则是ERROR或Fail。简单梳理如下:&& AP模式:发送“AT+CWMODE=2”开启AP,默认情况下它的AP地址为192.168.4.1,注意不要与STA的IP地址同一网段(第三位不一样即可,如192.168.5.X)&& STA模式:发送“AT+CWMODE=1”开启STA,若不明确要加入的SSID号或不确定SSID号是否可用,可以先发送AT+CWLAP列出当前全部可用wifi 的SSID,接着用”AT+CWJAP=SSID号,密码”即可进行接入,此时监测回复是否加入成功。&&&&&&一般在STA模式加入wifi失败则需主动开启AP模式等待其它wifi设备加入。第一次连好后,下次开机会自动连接,若无法连上可以发送“AT+CIPSTA?”查看是够有IP地址即可,STA的IP地址全为0表示为连上。新的模块时会自动建立AP,当手机接入后发送wifi的SSID及密码来自行切换到STA模式接入路由器。 &&&&&&TCP/UDP传输方式,两个各有好处,TCP特点是每次发送数据大些,安全可靠,但建立的要求条件多,响应随时性差些;UDP相对TCP没那么安全,它只管发出去,不管对方是否收到,不要求先检测目标地址随时可以发数据出去,数据量少。TCP需要一个作为服务器,一个作客户端,其中一个不在线则此连接断开,需再次建立连接后才可发送数据,例如对方突然断电或其他原因不在线将无法发送数据,发送数据灵活性低。开启UDP的方式需指定本地端口号及远程端口号,为了方便将端口号统一,UDP建立及收发数据如下:[attachment=7224408]&&&&&&先用CIPSTART建立一个UDP传输端口,例如:“AT+CIPSTART=1,&UDP&,&192.168.11.2&,”,目标地址是192.168.11.2,端口号4100.&&&&&&接着发送数据的长度,如数据是5字节则“AT+CIPSEND=5”,在串口收到“&”后发送数据即可,发完后会收到“SEND OK”。先建立UDP端口,再发送。&& 下面是发送函数:unsigned char UDPsend(unsigned char *p){&&&&&&&&unsigned char length=0,i=0;&&&&&&&&/********* 先发送数据长度 CIPSEND***********/&&&&&&&&if(Wifi_status&0x20)length=*p;&&//code的长度&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&else length=strlen(p);&&&&&&&&strcpy(SendNum,&AT+CIPSEND=&);&&&&&&&&//********* 将数字变为字符串接到SendNum数组后 *********//&&&&&&&&while(length!=0)&&&&&&&&{&&&&&&&&&&&&&&&&SendNum[29-i]=length%10+'0';//利用数组SendNum的29、28、27字节暂存数字变成的字符,此时数字的倒序的&&&&&&&&&&&&&&&&length/=10;i++;&&&&&&&&}&&&&&&&&length=11;&&&&&&&&while(i&0)//将上面转换的字符倒序&&&&&&&&{&&&&&&&&&&&&&&&&SendNum[length++]=SendNum[30-i];&&&&&&&&&&&&&&&&i--;&&&&&&&&}&&&&&&&&SendNum[length]=0;//加数组结束符&&&&&&&&Wifi_status &=0x7F;//关闭返校检测&&&&&&&&Judge_End=3;//////缩短结束判断,判断暂时缩短为3个周期&&&&&&&&CMD_W1(SendNum);//串口发送出去&&&&&&&&/************等待串口返回数据***********/&&&&&&&&while(i++&100)&&&&&&&&&&&&&&&&{if(Receive&0x04)//有数据&&&&&&&&&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//若返回了‘&’即0x3E表示可以发送&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&if(rbuffer[7+Receive_length]==0x20 && rbuffer[6+Receive_length]==0x3E)&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&{i=0;}&&&&&&&&&&&&&&&&&&&&&&&&else if(rbuffer[Len1+Receive_length-1]==0x20 && rbuffer[Len1+Receive_length-2]==0x3E)//两种判别&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&i=0;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&Receive&= 0xFB;//清零标志&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&&&&&delayms(5);&&&&&&&&&&&&&&&&}&&&&&&&&if(!i){//可以发送字节&&&&&&&&&&&& if(Wifi_status&0x20)&&&&&&&&&&&&&&&& {DataLength=*p; Wifi_status &= 0xDF;}&&&&&&&&&&&&&&&&CMD_W1(p);//串口发送出去&&&&&&&&&&&&&&&&DataLength=0;&&&&&&&&&&&&&&&&&&&&&&&&while(i++&200)&&&&&&&&&&&&&&&&&&&&&&&&&&{//send_date(Receive );///////////////////调试用&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&if(Receive&0x04)//有数据&&&&&&此处曾出现无法识别Receive&0x04,导致时间过长或死循环(编译器问题导致)&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&Receive&= 0xFB;//清零标志&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&if(rbuffer[Len1-3]=='K' && rbuffer[Len1-4]=='O')//返回OK表示以发完。由于之前写成Len导致死循环&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&{i=1;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&&&&&delay_1ms();&&&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&}&&&&&&&&else {i= 0;&&&&&&&&}&&&&&&&&Wifi_status |=0x80;//关闭返校检测&&&&&&&&Judge_End=18;/////恢复判断时长&&&&&&&&} &&&&&&&& 接收则很简单,只要本地端口号对,收到数据后ESP8266会主动发送数据到串口,单片机直接提取即可。以下是主函数的主循环里读取接收的数据(主体框架):while(1)&&&&{&&&&&&&&&&&&&&&&if(Len&Receive_length*2-100 && (Wifi_status&0x04)!=0)Len=0;//数据流过大清零&&&&&&&&&&&&&&&&&&&&&&&&&&if(Receive&0x04)//标记有数据时&&&&&&&&&& {&&&&&&&&&&&&&&&&//查找+IPD&&&&&&&&&&&&&&&&for(i=0;i&Len1;i++)&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&&&&&if(rbuffer[i+Receive_length]==0x2B && rbuffer[i+1+Receive_length]==0x49 && rbuffer[i+3+Receive_length]==0x44)&&&&&&&&&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&Cmd_start=Cmd_end=0;&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//先校验字符数量是否一致&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//第一字节是总数据长度,提取它&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&i += 5;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&while(rbuffer[i+Receive_length]!= ':' &&Cmd_end++&10)&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&Cmd_start=Cmd_start*10+rbuffer[i+Receive_length]-'0';&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&i++;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&if(Cmd_start==rbuffer[i+1+Receive_length]) //字节数量一致则有效&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&{ &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//先判断最后一字节的CRC校验码是否对,不对则舍弃数据&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&if(rbuffer[Cmd_end+Receive_length+4]==CRC8(rbuffer+Receive_length+Cmd_start,4+Cmd_end-Cmd_start))//计算校验码并且校验通过&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&{&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&if(rbuffer[Cmd_start+Receive_length+3]==Self)//是发给自己则分析数据&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//提取里面的控制指令并执行&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&else //转发出去&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&{//若不是发给自己的则将数据转发出去,以便最终的设备收到数据。&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&else&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//校验码不对舍弃本条指令&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&&&&&Receive&= ~0x04;//清零标志&&&&&&&&&&&&&&&&&&&&&&&&if(Len!=0 &&&&!(Receive&0x02)){Receive|=0x02;T2_period=0;TCNT2=0;}//数据读完后各重要寄存器清零&&&&&&&&&& }&&&&&&&&if(!(Wifi_status&0x08) &&&&!(Receive&0x02)){UDPstart(); Len=Len1=0;Receive &= 0xFB;}&&//若发现UDP处于未打开状态则自动开启&&&&&&&&&&delayms(50);//50ms为以周期监测、判断&&&&} &&&&&&无线透传。这是一个很实用的功能,虽然本次程序没用到,但还是简单说下,它是直接将wifi模块变成一个无线串口,前提是先设置好两方的端口号等。开启过程很简单,只要2个ESP8266能互相ping通就可使用。&&&&&&例如A处于AP模式,B是STA模式接到A模块上,假设此时A的AP IP地址为192.168.4.1,B的STA IP为192.168.4.2,则A的设置:AT+CIPSTART=&UDP&,&192.168.4.2&,,0AT+CIPMODE=1AT+CIPSEND&&&& B的设置:AT+CIPSTART=&UDP&,&192.168.4.1&,,0AT+CIPMODE=1AT+CIPSEND&&&&&&此外两者均需处于单链接模式AT+CIPMUX=0设置单链接模式,发送“+++”连续3个+终止透传,此时方可恢复正常操作,否则均将被当作数据发出去。&&&&&& 利用此功能可以将有线串口变为无线,比如可以无线下载STM32的程序、远程串口数据监视(数据量较大时)等。 三、数据解析及命令执行&&&&&& 一串控制指令可以以直白的文字或英文字母来表述,但不适用于大信息量的控制,比如要控制100个灯的不同亮度,是否需要像这样呢?-& LED1:25 LED2:40 LED3:70….(25表示25%亮度,其余同理)那得发送800个字节,或者分多次逐步发,所以就需考虑使用规约来,一串16进制数,按特定的格式放入数值,对方解析也是按此格式来。下面是个本程序里一个简化的规约,从简洁性及安全性上优化了下(其实主要是为了处理简单):[attachment=7224409]&&&&&&本质上主要是5部分:功能说明+要发给谁+要控制什么东西+怎么控制+数据校验(全部是以16进制数表示)&&&&&&如:06 01 09 01 FF 81,06有6个字节,01表示功能(自己定义),09表示第9个控制器,01表示这个控制器的第一个设备,FF表示全亮或开,81则是校验码。开始字节:表示这串指令有多长功能码:当前这个指令时什么用处,是为了读取设备状态还是遥控它。目标控制器地址:有的目标控制器地址不止控制一个设备,比如同时控制房间1的灯和房间2的灯。假如收到不是给自己的的命令则考虑丢掉或转发。被控设备地址:与上面的目标控制器地址是不同的,如上面的房间1的灯就是被控设备地址,此处假设为1,表示目标控制器里的第一个可控对象。写入的值:写入值为255(0xFF)表示全亮,0为灭,或者写入值不止一个字节,则可以搞定时之类的更多功能(如定时开关,则第一个字节表示定时多久关机、第二字节表示定时多久开机。若每个控制器能有准确的时钟则可以直接发送时间节点),完全靠自己去定义。CRC8校验:为了保证数据的可靠性将前面一串数据进行计算,其实可以采用和校验、CRC16、CRC32校验,为了节省单片资源最后折中选择CRC8。&&&&&&有了规约的“规定”,不仅处理数据清晰明了,且可靠性也提高了,同一个大网下基本不会出现误控。解析指令时则是按照这样的流程:先判断数据是否可用,校验是否对、长度是否对等;接着看是不是给自己的,不是则丢掉或转发;最后根据被控设备地址对其进行控制。&&&&&& 程序里也没什么需解释的,对串口里收到的数据逐个提取,其次是对不同的功能码可能会有不同长度的“写入值”(看怎么定义了),准确地控制好读取即可,不要识别错误即可,本来是读取功能码,却被程序当成地址读进去。程序里主要用了switch…case语句。 ●Android软件部分&&&&&& 安卓部分除了数据解析部分(和上面那个同样道理,按定义的规定解析或发出控制命令),就剩底层通讯及交互界面。&&&&&& 安卓方面我也是半路出家,只是在网上找资料学的点皮毛,系统性不强,以做这个手机控制端为目的去学的,不对之处只好让大家批评纠正了。&&&&&& 编译器是用eclipse,当然微软的VS也能编译安卓软件,没玩过。eclipse基础部分我也没必要说了,直接说主要的吧。&&&&&& 软件在打开后自动发指令搜索在线设备(IP X.X.X.255即可发往此网段内全部设备),也可手动切换被控设备,实现开启即用。有规约的控制即无需任何密码之类的繁琐操作。[attachment=7224410]&&&&&&利用socket通信,主要在udpthread.java里,try尝试建立UDP:public boolean ConnectSocket() {&&&&&&&&&&&&&&&&boolean result =&&&&&&&&&&&&&&&&try {&&&&&&&&&&&&&&&&&&&&&&&&if (rUdp == null) {&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&rUdp = new DatagramSocket(localPort);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&// System.out.println(& localport set ......&+localPort);/////////////////////&&&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&&&&&if (rPacket == null)&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&rPacket = new DatagramPacket(rBuffer, rBuffer.length);&&&&&&&&&&&&&&&&&&&&&&&&startThread();&&&&&&&&&&&&&&&&&&&&&&&&result =&&&&&&&&&&&&&&&&} catch (SocketException se) {&&&&&&&&&&&&&&&&&&&&&&&&DisConnectSocket();&&&&&&&&&&&&&&&&&&&&&&&&System.out.println(&open udp port error:& + se.getMessage());&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&&&&&} &&&&&& 接着是UDP发送数据,先用新开个DatagramSocket(发送数据的socket),再往sPacket填充数据及端口配置等:sPacket = new DatagramPacket(sBuffer,sBuffer.length,InetAddress.getByName(remoteIP),remotePort);&&&& 再调用类发送数据:sUdp.send(sPacket); sUdp.close();&&&& 发送数据后若未收到回复则会连续尝试3次,均无返回时则认为对方接收失败。&&&& 接收数据则是放入线程中处理:@Override&&&&&&&&public void run() {&&&&&&&&&&&&&&&&while (Thread.currentThread() == rthread) {&&&&&&&&&&&&&&&&&&&&&&&&try {&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&recvData();&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&vhandler.sendEmptyMessage(0);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&Thread.sleep(100);&&&&&&&&&&&&&&&&&&&&&&&&} catch (InterruptedException e) {&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&e.printStackTrace();&&&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&}&&&&&&&&}private void recvData() {&&&&&&&&&&&&&&&&int Len=0;&&&&&&&&&&&&&&&&try {&&&&&&&&&&&&&&&&&&&&&&&&rUdp.receive(rPacket);&&&&&&&&&&&&&&&&&&&&&&&&//传递接收的数据&&&&&&&&&&&&&&&&&&&&&&&&Len=rPacket.getLength();&&&&&&&&&&&&&&&&&&&&&&&&fBuffer = new byte[Len];&&&&&&&&&&&&&&&&&&&&&&&&System.arraycopy(rBuffer, 0, fBuffer, 0,Len);&&&&&&&&&&&&&&&&&&&&&&&&Data.setIndata(fBuffer);//传递值&&&&&&&&&&&&&&&&&&&&&&&&if (isRHex)&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&sRecvData = recvHexData(Len);&&&&&&&&&&&&&&&&&&&&&&&&else&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&sRecvData = new String(rPacket.getData(),0,Len,currentRCodes).trim();&&&&&&&&&&&&&&&&&&&&&&&&//System.out.println(sRecvData);//显示收到的数据, &&&&&&&&&&&&&&&&&&&&&&&&//显示 发送IP&&对方端口&&时间&&数据&&&&&&&&&&&&&&&&&&&&&&&&sRecvData = String.format(&[%s:%d]%s-%s&, rPacket.getAddress()&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&.getHostAddress(), rPacket.getPort(), sdf&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&.format(new Date()), sRecvData);&&&&&&&&&&&&&&&&} catch (IOException ie) {&&&&&&&&&&&&&&&&&&&&&&&&System.out.println(&recvdata error:& + ie.getMessage());&&&&&&&&&&&&&&&&&&&&&&&&// Toast.makeText(ct, &接收数据错误:& + ie.getMessage(),&&&&&&&&&&&&&&&&&&&&&&&&// Toast.LENGTH_LONG);&&&&&&&&&&&&&&&&}&&&&&&&&}&&&&&&在收到新数据后放到TEXT控件里,TEXT加入文字变化监测,当其中文字被刷新后就会产生一个事件,此时则可在其中处理收到的数据。界面部分则需要很多基础才行,为此找了很多网上资料,哪个控件适用哪个布局合理......。&&&& 比如上次做的手机风扇遥控界面,既然是手机界面控制,所以最好只需一个界面就能快捷操作所有必要的功能,而且简洁点好,所以加入了滑动条代替下拉菜单,档位直接选择,开机自动与风扇“握手”,并将手机时间下发到风扇控制单片机里,若风扇不在线则显示红色,调节时间用滑块不好设置,用按钮不是很直观,于是采用一个圆圈,顺时针沿着这个圆滑动则增加定时时间,逆时针则减少,通过判断手势运动的大致方向来决定,目前精度及加减速度还需进一步优化,加入滤波效果应该会更好。如下图:[attachment=7224411]&&&&&&上图圆圈会根据总定时时间与剩余时间的比值按比例缩减。自动模式下回根据晚上时间来调节是否开启(半夜凉时则关闭或进一步降低单位风量)。操作界面利用滑动代替按钮,省去了部分界面空间,且不同的工作模式下去掉不必要的按钮等。&&&&&& 如Period那上下滑动修改,在移动事件中监测手指移动到何处坐标,进行Period的增减:@Override&&&&&&&&public boolean onTouch(View arg0, MotionEvent arg1) {&&&&&&&&&&&&float y = arg1.getY(); &&&&&&&&&&&&&&&& switch (arg1.getAction()) {&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& case MotionEvent.ACTION_DOWN:&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//按下&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& timer_revisable=&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& case MotionEvent.ACTION_MOVE:&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//移动&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&if(y-y_last&8){if(period_T!=0)period_T--;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& period.setText(&&+period_T);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& //重新计算周期&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&period_T1=dutyratio*period_T/100;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&period_duty.setText(&周期风(/min)- Duty &+period_T1);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& y_last=y;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&else if(y_last-y&8){if(period_T!=255)period_T++;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&period.setText(Integer.toString(period_T));&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&period_T1=dutyratio*period_T/100;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&period_duty.setText(&周期风(/min)- Duty &+period_T1);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& y_last=y;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& case MotionEvent.ACTION_UP:&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//抬起&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& timer_revisable=&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& }&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&// TODO 自动生成的方法存根&&&&&&&&&&&&&&&&&&&&&&&&} &&&&&&&& 在发送数据后会等待对方返回数据,若连续发3次均无返回则认为对方无法收到。发送握手去测试部分:private void handshake() {&&&&&&&&&&&&&&&&//发送握手&&查询子站数据指令&&IP地址&&&&&&&&&&&&&&&&byte[] temp_data=new byte[255];//临时数组&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&temp_data[0]=11;temp_data[1]=0;temp_data[2]=0x45;&&&&&&&&&&&&&&&&temp_data[3]=T//对方地址码&&&&&&&&&&&&&&&&temp_data[4]=S//本机地址码&&&&&&&&&&&&&&&&temp_data[5]=Integer.valueOf(0x81).byteValue();&&&&&&&&&&&&&&&&//发送本机IP地址&&&&&&&&&&&&&&&&temp_data[6]=net_1;temp_data[7]=net_2;&&&&&&&&&&&&&&&&temp_data[8]=net_3;temp_data[9]=net_4;&&&&&&&&&&&&&&&&//其他数字temp_data[10]= 0x2c;temp_data[11]=0x5A;temp_data[12]=5;&&&&&&&&&&&&&&&&temp_data[13]= Integer.valueOf(0xA1).byteValue();&&&&&&&&&&&&&&&&temp_data[10]=Integer.valueOf(CRC8(temp_data,14)).byteValue();&&&&&&&&&&&&&&&&outdata=new byte[11];&&&&&&&&&&&&&&&&System.arraycopy(temp_data, 0, outdata, 0,11);//拷贝数据到发送缓冲区&&&&&&&&&&&&&&&&udp.setOutdata(outdata);&&&&&&&&&&&&&&&&new UdpSend(&&).start();&&&&&&&&&&&&&&&&receive_OK=0;//开启发送后返校&&&&&&&&} &&&&&& 定时器一直开启,在receive_OK&10时执行定时器里的程序,也就是直接将receive_OK赋值大于10则将不执行定时器里的程序,不过这样做操作虽方便,但是可能会增加系统的功耗。//定时器作用:发送完指令后等待返校(每3s一次) &&&&&&&&&&&&&&&&Timer Timer1 = new Timer();&&&&&&&&&&&&&&&&&& TimerTask task = new TimerTask() {&&&&&&&&&&&&&&&&@Override&&&&&&&&&&&&&&&&&&&&&& public void run() {&&&&&&&&&&&&&&&&&&&&&&&&if( receive_OK&10){&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&receive_OK++;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&if(receive_OK==2){//再发一次&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&udp.setOutdata(outdata);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&new UdpSend(&&).start();&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&else if(receive_OK&3){receive_OK=14;link_OK=&&&&&&&&&&&&&&&&&&&&&&&&&&&& //targetNo.setText(&×&);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//targetNo.setBackgroundColor(0xAAFF3333);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&new AnotherTask().execute(&×&);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&& }&&&&&&&&&&&&};其次多线程由于线程安全是不能够直接更新界面的控件,控件的更新须由主线程来完成。 不过也可通过Handler 这个对象来对主线程中的控件进行更新。 &&&&&& 下面是程序源码,不过若是真想自己做的话就没必要看它们了,理解总的思路自己做才能做得好:[attachment=7224481][attachment=7224501]&&&&&& 最后,单片机的程序其实只要性能满足要求,51、AVR等都可以,掌握程序原理就可以移植到任何单片机上(前提是会它的基本硬件使用),之前改装的那风扇游人说不值,但我觉得值,里面的控制部分稍改程序就可以控制其它220V的家用电器等,以上是个人愚见,希望对制作wifi控制类的东西有一点点参考价值。
赞助商链接
买了2866,还没试,楼主都总结经验了不过我感觉控制几个开关信号直接用2866的gpio就行了,不要再搞编解码那麻烦的狠
赞助商链接
专业大神,大赞
謝謝分享&&我是来顶贴的。
謝謝分享&&我是来顶贴的。
很不错的文章,下载收藏先
顶楼主大神,最近也在弄这玩意,多多交流
謝謝分享,通俗易懂,大略看了,值得以后“借鉴”!!!!!!!!!
優秀文章,这个厉害!
收藏先,有空也玩玩。
楼主辛苦,谢谢分享。
好多自制的啊,好厉害
好东西 顶!!一定要顶上去
我也想学安卓的上位机开发,主要玩玩蓝牙串口什么的,请问lz的自学资料能否分享一下
收藏先,学习下!
很不错的文章,下载收藏先
LZ我的个问题是为什么工业上不用wifi不是因为不好用,所以我觉得LZ可以考滤用zibee试试,然后多协议走wifi集中控制这样我觉得比较有感觉
優秀文章,谢谢分享。
刚好是我要找的资料! wifi模块+单片机+光耦
楼主厉害,对了可以搞个WiFi开关么?就是当与手机或者其他WiFi连接上的时候就接通开关,信号断开就断开开关。可以应用在汽车自动点火防盗上,路灯自动开关等等
高手.打算买个来玩玩.
感谢楼主,留个印,先收藏
真是精品的好东东呀!赞一个!!!!!!!
感谢楼主,先收藏
进来听课,精彩。
楼主说的很详细,好棒!
新人进来看看。感谢大神分享
求助,如果你看到了请联系我,我的qq:
楼主做的这个试验很值!!!
我用arduino直接写esp8266,就可以用手机控制,简单些
很有借鉴意义
这玩意太高大上了,仰望大神!
&&看你写得这么复杂...为毛还要单片机呢!!!!!!!!&& 那个WIFI芯片本身就有GPIO 输出&&你加个 74HC 系列的位电平芯片就可以扩展...
谢谢楼主,很有兴趣,水平不行,楼主的文章很有参考价值。
太牛逼了!
这是高端的,玩到这个程度,年收入要10万+吧
不错的。现在好像挺流行的
真不错.是下了功夫的,谢谢分享.
谢谢分享资料
看了一下文章,很厉害,学习一下
謝謝分享!优秀原创!支持LZ,有来有往!
谢谢分享写的很好
这篇文章对新手绝对有指导作用.谢谢楼主的无私分享
只能仰望, 无法理解。。&&
天哪,楼主是高人和好人啊,这样的好文章近来很少见到。谢谢楼主的无私。赠人玫瑰手有余香啊。
MARK一下,不错很详细。太长没看完,等用的时候再详读。好东西,太感谢了
大神,软硬兼施
谢谢楼主分享
谢谢学习了!
这都看的头晕眼花了,感觉好复杂,但是控制原理在自己头脑里却很清晰
查看完整版本: [--
Powered by
Time 0.083072 second(s),query:5 Gzip enabled}

我要回帖

更多关于 udp ping工具 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信