赞
踩
在这篇文章中我将从头教大家如何自己做一个物联网的demo出来。这个demo对于初学者来说如果是一步步去探索的话真的挺费时间的,期间也会遇到各种各样的问题,这里呢我就把我自己探索的路子分享给大家(demo基于TCP/IP协议,只要配置正确不存在连不上网的问题,因为所有的网络都是支持TCP/IP的)
1.材料准备工作:
购买一块STM32开发板,一个ESP8266模块,杜邦线若干,租用一台阿里云服务器。
2.硬件连接:
ESP8266的VCC接3.3v(5v也还凑合,不至于烧坏)
ESP8266的GND接GND
ESP8266的TXD接板子USART的RXD引脚
ESP8266的RXD接板子USART的TXD引脚
RST引脚与IO_0引脚不需要控制,悬空即可
3.服务器准备
第一步:登陆阿里云官网租用一台服务器,我选用的是学生轻量应用服务器(9.5元每月),操作系统windows server2012R2
第二步:购买完成后会跳转轻量应用服务器的控制台页面,设置远程桌面:
我选用的是win10自带的远程连接工具:
通过账号密码连接桌面。
第三步:端口设置
如图,点击防火墙,为了方便我把TCP和UDP的所有端口都开放了。点击添加规则即可开放端口。
第四步:服务器端安装软件
我把我电脑的D盘通过映射网络驱动器的方式映射到服务器(配置很简单,百度一下你就知道),在服务器内可以直接把D盘的软件复制过去。这里我们需要JDK,eclips,如果后期想运行java web项目的话建议再安装一个tomcat,然后再安装一个MySQL数据库,安装的时候要勾上允许远程访问,端口默认3306就OK了。关于java环境的配置以及软件安装我就不写了,网上到处都是这方面的文章。
4.硬件端的代码编写
基本的原理参见我的上一篇博客(https://blog.csdn.net/naruhina/article/details/104211705),今天的代码与上篇博客的代码略有不同,加入了防TCP自己断掉的心跳包机制,每隔十秒发送一次,由定时器驱动。代码与说明详见上传的资源,这里只放主要代码.
#include "sys.h" #include "delay.h" #include "usart.h" #include "usart3.h" #include "common.h" #include "StaConfig.h" #include "timer3.h" /************************************************ 第一次测试完成日期:2020/2/7 第一次描述:通过USART3连接ESP8266的TX与RX。相关AT指令以及数据发送均通过USART3进行 主函数调用setClient设置为STAClient透传模式与阿里云服务器取得通信,通过在电脑上使用 串口助手发送字符串到串口1并在串口1中断服务函数内通过调用发送数据函数通过串口3发送给 ESP8266,然后再经由路由器发送到云服务器。云服务器端通过网络调试助手创建一个TCP SERVER 然后就可以向STM32发送数据了,接收到的数据由相应函数处理回显到串口调试助手内。 备注:发送成功后atk_8266_send_data函数返回了失败,但实际上发送成功,应该是第二个参数不对应 导致的,但无关紧要。并且程序内并没有调用退出透传的函数,重新烧录程序完成后掉一次电恢复一下。 心跳包机制尚未加入 ************************************************/ /************************************************ 第二次测试完成日期:2020/2/9 本次主要修改了发送数据受缓存影响的bug,以及与向服务器发送的时候没有0x0a,0x0d的bug。新增防止因长时间无操作的定时发送心跳包的功能,以及确定 后atk_8266_send_data函数无误,在透传模式下的返回值1是第二个参数不对应的误报,实际没任何错误。新增TCP Client 非透传模式 ************************************************/ int main(void) { u8 ipbuf[50]; delay_init(); //延时函数初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级 uart_init(115200); //串口初始化为115200 usart3_init(115200); //初始化串口3 TIM3_Int_Init(49999,14399);//5Khz的计数频率,计数到5000为1s setClient(ipbuf);//TCP Client 透传模式 //setClientNonPierce(ipbuf); while(1) { atk_8266_at_response(1); delay_ms(100); } }
#include "StaConfig.h" #include "common.h" /***********************************************************/ //第一次测试完工日期:2020/2/7 //作者:lht //2020/2/9 新增TCP Client 非透传模式 /***********************************************************/ void setClient(u8 *ipbuf)//设置ESP8266工作在STA模式的CLIENT设置并开启透传 { //printf("AT恢复出厂设置:%d\n",atk_8266_send_cmd("AT+RESTORE","OK",1000)); printf("AT测试:%d\n",atk_8266_send_cmd("AT","OK",500)); printf("设置为STA模式:%d\n",atk_8266_send_cmd("AT+CWMODE=1","OK",500));//设置为STA模式 printf("重启:%d\n",atk_8266_send_cmd("AT+RST","OK",500));//重启生效 delay_ms(1000); //延时3S等待重启成功 delay_ms(1000); delay_ms(1000); printf("连接到路由器:%d\n",atk_8266_send_cmd("AT+CWJAP=\"FAST666\",\"你的密码\"","OK",1000));//连接路由器 printf("设置单链接:%d\n",atk_8266_send_cmd("AT+CIPMUX=0","OK",3500)); atk_8266_get_wanip(ipbuf); printf("IP:%s\n",ipbuf); //端口号不要带引号,否则会有意想不到的错误。 printf("连接到服务器:%d\n",atk_8266_send_cmd("AT+CIPSTART=\"TCP\",\"服务器公网IP\",8086","OK",3000));//连接到SERVER printf("开启透传模式:%d\n",atk_8266_send_cmd("AT+CIPMODE=1","OK",3500));//开启透传模式 printf("开始透传:%d\n",atk_8266_send_cmd("AT+CIPSEND","OK",550));//开始透 } void setServer(u8 *ipbuf)//设置ESP8266工作在STA模式的SERVER设置 { //printf("AT恢复出厂设置:%d\n",atk_8266_send_cmd("AT+RESTORE","OK",1000)); printf("AT测试:%d\n",atk_8266_send_cmd("AT","OK",500)); printf("设置为STA模式:%d\n",atk_8266_send_cmd("AT+CWMODE=1","OK",500));//设置为STA模式 printf("重启:%d\n",atk_8266_send_cmd("AT+RST","OK",500));//重启生效 delay_ms(1000); //延时3S等待重启成功 delay_ms(1000); delay_ms(1000); printf("连接到路由器:%d\n",atk_8266_send_cmd("AT+CWJAP=\"FAST666\",\"你的密码\"","OK",1000));//连接路由器 printf("设置多链接:%d\n",atk_8266_send_cmd("AT+CIPMUX=1","OK",3500)); printf("开启服务器:%d\n",atk_8266_send_cmd("AT+CIPSERVER=1,8086","OK",2000)); atk_8266_get_wanip(ipbuf); printf("IP:%s\n",ipbuf); printf("开始传输:%d\n",atk_8266_send_cmd("AT+CIPSEND=3,25","OK",550));//开始透传 } void setClientNonPierce(u8 *ipbuf)//STA Client 非透传模式 { printf("AT测试:%d\n",atk_8266_send_cmd("AT","OK",500)); printf("设置为STA模式:%d\n",atk_8266_send_cmd("AT+CWMODE=1","OK",500));//设置为STA模式 printf("重启:%d\n",atk_8266_send_cmd("AT+RST","OK",500));//重启生效 delay_ms(1000); //延时3S等待重启成功 delay_ms(1000); delay_ms(1000); printf("连接到路由器:%d\n",atk_8266_send_cmd("AT+CWJAP=\"FAST666\",\"你的密码\"","OK",1000));//连接路由器 printf("设置单链接:%d\n",atk_8266_send_cmd("AT+CIPMUX=0","OK",3500)); atk_8266_get_wanip(ipbuf); printf("IP:%s\n",ipbuf); //端口号不要带引号,否则会有意想不到的错误。 printf("连接到服务器:%d\n",atk_8266_send_cmd("AT+CIPSTART=\"TCP\",\"服务器公网IP\",8086","OK",3000));//连接到SERVER //printf("开启透传模式:%d\n",atk_8266_send_cmd("AT+CIPMODE=1","OK",3500));//开启透传模式 printf("允许数据传输:%d\n",atk_8266_send_cmd("AT+CIPSEND=8","OK",550));//允许数据发送,每次最大8字节 }
#include "common.h" //4个网络模式 const u8 *ATK_ESP8266_CWMODE_TBL[3]={"STA模式 ","AP模式 ","AP&STA模式 "}; //ATK-ESP8266,3种网络模式,默认为路由器(ROUTER)模式 //4种工作模式 const u8 *ATK_ESP8266_WORKMODE_TBL[3]={"TCP服务器","TCP客户端"," UDP 模式"}; //ATK-ESP8266,4种工作模式 //5种加密方式 const u8 *ATK_ESP8266_ECN_TBL[5]={"OPEN","WEP","WPA_PSK","WPA2_PSK","WPA_WAP2_PSK"}; /// //usmart支持部分 //将收到的AT指令应答数据返回给电脑串口 //mode:0,不清零USART3_RX_STA; // 1,清零USART3_RX_STA; void atk_8266_at_response(u8 mode) { if(USART3_RX_STA&0X8000) //接收到一次数据了 { USART3_RX_BUF[USART3_RX_STA&0X7FFF]=0;//添加结束符 printf("%s",USART3_RX_BUF); //发送到串口 if(mode)USART3_RX_STA=0; } } //ATK-ESP8266发送命令后,检测接收到的应答 //str:期待的应答结果 //返回值:0,没有得到期待的应答结果 // 其他,期待应答结果的位置(str的位置) u8* atk_8266_check_cmd(u8 *str) { char *strx=0; if(USART3_RX_STA&0X8000) //接收到一次数据了 { USART3_RX_BUF[USART3_RX_STA&0X7FFF]=0;//添加结束符 strx=strstr((const char*)USART3_RX_BUF,(const char*)str); } return (u8*)strx; } //向ATK-ESP8266发送命令 //cmd:发送的命令字符串 //ack:期待的应答结果,如果为空,则表示不需要等待应答 //waittime:等待时间(单位:10ms) //返回值:0,发送成功(得到了期待的应答结果) // 1,发送失败 u8 atk_8266_send_cmd(u8 *cmd,u8 *ack,u16 waittime) { u8 res=0; USART3_RX_STA=0; u3_printf("%s\r\n",cmd); //发送命令 if(ack&&waittime) //需要等待应答 { while(--waittime) //等待倒计时 { delay_ms(10); if(USART3_RX_STA&0X8000)//接收到期待的应答结果 { if(atk_8266_check_cmd(ack)) { printf("ack:%s\r\n",(u8*)ack); break;//得到有效数据 } USART3_RX_STA=0; } } if(waittime==0)res=1; } return res; } //向ATK-ESP8266发送指定数据 //data:发送的数据 //ack:期待的应答结果,如果为空,则表示不需要等待应答 //waittime:等待时间(单位:10ms) //返回值:0,发送成功(得到了期待的应答结果) u8 atk_8266_send_data(u8 *data,u8 *ack,u16 waittime) { u8 res=0; USART3_RX_STA=0; u3_printf("%s\r\n",data); //发送数据,为了方便云服务器接收加入了回车换行符 if(ack&&waittime) //需要等待应答 { while(--waittime) //等待倒计时 { delay_ms(10); if(USART3_RX_STA&0X8000)//接收到期待的应答结果 { if(atk_8266_check_cmd(ack))break;//得到有效数据 USART3_RX_STA=0; } } if(waittime==0)res=1; } return res; } //ATK-ESP8266退出透传模式 //返回值:0,退出成功; // 1,退出失败 u8 atk_8266_quit_trans(void) { while((USART3->SR&0X40)==0); //等待发送空 USART3->DR='+'; delay_ms(15); //大于串口组帧时间(10ms) while((USART3->SR&0X40)==0); //等待发送空 USART3->DR='+'; delay_ms(15); //大于串口组帧时间(10ms) while((USART3->SR&0X40)==0); //等待发送空 USART3->DR='+'; delay_ms(500); //等待500ms return atk_8266_send_cmd("AT","OK",20);//退出透传判断. } //获取ATK-ESP8266模块的AP+STA连接状态 //返回值:0,未连接;1,连接成功 u8 atk_8266_apsta_check(void) { if(atk_8266_quit_trans())return 0; //退出透传 atk_8266_send_cmd("AT+CIPSTATUS",":",50); //发送AT+CIPSTATUS指令,查询连接状态 if(atk_8266_check_cmd("+CIPSTATUS:0")&& atk_8266_check_cmd("+CIPSTATUS:1")&& atk_8266_check_cmd("+CIPSTATUS:2")&& atk_8266_check_cmd("+CIPSTATUS:4")) return 0; else return 1; } //获取ATK-ESP8266模块的连接状态 //返回值:0,未连接;1,连接成功. u8 atk_8266_consta_check(void) { u8 *p; u8 res; if(atk_8266_quit_trans())return 0; //退出透传 atk_8266_send_cmd("AT+CIPSTATUS",":",50); //发送AT+CIPSTATUS指令,查询连接状态 p=atk_8266_check_cmd("+CIPSTATUS:"); res=*p; //得到连接状态 return res; } //获取Client ip地址 //ipbuf:ip地址输出缓存区 void atk_8266_get_wanip(u8* ipbuf) { u8 *p,*p1; if(atk_8266_send_cmd("AT+CIFSR","OK",500))//获取WAN IP地址失败 { ipbuf[0]=0; return; } p=atk_8266_check_cmd("\""); p1=(u8*)strstr((const char*)(p+1),"\""); *p1=0; sprintf((char*)ipbuf,"%s",p+1); } u8 atk_8266_chaxun(u8 *cmd,u16 waittime) { u8 res=0; USART3_RX_STA=0; u3_printf("%s\r\n",cmd); //发送命令 if(waittime) //需要等待应答 { while(--waittime) //等待倒计时 { delay_ms(10); if(USART3_RX_STA&0X8000)//接收到期待的应答结果 { USART3_RX_STA=0; printf("查询指令ack:%s\r\n",USART3_RX_BUF); break;//得到有效数据 } } if(waittime==0)res=1; } return res; }
5.服务器端
服务器端则是用Socket建立TCP连接并监听指定端口的信息,然后连接MySQL数据库把数据写进去。这里只放Socket部分,jdbc以及其他部分见上传的资源
package main; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; import DB.DBTool; import changeCode.ChangeToUtf8; /** * *双向通信,首先硬件端向服务器发送数据,然后服务器端在控制台输入响应敲回车发送给硬件端完成一次应答。 * */ public class DuplexTrans { public static void main(String[] args){ String sql; Socket socket = null; BufferedReader in = null; BufferedWriter out = null; BufferedReader br = null; try { //创建服务器端套接字:指定监听端口 ServerSocket server = new ServerSocket(8086); //监听客户端的连接 socket = server.accept(); //获取socket的输入输出流接收和发送信息 in = new BufferedReader(new InputStreamReader(socket.getInputStream())); out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); br = new BufferedReader(new InputStreamReader(System.in)); while (true) { //接收客户端发送的信息 String str = in.readLine(); str = ChangeToUtf8.toUTF8(str);//转换编码防止乱码 String str2 = ""; //如果客户端发送的是“end”则终止连接 if (str.equals("end")){ break; }else if(str.equals("heartBeat")) { }else {//非心跳包,发送反馈信息并写入数据库 System.out.println("客户端发来:" + str); sql = "insert into iottest(content) values(?)"; DBTool.update(sql, str); str2 = br.readLine(); // 读到\n为止,因此一定要输入换行符! out.write(str2 + "\n"); out.flush(); } } } catch (IOException e) { e.printStackTrace(); } finally { //关闭资源 if(in != null){ try { in.close(); } catch (IOException e) { e.printStackTrace(); } } if(out != null){ try { out.close(); } catch (IOException e) { e.printStackTrace(); } } if(br != null){ try { br.close(); } catch (IOException e) { e.printStackTrace(); } } if(socket != null){ try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
6.测试
在左边远程连接窗口内可以看到控制台中输出了fromStm32,它是从本地的串口调试助手输入到USART1然后在到USART3,而USART3连接我的ESP8266。右边串口调试助手收到的fromServer是在服务器的eclipse的控制台输入的,数据到达ESP8266后发送给串口3,再发送到串口1让串口调试助手显示信息。
我们再来看看此时云端数据库内有没有被写入信息:
可以看到服务器收到的信息已经被写入了云端的数据库
完整代码:https://download.csdn.net/download/naruhina/12146142
顺带一提,可以建一个web项目,2.5版本即可,代码调试完成后导出一个war包放到服务器端的Tomcat里运行,这样就不用在服务器端启动eclipse来看控制台输出了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。