工程说明
本工程基于PIO(PlatformIO)搭建,采用Arduino框架,采取的外部软件包及其依赖如下所示:
Dependency Graph
|-- <Seeed Arduino rpcUnified> 2.1.3
| |-- <Seeed Arduino FreeRTOS> 1.1.0
| |-- <Seeed_Arduino_mbedtls> 3.0.1
|-- <Seeed Arduino rpcWiFi> 1.0.5
| |-- <Seeed Arduino rpcUnified> 2.1.3
| | |-- <Seeed Arduino FreeRTOS> 1.1.0
| | |-- <Seeed_Arduino_mbedtls> 3.0.1
| |-- <Seeed_Arduino_mbedtls> 3.0.1
| |-- <Seeed Arduino FS> 2.1.1
| | |-- <SPI> 1.0
| | | |-- <Adafruit Zero DMA Library> 1.0.4
|-- <Seeed Arduino FS> 2.1.1
| |-- <SPI> 1.0
| | |-- <Adafruit Zero DMA Library> 1.0.4
|-- <Seeed Arduino SFUD> 2.0.2
| |-- <Seeed Arduino FS> 2.1.1
| | |-- <SPI> 1.0
| | | |-- <Adafruit Zero DMA Library> 1.0.4
| |-- <SPI> 1.0
| | |-- <Adafruit Zero DMA Library> 1.0.4
|-- <Seeed_Arduino_mbedtls> 3.0.1
|-- <millisDelay> 1.3
|-- <ArduinoJson> 6.18.0
|-- <lvgl> 8.0.1
| |-- <Seeed Arduino rpcUnified> 2.1.3
| | |-- <Seeed Arduino FreeRTOS> 1.1.0
| | |-- <Seeed_Arduino_mbedtls> 3.0.1
| |-- <Seeed Arduino FreeRTOS> 1.1.0
|-- <Seeed Arduino RTC> 2.0.0
|-- <Seeed_Arduino_LCD> 1.6.0
| |-- <SPI> 1.0
| | |-- <Adafruit Zero DMA Library> 1.0.4
| |-- <Seeed Arduino FS> 2.1.1
| | |-- <SPI> 1.0
| | | |-- <Adafruit Zero DMA Library> 1.0.4
|-- <SPI> 1.0
| |-- <Adafruit Zero DMA Library> 1.0.4
|-- <Wire> 1.0
-
其中
millisDelay和Seeed_Arduino_mbedtls这两个库在PIO官方库中均不存在,已经额外添加到本工程的lib下,其余库均为PIO提供或bsp中提供
本工程的基本结构如下:
-
include、test:PIO工程默认生成文件夹,本工程中暂时未使用
-
lib:PIO中没有的库
-
src:整个工程的源码
-
assets:各种图标与字体
-
整体资源占用如下:
编译下载
在PlatformIO中打开,点击编译并烧录即可编译工程并下载到板子中
实现功能
主要实现如下工程:
-
通过wifi链接网络,并从和风天气上在线获取当地的天气情况
-
采用LVGL设计界面,分别展示当前时间与天气
-
采用NTP同步时间,并且用数字表盘相似
-
所有字体图标等资源直接内嵌到代码中,无需外部flash或sd卡
-
展示当前地区的温湿度、天气情况、空气质量以及未来三天内的天气变化
-
-
状况
各功能主要代码 main
void setup()
{
pinMode(WIO_KEY_A, INPUT_PULLUP);
...
pinMode(WIO_BUZZER, OUTPUT);
lvgl_init();
device_init();
}
void loop()
{
long last_time = millis();
delay(5);
lv_timer_handler(); /* let the GUI do its work */
lv_tick_inc(int(millis() - last_time));
ntp_handler();
}
-
Arduino的主体框架,包括lvgl的初始化与gpio的初始化
-
device_init中会初始化wifi、ntp以及相关界面,同时会通过lvgl在屏幕上输出开机进度条
ntp
void ntp_init()
{
// declare a time object
DateTime now;
// localtime
unsigned long devicetime = getNTPtime();
...
// get and print the current rtc time
now = rtc.now();
Serial.print("RTC time is: ");
Serial.println(now.timestamp(DateTime::TIMESTAMP_FULL));
// adjust time using ntp time
rtc.adjust(DateTime(devicetime));
// print boot update details
Serial.println("RTC (boot) time updated.");
// get and print the adjusted rtc time
now = rtc.now();
Serial.print("Adjusted RTC (boot) time is: ");
Serial.println(now.timestamp(DateTime::TIMESTAMP_FULL));
// start millisdelays timers as required, adjust to suit requirements
updateDelay.start(12 * 60 * 60 * 1000); // update time via ntp every 12 hrs
}
void ntp_handler()
{
DateTime now;
unsigned long devicetime;
if (updateDelay.justFinished())
{ // 12 hour loop
// repeat timer
updateDelay.repeat(); // repeat
// update rtc time
devicetime = getNTPtime();
if (devicetime == 0)
{
Serial.println("Failed to get time from network time server.");
}
else
{
rtc.adjust(DateTime(devicetime));
Serial.println("");
Serial.println("rtc time updated.");
// get and print the adjusted rtc time
now = rtc.now();
Serial.print("Adjusted RTC time is: ");
Serial.println(now.timestamp(DateTime::TIMESTAMP_FULL));
}
}
}
-
ntp_init中通过网络获取时间,同时更新本地时间,接着会通过millisDelay库设置没12小时更新一次时间 -
ntp_handler会每隔一段时间调用一次,查看是否需要更新本地时间
HeFeng
void HeFeng::doUpdateCurr(CurrentData &data)
{
HTTPClient https;
if (https.begin(client, url))
{ // HTTPS
int httpCode = https.GET();
if (httpCode > 0)
{
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY)
{
String payload = https.getString();
Serial.println(payload);
DynamicJsonDocument jsonBuffer(2048);
deserializeJson(jsonBuffer, payload);
JsonObject root = jsonBuffer.as<JsonObject>();
// data.code = root["code"].toInt();
data.code = root["code"];
...
data.dew = root["now"]["dew"].as<String>();
}
}
else
...
https.end();
}
else
...
}
const lv_img_dsc_t* HeFeng::getMeteoconIcon(int cond_code)
{
switch (cond_code)
{
case 100:
case 150:
return &icon_qingtian;
...
case 504:
return &icon_fuchen;
}
return NULL;
}
-
通过wifi解析和风天气的API,获得对应的数据
-
通过解析的数据编号,获得相应的图标地址
app_clock
void app_weather_init(lv_obj_t * scr)
{
CurrentData nowdata;
hefeng.doUpdateCurr(nowdata);
AirQualityData airdata;
hefeng.doUpdateAirQuality(airdata);
int days = 3;
DailyData dailyData[days];
hefeng.doUpdateDaily(dailyData, days);
//当天
const lv_img_dsc_t* img = hefeng.getMeteoconIcon(nowdata.icon);
lv_obj_t * img1 = lv_img_create(scr);
...
//后三天
img = hefeng.getMeteoconIcon(dailyData[0].iconDay);
img1 = lv_img_create(scr);
...
}
-
调用
HeFeng模块获得天气数据并通过lvgl显示
app_weather
static void set_sec_value(void * indic, int32_t v)
{
lasttime = rtc.now();
lv_meter_set_indicator_value(meter, (lv_meter_indicator_t *)indic_sec, lasttime.second()%60);
lv_meter_set_indicator_value(meter, (lv_meter_indicator_t *)indic_min, lasttime.minute()%60);
lv_meter_set_indicator_value(meter, (lv_meter_indicator_t *)indic_hour, (lasttime.hour()%12)*5);
}
void app_clock_init(lv_obj_t * scr)
{
meter = lv_meter_create(scr);
lv_obj_set_size(meter, 220, 220);
lv_obj_center(meter);
...
}
-
调用
rtc模块获得本地时间数据并通过lvgl显示
功能展示及说明
开机进度条:
时钟:
天气:
心得体会
感谢硬禾举办的这次活动,让我有机会接触到wio terminal这款非常不错的板卡,丰富的资料与外设让我能够学到很多相关知识。
最后还是要吐槽下电子森林这个编辑器,对代码和图片编辑不太友好,建议支持markdown格式
再多吐槽一句,编辑项目时每一栏都需要分开保存,有点小小的无语。。。