在項(xiàng)目中朝刊,有時(shí)我們需要很多的代碼残炮。如果將這些代碼全部都存放于一個(gè)文件中负懦,那么該文件將會(huì)過長筒捺,因此我們可以將 Arduino 代碼進(jìn)行拆分,存放于多個(gè)文件中纸厉。而一些可能以后會(huì)服復(fù)用到的文件系吭,也可以直接將文件粘貼過來,而不需要修改颗品,就可以使用肯尺。
比如,我們?cè)谑褂?Esp8266 系列的時(shí)候躯枢,經(jīng)常需要將 Esp8266 聯(lián)網(wǎng)则吟,而在以前,我們是將 WiFi 信息在代碼中寫死的锄蹂。如果想要將 WiFi 設(shè)置為配置式氓仲,可參考 http://www.reibang.com/p/5dc724e39fd1 這篇文章。但是這里代碼很長得糜,如果我們?cè)谶@里進(jìn)行修改敬扛,以后再其他項(xiàng)目中還需要進(jìn)行修改。所以我們可以將配置 WiFi 這一功能朝抖,做成一個(gè)通用的模塊啥箭,這樣我們就可以將其通用化,以后隨用隨取治宣,不必另行修改急侥。
比如我們一個(gè)很簡單的 Blink 代碼:
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
}
// the loop function runs over and over again forever
void loop() {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
總共不超過 10 行,而配置 WiFi 的代碼就將近 300 行侮邀,將兩者合并到一個(gè)文件中缆巧,不僅主業(yè)務(wù)流程讀起來不清晰,還不方便進(jìn)行修改豌拙。
而我們可以將文章中配置 WiFi 的代碼稍作修改陕悬,存儲(chǔ)于一個(gè)獨(dú)立的文件中,以后不管哪個(gè)項(xiàng)目中需要使用按傅,只需要將此文件拷貝到相應(yīng)的項(xiàng)目文件夾中就可以使用了捉超。
WiFi 配置代碼修改如下:
//聲明
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <EEPROM.h>
#include <ESP8266mDNS.h>
int EPPROM_Address = 512;
// WiFi,可以寫入在這里預(yù)先輸入自己最常用的 WiFi 信息唯绍,也可以設(shè)置為空字符串
String WiFi_SSID = "";
String WiFi_Password = "";
//Ap 設(shè)置熱點(diǎn)信息
const char* AP_Host = "esp8266";
const char* AP_SSID = "Esp8266AP";
const char* AP_Password = "12345678";
// web
String webContent;
int webStatusCode;
String wifiScanContent;
ESP8266WebServer WebServer(80);
void initWiFi() {
EEPROM.begin(EPPROM_Address);
readWiFiInfoFromEEPROM();
bool connectStatus = tryToConnectToWiFi();
if (connectStatus)
{
createConnectedWeb();
}
else
{
ScanNetwork();
SetupToAPMode();
connectStatus = tryToConnectToWiFi();
}
WebServer.begin();
delay(100);
}
void wifiTask() {
WebServer.handleClient();
}
/********* 從存儲(chǔ)器中讀取 WiFi 信息 ***************/
void readWiFiInfoFromEEPROM()
{
//--- 從 EEPROM 中讀取 WiFi 的 SSID 和密碼
//--- 讀取 wifi ssid
WiFi_SSID = "";
for (int i = 0; i < 32; ++i)
{
WiFi_SSID += char(EEPROM.read(i));
}
delay(100);
//--- 讀取 wifi 密碼
WiFi_Password = "";
for (int i = 32; i < 96; ++i)
{
WiFi_Password += char(EEPROM.read(i));
}
delay(100);
}
/********* 嘗試連接 WiFi ***************/
bool tryToConnectToWiFi()
{
WiFi.mode(WIFI_STA);
WiFi.begin(WiFi_SSID.c_str(), WiFi_Password.c_str());
delay(100);
// WiFi 連接需要時(shí)間拼岳,因此這里相當(dāng)于持續(xù)檢測 10 秒
int times = 0;
while ( times < 10 ) {
if (WiFi.status() == WL_CONNECTED) {
return true;
}
delay(1000);
times++;
}
return false;
}
/********* 設(shè)置為 AP 模式 ***************/
void SetupToAPMode() {
WiFi.mode(WIFI_AP);
WiFi.softAP(AP_SSID, AP_Password, 6, 0);
createApModeWeb();
//貌似 dns 不生效
if (MDNS.begin(AP_Host))
{
MDNS.addService("http", "tcp", 80);
}
}
/********* 創(chuàng)建 AP 模式網(wǎng)頁 ***************/
void createApModeWeb()
{
//加載網(wǎng)頁
WebServer.on("/", []() {
IPAddress ip = WiFi.softAPIP();
webContent = "<!DOCTYPE HTML>";
webContent += "<html>";
webContent += "<title>WiFi 信息設(shè)置</title>";
webContent += "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">";
webContent += "<p>請(qǐng)輸入 WiFi 信息</p>";
webContent += wifiScanContent;
// 代表插入一個(gè)空格, 重復(fù)5個(gè)就是插入5個(gè)空格
webContent += "<br>";
webContent += "<form method='get' action='setting'>";
webContent += "<table border=\"0\"><tr><td><label>SSID</label></td><td><input type=\"text\" placeholder=\"請(qǐng)輸入你要連接的 SSID\" name='ssid' maxlength=32 size=64></td></tr>";
webContent += "<tr><td><label>PASSWORD</label></td><td><input type=\"text\" placeholder=\"請(qǐng)輸入該 WiFi 密碼\" name='pass' maxlength=64 size=64></td></tr></table>";
// webContent += "<input type=\"button\" value=\"重新掃描網(wǎng)絡(luò)\" onclick=\"self.location.href='/rescannetwork'\">";
webContent += " <input type='reset' value=\"重設(shè)\"> <input type='submit' value=\"存儲(chǔ)\"></form></html>";
WebServer.send(200, "text/html", webContent); //200代表服務(wù)器狀態(tài)碼為 OK, text/html代表用html網(wǎng)頁類型, 不加這個(gè)會(huì)找不到網(wǎng)頁
});
WebServer.on("/setting", []() {
WiFi_SSID = WebServer.arg("ssid");
WiFi_Password = WebServer.arg("pass");
if (WiFi_SSID.length() > 0 && WiFi_Password.length() > 0)
{
if (WiFi_SSID.length() <= 32 && WiFi_Password.length() <= 64)
{
for (int i = 0; i < 96; ++i) {
EEPROM.write(i, 0);
}
for (int i = 0; i < WiFi_SSID.length(); ++i)
{
EEPROM.write(i, WiFi_SSID[i]);
}
for (int i = 0; i < WiFi_Password.length(); ++i)
{
EEPROM.write(32 + i, WiFi_Password[i]);
}
EEPROM.commit(); //EEPROM.write 并不會(huì)馬上寫入 EEPROM, 而是要執(zhí)行 EEPROM.commit()才會(huì)實(shí)際的寫入EEPROM
delay(50);
webContent = "存儲(chǔ)成功, 請(qǐng)按 RESET 鍵重新開機(jī)!";
webStatusCode = 200;
}
else {
webContent = "<p>輸入錯(cuò)誤!!! SSID 允許的最大長度為 32,PASSWORD 允許的最大長度為 64, 按上一頁重新輸入</p>";
webContent += "<input type=\"button\" value=\"上一頁\" onclick=\"self.location.href='/'\"></html>";
webStatusCode = 404;
}
}
else {
webContent = "<p>輸入錯(cuò)誤!!! SSID 和 PASSWORD 都不允許為空, 按上一頁重新輸入</p>";
webContent += "<input type=\"button\" value=\"上一頁\" onclick=\"self.location.href='/'\"></html>";
webStatusCode = 404;
}
WebServer.send(webStatusCode, "text/html", webContent);
});
}
/********* 掃描無線網(wǎng)絡(luò) ***************/
void ScanNetwork() {
WiFi.disconnect();
WiFi.mode(WIFI_STA);
delay(100);
int wifiCount = WiFi.scanNetworks();
// 將 WiFi 信息構(gòu)造成 html 格式
wifiScanContent = "<ol type=\"1\" start=\"1\">";
for (int i = 0; i < wifiCount; ++i)
{
// Print SSID and RSSI for each network found
wifiScanContent += "<table border=\"0\"><tr><td width=\"300px\">";
wifiScanContent += String(i + 1) + ". ";
wifiScanContent += WiFi.SSID(i);
wifiScanContent += " (";
wifiScanContent += WiFi.RSSI(i);
wifiScanContent += ")";
wifiScanContent += "</td><td width=\"200px\">";
byte encryption = WiFi.encryptionType(i);
wifiScanContent += getEncryptionTypeString(encryption);
wifiScanContent += "</td></tr>";
}
wifiScanContent += "</ol></table><br>";
}
String getEncryptionTypeString(byte type)
{
String str = "";
switch (type) {
case 2: str = "TKIP(WPA)"; break;
case 5: str = "WEP"; break;
case 4: str = "CCMP(WPA)"; break;
case 7: str = "NONE"; break;
case 8: str = "AUTO(WPA or WPA2)"; break;
default:
str = "";
}
return str;
}
void createConnectedWeb()
{
WebServer.on("/", []() {
webContent = "<!DOCTYPE HTML>";
webContent += "<html>";
webContent += "<title>WiFi 信息</title>";
webContent += "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">";
webContent += "<p>當(dāng)前 WiFi 信息</p>";
// webContent += wifiScanContent;
// 代表插入一個(gè)空格, 重復(fù)5個(gè)就是插入5個(gè)空格
webContent += "<br>";
webContent += "<table border=\"0\"><tr><td><label>當(dāng)前 SSID: </label></td>";
webContent += "<td><label>" + WiFi_SSID + "</label></td></tr>";
webContent += "<tr><td><label>當(dāng)前 IP 地址: </label></td>";
webContent += "<td><label>" + WiFi.localIP().toString() + "</label></td></tr></table>";
webContent += "</html>";
WebServer.send(200, "text/html", webContent);
});
}
**BLink 程序修改如下
void setup() {
//初始化 WiFi
initWiFi();
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
}
// the loop function runs over and over again forever
void loop() {
wifiTask();
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
只需要在 setup() 函數(shù)中添加一行 initWiFi() 况芒,在 Loop 中添加一行 wifiTask() 即可惜纸。
將上述 WiFi 文件復(fù)制到 Blink 項(xiàng)目文件夾內(nèi),重新打開 Blink 項(xiàng)目,即可加載耐版。