简述:小项目不到300行,包括platfromIO环境搭建,水墨屏显示,字库制作,https请求解析,定时休眠唤醒,适合刚入门esp32的同学们。
代码链接 esp32LunarDay: esp32赛博黄历,水墨屏显示,定时刷新
0.platfromIO环境搭建
参考博客:ESP32(VSCode+PlatformIO)开发环境搭建教程(2024版)_esp32 vscode-CSDN博客
0-1.选择芯片类型, 添加对应库文件
![](https://i-blog.csdnimg.cn/direct/721edf5718a04c7d83065b431bb1e144.png)
0-2.显示helloworld
display.init(115200);
display.setRotation(1);
display.setFont(&FreeSansBold24pt7b);
display.setCursor(60,60);
display.setTextColor(GxEPD_BLACK);
display.print("hello world!");
display.firstPage();
1.水墨屏显示字符
1-1.U8g2显示中文汉字 vscode代码设置编码:UTF-8!!!
U8G2_FOR_ADAFRUIT_GFX u8g2Fonts;//全局变量
void showData()
{
Serial.println("Enter showData");
display.fillScreen(GxEPD_WHITE);
u8g2Fonts.setForegroundColor(GxEPD_RED);//设置前景色(文字颜色)
u8g2Fonts.setBackgroundColor(GxEPD_WHITE);//设置背景色
display.setRotation(1);//屏幕方向
u8g2Fonts.setFont(u8g2_font_wqy12_t_chinese1);//设置 _wqy_字体
u8g2Fonts.setCursor(160,70);
u8g2Fonts.print("你好呀!");
}
1-2.自定义字库文件显示
显示自己喜欢的字体参考:Adafruit_GFX u8g2库添加中文字体_u8g2 字体-CSDN博客
需要的黄历汉字太多,快速生成:python获取黄历统计字符并去重
2.https请求与解析
2-1.对应的api接口
这里我用的是免费的API,也可以替换为你自己的;
https://www.36jxs.com/api/Commonweal/almanac?sun=2026-12-30
2-2.发起请求 解析数据
esp32发起https请求,和http有一点区别,代码如下:
String connectLunar(String &str_time)
{
String str_org_data = "";
WiFiClientSecure client;
client.setInsecure();
if (!client.connect("www.36jxs.com", 443))
{
Serial.println("www.36jxs.com failed");
return String("Connect www.36jxs.com failed");
}
Serial.println("Connection 36jxs success");
//发送Get请求
client.print(String("GET /api/Commonweal/almanac?sun=") + str_time.c_str() + " HTTP/1.1\r\n" +
"Host: www.36jxs.com\r\n" +
"Connection: close\r\n" +
"User-Agent: ESP8266\r\n" +
"\r\n");
while (client.connected() || client.available())
{
if (client.available())//读取数据并存入 str_org_data
{
str_org_data += client.readStringUntil('\r');
}
}
Serial.println(str_org_data);
client.stop();
return str_org_data;
}
存储数据 std::map
原生自带的C++没有相关容器,这里我们引入需要头文件#include <ArxContainer.h>
#include <ArxContainer.h>
std::map<String, String> dataMap;
添加后可使用C++一系列容器,对上面获取解析内容进行存储。
解析Json数据:
void parseJsonString(String &strClear)
{
int istart = strClear.indexOf("}}");
int iend = strClear.indexOf("{\"code\"");
String strrDate = strClear.substring(iend, istart + 2);//截取JSon字符串部分
Serial.println("===========strDate begin=========");
Serial.println(strrDate);
Serial.println("===========strDate end=========");
DynamicJsonDocument doc(2048); // 创建一个JSON文档对象,指定缓冲区大小
DeserializationError error = deserializeJson(doc, strrDate);
if (error)
{
Serial.print("Failed to parse JSON: ");
Serial.println(error.c_str());
return;
}
JsonObject data = doc["data"]; // 获取data字段的JsonObject
// 遍历data字段中的所有子字段
for (JsonPair kv : data)
{
String key = kv.key().c_str();
String value = kv.value().as<String>();
if (value.isEmpty())
{
value = "NULL";
}
dataMap[key] = value;
}
// 遍历并打印 dataMap 中的键值对
for (auto const &pair : dataMap)
{
Serial.print("Key: ");
Serial.print(pair.first);
Serial.print(" ==== Value: ");
Serial.println(pair.second);
}
}
3.排版显示数据
可自行调整排版,实现效果;
因为自定义字体不能生成太大的字符(我不会 ┭┮﹏┭┮),所以数字显示使用display.print();中文部分使用U8g2.print();
显示大号日期数字:
display.setFont(&FreeSansBold24pt7b);//设置文字字体
display.setCursor(110, 330);//显示位置坐标 (x,y)
display.setTextSize(6);//字体大小
display.setTextColor(GxEPD_RED);//字体颜色
String dateTime = dataMap["GregorianDateTime"]; //时间字符串
if (dateTime.length() >= 2)
{
String lastTwoChars = dateTime.substring(dateTime.length() - 2);//获取最后两位日期进行显示
display.print(lastTwoChars);
}
显示黄历文字:
u8g2Fonts.setCursor(160, 65);
u8g2Fonts.print(String("宜 : " + dataMap["Yi"]));
u8g2Fonts.setForegroundColor(GxEPD_GREEN);
u8g2Fonts.setBackgroundColor(GxEPD_WHITE);
u8g2Fonts.setCursor(160, 105);
u8g2Fonts.print(String("忌 : " + dataMap["Ji"]));
u8g2Fonts.setForegroundColor(GxEPD_ORANGE);
u8g2Fonts.setBackgroundColor(GxEPD_WHITE);
u8g2Fonts.setCursor(200, 400);
u8g2Fonts.print(String(dataMap["LMonth"]));
u8g2Fonts.setCursor(260, 400);
u8g2Fonts.print(String(dataMap["LDay"]));
4.设置休眠 定时更新
只获取一次接口数据,板子不需要一直运行,设置休眠并定时唤醒
4-1设置休眠
void deepSleepToMidnight()
{
// 获取当前时间
time_t now = time(nullptr);
struct tm timeinfo;
localtime_r(&now, &timeinfo);
int currentSeconds = timeinfo.tm_hour * 3600 + timeinfo.tm_min * 60 + timeinfo.tm_sec;
int secondsToMidnight = 86400 - currentSeconds; // 一天86400秒 - 当前时间
uint64_t oneDayMicros = secondsToMidnight * 1000ULL * 1000ULL; //uint64_t (int 存不下)
// 设置定时器唤醒时间
esp_sleep_enable_timer_wakeup(oneDayMicros);
// 进入深度睡眠模式
Serial.println("Entering deep sleep..after " + String(oneDayMicros) + " wake up");
esp_deep_sleep_start();
}
4-2打印唤醒原因
#include <esp_sleep.h>
#include <esp32/ulp.h>
esp_sleep_wakeup_cause_t wakeup_reason;//定义全局变量
void setup()
{
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println();
Serial.println("setup");
Serial.println("printlnwidth:" + String(display.width()));
Serial.println("printlnheight:" + String(display.height()));
// 获取睡眠唤醒原因
wakeup_reason = esp_sleep_get_wakeup_cause();
// 根据唤醒原因输出信息
switch (wakeup_reason)
{
case ESP_SLEEP_WAKEUP_TIMER:
Serial.println("Wake up from timer");
break;
case ESP_SLEEP_WAKEUP_ALL:
Serial.println("ESP_SLEEP_WAKEUP_ALL");
break;
case ESP_SLEEP_WAKEUP_UNDEFINED:
Serial.println("Wake up reason undefined");
break;
// 其他唤醒原因的case可以根据需要添加
default:
Serial.println("Wake up from other reasons");
break;
}
}
总结:
完整代码已开源,需要自取哈~
跑出来效果就是这样的啦!(屏幕磕到了┭┮﹏┭┮忽略就好~)
![](https://i-blog.csdnimg.cn/direct/638c132704e549e79d3eb0a1bbc4b676.jpeg)
版权归原作者 Tan Xi 所有, 如有侵权,请联系我们删除。