一、项目介绍
本项目使用了乐鑫公司的ESP-S2-Mini-1模块,这是一颗通用型Wi-FiMCU模组,功能强大,具有丰富的外设接口,可用于可穿戴电子设备、智能家居等场景。系统款图如下:
在本次“2022寒假在家练”活动中,本人选择的是项目6 制作一个本地气象台/温度计
-
利用OLED显示
-
显示当前本地的时间、温度和气象信息
制作过程中主要使用到了模块的三个核心功能:
-
基于ESP32-S2 WiFi核心模块
-
128*64 OLED显示,SPI接口,显示信息、参数、波形
-
4个按键,用于参数控制、菜单选择
二、设计思路
1.利用ESP32-S2 WiFi核心模块使板载接入到网络之中;
2.利用WiFi功能接入API接口获取网络的IP地址和本地的气象信息;
3.利用NTP更新板载的RTC;
4.通过按键来切换OLED上的信息。
三、使用方法
将WiFi名称和密码更改即可。
按下按键1可以查看不同的信息(具体可以跳转到六、实现的功能)。
const char *ssid = "****"; //wifi名称
const char *password = "*****"; //wifi密码
四、软硬件
1.软件
本项目主要使用到的是ArduinoIDE,安装链接。
配置ESP32的教程。
2.硬件
乐鑫公司的ESP-S2-Mini-1模块。ESP32-S2-MINI-1采用PCB板载天线,模组配置了4MB SPI flash,采用的是 ESP32-S2FN4 芯片。该芯片搭载了Xtensa® 32 位LX7 单核处理器,工作频率高达 240 MHz。用户可以关闭 CPU 的电源,利用低功耗协处理器监测外设的状态变化或某些模拟量是否超出阈值。ESP32-S2-FH4 还集成了丰富的外设接口。
五、设计详述
1.OLED显示
本项目使用的是U8g2库,U8g2是一个嵌入式设备的单色图形库,其兼容多种多样的显示控制器,即兼容性良好。
通过查阅资料可以知道电子森林在这个板载上使用的是SSD1306驱动的OLED显示屏,根据资料对上相应的管脚号,这里的cs一般默认接地,所以本人就没有用一个明确的管脚号。
考虑到项目中将使用到大量的重复的U8g2库的函数,本人决定对U8g2库进行进一步的小封装,具体封装如下:
#include "Oled.h"
U8G2_SSD1306_128X64_NONAME_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 36, /* data=*/ 35, /* cs=*/ -1, /* dc=*/ 33, /* reset=*/ 34);
void Oled_init()
{
u8g2.begin();
u8g2.enableUTF8Print(); // enable UTF8 support for the Arduino print() function
}
void Oled_show_char(short int x,short int y,const char *massage)
{
u8g2.setCursor(x, y);
u8g2.print(massage);
}
void Oled_show_string(short int x,short int y,String massage)
{
u8g2.setCursor(x, y);
u8g2.print(massage);
}
具体使用的案例如下:
void Oled_show_now_weather()
{
// Serial.println("oled begin");
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_wqy14_t_gb2312 ); //9
Oled_show_string(22, 12, "当前气象信息");
Oled_show_string(34, 36, "天气:");
Oled_show_char(74,36,weather);
Oled_show_string(34, 58, "温度:");
Oled_show_char(74,58,temperature);
Oled_show_string(90, 58, "℃");
u8g2.sendBuffer();
// Serial.println("oled end");
}
2.接入API获取IP地址
对于IP地址的获取,本人经过查阅和学习资料后,选择了接入API接口来获取所连网络的IP地址,具体使用的是bilibili的API,实现代码如下:
void Http_get_ip()
{
short int http_code;
ip_req = "https://api.live.bilibili.com/client/v1/Ip/getInfoNew";
Serial.println(ip_req);
while (1)
{
if (http_ip_client.begin(ip_req))
{
Serial.println("Http_get_ip setUp done!");
}
http_code = http_ip_client.GET();
Serial.println(http_code);
if (http_code > 0)
{
Serial.printf("HTTP get code: %d\n", http_code);
if (http_code == HTTP_CODE_OK)
{
ip_rsp = http_ip_client.getString();
Serial.println(ip_rsp);
break;
}
else
{
Serial.printf("fail to get ip,code:%d\n", http_code);
}
}
}
}
3.接入API获取气象信息
对于气象信息,同样可以通过接入API接口来获取相应的信息,这里选择的是心知天气的API,以此来获取当前和今天的气象信息,实现代码如下:
void Http_get_now_weather()
{
short int http_code;
now_weather_req = (String)host + "/v3/weather/now.json?key=";
now_weather_req += apiKey;
now_weather_req += "&location=";
now_weather_req += ip;
now_weather_req += "&language=zh-Hans&unit=c";
Serial.println(now_weather_req);
while(1)
{
if (http_weather_client.begin(now_weather_req))
{
Serial.println("Http_get_now_weather setUp done!");
}
http_code = http_weather_client.GET();
Serial.println(http_code);
if (http_code > 0)
{
Serial.printf("HTTP get code: %d\n", http_code);
if (http_code == HTTP_CODE_OK)
{
now_weather_rsp = http_weather_client.getString();
Serial.println(now_weather_rsp);
break;
}
else
{
Serial.printf("fail to get cityWeather,code:%d\n", http_code);
}
}
}
}
void Http_get_daily_weather()
{
short int http_code;
daily_weather_req = (String)host + "/v3/weather/daily.json?key=";
daily_weather_req += apiKey;
daily_weather_req += "&location=";
daily_weather_req += ip;
daily_weather_req += "&language=zh-Hans&unit=c";
daily_weather_req += "&start=0&days=1";
Serial.println(daily_weather_req);
while(1)
{
if (http_weather_client.begin(daily_weather_req))
{
Serial.println("Http_get_daily_weather setUp done!");
}
http_code = http_weather_client.GET();
Serial.println(http_code);
if (http_code > 0)
{
Serial.printf("HTTP get code: %d\n", http_code);
if (http_code == HTTP_CODE_OK)
{
daily_weather_rsp = http_weather_client.getString();
Serial.println(daily_weather_rsp);
break;
}
else
{
Serial.printf("fail to get cityWeather,code:%d\n", http_code);
}
}
}
}
4.通过NTP同步时间
对于时间,可以利用网络时间同步协议(NTP)来更新RTC,实现代码如下:
//如果获取本地时间失败,就开启联网模式,获取时间
if (!getLocalTime(&timeinfo))
{
Serial.println("Failed to obtain time");
WiFi.disconnect(false);
Wifi_connect();
configTime(8 * 3600, 0, NTP1, NTP2,NTP3);
return;
}
5.按键控制OLED显示信息
为了可以最大化的利用OLED屏幕,本人通过判断按键1的按键情况来显示不同的OLED信息,实现代码如下:
if(!Get_key(key1))
{
flag1 +=1;
Serial.println(flag1);
}
if(flag1 % 3 == 0)
{
Time_get();
Oled_show_time();
}
else if(flag1 % 3 == 1)
{
Oled_show_now_weather();
}
else
{
Oled_show_daily_weather();
}
六、实现的功能
1.显示实时时间和所在地
通过代码输入网络的名称和密码并联网成功后,可以不断更新并显示现在的时间,同时也会根据网络来判断和显示现在的城市。
2.显示现在的气象信息
通过 按下按键1 可以切换OLED屏幕,以此来查看现在的气象信息: 天气和温度。
3.显示今天的气象信息
在 2.显示现在的气象信息 的基础上 再次按下 按键1,可以查看今天的气象信息:白天和夜晚的天气、今日的最低和最高温度,以及今日的风向和风力等级。
4.再次显示实时时间和所在地
再次按下按键1 可以回到最开始的界面。
七、主要难题
1.ArduinoIDE配置Esp32失败
在配置过程中遇到了下载速度慢和配置之后无法编译的问题,最终本人总结出了解决的办法。
2.请求网络时间失败
对于网络时间,本人一开始的想法是通过API不断的请求以此来频繁地更新时间并将其显示在OLED上,结果发现请求过于频繁后就无法在更新时间,所以就需要另辟蹊径,选择使用NTP来完成项目。