ESP8266系列模块初始化成可以OTA,通过Web页进行升级(1)-Arduino中文社区 - Powered by Discuz! Archiver

wherestheway 发表于 2018-10-16 19:54

ESP8266系列模块初始化成可以OTA,通过Web页进行升级(1)

本帖最后由 wherestheway 于 2018-10-16 20:11 编辑

大家好,下面分享一下本人的一些经验。ESP8266系列模块(有ESP-01、ESP-12)具有WiFi功能,Arduino常常与之相连实现无线上网。其实,ESP8266系列模块不但具有WiFi功能,还具有MCU功能,可以对IO脚进行输入输出控制,完全可以替代Arduino模块。还可以通过域名直接访问(局域网内),实现Web页无线升级。升级界面:下面是代码:
/*
日期:2018.8.12
Arduino IDE 版本:1.8.6
ESP8266 for Arduino 版本:2.4.2
芯片:WeMos D1 mini功能:初始化芯片,使其具有Web Browser OTA升级功能,NTP时间获取   
通过h t t p://D1-mini.local/可以访问状态
通过h t t p://D1-mini.local/update可以进行OTA升级
*/#include <ESP8266WiFiMulti.h>
#include <WiFiUdp.h>
#include <ESP8266WebServer.h>
#include <ESP8266LLMNR.h>
#include <ESP8266HTTPUpdateServer.h>
#include<time.h>
#include <Ticker.h>
ADC_MODE(ADC_VCC);const char *host = "D1-mini";   //节点名,web update server hostname//数字输出管脚定义
byte board_led = 2;   //D1-mini板载灯脚,D4
//byte board_led = 1; //ESP-01板载灯脚// 获取NTP时间相关配置
unsigned int localPort = 2390;      // 本地端口,侦听UDP packets
IPAddress timeServerIP;            //时间服务器动态IP地址
//const char* ntpServerName = "time.nist.gov";//时间服务器域名
const char* ntpServerName = "cn.pool.ntp.org";//国内时间服务器域名
const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
unsigned long NTPtime;                //获取的NTP时间(秒)
unsigned long nowtime;                //实时时间(毫秒)
unsigned long savetime;               //获取NTP时间时,对应的系统时间(millis)
bool NTP_got = 0;                     //成功获取NTP时间,1为成功,0为失败
#define Detect_Interval   3000      // 检测周期,3秒
unsigned int next_Detect_Time;      //下次检测时间//创建对象Ticker slow_ticker;                     //用于板载灯慢闪烁控制
WiFiUDP udp;                              //获取NTP时间需要
ESP8266WebServer httpServer(80);      //用于web服务器
ESP8266HTTPUpdateServer httpUpdater;   //用于代码OTA更新
ESP8266WiFiMulti wifiMulti;             //多WiFi名称登陆void setup() {
    Serial.begin(115200);
    delay(10);
    Serial.println();
    Serial.println("D1 Initialize");
    //Serial.setDebugOutput(true);
    pinMode(board_led,OUTPUT);      //设置板载灯脚为输出状态
   
    digitalWrite(board_led,LOW);    //点亮板载灯(低电平有效),开始连接WiFi    //预置WiFi名称和密码,这样模块在家和单位就都可以使用了
    wifiMulti.addAP("WiFi名称", "密码");//家
    wifiMulti.addAP("WiFi名称", "密码");//单位
    //还可以再加,好像最多为6个
   
    wifi_conn();//连接WiFi
    //WiFi.printDiag(Serial);
}

void loop() {    nowtime = (millis()-savetime)/1000 + NTPtime;   //现在时间计算赋值

    // Handle http server.
    httpServer.handleClient();    //再次获得时间
    if( (millis() > next_Detect_Time && !NTP_got) || millis() < 250){
      //如果获取NTP时间失败,并累计超过3秒,再或模块系统时间清零,重新获取
      Serial.print("begin fetch NTP time again\r\n");   
      fetchNTPtime();
      next_Detect_Time = millis() + Detect_Interval;//设置下次检测时间
    }
   
    //在下面输入你的代码
    Serial.print("ESP.getVcc(): ");
    Serial.println(ESP.getVcc());    delay(2500);
}void fetchNTPtime(){//获取NTP时间//通过域名获取IP地址
WiFi.hostByName(ntpServerName, timeServerIP); sendNTPpacket(timeServerIP); // 调用这个函数,向时间服务器发请求
// wait to see if a reply is available
delay(1000);

int cb = udp.parsePacket();
if (!cb) {//没有接收到数据
    //Serial.println("no packet yet");
    NTP_got = 0;
}
else {//接收到数据    udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer    //从接收包第40个字节开始的4个字为节时间戳,先分别赋值到2 word
    unsigned long highWord = word(packetBuffer, packetBuffer);
    unsigned long lowWord = word(packetBuffer, packetBuffer);
    //合并4字节成长整型,这就是NTP时间(从1900.1.1开始的秒数)
    // this is NTP time (seconds since Jan 1 1900):
    unsigned long secsSince1900 = highWord << 16 | lowWord;
    //Serial.print("Seconds since Jan 1 1900 = " );
    //Serial.println(secsSince1900);    // now convert NTP time into everyday time:
    //Serial.print("Unix time = ");
    // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
    const unsigned long seventyYears = 2208988800UL;
    // subtract seventy years:
    NTPtime = secsSince1900 - seventyYears;
    NTPtime += 8 * 3600;//北京时间,东八区修正
    NTP_got = 1;
    //Serial.print("got NTP time\r\n");
    savetime = millis();//获得NTP时间的系统时刻
}    nowtime = (millis()-savetime)/1000 + NTPtime;    //打印小时、分钟和秒:
    Serial.print("The Beijing time is ");
    Serial.println(displaytime(nowtime));
}//发送NTP请求到指定IP地址的时间服务器
unsigned long sendNTPpacket(IPAddress& address)
{
//Serial.println("sending NTP packet...");
//将缓冲区里所有字节清零
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// 准备NTP请求数据
packetBuffer = 0b11100011;   // LI, Version, Mode
packetBuffer = 0;   // Stratum, or type of clock
packetBuffer = 6;   // Polling Interval
packetBuffer = 0xEC;// Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer= 49;
packetBuffer= 0x4E;
packetBuffer= 49;
packetBuffer= 52;// all NTP fields have been given values, now
// you can send a packet requesting a timestamp:
udp.beginPacket(address, 123); //NTP requests are to port 123
udp.write(packetBuffer, NTP_PACKET_SIZE);
udp.endPacket();
   
}void handleRoot() {
IPAddress local_ip;String message = "<!DOCTYPE HTML>";
message += "<html><head><meta charset=\"UTF-8\"><title>初始化芯片</title>";
message += "</head><body><div align=\"center\">";
message += "<div id=\"container\" style=\"width:600px\">";

message += "<div id=\"header\" style=\"background-color:#FFB3B3;\">";
message += "<h2 style=\"margin-bottom:0;\">D1-mini芯片连接成功!</h2></div>";
message += "<div id=\"hoststatus\" style=\"background-color:#FFE5E5;height:160px;width:600px;float:left;\"><form><br>";
message += "模块时间:";
message += displaytime(nowtime);
message += " 星期";
   switch (weekday(nowtime)){
   case 0 :
      message += "一";
      break;
   case 1 :
      message += "二";
      break;
   case 2 :
      message += "三";
      break;
   case 3 :
      message += "四";
      break;
   case 4 :
      message += "五";
      break;
   case 5 :
      message += "六";
      break;
   case 6 :
      message += "日";
   }

message += "<br><br><div id=\"SSID\">SSID:";
message += WiFi.SSID();
message += "</div><div id=\"IP_Address\">IP 地址:";
local_ip = WiFi.localIP();
for (uint8_t i=0; i<3; i++){
    message += local_ip;
    message += ".";   
}
message += local_ip;
message += "<br><br><a href=\"/update\">点击这里</a> 进入OTA升级界面";
message += "</div></div></body></html>";
    httpServer.send ( 200, "text/html", message );
}void handleNotFound(){
//digitalWrite(board_led, 1);
String message = "File Not Found\n\n";
message += "URI: ";
message += httpServer.uri();
message += "\nMethod: ";
message += (httpServer.method() == HTTP_GET)?"GET":"POST";
message += "\nArguments: ";
message += httpServer.args();
message += "\n";
for (uint8_t i=0; i<httpServer.args(); i++){
    message += " " + httpServer.argName(i) + ": " + httpServer.arg(i) + "\n";
}
httpServer.send(404, "text/plain", message);
//digitalWrite(board_led, 0);
}String displaytime(unsigned long nt)
{
    //显示日期,小时、分钟和秒:
    String dt;
    time_t nowtm;   
    struct tm *timeinfo;   
            //time( &nowtime );   
            //timeinfo = localtime( &nowtime );   
    nowtm = nt;
    timeinfo = localtime(&nowtm);
    int xtn = timeinfo->tm_year + 1900;   
    int xty = timeinfo->tm_mon + 1;   
    int xtr = timeinfo->tm_mday;   
    int xts = timeinfo->tm_hour;
    int xtf = timeinfo->tm_min;
    int xtm = timeinfo->tm_sec;    dt += xtn;
    dt += "-";
    dt += xty;
    dt += "-";
    dt += xtr;
    dt += " ";
    if (xts < 10 ) {
      // 前10小时加“ ”
      dt += ' ';
    }
    dt += xts;
    dt += ":";
    if (xtf < 10 ) {
      // 前10分加“0”
      dt += '0';
    }
    dt += xtf;
    dt += ":";
    if (xtm < 10 ) {
      // 前10秒加“0”
      dt += '0';
    }
    dt += xtm;    return dt;
}byte weekday(unsigned long nt)
{
    //显示星期数:周一为0,周二为1,周三为2,周四为3,周五为4,周六为5,周日为6
    byte wd;
    time_t nowtm;   
    struct tm *timeinfo;   
            //time( &nowtime );   
            //timeinfo = localtime( &nowtime );   
    nowtm = nt;
    timeinfo = localtime(&nowtm);
    int xtn = timeinfo->tm_year + 1900; //年份
    int xty = timeinfo->tm_mon + 1;   //月份
    int xtr = timeinfo->tm_mday;      //日
    int xtc = xtn / 100;                //世纪
    xtn = xtn % 100;                  //年数    if (xty < 3){   //如果是一月或二月,需要修正
      xtn --;
      xty += 12;
    }
      wd = (xtn + int(xtn * 0.25) + int(xtc * 0.25) - xtc * 2 + int((xty + 1) * 2.6) + xtr - 2) % 7;
    return wd;
}void led_blink(byte pin)
{ //指定pin脚改变其状态
bool state = digitalRead(pin);// 获得pin脚当前状态
digitalWrite(pin, !state);      // 设置pin脚为反
}void wifi_conn() {//进行WiFi连接
NTPtime = 8*3600;//给NTP时间赋初值
savetime = millis();
NTP_got = 0;
udp.begin(localPort);//连接UDP,获取NTP时间需要
      
// 开启 LLMNR responder
LLMNR.begin(host);                      //开启LLMNR域名解析
httpServer.on("/", handleRoot);         //调用主页面
httpServer.onNotFound(handleNotFound);//出错调用
   
// 开启 Web Update server.
httpUpdater.setup(&httpServer);
// 开启 HTTP server
httpServer.begin();
Serial.printf("HTTPUpdateServer ready! Open h t t p://%s.local/update in your browser\n", host);Serial.println("Wait for WiFi connection.");
   
// ... 给ESP10秒时间连接wifi.
unsigned long startTime = millis();
while (wifiMulti.run() != WL_CONNECTED && millis() - startTime < 10000)
{
      Serial.print(".");//如果没有连通向串口发送.....            
      delay(250);
}

// 检查连接状态
if(WiFi.status() == WL_CONNECTED)
{//如果WiFi连接成功
      Serial.print("IP address: ");
      Serial.println(WiFi.localIP());
      slow_ticker.attach(0.8, led_blink, board_led);//WiFi连接正常,板载灯闪烁
      fetchNTPtime();       //获取NTP时间
}
else
{//WiFi连接不成功
      Serial.println("wifi connect fail!");
      digitalWrite(board_led,HIGH);//WiFi连接失败,板载灯灭
}
}


模块启动时,板载灯点亮。WiFi连接成功后,板载灯闪烁;WiFi连接失败后,板载灯熄灭。



qqq351520 发表于 2020-12-10 21:44

哪复制的代码,中间多了很多多余的,影响下载
页: [1]
查看完整版本: ESP8266系列模块初始化成可以OTA,通过Web页进行升级(1)