零基础入门学用物联网(ESP8266) 第一部分 基础知识篇(六)

参考教程:https://www.bilibili.com/video/BV1L7411c7jw/?spm_id_from=333.1387.favlist.content.click

十、ESP8266应用技巧

1、ESP8266自动配网------WiFiManager库使用说明

(1)在开发物联网项目时,经常需要为ESP8266设置Wi-Fi,在以往的章节例程里,设置Wi-Fi的方法是通过修改程序中的内容来实现的,但是假如这是一个面向用户的产品,用户拿到产品后不可能通过修改程序设置Wi-Fi,因此需要有一个Wi-Fi配置流程,即使是不懂编程的用户,也能为产品设置Wi-Fi。

(2)以下是理想的Wi-Fi配置流程,为了实现该流程,可借助ESP8266的一个第三方库------WiFiManager库。

(3)Wi-Fi配置示例程序:

①预备程序:清理ESP8266储存的Wi-Fi连接信息。

ESP8266的Wi-Fi设置是储存在它的闪存系统中的,因此在启动ESP8266并连接Wi-Fi时,它都会尝试使用闪存系统中储存的信息来进行Wi-Fi连接

在开始介绍如何使用WiFiManager库来配置ESP8266的Wi-Fi设置前,首先需要清除ESP8266的Wi-Fi连接信息,这样才能看到WiFiManager库的工作效果,而WiFiManager类的resetSettings函数即可实现清除功能

运行以下示例程序,可以清除ESP8266的闪存中存储的Wi-Fi连接信息

cpp 复制代码
#include <ESP8266WiFi.h>          
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>         
void setup() {
  Serial.begin(9600);       
  WiFiManager wifiManager;  // 建立WiFiManager对象
  wifiManager.resetSettings(); // 清除ESP8266所存储的WiFi连接信息
  Serial.println("ESP8266 WiFi Settings Cleared");
}
void loop() {}

②示例程序:

创建WiFiManager类后,直接调用其成员函数autoConnect,就能实现ESP8266理想的Wi-Fi配置流程

autoConnect函数有两种重载形式:如果希望启动AP模式构建的Wi-Fi网络无密码,则函数参数只有一个,为Wi-Fi网络名字符串;如果希望启动AP模式构建的Wi-Fi网络有密码,则函数参数有两个,依次为Wi-Fi网络名字符串、Wi-Fi网络密码字符串

cpp 复制代码
#include <ESP8266WiFi.h>          
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>         
void setup() {
    Serial.begin(9600);       
    WiFiManager wifiManager;  // 建立WiFiManager对象
    // 自动连接Wi-Fi,如果连接不上,启动AP模式,Wi-Fi网络名为"AutoConnectAP"
    wifiManager.autoConnect("AutoConnectAP");
    // 如果希望启动AP模式构建的Wi-Fi网络带有密码,则可使用以下语句
    // wifiManager.autoConnect("AutoConnectAP", "00114514");
    
    // WiFi连接成功后将通过串口监视器输出连接成功信息 
    Serial.println(""); 
    Serial.print("ESP8266 Connected to "); Serial.println(WiFi.SSID());
    Serial.print("IP address:\t"); Serial.println(WiFi.localIP());
}
void loop() {}

2、ESP8266多任务处理------Ticker库使用说明

(1)ESP8266在运行过程中,只能一条线式的依次执行任务,但是在开发物联网项目时,可能需要ESP8266在执行某一任务的过程中,还能处理其它任务,比如使用ESP8266来控制电机运行的同时,还需要定时检查某一个引脚上连接按钮有没有被用户按下。为了解决以上问题,可以使用Ticker库(如果有《操作系统》的前置知识储备,以下介绍会更容易理解)。

(2)Ticker类提供了以下几个成员函数:

①attach函数:该函数用于创建任务,并设置其运行周期,需要注意一个Ticker对象只能对应创建一个任务,要想创建多个任务,需要先创建多个Ticker对象。

第一种重载形式有两个函数参数,第一个参数指定调用函数的时间间隔,单位为秒,第二个参数指定调用函数(无参函数)的函数名

第二种重载形式有三个函数参数,第一个参数指定调用函数的时间间隔,单位为秒,第二个参数指定调用函数的函数名,第三个参数是传递给调用函数的参数值(最多有一个,且数据类型局限于char、short、int、float、void*、char*)

②attach_ms函数:该函数用于创建任务,并设置其运行周期,需要注意一个Ticker对象只能对应创建一个任务,要想创建多个任务,需要先创建多个Ticker对象。

第一种重载形式有两个函数参数,第一个参数指定调用函数的时间间隔,单位为毫秒,第二个参数指定调用函数(无参函数)的函数名

第二种重载形式有三个函数参数,第一个参数指定调用函数的时间间隔,单位为毫秒,第二个参数指定调用函数的函数名,第三个参数是传递给调用函数的参数值(最多有一个,且数据类型局限于char、short、int、float、void*、char*)

③detach函数:该函数用于停止其对应的任务被调度运行,该函数无参数。

(3)基本操作示例:

①示例1:

1\]任务调度示意图: ![](https://i-blog.csdnimg.cn/direct/9f3d8acecdc246189fa77d8e791b67e0.png) \[2\]程序代码: ```cpp #include Ticker ticker;// 建立Ticker用于实现定时功能 int count; // 计数用变量 void setup() { Serial.begin(9600); pinMode(LED_BUILTIN, OUTPUT); ticker.attach(1, sayHi); } void loop() { // 用LED呼吸灯效果来演示,在Tinker对象控制下,ESP8266可以定时执行其它任务 for (int fadeValue = 0 ; fadeValue <= 1023; fadeValue += 5) { analogWrite(LED_BUILTIN, fadeValue); delay(10); } for (int fadeValue = 1023 ; fadeValue >= 0; fadeValue -= 5) { analogWrite(LED_BUILTIN, fadeValue); delay(10); } delay(3000); } // 在Tinker对象控制下,此函数将会定时执行 void sayHi(){ count++; Serial.print("Hi "); Serial.println(count); } ``` ②示例2: \[1\]任务调度示意图: ![](https://i-blog.csdnimg.cn/direct/3b7bb38aaea44a6c94b9fc3c94f07e45.png) \[2\]程序代码: ```cpp #include Ticker ticker;// 建立Ticker用于实现定时功能 int count; // 计数用变量 void setup() { Serial.begin(9600); pinMode(LED_BUILTIN, OUTPUT); ticker.attach(1, sayHi); } void loop() { // 用LED呼吸灯效果来演示,在Tinker对象控制下,ESP8266可以定时执行其它任务 for (int fadeValue = 0 ; fadeValue <= 1023; fadeValue += 5) { analogWrite(LED_BUILTIN, fadeValue); delay(10); } for (int fadeValue = 1023 ; fadeValue >= 0; fadeValue -= 5) { analogWrite(LED_BUILTIN, fadeValue); delay(10); } delay(3000); } // 在Tinker对象控制下,此函数将会定时执行 void sayHi(){ count++; Serial.print("Hi "); Serial.println(count); // 当定时调用了6次后,停止定时调用函数 if (count >= 6) { ticker.detach(); // 使用detach来停止ticker对象定时调用函数 Serial.print("ticker.detach()"); } } ``` ③示例3: \[1\]任务调度示意图: ![](https://i-blog.csdnimg.cn/direct/06e7fa3ae91c474498ececc841c9dec4.png) \[2\]程序代码: ```cpp #include Ticker ticker; int count; void setup() { Serial.begin(9600); pinMode(LED_BUILTIN, OUTPUT); ticker.attach(1, sayHi, 8); } void loop() { for (int fadeValue = 0 ; fadeValue <= 1023; fadeValue += 5) { analogWrite(LED_BUILTIN, fadeValue); delay(10); } for (int fadeValue = 1023 ; fadeValue >= 0; fadeValue -= 5) { analogWrite(LED_BUILTIN, fadeValue); delay(10); } delay(3000); } void sayHi(int hiTimes){ count++; Serial.print("Hi "); Serial.println(count); if (count >= hiTimes) { ticker.detach(); Serial.print("ticker.detach();"); } } ``` ④示例4: \[1\]任务调度示意图: ![](https://i-blog.csdnimg.cn/direct/ff28a3c4091d48baa5b23b98dec5828f.png) \[2\]程序代码: ```cpp #include Ticker ticker; Ticker buttonTicker; int count; void setup() { Serial.begin(9600); pinMode(LED_BUILTIN, OUTPUT); pinMode(D3, INPUT_PULLUP); ticker.attach(1, sayHi, 60); buttonTicker.attach_ms(100, buttonCheck); } void loop() { for (int fadeValue = 0 ; fadeValue <= 1023; fadeValue += 5) { analogWrite(LED_BUILTIN, fadeValue); delay(10); } for (int fadeValue = 1023 ; fadeValue >= 0; fadeValue -= 5) { analogWrite(LED_BUILTIN, fadeValue); delay(10); } delay(3000); } void sayHi(int hiTimes){ count++; Serial.print("Hi "); Serial.println(count); if (count >= hiTimes) { ticker.detach(); Serial.print("ticker.detach();"); } } void buttonCheck(){ if (digitalRead(D3) == LOW){ Serial.println("D3 Button Pushed..."); } } ``` (3)Ticker定时调用的函数必须要"短小精悍",简单来说就是不能消耗过多CPU资源,执行时间不能太长,否则可能引发难以预料的问题,那么假如需要ESP8266定时执行的操作较为复杂,就不能直接将该操作封装为Ticker定时调用的函数了,而是应该"另辟蹊径",可以在Ticker类定时调用的函数中增加计数逻辑,当计数值达到一定值时,意味着间隔时间到达一定值,主程序可以根据这个计数值调用需要定时执行的复杂操作,如下所示的示例程序正是运用了这种思想。 ```cpp #include #include #include #define URL "http://www.example.com" const char* ssid = "Zevalin_Computer"; const char* password = "00114514"; Ticker ticker; int count; void setup() { Serial.begin(9600); WiFi.mode(WIFI_STA); connectWifi(); ticker.attach(1, tickerCount); //每隔1s执行一次tickerCount函数 } void loop() { if (count >= 5){ //计数值达到5,说明已经间隔5s httpRequest(); //执行复杂的操作 count = 0; //计数值清零,准备下一次计时 } } void tickerCount(){ count++; //执行一次tickerCount函数,计数值加1 Serial.print("count = "); Serial.println(count); } void httpRequest(){ HTTPClient httpClient; httpClient.begin(URL); Serial.print("URL: "); Serial.println(URL); int httpCode = httpClient.GET(); Serial.print("Send GET request to URL: "); Serial.println(URL); if (httpCode == HTTP_CODE_OK) { String responsePayload = httpClient.getString(); Serial.println("Server Response Payload: "); Serial.println(responsePayload); } else { Serial.println("Server Respose Code:"); Serial.println(httpCode); } httpClient.end(); } void connectWifi(){ WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.print("."); } Serial.println(""); Serial.print("WiFi Connected!"); } ```

相关推荐
爱喝纯牛奶的柠檬2 小时前
STM32红外遥控解码,NEC协议驱动
单片机·嵌入式硬件
羽获飞2 小时前
从零开始学嵌入式之STM32——30.使用触发输入和从模式测量PWM信号的占空比
stm32·单片机·嵌入式硬件
技术民工之路3 小时前
Keil MDK 5.40:STM32 工程编译 + 调试完整教程
stm32·单片机·嵌入式硬件
ALex_zry3 小时前
物联网OTA升级系统设计:从固件分发到版本管理
c++·经验分享·物联网·跨平台
C^h3 小时前
RTthread消息队列学习
开发语言·算法·嵌入式
北京耐用通信4 小时前
工业级抗干扰!耐达讯自动化CC-Link IE转Modbus RTU网关,稳定运行,让数据不丢包
人工智能·科技·物联网·网络协议·自动化·信息与通信
ALex_zry4 小时前
C++ MQTT物联网通信实战:从入门到生产环境
java·c++·物联网
项目題供诗4 小时前
51单片机入门-直流电机(十四)
单片机·嵌入式硬件·51单片机
安庆平.Я5 小时前
STM32——FreeRTOS - 任务创建和删除 ~ 静态方法
stm32·单片机·嵌入式硬件