sonicfirr 发表于 2022-9-4 21:25

【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>&nbsp; &nbsp; &nbsp; &nbsp;利用周日,本人整合前两篇测评案例,整了一个&ldquo;大活儿&rdquo;,功能如下:</p>

<p>1)OLED可以显示两个画面(代码中称为PAGE),&ldquo;时钟+AHT10温湿度&rdquo;与&ldquo;天气图标+气温&rdquo;。</p>

<p>2)按键(连接IO7)用于控制OLED画面变换。</p>

<p>&nbsp; &nbsp; &nbsp; &nbsp;本篇先给出完整代码,后面准备再写篇测评说明,代码逻辑&mdash;&mdash;搞了一天了,确实每精力再说明逻辑了。&nbsp;</p>

<p>&nbsp;</p>

<pre>
<code>#include &lt;Arduino.h&gt;
#include &lt;WiFi.h&gt;
#include &lt;WiFiMulti.h&gt;
#include &lt;HTTPClient.h&gt;
#include &lt;ArduinoJson.h&gt;
#include &lt;U8g2lib.h&gt;
#include &lt;Wire.h&gt;
#include &lt;Adafruit_AHTX0.h&gt;

//-----SSID &amp; password
const char *ssid = "yourssid";      //WIFI AP ssid
const char *password = "yourpsw";   //WIFI AP password

//-----NTP server &amp; 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 &amp; instance for json parsing
DynamicJsonDocument doc(1024);      //json doc instance
const char *url = "https://api.thinkpage.cn/v3/weather/now.json?key=your_apikey&amp;location=tianjin&amp;language=en&amp;unit=c";
void getWeather(void);                //request now weather func
int code = 0;                         //weather code
int degree = 0;                     //weather temperature

//-----u8g2 instance &amp; 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 &amp; 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(&amp;t)){
    Serial.println("Failed to obtain time");
    return;
} else {
    Serial.println(&amp;t, "%A, %B %d %Y %H:%M:%S");
    initTimer();
    getWeather();
}
}

void loop() {
//-----update time state per second
if(xSemaphoreTake(timersem, 0) == pdTRUE) {
    getLocalTime(&amp;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 &amp;&amp; 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, &amp;onTimer, true);
timerAlarmWrite(timer, 1000000, true); //1000000us timer
timerAlarmEnable(timer);
}

//-----print local time function
void printLocalTime(void) {
if(!getLocalTime(&amp;t)) {
    Serial.println("Failed to obtain time");
    return;
}
Serial.println(&amp;t, "%F %T %A");
}
//-----read AHT10 sensor function
void getAHT10(void) {
aht.getEvent(&amp;aht_humi, &amp;aht_temp);
}
//-----draw local time function
void drawLocalTimePage(void) {
char str = {0};
u8g2.clearBuffer();
//line1. set time &amp; weekday
u8g2.setFont(u8g2_font_ncenB14_tr);
u8g2.setCursor(0, 0);
u8g2.print(&amp;t, "%H:%M:%S%a");
u8g2.setCursor(24, 18);
//line2. set date
u8g2.setFont(u8g2_font_8x13_mf);
u8g2.print(&amp;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&gt;=0 &amp;&amp; symbol&lt;4) {         //Sun
    u8g2.setFont(u8g2_font_open_iconic_weather_6x_t);
    u8g2.drawGlyph(x, y, 69);
} else if(symbol&gt;=4 &amp;&amp; symbol&lt;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&gt;=10 &amp;&amp; symbol&lt;13) {//Thunder
    u8g2.setFont(u8g2_font_open_iconic_embedded_6x_t);
    u8g2.drawGlyph(x, y, 67);
} else if(symbol&gt;=13 &amp;&amp; symbol&lt;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 &gt; 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&lt;JsonObject&gt;();
      //get "results" property then parse the value to Json-Array
      JsonVariant resultsvar = obj["results"];
      JsonArray resultsarr = resultsvar.as&lt;JsonArray&gt;();
      //get array index 0 which is now weather info
      JsonVariant resultselementvar = resultsarr;
      JsonObject resultselementobj = resultselementvar.as&lt;JsonObject&gt;();
      /* get values of city, temp, code, update */
      //get city
      JsonVariant namevar = resultselementobj["location"]["name"];
      String namestr = namevar.as&lt;String&gt;();
      Serial.println(namestr);
      //get temperature
      JsonVariant temperaturevar = resultselementobj["now"]["temperature"];
      String temperaturestr = temperaturevar.as&lt;String&gt;();
      degree = temperaturevar.as&lt;int&gt;();
      Serial.println(temperaturestr);
      //get weather code
      JsonVariant codevar = resultselementobj["now"]["code"];
      code = codevar.as&lt;int&gt;();
      Serial.println(code);
      //get last_update time
      JsonVariant last_updatevar = resultselementobj["last_update"];
      String last_updatestr = last_updatevar.as&lt;String&gt;();
      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>&nbsp;</p>

<p class="imagemiddle" style="text-align: center;"></p>

<p align="center">&nbsp;</p>

<p class="imagemiddle" style="text-align: center;"></p>

<p align="center">图8-1 案例OLED显示效果</p>

<p align="center">&nbsp;</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>

bigbat 发表于 2022-9-5 09:26

<p>楼主的OLD SSD1306是spi口还是I2c的接口</p>

wangerxian 发表于 2022-9-5 09:32

<p>看着效果还不错,我前两天也搞了获取时间这么个功能~</p>

sonicfirr 发表于 2022-9-5 09:50

bigbat 发表于 2022-9-5 09:26
楼主的OLD SSD1306是spi口还是I2c的接口

<p>I2C接口,省IO</p>

lugl4313820 发表于 2022-9-5 09:58

bigbat 发表于 2022-9-5 09:26
楼主的OLD SSD1306是spi口还是I2c的接口

<p>看了图,是四线,应该是IIC接口的。</p>

bigbat 发表于 2022-9-5 13:30

sonicfirr 发表于 2022-9-5 09:50
I2C接口,省IO

<p>SSD1306的SPI接口也可以是2条线,其中一条可以不用。</p>

sonicfirr 发表于 2022-9-5 14:41

bigbat 发表于 2022-9-5 13:30
SSD1306的SPI接口也可以是2条线,其中一条可以不用。

<p>也是哈</p>

damiaa 发表于 2022-9-6 09:07

<p>谢谢分享!</p>
页: [1]
查看完整版本: 【Beetle ESP32-C3】八、OLED时钟和天气助手(Arduino)