ESP8266-12F一键配网(SmartConfig)+EEPROM储存密码(基于ArduinoIDE)

ESP8266-12F智能配网

第一次写博客有错误请大佬们见谅!其实我看网上有很多类似的Smart-config配网的贴子。但是如果是自己是做产品的让用户去用,用户一定不会希望每次断电开机之前都需要自己去配网,肯定希望自己连上去一次的WIFI的密码和名称能够被储存,下次开机时自动连接。

	ESP8266智能配网是什么?		

ESP8266的配网实际上就是把WIFI设置成为STA模式(即客户端模式)。原理,将手机端已连接的WIFI,输入密码后,广播,等待物联网模块接收后自动配网连接网络。

无线配网手机端

可能就会有人去问了,怎么样让自己的手机能将自己连上的WIFI信息广播给自己的ESP8266?

安信可公司的公众号就有配网的功能,关注安信可科技公众号,然后点击微信配网就可以将当前WIFI信息广播给esp8266了,esp8266的配置后文会讲。

在这里插入图片描述

ESP8266- smartconfig配置代码及其操作

首先我们得配置好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串口输出的信息,有的时候微信配网会显示没有配置成功,自己看串口打印的消息才知道是否真的成功了。

ESP8266-eeprom的操作

EEPROM可以在不使用文件和文件系统的情况下用来固化一些数据,常见的比如用来保存SSID或是Password,保存用户名及密码,保存用户设置等数据,这样就可以不用每次都通过烧写程序来改变系统运行时的初值了。可以实现更复杂的应用。

EEPROM
EEPROM主要要注意几点

  • 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;

    扫描二维码关注公众号,回复: 11493919 查看本文章
  • 使用EEPROM.read(addr)来读数据addr是要读取的地址;

  • 调用#include <EEPROM.h>来使用EEPROM;

  • 写完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 <ESP8266WiFi.h>
#include <EEPROM.h>

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:

}

这样就可以每次都不用自己都要配网什么的了!希望对大家有帮助,第一次写博客记录一下。

猜你喜欢

转载自blog.csdn.net/weixin_45427925/article/details/107757139