墨水屏显示温度
main.cpp
#include <Arduino.h>
#include "GxEPD2_BW.h"
#include "U8g2_for_Adafruit_GFX.h"
#include <Adafruit_AHTX0.h>
#include <Ticker.h>
#include <LinkedList.h>
int listSize = 144;
int flushTime = 60 * 20; // 刷新间隔时间(秒) 20 分钟刷新一次,否则需要更改横坐标
int samplingTime = 15; // 采样间隔时间(秒),每 15 秒采样一次温度数并记录
// 到刷新时间后计算全部采样数据平均值,减少单次采样时温度抖动的影响
LinkedList<float> myList = LinkedList<float>();
LinkedList<float> avgTemperatureList = LinkedList<float>(); // 临时存放温度,用于减少偏差
Adafruit_AHTX0 aht;
sensors_event_t humidity, temp;
Ticker time1;
Ticker time2;
GxEPD2_BW<GxEPD2_290_T5D, GxEPD2_290_T5D::HEIGHT> display(GxEPD2_290_T5D(/*CS*/ SS, /*DC*/ 10, /*RST*/ 3, /*BUSY*/ 2));
U8G2_FOR_ADAFRUIT_GFX u8g2Fonts;
void writeFont(int16_t cursorX, int16_t cursorY, String str, const uint8_t font[])
{
u8g2Fonts.setFont(font);
int16_t ta = u8g2Fonts.getFontAscent();
int16_t td = u8g2Fonts.getFontDescent();
int16_t th = ta - td;
u8g2Fonts.setCursor(cursorX, cursorY + th);
u8g2Fonts.print(str);
}
void printStack()
{
float now;
float max;
float min;
// 计算最大和最小温度,用于动态修改 x 坐标范围
for (uint16_t i = 0; i < myList.size(); i++)
{
now = myList.get(i);
if (i == 0)
{
max = now;
min = now;
}
else
{
if (max < now)
{
max = now;
}
if (now < min)
{
min = now;
}
}
}
// 最大值往上取 5 的倍数 e.g. 17.1 -> 20.0 23.3 -> 25.0
int temp = max / 5;
max = (temp + 1) * 5;
// 最小值往下取 5 的倍数 e.g. 17.1 -> 15.0 23.3 -> 20.0
temp = min / 5;
min = temp * 5;
writeFont(110, 265, String(max), u8g2_font_t0_15_tf);
writeFont(10, 265, String(min), u8g2_font_t0_15_tf);
// 画温度
for (uint16_t i = 0; i < myList.size(); i++)
{
now = myList.get(i);
// Serial.println(now);
// 计算 x (max -now) * 100 / (max - min) + 10(距顶端偏移量)
int x = (100 - (max - now) * 100 / (max - min)) + 10;
// 计算 y
int y = (myList.size() - i) * 2;
display.fillRect(x, y, 2, 2, GxEPD_BLACK);
}
// 划分时间
// 12h
display.fillRect(10, 72, 100, 1, GxEPD_BLACK);
writeFont(0, 72 - 16, "12h", u8g2_font_6x10_tf);
// 24h
display.fillRect(10, 144, 100, 1, GxEPD_BLACK);
writeFont(0, 144 - 16, "24h", u8g2_font_6x10_tf);
// 36h
display.fillRect(10, 216, 100, 1, GxEPD_BLACK);
writeFont(0, 216 - 16, "36h", u8g2_font_6x10_tf);
// 上下横线
display.fillRect(10, 0, 1, 270, GxEPD_BLACK);
display.fillRect(110, 0, 1, 270, GxEPD_BLACK);
}
void addTemperature2AvgList()
{
aht.getEvent(&humidity, &temp);
avgTemperatureList.add(temp.temperature);
}
/*
获取统计间隔的平均温度,防止温度抖动
*/
float getAvgTemperature()
{
if (avgTemperatureList.size() == 0)
{
aht.getEvent(&humidity, &temp);
return temp.temperature;
}
LinkedList<float> tempList = LinkedList<float>();
// 存入临时变量,防止累加完后计算平均温度前增加了数据,导致温度异常
for (uint16_t i = 0; i < avgTemperatureList.size(); i++)
{
tempList.add(avgTemperatureList.get(i));
}
float sum = 0.0;
for (uint16_t i = 0; i < tempList.size(); i++)
{
sum += tempList.get(i);
}
float avgTemperature = sum / tempList.size();
tempList.clear();
avgTemperatureList.clear();
return avgTemperature;
}
void flushPaper()
{
aht.getEvent(&humidity, &temp);
// 控制数组最大的长度
if (myList.size() >= listSize)
{
myList.shift();
}
myList.add(getAvgTemperature());
display.firstPage();
do
{
// 当前的温度和湿度
writeFont(112, 0, String(temp.temperature), u8g2_font_t0_15_tf);
writeFont(112, 50, String(humidity.relative_humidity), u8g2_font_t0_15_tf);
printStack();
} while (display.nextPage());
display.hibernate();
}
void setup()
{
Serial.begin(115200);
Serial.println("begin...");
display.init(115200);
display.setRotation(0);
// display.setPartialWindow(0, 0, 128, 296); // 局部刷新
display.setFullWindow(); // 全局刷新
u8g2Fonts.begin(display);
u8g2Fonts.setFontMode(0);
u8g2Fonts.setFontDirection(1);
u8g2Fonts.setForegroundColor(GxEPD_BLACK);
u8g2Fonts.setBackgroundColor(GxEPD_WHITE);
if (!aht.begin())
{
Serial.println("Could not find AHT? Check wiring");
display.firstPage();
do
{
writeFont(50, 50, "Could not find AHT", u8g2_font_t0_15_tf);
} while (display.nextPage());
display.hibernate();
return;
}
Serial.println("AHT10 or AHT20 found");
time1.attach(flushTime, flushPaper);
delay(1000);
time2.attach(samplingTime, addTemperature2AvgList);
}
void loop()
{
}
platform.io
[env:esp32-c3-devkitm-1]
platform = espressif32
board = esp32-c3-devkitm-1
framework = arduino
board_build.flash_mode = dio
lib_ldf_mode = deep+
monitor_speed = 115200
lib_deps =
zinggjm/GxEPD2@^1.5.0
olikraus/U8g2_for_Adafruit_GFX@^1.8.0
olikraus/U8g2@^2.34.15
adafruit/Adafruit AHTX0@^2.0.3
ivanseidel/LinkedList@0.0.0-alpha+sha.dac3874d28