基于ESP32-S2实现本地气象台温度计
本项目是使用硬禾学堂的音频信号板卡,通过WIFI-S2模块联网后调用心知天气API获取本地当天的天气、气温信息以及实时时间,数据经过解析后将其显示在板卡自带的OLED上。实现一个本地气象台。
标签
MPU
显示
网络与通信
2022寒假在家练
科技不福利
更新2022-03-02
合肥学院
878

基于ESP32-S2-Mini-1模块的本地气象台

项目介绍:

本项目是使用硬禾学堂的音频信号板卡,通过WIFI-S2模块联网后调用心知天气API获取本地当天的天气、气温信息以及实时时间,数据经过解析后将其显示在板卡自带的OLED上。实现一个本地气象台。

项目要求:

利用OLED显示当前本地的时间、温度和气象信息

使用软件:

arduino

设计思路(框图):

FlKRQYkVKkrbNfXQgLMev92G2dmU

本项目流程较简单,先使用ESP32 S2模块连接WiFi网络。之后通过访问阿里云时间服务器获去本地实时时间。关于获取天气信息,我们可以先注册一个心知天气的账户,申请免费的产品,获取免费的API并调用,得到JSON格式的数据,再使用ArduinoJson库函数进行解析,将获取的天气温度信息显示在OLED上,并以合适速率刷新。

简单的硬件介绍:

1、核心控制器介绍:

本平台使用了乐鑫公司的ESP32-s2-Mini-1模块,ESP32-s2-Mini-1是一颗通用型Wi-Fi MCU模组,功能强大,具有丰富的外设接口,可用于穿戴电子设备,智能家居等场景,ESP-S2-Mini-1采用PCB板载天线,模块配置了4MB SPI Flash,采用的是ESP32-S2FN4芯片。该芯片搭载了Xtensa R 32位LX7单核处理器,工作频率高达240MHz。用户可以关闭CPU的电源,利用低功耗处理器监测外设的状态变化或某些模拟量是否超出阈值。ESP32-S2-FH4还集成了丰富的外设接口。

FoJNy5hrDTym4DDeRAlkVBhrcrbR

                        ESP32-s2-MINI-1的构成

音频信号处理板卡构成:

基于ESP32-S2 WiFi核心模块;128*64 SPI接口OLED显示;4个按键用于参数控制或菜单选择;1路Mic音频输入-模拟电路;2路音频输出,并有功率放大,可以驱动喇叭和耳机插座;一个FM接收模块;一个用于切换来自ESP32产生的音频还是FM输出的音频到喇叭或者耳机。

FkV0Kna8lHRN0m2-D9FuVgQ7T7R3

板卡功能框图

FuWllERXFS5EWdL4-G0cK157RSzr

板卡实物图

实现的功能及图片展示:

FqJB-73EMecypsJQgHkGU8umAk-z

在本次项目中,我仅仅实现了简单的天气和时间显示功能,由于天气短时间内不会突变,我通过使用定时器中断,每小时刷新一次。关于时间信息,由于要实时显示,我将时间刷新设置为200ms,由于ESP32是第一次接触,有些问题也困扰了一些时间,但同时ESP32丰富的功能也令我眼前一亮,未来我会多使用相关产品,做出更多有意思的东西。

主要的代码片段及说明:

各变量的定义

const char * temperature ;  
const char * currenttime ;
const char * weather;
const char * area;
unsigned long currentMillis;
DynamicJsonDocument doc(1400);  //分配空间,用于保存JSON数据
WiFiServer server(80);          //端口号  
struct tm timeinfo;
hw_timer_t * timer = NULL;
volatile uint32_t isrCounter = 3600;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;  
U8G2_SSD1306_128X64_NONAME_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 36, /* data=*/ 35, /* cs=*/ 10, /* dc=*/ 33, /* reset=*/ 34);  //为OLED设置引脚

中断函数

void ARDUINO_ISR_ATTR onTimer(){  //中断函数, 1s中断用于刷新天气信息
  portENTER_CRITICAL_ISR(&timerMux);
  isrCounter++;                   //记录中断次数 写入与中断共享的变量时禁用中断。这样我们就可以确保                                  
                                  //主代码和ISR之间不存在任何对它的并发访问。 
  portEXIT_CRITICAL_ISR(&timerMux);
}

以下代码是串口、OLED、定时器等初始化。

Serial.begin(115200);
u8g2.begin();
Serial.print("Connecting to ");

WiFi.begin(ssid, password);      
while (WiFi.status() != WL_CONNECTED) {
   delay(500);
   Serial.print(".");
}
Serial.println("Connected ");

configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
if(!getLocalTime(&timeinfo)){
  Serial.println("failde to obtain time");
  return;
}
Serial.println(&timeinfo, "%A, %B  %d  %Y  %H:%M:%S");
server.begin();
//定时器配置
timer = timerBegin(0, 80, true);        //定时器0,80预分频
timerAttachInterrupt(timer, &onTimer, true);
timerAlarmWrite(timer, 1000000, true);  //1秒
timerAlarmEnable(timer);                //定时器使能
}

以下代码是在循环中反复检查连接情况,如果WiFi意外断开会重新尝试连接,以防连接过程外界WiFi突然断开又恢复后WiFi模块无法自动重连。

if(WiFi.status() != WL_CONNECTED){
   currentMillis = millis();
   if ((WiFi.status() != WL_CONNECTED) && (currentMillis - previousMillis >=interval)) {
      Serial.print(millis());
      Serial.println("Reconnecting to WiFi...");
      WiFi.begin(ssid, password);
      previousMillis = currentMillis;
      configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
      }
}

以下代码是1s定时器计数累加值达到3600,既1小时,连接知心天气API重新获取天气信息,解析JSON数据,对相应变量进行刷新。

if (isrCounter > 3600){
   portENTER_CRITICAL_ISR(&timerMux);
   isrCounter = 0;    //重新计时
   portEXIT_CRITICAL_ISR(&timerMux);

   HTTPClient https;
   https.begin(Targethttp);    //连接心知天气API
   int httpCode = https.GET(); //获取连接状况
   Serial.print(httpCode);     //串口打印

   if(httpCode == HTTP_CODE_OK){          //如果连接成功
      String payload = https.getString(); //将获取的响应数据转换为字符串
      deserializeJson(doc, payload);      //反序列化JSON数据
      JsonObject results_0 = doc["results"][0];
      JsonObject results_0_now = results_0["now"];
      JsonObject results_0_location = results_0["location"];
      weather = results_0_now["text"];    //天气
      temperature = results_0_now["temperature"];  //温度
      area = results_0_location["name"];  //地理位置
    }
}
getLocalTime(&timeinfo);                  //获取时间 每隔200ms

以下代码是负责OLED的显示。

u8g2.clearBuffer();                 // 清除内部缓冲区
u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font
u8g2.setCursor(0,10);
u8g2.print("weather:");
u8g2.setCursor(74,10);
u8g2.print(weather);
u8g2.drawLine(0, 22, 127, 22);      //横线
           
u8g2.setCursor(0,23);
u8g2.print("area:");
u8g2.setCursor(74,23);
u8g2.print(area);
u8g2.drawLine(0, 25, 127, 25);      //横线

u8g2.setCursor(0,36);
u8g2.print("temperature:");
u8g2.setCursor(74,36);
u8g2.print(temperature);
u8g2.drawLine(0, 38, 127, 38);      //横线
u8g2.drawLine(72, 0, 72, 53);       //横线
u8g2.drawLine(0, 53, 127, 53);      //纵线

u8g2.setCursor(0,60);
u8g2.print(&timeinfo, "%F %T");
u8g2.sendBuffer();             
delay(200); 
}

遇到的主要难题及解决方法:

使用开发板在连接手机WiFi时发生重启,代码检查了好多次,最后发现是由于粗心使用OLED的显示函数时出现了问题。arduino查错是真不方便,最好还是使用原生的IDF。关于ESP32的联网方式我觉得可以做到更好,似乎可以通过AP模式让用户通过网页进行网络配置。这样就可以在不改变代码的情况下配网了,后面我会继续进行尝试。

未来的计划及建议等:

自己对相应的库及原理还是不够清楚,虽然这个项目的实现很简单,但其中涉及到的知识可不少如HTTP请求的过程、TCP和UDP协议等等,未来要多学习ESP32的各种功能,将这个模块的潜力发掘出来。我也正式成为esp32粉丝大军的一员了。感谢硬禾学堂给我这次学习的机会,希望硬禾学堂相关活动越办越好。

附件下载
hanjia3weather.ino
团队介绍
科技不福利
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号