利用arduino D1mini板子作为载体开发。本文的源程序代码链接放到最后。
1.OLED屏接口为I2C,4个引脚的,,0.96寸,128*64,
2.温度传感器:DS18b20
3.D1mini
先上图D1mini:
显示效果一屏:
#include
#include
#include
#include
#include
#include
#include
// time
#include // time() ctime()
#include // struct timeval
#include // settimeofday_cb()
#include "SH1106Wire.h"//or #include "SSD1306Wire.h"
#include "OLEDDisplayUi.h"
#include "Wire.h"
#include "HeFeng.h"
#include "WeatherStationFonts.h"
#include "WeatherStationImages.h"
/***************************
* Begin Settings
**************************/
DS18B20 ds(D7); //温度传感器io口。
#define TZ -8 // (utc+) TZ in hours
#define DST_MN 0 // use 60mn for summer time in some countries
// Setup
const int UPDATE_INTERVAL_SECS = 20 * 60; // Update every 20 minutes online weather
// Setup
const int UPDATE_CURR_INTERVAL_SECS = 10; // Update every 10 secs DS18B20
// Display Settings
const int I2C_DISPLAY_ADDRESS = 0x3c;
#if defined(ESP8266)
const int SDA_PIN = D2;
const int SDC_PIN = D5;
#endif
const String WDAY_NAMES[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
const String MONTH_NAMES[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
/***************************
* End Settings
**************************/
// Initialize the oled display for address 0x3c
// sda-pin=14 and sdc-pin=12
SH1106Wire display(I2C_DISPLAY_ADDRESS, SDA_PIN, SDC_PIN); // or SSD1306Wire display(I2C_DISPLAY_ADDRESS, SDA_PIN, SDC_PIN);
OLEDDisplayUi ui( &display );
HeFengCurrentData currentWeather;
HeFengForeData foreWeather[3];
HeFeng HeFengClient;
//OpenWeatherMapForecastData forecasts[MAX_FORECASTS];
//OpenWeatherMapForecast forecastClient;
#define TZ_MN ((TZ)*60)
#define TZ_SEC ((TZ)*3600)
#define DST_SEC ((DST_MN)*60)
const char* HEFENG_KEY="16c945b44ba847589ec6df9f93efd1b6"; //和风天气key
const char* HEFENG_LOCATION="CN101250303"; //城市代码
time_t now;
// flag changed in the ticker function every 10 minutes
bool readyForWeatherUpdate = false;
String lastUpdate = "--";
long timeSinceLastWUpdate = 0;
long timeSinceLastCurrUpdate = 0;
String currTemp="-1.0";
//declaring prototypes
void drawProgress(OLEDDisplay *display, int percentage, String label);
void updateData(OLEDDisplay *display);
void drawDateTime(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
void drawCurrentWeather(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
void drawForecast(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
void drawForecastDetails(OLEDDisplay *display, int x, int y, int dayIndex);
void drawHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state);
void setReadyForWeatherUpdate();
// Add frames
// this array keeps function pointers to all frames
// frames are the single views that slide from right to left
FrameCallback frames[] = { drawDateTime, drawCurrentWeather,drawForecast };
//drawForecast
int numberOfFrames = 3;
OverlayCallback overlays[] = { drawHeaderOverlay };
int numberOfOverlays = 1;
bool autoConfig()
{
WiFi.mode(WIFI_STA);
WiFi.begin();
Serial.print("AutoConfig Waiting......");
int counter = 0;
for (int i = 0; i < 20; i++)
{
if (WiFi.status() == WL_CONNECTED)
{
Serial.println("AutoConfig Success");
Serial.printf("SSID:%s\r\n", WiFi.SSID().c_str());
Serial.printf("PSW:%s\r\n", WiFi.psk().c_str());
WiFi.printDiag(Serial);
return true;
}
else
{
delay(500);
Serial.print(".");
display.clear();
display.drawString(64, 10, "Connecting to WiFi");
display.drawXbm(46, 30, 8, 8, counter % 3 == 0 ? activeSymbole : inactiveSymbole);
display.drawXbm(60, 30, 8, 8, counter % 3 == 1 ? activeSymbole : inactiveSymbole);
display.drawXbm(74, 30, 8, 8, counter % 3 == 2 ? activeSymbole : inactiveSymbole);
display.display();
counter++;
}
}
Serial.println("AutoConfig Faild!" );
return false;
}
ESP8266WebServer server(80);
String str = "ESP8266网页配网 hello,我是fxy,输入wifi信息给wifi时钟配网: ";
void handleRoot() {
server.send(200, "text/html", str);
}
void HandleWifi()
{
String wifis = server.arg("ssid"); //从JavaScript发送的数据中找ssid的值
String wifip = server.arg("password"); //从JavaScript发送的数据中找password的值
Serial.println("received:"+wifis);
server.send(200, "text/html", "连接中..");
WiFi.begin(wifis,wifip);
}
void handleNotFound() {
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i = 0; i < server.args(); i++) {
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message);
}
void htmlConfig()
{
WiFi.mode(WIFI_AP_STA);//设置模式为AP+STA
WiFi.softAP("wifi_clock");
IPAddress myIP = WiFi.softAPIP();
if (MDNS.begin("clock")) {
Serial.println("MDNS responder started");
}
server.on("/", handleRoot);
server.on("/HandleWifi", HTTP_GET, HandleWifi);
server.onNotFound(handleNotFound);//请求失败回调函数
MDNS.addService("http", "tcp", 80);
server.begin();//开启服务器
Serial.println("HTTP server started");
int counter = 0;
while(1)
{
server.handleClient();
MDNS.update();
delay(500);
display.clear();
display.drawString(64, 5, "WIFI AP:wifi_clock");
display.drawString(64, 20, "192.168.4.1");
display.drawString(64, 35, "waiting for config wifi.");
display.drawXbm(46, 50, 8, 8, counter % 3 == 0 ? activeSymbole : inactiveSymbole);
display.drawXbm(60, 50, 8, 8, counter % 3 == 1 ? activeSymbole : inactiveSymbole);
display.drawXbm(74, 50, 8, 8, counter % 3 == 2 ? activeSymbole : inactiveSymbole);
display.display();
counter++;
if (WiFi.status() == WL_CONNECTED)
{
Serial.println("HtmlConfig Success");
Serial.printf("SSID:%s\r\n", WiFi.SSID().c_str());
Serial.printf("PSW:%s\r\n", WiFi.psk().c_str());
Serial.println("HTML连接成功");
break;
}
}
server.close();
WiFi.mode(WIFI_STA);
}
void setup() {
Serial.begin(115200);
Serial.println();
Serial.println();
// initialize dispaly
display.init();
display.clear();
display.display();
//display.flipScreenVertically();
display.setFont(ArialMT_Plain_10);
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.setContrast(255);
bool wifiConfig = autoConfig();
if(wifiConfig == false){
htmlConfig();//HTML配网
}
ui.setTargetFPS(30);
ui.setActiveSymbol(activeSymbole);
ui.setInactiveSymbol(inactiveSymbole);
// You can change this to
// TOP, LEFT, BOTTOM, RIGHT
ui.setIndicatorPosition(BOTTOM);
// Defines where the first frame is located in the bar.
ui.setIndicatorDirection(LEFT_RIGHT);
// You can change the transition that is used
// SLIDE_LEFT, SLIDE_RIGHT, SLIDE_TOP, SLIDE_DOWN
ui.setFrameAnimation(SLIDE_LEFT);
ui.setFrames(frames, numberOfFrames);
ui.setTimePerFrame(7500);
ui.setOverlays(overlays, numberOfOverlays);
// Inital UI takes care of initalising the display too.
ui.init();
Serial.println("");
configTime(TZ_SEC, DST_SEC, "pool.ntp.org","0.cn.pool.ntp.org","1.cn.pool.ntp.org");
updateData(&display);
}
void loop() {
if (millis() - timeSinceLastWUpdate > (1000L*UPDATE_INTERVAL_SECS)) {
setReadyForWeatherUpdate();
timeSinceLastWUpdate = millis();
}
if (millis() - timeSinceLastCurrUpdate > (1000L*UPDATE_CURR_INTERVAL_SECS)) {
if( ui.getUiState()->frameState == FIXED)
{
currTemp=String(ds.getTempC(), 1);
timeSinceLastCurrUpdate = millis();
}
}
if (readyForWeatherUpdate && ui.getUiState()->frameState == FIXED) {
updateData(&display);
}
int remainingTimeBudget = ui.update();
if (remainingTimeBudget > 0) {
// You can do some work here
// Don't do stuff if you are below your
// time budget.
delay(remainingTimeBudget);
}
}
void drawProgress(OLEDDisplay *display, int percentage, String label) {
display->clear();
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(ArialMT_Plain_10);
display->drawString(64, 10, label);
display->drawProgressBar(2, 28, 124, 10, percentage);
display->display();
}
void updateData(OLEDDisplay *display) {
drawProgress(display, 30, "Updating weather...");
for(int i=0;i<5;i++){
HeFengClient.doUpdateCurr(¤tWeather, HEFENG_KEY, HEFENG_LOCATION);
if(currentWeather.cond_txt!="no network"){
break;}
}
drawProgress(display, 50, "Updating forecasts...");
for(int i=0;i<5;i++){
HeFengClient.doUpdateFore(foreWeather, HEFENG_KEY, HEFENG_LOCATION);
if(foreWeather[0].datestr!="N/A"){
break;}
}
readyForWeatherUpdate = false;
drawProgress(display, 100, "Done...");
delay(1000);
}
void drawDateTime(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
now = time(nullptr);
struct tm* timeInfo;
timeInfo = localtime(&now);
char buff[16];
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(ArialMT_Plain_16);
String date = WDAY_NAMES[timeInfo->tm_wday];
sprintf_P(buff, PSTR("%04d-%02d-%02d, %s"), timeInfo->tm_year + 1900, timeInfo->tm_mon+1, timeInfo->tm_mday, WDAY_NAMES[timeInfo->tm_wday].c_str());
display->drawString(64 + x, 5 + y, String(buff));
display->setFont(ArialMT_Plain_24);
sprintf_P(buff, PSTR("%02d:%02d:%02d"), timeInfo->tm_hour, timeInfo->tm_min, timeInfo->tm_sec);
display->drawString(64 + x, 22 + y, String(buff));
display->setTextAlignment(TEXT_ALIGN_LEFT);
}
void drawCurrentWeather(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
display->setFont(ArialMT_Plain_10);
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->drawString(64 + x, 38 + y, currentWeather.cond_txt+" | Wind: "+currentWeather.wind_sc);
display->setFont(ArialMT_Plain_24);
display->setTextAlignment(TEXT_ALIGN_LEFT);
String temp = currentWeather.tmp + "°C" ;
display->drawString(60 + x, 3 + y, temp);
display->setFont(ArialMT_Plain_10);
display->drawString(70 + x, 26 + y, currentWeather.fl+"°C | "+currentWeather.hum+"%");
display->setFont(Meteocons_Plain_36);
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->drawString(32 + x, 0 + y, currentWeather.iconMeteoCon);
}
void drawForecast(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
drawForecastDetails(display, x, y, 0);
drawForecastDetails(display, x + 44, y, 1);
drawForecastDetails(display, x + 88, y, 2);
}
void drawForecastDetails(OLEDDisplay *display, int x, int y, int dayIndex) {
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(ArialMT_Plain_10);
display->drawString(x + 20, y, foreWeather[dayIndex].datestr);
display->setFont(Meteocons_Plain_21);
display->drawString(x + 20, y + 12, foreWeather[dayIndex].iconMeteoCon);
String temp=foreWeather[dayIndex].tmp_min+" | "+foreWeather[dayIndex].tmp_max;
display->setFont(ArialMT_Plain_10);
display->drawString(x + 20, y + 34, temp);
display->setTextAlignment(TEXT_ALIGN_LEFT);
}
void drawHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state) {
now = time(nullptr);
struct tm* timeInfo;
timeInfo = localtime(&now);
char buff[14];
sprintf_P(buff, PSTR("%02d:%02d"), timeInfo->tm_hour, timeInfo->tm_min);
display->setColor(WHITE);
display->setFont(ArialMT_Plain_10);
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->drawString(6, 54, String(buff));
display->setTextAlignment(TEXT_ALIGN_RIGHT);
String temp =currTemp +"°C";
display->drawString(128, 54, temp);
display->drawHorizontalLine(0, 52, 128);
}
void setReadyForWeatherUpdate() {
Serial.println("Setting readyForUpdate to true");
readyForWeatherUpdate = true;
}
百度链接:(如果能对你有帮助,请给个赞,开源代码分享不容易,大家多多支持!)
链接:https://pan.baidu.com/s/1cL8hdTpYwDRFqQuiEcysEQ
提取码:i0jy