零基础入门学用物联网(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任务调度示意图:

2程序代码:

cpp 复制代码
#include <Ticker.h>
 
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任务调度示意图:

2程序代码:

cpp 复制代码
#include <Ticker.h>
 
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任务调度示意图:

2程序代码:

cpp 复制代码
#include <Ticker.h>
 
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任务调度示意图:

2程序代码:

cpp 复制代码
#include <Ticker.h>
 
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 <Ticker.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
 
#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!");   
}
相关推荐
JNX_SEMI10 小时前
EG2226 全桥驱动芯片技术解析:600V/1A 耐压、SSOP16 封装,助力逆变器与无刷电机驱动设计
单片机·嵌入式硬件·物联网
周周记笔记13 小时前
【元器件专题】用阻抗等效分析法来分析开关电路
单片机·嵌入式硬件
iCxhust13 小时前
如何利用iret修改cs ip
汇编·单片机·嵌入式硬件·微机原理·8088单板机
m0_3771081414 小时前
stm32平衡车
stm32·单片机·嵌入式硬件
Deitymoon16 小时前
FreeRTOS——列表与列表项
stm32·单片机·嵌入式硬件
总结所学16 小时前
电路定理 叠加定理 基尔霍夫定律
单片机·嵌入式硬件
Geometry Fu18 小时前
《物联网安全》第3.2章 无线传感器网络安全
物联网·安全·物联网安全·无线传感器网络·wsn
加成BUFF19 小时前
机器人专业2025年12月5日《嵌入式系统STM32》期末考试范围+试卷
stm32·嵌入式·期末复习
雪度娃娃19 小时前
存储器层次结构——随机访问存储器
单片机·嵌入式硬件·计算机组成原理
少年潜行20 小时前
ESP01S使用笔记05--ESP01S 进行 MQTT 通信 发送 JSON 字符串遇到的问题
单片机