第一次写博客有错误请大佬们见谅!其实我看网上有很多类似的Smart-config配网的贴子。但是如果是自己是做产品的让用户去用,用户一定不会希望每次断电开机之前都需要自己去配网,肯定希望自己连上去一次的WIFI的密码和名称能够被储存,下次开机时自动连接。
ESP8266智能配网是什么?
ESP8266的配网实际上就是把WIFI设置成为STA模式(即客户端模式)。原理,将手机端已连接的WIFI,输入密码后,广播,等待物联网模块接收后自动配网连接网络。
可能就会有人去问了,怎么样让自己的手机能将自己连上的WIFI信息广播给自己的ESP8266?
安信可公司的公众号就有配网的功能,关注安信可科技公众号,然后点击微信配网就可以将当前WIFI信息广播给esp8266了,esp8266的配置后文会讲。
首先我们得配置好ArduinoIDE,以及一些环境的配置,在这里推荐亲们看其他的,在此不做赘述。
void smart_config(){
WiFi.mode(WIFI_STA); //这里一定要将WIFI设置为客户端模式才能进行配网
WiFi.beginSmartConfig();//将esp8266设置为智能配网模式
Serial.println("Waiting for SmartConfig.");
while (!WiFi.smartConfigDone()) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("SmartConfig received.");
//Wait for WiFi to connect to AP
Serial.println("Waiting for WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("WiFi Connected.");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());//串口输出现在的IP地址
WiFi.mode(WIFI_AP_STA);//这里将模式设置回AP和STA双模式,不设置亲测也是可以的,但是不能只设置为AP模式,要不然联网后没办法连上互联网。
delay(5);
}
这时只需要打开自己手机的微信公众号进行智能配网就行了。强调一句,记得看esp8266串口输出的信息,有的时候微信配网会显示没有配置成功,自己看串口打印的消息才知道是否真的成功了。
EEPROM可以在不使用文件和文件系统的情况下用来固化一些数据,常见的比如用来保存SSID或是Password,保存用户名及密码,保存用户设置等数据,这样就可以不用每次都通过烧写程序来改变系统运行时的初值了。可以实现更复杂的应用。
Arduino for esp8266
中用的EEPROM其实是从外部flash中存储器最末尾开辟的4096字节空间,结合官方说明,我们每次操作写入的数据在4~4096字节之间;(及可操作的地址为0-4095)
使用EEPROM时,首先调用EEPROM.begin(size),size为需要读写的数据字节最大地址+1
使用EEPROM.write(addr,data)来写数据,参数分别为地址&数据,写数据后需要通过EEPROM.commit()或EEPROM.end()将数据保存到EEPROM;
使用EEPROM.read(addr)来读数据addr是要读取的地址;
调用#include
写完EEPROM之后一定要调用EEPROM.commit()来对上面的写操作进行保存!!! 要不然不掉电的时候依然能够正常的读出你当时写入的数值,但是掉电之后数据就复位了。(当时吃过很大的亏)
补充说明一下,由于调用的EEPROM是开辟的储存器尾部的地址所以完全不用担心之前程序会受到影响。
附上EEPROM的代码库 https://github.com/esp8266/Arduino/tree/master/libraries/EEPROM
接下来代码部分,我们要重新考虑一个问题,那就是写入的一个字节到底有多大,计算机当中的一个字节为8位,也就是一个字节最大能保存的数值为256。一个整型(int)的数必须得靠4个字节来保存。理解了这个之后,我们一般会用char来代表我们要储存得值,char数值一般为-128到127,按道理说是一个字节就能储存响应的字符,但是实际读取出来会变成乱码。因为我们用的Arduino IDE是基于JAVA开发的,它的编码方式决定了char必须两个字节来储存一个类型的值(记住就好)。
怎么样在Arduino当中更直观的来实现存储两个字节的char类型的值或者四个字节的int类型??
采用unino联合体能使代码更简洁直观
转换代码如下首先定义一个unino的代码块
union data //定义一个联合体
{
char a; //其中成员有 char 和两个字节的数组
byte b[2];
};
由于我们的WIFI的SSID和secret都是字符串的样子,所以我们要将String类型变成到联合体当中的char数组中去
data col[50];
void change(String name1){
for(int i = 0; i<name1.length();i++){
col[i].a = name1[i]; //将字符串的第i个char转换到联合体当中的char变量当中
}
}
然后我举一个例子怎么将一个char存入到EEPROM当中去
int num;
change("1234"); //将要转换的字符串转换到数组当中去
for(int i = 0 ;i < "1234".length();i++) //这个字符串的长度循环
for(int k = 0; k<2;k++) //两个字节保存一个char,所以循环两次
{
EEPROM.write(num+addr, col[i].b[k]); //col为要储存的自己变量名,num+addr是要储存的地址
num++; //每次要增加一个字节的地址去储存下一个字节
//建议这里延时一会儿,不延时可能会出问题
}
EEPROM.commit(); //一定要记得!!!!!!要不然断电丢失
相信大家看到这里差不多知道怎么样去储存一个字符串了,读取一个字符串就是和这个代码差不多的功能,我就不写了。
最后附上我写的代码(写得不是很好,有错误希望大佬们指正)
#include
#include
char get_ssid[50]; //从EEPROM中读取得到的SSIDchar类型数组
char get_psk[30]; //从EEPROM中读取得到的WIFI密码
#define addr 200 //这个地址可以随意设置,如果用本程序则不能设置为小于50以下的值(为读取密码字符串预留空间)
int m ; //读取字符串长度的缓冲变量
union data //定义一个联合体数据类型
{
char a;
byte b[2];
};
data col[50]; //两个缓存联合体用来分别用来读取 WIFI密码和名称
data col_2[50];
//两个用来分别转换字符串的数组
void change(String name1){
for(int i = 0; i<name1.length();i++){
col[i].a = name1[i];
}
}
void change_2(String name1){
for(int i = 0; i<name1.length();i++){
col_2[i].a = name1[i];
}
}
//智能配网
void smart_config(){
WiFi.mode(WIFI_STA);
WiFi.beginSmartConfig();
Serial.println("Waiting for SmartConfig.");
while (!WiFi.smartConfigDone()) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("SmartConfig received.");
//Wait for WiFi to connect to AP
Serial.println("Waiting for WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("WiFi Connected.");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
WiFi.mode(WIFI_AP_STA); //亲测不写也行
delay(5);
}
//初始化相关硬件
void setup() {
Serial.begin(115200);
EEPROM.begin(512); //申请512个缓存字节
//首先判断是否之前已经缓存了一个WIFI密码和名称,如果没有则进行智能配网,并将WIFI信息进行储存
if(EEPROM.read(addr+29)==0 ||EEPROM.read(0)==0){
smart_config();//智能配网
change(WiFi.SSID()); //将WIFI的名称和密码转换到缓存数组当中去
change_2(WiFi.psk());
for(int h = 0 ;h<WiFi.SSID().length();h++) //将名称一个字节一个字节缓存进EEPROM里面
{
for(int k = 0 ;k <2;k++){
EEPROM.write(m+addr, col[h].b[k]);
m++; //m为字符串的个数
}
}
EEPROM.write(addr+29,m); //将WIFI名称的长度写入到存储到EPRROM里面,将用来前面的判断是否之前存储过WIFI
m=0; //将缓存清0
for(int h = 0 ;h<WiFi.psk().length();h++) //同理 密码
{
for(int k = 0 ;k <2;k++){
EEPROM.write(4+m, col_2[h].b[k]);
m++;
}
}
//Serial.println("写入m得值为:"+m);
EEPROM.write(0,m); //同理写入密码的长度
EEPROM.commit(); //不要忘记储存!!!!
}
else //如果之前已经储存过密码则对其进行读取
{
int n = 0;
for(int i =0 ; i<(int)EEPROM.read(addr+29);i++){
if(i%2==0){
col[30+n].b[0] = EEPROM.read(addr+i);
delay(100);
}
else
{
col[30+n].b[1] = EEPROM.read(addr+i);
Serial.print((char)col[30+n].a);
get_ssid[n] = (char)col[30+n].a ;
n++;
delay(100);
}
}
n = 0;
for(int i =0 ; i<(int)EEPROM.read(0);i++){
if(i%2==0){
col_2[30+n].b[0] = EEPROM.read(4+i);
delay(100); //读取的时候记得延时合理的时间
}
else
{
col_2[30+n].b[1] = EEPROM.read(4+i);
Serial.print((char)col_2[30+n].a);
get_psk[n] = (char)col_2[30+n].a ;
n++;
delay(100);
}
}
String SSID_S(get_ssid);
String psk_s(get_psk);
Serial.println("字符串ssid: "+SSID_S);
Serial.println("字符串secret: "+psk_s);
WiFi.begin(&SSID_S[0], &psk_s[0]);
//WiFi.begin(ssid);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
}
void loop() {
// put your main code here, to run repeatedly:
}
这样就可以每次都不用自己都要配网什么的了!希望对大家有帮助,第一次写博客记录一下。各位,原创不易,如果对各位有帮助希望能给个赞!