从零开始使用ESP8266+OLED打造智能时钟(网络校时+实时天气+天气预报)
目录
零、前言
一、材料准备
1、ESP8266(NodeMCU V3)
![在这里插入图片描述](https://img-blog.csdnimg.cn/096100171ea3420abd830e6afc2bc892.jpg?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5LiL6Zuq6L-Y5piv5LiL6Zuo,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
2、OLED(SSD1306)(四针脚,利用I2C通信)
![在这里插入图片描述](https://img-blog.csdnimg.cn/060b04e7c6104866897c1482b56a6430.jpg?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5LiL6Zuq6L-Y5piv5LiL6Zuo,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
3、杜邦线(我使用4根母对母)
![在这里插入图片描述](https://img-blog.csdnimg.cn/1749a3c646334e7fa83547cf6fef1d87.jpg?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5LiL6Zuq6L-Y5piv5LiL6Zuo,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
3、WiFi或者手机热点
温馨提示:不要打开WIFI6,不要打开5.0GHz频段温馨提示:不要打开WIFI6,不要打开5.0GHz频段温馨提示:不要打开WIFI6,不要打开5.0GHz频段
4.一台能上网的电脑
5、心知天气账号(免费版即可)(👉传送门)
二、开发环境配置
1、Arduino基础安装
(1)访问Arduino官网,下载Arduino IDE (2)接入开发板,查看端口是否可选,如果端口是灰色的,请查看文末的Q&A
2、安装ESP8266所需要的库
(1)打开 文件->首选项 (2)在附加开发板管理器网址里添加以下内容
https://arduino.esp8266.com/stable/package_esp8266com_index.json
(3)打开工具->开发板->开发板管理器,等待同步完成(由于网络原因,可能会失败,请多试几次) ![在这里插入图片描述](https://img-blog.csdnimg.cn/6c6b117923874056874097322eb711c8.PNG?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5LiL6Zuq6L-Y5piv5LiL6Zuo,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
(4)搜索esp8266并安装(由于网络原因,可能会失败,请多试几次) ![在这里插入图片描述](https://img-blog.csdnimg.cn/37f73cb69e8840448253d5143cd2aa3f.PNG?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5LiL6Zuq6L-Y5piv5LiL6Zuo,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
3、安装所需要的库
展示需要引入的头文件(其实装了太多,我也忘记那些是必须的了
#include //JSON解析
#include //WIFI
#include
#include
#include
#include //时间
#include
#include
三、ESP8266与OLED连接
OLED 显示模块ESP8266开发板GNDGVCC3VSCLD1SDAD2
注意图中杜邦线颜色 ![在这里插入图片描述](https://img-blog.csdnimg.cn/66ec42f05f564d50a379743f58b7b42c.jpg?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5LiL6Zuq6L-Y5piv5LiL6Zuo,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
![在这里插入图片描述](https://img-blog.csdnimg.cn/4ff90a98221f47ca8a9322961339dcd8.jpg?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5LiL6Zuq6L-Y5piv5LiL6Zuo,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
四、代码编写
//引入必要的头文件
#include
#include
#include
#include
#include
#include
#include
#include
WiFiUDP Udp;
unsigned int localPort = 8888; // 用于侦听UDP数据包的本地端口
//网络校时的相关配置
static const char ntpServerName[] = "ntp1.aliyun.com"; //NTP服务器,使用阿里云
int timeZone = 8; //时区设置,采用东8区
//保存断网前的最新数据
int results_0_now_temperature_int_old;
String results_0_now_text_str_old;
int results_0_daily_1_high_int_old;
int results_0_daily_1_low_int_old;
String results_0_daily_1_text_day_str_old;
//函数声明
time_t getNtpTime();
void sendNTPpacket(IPAddress &address);
void oledClockDisplay();
void sendCommand(int command, int value);
void initdisplay();
void connectWiFi();
void parseInfo_now(WiFiClient client,int i);
void parseInfo_fut(WiFiClient client,int i);
//
boolean isNTPConnected = false;
const unsigned char xing[] U8X8_PROGMEM = {
0x00, 0x00, 0xF8, 0x0F, 0x08, 0x08, 0xF8, 0x0F, 0x08, 0x08, 0xF8, 0x0F, 0x80, 0x00, 0x88, 0x00,
0xF8, 0x1F, 0x84, 0x00, 0x82, 0x00, 0xF8, 0x0F, 0x80, 0x00, 0x80, 0x00, 0xFE, 0x3F, 0x00, 0x00}; /*星*/
const unsigned char liu[] U8X8_PROGMEM = {
0x40, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00,
0x20, 0x02, 0x20, 0x04, 0x10, 0x08, 0x10, 0x10, 0x08, 0x10, 0x04, 0x20, 0x02, 0x20, 0x00, 0x00}; /*六*/
typedef struct
{ //存储配置结构体
int tz; //时间戳
} config_type;
config_type config;
WiFiClient clientNULL;
DNSServer dnsServer;
ESP8266WebServer server(80);
//----------WIFI连接配置----------
const char* ssid = "XXX"; // 连接WiFi名(此处使用XXX为示例)
const char* password = "12345678"; // 连接WiFi密码(此处使用12345678为示例)
// 请将您需要连接的WiFi密码填入引号中
//----------天气API配置----------
const char* host = "api.seniverse.com"; // 将要连接的服务器地址
const int httpPort = 80; // 将要连接的服务器端口
// 心知天气HTTP请求所需信息
String reqUserKey = "XXXXXX"; // 私钥
String reqLocation = "hangzhou"; // 城市
String reqUnit = "c"; // 摄氏/华氏
//----------设置屏幕----------
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE);
int sta = 0;
//----------初始化OLED----------
void initdisplay()
{
u8g2.begin();
u8g2.enableUTF8Print();
}
//----------用于获取实时天气的函数(0)----------
void TandW(){
String reqRes = "/v3/weather/now.json?key=" + reqUserKey +
+ "&location=" + reqLocation +
"&language=en&unit=" +reqUnit;
// 向心知天气服务器服务器请求信息并对信息进行解析
httpRequest(reqRes,0);
//延迟,需要低于20次/分钟
delay(5000);
}
void display_1(int results_0_now_temperature_int,String results_0_now_text_str);//声明函数,用于显示温度、天气
//----------获取3天预报(1)----------
void threeday(){
// 建立心知天气API当前天气请求资源地址
String reqRes = "/v3/weather/daily.json?key=" + reqUserKey +
+ "&location=" + reqLocation + "&language=en&unit=" +
reqUnit + "&start=0&days=3";
// 向心知天气服务器服务器请求信息并对信息进行解析
httpRequest(reqRes,1);
delay(5000);
}
void clock_display(time_t prevDisplay){
server.handleClient();
dnsServer.processNextRequest();
if (timeStatus() != timeNotSet)
{
if (now() != prevDisplay)
{ //时间改变时更新显示
prevDisplay = now();
oledClockDisplay();
}
}
}
void setup(){
Serial.begin(9600);
Serial.println("");
initdisplay();
// 连接WiFi
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_unifont_t_chinese2);
u8g2.setCursor(0, 14);
u8g2.print("Waiting for WiFi");
u8g2.setCursor(0, 30);
u8g2.print("connection...");
u8g2.sendBuffer();
connectWiFi();
Udp.begin(localPort);
setSyncProvider(getNtpTime);
setSyncInterval(300); //每300秒同步一次时间
}
time_t prevDisplay = 0; //当时钟已经显示
void loop(){
if (sta>=0 && sta 0)
; // 丢弃以前接收的任何数据包
Serial.println("Transmit NTP Request");
// 从池中获取随机服务器
WiFi.hostByName(ntpServerName, ntpServerIP);
Serial.print(ntpServerName);
Serial.print(": ");
Serial.println(ntpServerIP);
sendNTPpacket(ntpServerIP);
uint32_t beginWait = millis();
while (millis() - beginWait = NTP_PACKET_SIZE)
{
Serial.println("Receive NTP Response");
isNTPConnected = true;
Udp.read(packetBuffer, NTP_PACKET_SIZE); // 将数据包读取到缓冲区
unsigned long secsSince1900;
// 将从位置40开始的四个字节转换为长整型,只取前32位整数部分
secsSince1900 = (unsigned long)packetBuffer[40] |