#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#define TFT_CS 10
#define TFT_DC 9
#define TFT_RST 8
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
// 自定义颜色
#define MY_GRAY tft.color565(128, 128, 128)
#define MY_LIGHTGRAY tft.color565(200, 200, 200)
#define MY_PINK tft.color565(255, 105, 180)
// 模拟数据
float tv = 12.59;
float cur = 1.20;
float pwr = 123.0;
float dv = 0.050;
float soc = 85.0;
bool charging = true;
void drawDisplay() {
tft.fillScreen(ILI9341_BLACK);
// ---- 颜色计算 ----
uint16_t socColor;
if (charging) {
socColor = ILI9341_GREEN;
} else if (soc < 20) {
socColor = ILI9341_RED;
} else if (soc < 80) {
socColor = ILI9341_YELLOW;
} else {
socColor = ILI9341_WHITE;
}
uint16_t pwrColor;
if (pwr > 300) {
pwrColor = ILI9341_RED;
} else if (pwr > 150) {
pwrColor = ILI9341_YELLOW;
} else {
pwrColor = ILI9341_GREEN;
}
// ---- 顶部电池图标 ----
int batX = 15, batY = 15, batW = 60, batH = 30;
tft.drawRect(batX, batY, batW, batH, ILI9341_WHITE);
tft.fillRect(batX + batW, batY + 5, 5, batH - 10, ILI9341_WHITE);
int fillW = (int)(soc / 100.0 * (batW - 4));
if (fillW > 0) {
tft.fillRect(batX + 2, batY + 2, fillW, batH - 4, socColor);
}
tft.setCursor(batX + batW + 15, batY + 5);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(2);
tft.printf("%.0f%%", soc);
// ---- 功率仪表盘 ----
int cx = 120, cy = 160; // 稍微下移,因为ILI9341是320x240,画布是240x320,但旋转后宽高互换
int radius = 90;
float startAngle = -140.0;
float endAngle = 140.0;
float pwrNorm = constrain(pwr / 400.0, 0.0, 1.0);
float currentAngle = startAngle + pwrNorm * (endAngle - startAngle);
float rad = currentAngle * DEG_TO_RAD;
// 刻度弧线
for (int deg = (int)startAngle; deg <= (int)endAngle; deg++) {
float radStep = deg * DEG_TO_RAD;
int x1 = cx + (radius - 5) * cos(radStep);
int y1 = cy + (radius - 5) * sin(radStep);
int x2 = cx + radius * cos(radStep);
int y2 = cy + radius * sin(radStep);
tft.drawLine(x1, y1, x2, y2, MY_GRAY);
}
// 刻度标签
tft.setTextSize(1);
for (int w = 0; w <= 400; w += 50) {
float ratio = w / 400.0;
float ang = (startAngle + ratio * (endAngle - startAngle)) * DEG_TO_RAD;
int labelR = radius + 15;
int x = cx + labelR * cos(ang);
int y = cy + labelR * sin(ang);
tft.setCursor(x - 10, y - 7);
tft.setTextColor(MY_LIGHTGRAY);
tft.printf("%d", w);
}
// 指针
int tipX = cx + (radius - 15) * cos(rad);
int tipY = cy + (radius - 15) * sin(rad);
tft.drawLine(cx, cy, tipX, tipY, pwrColor);
tft.fillCircle(cx, cy, 6, ILI9341_WHITE);
tft.fillCircle(cx, cy, 3, pwrColor);
// 功率数值
tft.setTextSize(4);
tft.setCursor(cx - 45, cy - 30);
tft.setTextColor(pwrColor);
tft.printf("%.0f", pwr);
tft.setTextSize(2);
tft.setCursor(cx - 10, cy + 10);
tft.setTextColor(ILI9341_WHITE);
tft.print("W");
// ---- 底部数据 ----
int baseY = 280; // 因为ILI9341高度320,底部留空间
tft.setTextSize(2);
tft.setCursor(20, baseY);
tft.setTextColor(ILI9341_CYAN);
tft.printf("%.2fV", tv);
tft.setCursor(100, baseY);
if (charging) {
tft.setTextColor(ILI9341_GREEN);
tft.printf("↑%.2fA", cur);
} else if (cur < -0.05) {
tft.setTextColor(ILI9341_ORANGE);
tft.printf("↓%.2fA", -cur);
} else {
tft.setTextColor(ILI9341_WHITE);
tft.print("·0.00A");
}
tft.setCursor(180, baseY);
tft.setTextColor(MY_PINK);
tft.printf("d%.0f", dv * 1000);
}
void setup() {
Serial.begin(115200);
tft.begin();
tft.setRotation(0); // 0: 240x320 (宽240, 高320)
tft.fillScreen(ILI9341_BLACK);
delay(100);
}
void loop() {
static unsigned long lastUpdate = 0;
if (millis() - lastUpdate > 500) {
lastUpdate = millis();
pwr += 10;
if (pwr > 400) pwr = 0;
tv = 12.5 + pwr / 800.0;
cur = pwr / 100.0;
soc = 50 + pwr / 8.0;
if (soc > 100) soc = 100;
if (soc < 10) soc = 10;
dv = 0.020 + pwr / 20000.0;
charging = (cur > 0.1);
drawDisplay();
}
}