【Beetle ESP32-C3】八、OLED时钟和天气助手(Arduino)
<div class='showpostmsg'> 本帖最后由 sonicfirr 于 2022-9-5 07:45 编辑<p>前面的两篇测评,本篇案例基于这两篇:</p>
<p><a href="https://bbs.eeworld.com.cn/thread-1216204-1-1.html" target="_blank">【</a><a href="https://bbs.eeworld.com.cn/thread-1214823-1-1.html" target="_blank">Beetle ESP32-C3】六、OLED、AHT10和TCP(Arduino)</a></p>
<p><a href="https://bbs.eeworld.com.cn/thread-1216204-1-1.html" target="_blank">【Beetle ESP32-C3】七、网络授时和请求天气(Arduino)</a></p>
<hr />
<p> 利用周日,本人整合前两篇测评案例,整了一个“大活儿”,功能如下:</p>
<p>1)OLED可以显示两个画面(代码中称为PAGE),“时钟+AHT10温湿度”与“天气图标+气温”。</p>
<p>2)按键(连接IO7)用于控制OLED画面变换。</p>
<p> 本篇先给出完整代码,后面准备再写篇测评说明,代码逻辑——搞了一天了,确实每精力再说明逻辑了。 </p>
<p> </p>
<pre>
<code>#include <Arduino.h>
#include <WiFi.h>
#include <WiFiMulti.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <U8g2lib.h>
#include <Wire.h>
#include <Adafruit_AHTX0.h>
//-----SSID & password
const char *ssid = "yourssid"; //WIFI AP ssid
const char *password = "yourpsw"; //WIFI AP password
//-----NTP server & timezone offset
const char *ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 14400; //3600*4 for UTC+8
const intdaylightOffset_sec = 14400;
struct tmt; //time struct
void printLocalTime(void);
//-----timer HW per second
hw_timer_t *timer = NULL; //timer variable
volatile SemaphoreHandle_t timersem;//timer fire sem
void IRAM_ATTR onTimer(void); //callback func
void initTimer(void);
//-----weather server URL & instance for json parsing
DynamicJsonDocument doc(1024); //json doc instance
const char *url = "https://api.thinkpage.cn/v3/weather/now.json?key=your_apikey&location=tianjin&language=en&unit=c";
void getWeather(void); //request now weather func
int code = 0; //weather code
int degree = 0; //weather temperature
//-----u8g2 instance & functions
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);
void drawLocalTimePage(void);
void drawNowWeatherPage(int code, int temp);
//-----input key
#define KEY 7
//-----show page enum
typedef enum {
TIMEPAGE = 0,
WEATHERPAGE,
} AITA_PAGE_INDEX;
//-----global variable of page No
int pagestate = TIMEPAGE;
//-----AHT10 instance & sensor variables
Adafruit_AHTX0 aht; //aht instance
sensors_event_t aht_humi, aht_temp; //sensor variables
void getAHT10(void); //read aht10 sensor
void setup() {
//-----initialize BSP
Serial.begin(115200);
pinMode(KEY, INPUT_PULLUP);
//-----initialize u8g2
u8g2.begin();
u8g2.setFontPosTop();
u8g2.enableUTF8Print();
//-----initialize AHT10
if(!aht.begin()) {
Serial.println("Could not find AHT");
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_osb18_tf);
u8g2.drawStr(5,10,"no AHT");
u8g2.sendBuffer();
while(1) delay(10);
}
Serial.println("AHT10 or AHT20 found");
getAHT10();
//-----connect AP
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
//-----print IP address
Serial.println(" CONNECTED");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
//-----initialize and get the time then initialize timer(per sec)
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
if(!getLocalTime(&t)){
Serial.println("Failed to obtain time");
return;
} else {
Serial.println(&t, "%A, %B %d %Y %H:%M:%S");
initTimer();
getWeather();
}
}
void loop() {
//-----update time state per second
if(xSemaphoreTake(timersem, 0) == pdTRUE) {
getLocalTime(&t);
}
//-----refresh screen
if(pagestate == TIMEPAGE)
drawLocalTimePage();
else if(pagestate == WEATHERPAGE)
drawNowWeatherPage(code, degree);
//-----update weather info per 5 minutes
if(t.tm_min%5==0 && t.tm_sec==0) {
getAHT10();
if(WiFi.status() == WL_CONNECTED) {
getWeather();
}
}
//-----read KEY
if(digitalRead(KEY) == 0) {
delay(30);
if(digitalRead(KEY) == 0) {
if(pagestate == WEATHERPAGE) pagestate = TIMEPAGE;
else pagestate++;
}
}
}
//-----second timer callback function
void IRAM_ATTR onTimer() {
xSemaphoreGiveFromISR(timersem, NULL);
}
//-----intialize timer function
void initTimer() {
timersem = xSemaphoreCreateBinary();
//ESP32 sysclk is 80MHz.
//frequency division factor to 80,
//then timer clock is 1MHz.
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &onTimer, true);
timerAlarmWrite(timer, 1000000, true); //1000000us timer
timerAlarmEnable(timer);
}
//-----print local time function
void printLocalTime(void) {
if(!getLocalTime(&t)) {
Serial.println("Failed to obtain time");
return;
}
Serial.println(&t, "%F %T %A");
}
//-----read AHT10 sensor function
void getAHT10(void) {
aht.getEvent(&aht_humi, &aht_temp);
}
//-----draw local time function
void drawLocalTimePage(void) {
char str = {0};
u8g2.clearBuffer();
//line1. set time & weekday
u8g2.setFont(u8g2_font_ncenB14_tr);
u8g2.setCursor(0, 0);
u8g2.print(&t, "%H:%M:%S%a");
u8g2.setCursor(24, 18);
//line2. set date
u8g2.setFont(u8g2_font_8x13_mf);
u8g2.print(&t, "%Y-%m-%d");
//line3. set aht10 humidity
u8g2.drawStr(0, 32, "Humi: ");
memset(str, 0, 6);
dtostrf(aht_humi.relative_humidity, 6, 2, str);
u8g2.drawStr(48, 32, str);
u8g2.drawStr(96,32, "% rH");
//line4. set aht10 temperature
u8g2.drawStr(0, 48, "Temp: ");
memset(str, 0, 6);
dtostrf(aht_temp.temperature, 6, 2, str);
u8g2.drawStr(48, 48, str);
u8g2.setCursor(96, 48);
u8g2.print("°C");
//draw screen
u8g2.sendBuffer();
}
//-----set weather icon function
void drawWeatherSymbol(u8g2_uint_t x, u8g2_uint_t y, uint8_t symbol) {
if(symbol>=0 && symbol<4) { //Sun
u8g2.setFont(u8g2_font_open_iconic_weather_6x_t);
u8g2.drawGlyph(x, y, 69);
} else if(symbol>=4 && symbol<9) {//Cloudy
u8g2.setFont(u8g2_font_open_iconic_weather_6x_t);
u8g2.drawGlyph(x, y, 65);
} else if(symbol==9) { //Overcast
u8g2.setFont(u8g2_font_open_iconic_weather_6x_t);
u8g2.drawGlyph(x, y, 64);
} else if(symbol>=10 && symbol<13) {//Thunder
u8g2.setFont(u8g2_font_open_iconic_embedded_6x_t);
u8g2.drawGlyph(x, y, 67);
} else if(symbol>=13 && symbol<21) {//Rain
u8g2.setFont(u8g2_font_open_iconic_weather_6x_t);
u8g2.drawGlyph(x, y, 67);
} else { //Others show star
u8g2.setFont(u8g2_font_open_iconic_weather_6x_t);
u8g2.drawGlyph(x, y, 68);
}
}
//-----set weather temperature degree function
void drawWeatherDegree(uint8_t symbol, int degree) {
drawWeatherSymbol(0, 0, symbol);
u8g2.setFont(u8g2_font_logisoso32_tf);
u8g2.setCursor(48+6, 10);
u8g2.print(degree);
u8g2.print("°C"); //requires enableUTF8Print()
}
//-----draw now weather function
void drawNowWeatherPage(int code, int temp) {
u8g2.clearBuffer();
drawWeatherDegree(code, temp);
u8g2.setCursor(32, 48);
u8g2.setFont(u8g2_font_8x13_mf);
u8g2.print("Tianjin");
u8g2.sendBuffer();
}
//-----request now weather function
void getWeather() {
if((WiFi.status() == WL_CONNECTED)) {
HTTPClient http; //create HTTPClient instance
http.begin(url); //begin HTTP request
int httpCode = http.GET(); //get response code - normal:200
if(httpCode > 0) {
Serial.printf(" GET... code: %d\n", httpCode);
if(httpCode == HTTP_CODE_OK) {
String payload = http.getString();
Serial.println(payload);
//parse response stringto DynamicJsonDocument instance
deserializeJson(doc, payload);
//get top level Json-Object
JsonObject obj = doc.as<JsonObject>();
//get "results" property then parse the value to Json-Array
JsonVariant resultsvar = obj["results"];
JsonArray resultsarr = resultsvar.as<JsonArray>();
//get array index 0 which is now weather info
JsonVariant resultselementvar = resultsarr;
JsonObject resultselementobj = resultselementvar.as<JsonObject>();
/* get values of city, temp, code, update */
//get city
JsonVariant namevar = resultselementobj["location"]["name"];
String namestr = namevar.as<String>();
Serial.println(namestr);
//get temperature
JsonVariant temperaturevar = resultselementobj["now"]["temperature"];
String temperaturestr = temperaturevar.as<String>();
degree = temperaturevar.as<int>();
Serial.println(temperaturestr);
//get weather code
JsonVariant codevar = resultselementobj["now"]["code"];
code = codevar.as<int>();
Serial.println(code);
//get last_update time
JsonVariant last_updatevar = resultselementobj["last_update"];
String last_updatestr = last_updatevar.as<String>();
Serial.println(last_updatestr);
}
} else {
Serial.printf(" GET... failed, error: %s\n",
http.errorToString(httpCode).c_str());
}
http.end(); //end http connectiong
}
}</code></pre>
<p> </p>
<p class="imagemiddle" style="text-align: center;"></p>
<p align="center"> </p>
<p class="imagemiddle" style="text-align: center;"></p>
<p align="center">图8-1 案例OLED显示效果</p>
<p align="center"> </p>
</div><script> var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;" style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
if(parseInt(discuz_uid)==0){
(function($){
var postHeight = getTextHeight(400);
$(".showpostmsg").html($(".showpostmsg").html());
$(".showpostmsg").after(loginstr);
$(".showpostmsg").css({height:postHeight,overflow:"hidden"});
})(jQuery);
} </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script> <p>楼主的OLD SSD1306是spi口还是I2c的接口</p>
<p>看着效果还不错,我前两天也搞了获取时间这么个功能~</p>
bigbat 发表于 2022-9-5 09:26
楼主的OLD SSD1306是spi口还是I2c的接口
<p>I2C接口,省IO</p>
bigbat 发表于 2022-9-5 09:26
楼主的OLD SSD1306是spi口还是I2c的接口
<p>看了图,是四线,应该是IIC接口的。</p>
sonicfirr 发表于 2022-9-5 09:50
I2C接口,省IO
<p>SSD1306的SPI接口也可以是2条线,其中一条可以不用。</p>
bigbat 发表于 2022-9-5 13:30
SSD1306的SPI接口也可以是2条线,其中一条可以不用。
<p>也是哈</p>
<p>谢谢分享!</p>
页:
[1]