Настройки собраны в config.h: пины, ориентация, пороги тревоги, шкала графика, тайминги и скорость Serial. Раньше они были раскиданы по модулям, и подстройка требовала лазить по коду. Тревога включается на ALARM_ON_C и отпускает только на ALARM_OFF_C (85 и 82 градуса). Один порог заставлял бы её дёргаться каждую секунду, пока температура топчется на границе. В тревоге экран мигает негативом (инверсия буфера, а не команда контроллера - не зависит от микросхемы дисплея), светодиод GPIO8 мигает с ним в общей фазе. Без данных светодиод горит ровно, в норме погашен. Зажигается низким уровнем: проверено опытом, заодно в простое пин стоит высоким, что безопасно для GPIO8 как пина начальной загрузки. Переменная alarm переименована в alarmActive: имя alarm занято функцией из unistd.h, которая попадает в сборку ESP32. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
68 lines
2.2 KiB
Arduino
68 lines
2.2 KiB
Arduino
// Индикатор температуры CPU: плата принимает строки "T=67.0;L=34" по USB-COM
|
|
// от агента на ПК и рисует их на встроенном OLED 72x40. Сама ничего не меряет.
|
|
//
|
|
// Все настройки — в config.h.
|
|
|
|
#include "config.h"
|
|
#include "link.h"
|
|
#include "ui.h"
|
|
|
|
static CpuStats stats = {0.0f, 0};
|
|
static uint32_t lastData = 0;
|
|
static uint32_t lastSample = 0;
|
|
static uint32_t lastDraw = 0;
|
|
static bool everGot = false;
|
|
static bool alarmActive = false;
|
|
|
|
void setup() {
|
|
pinMode(PIN_LED, OUTPUT);
|
|
digitalWrite(PIN_LED, !LED_ACTIVE_LEVEL);
|
|
|
|
linkBegin();
|
|
uiBegin();
|
|
}
|
|
|
|
// Гистерезис: включаемся на верхнем пороге, отпускаем только на нижнем.
|
|
static void updateAlarm(float tempC) {
|
|
if (!alarmActive && tempC >= ALARM_ON_C) alarmActive = true;
|
|
else if (alarmActive && tempC <= ALARM_OFF_C) alarmActive = false;
|
|
}
|
|
|
|
void loop() {
|
|
CpuStats fresh;
|
|
if (linkPoll(fresh)) {
|
|
stats = fresh;
|
|
lastData = millis();
|
|
everGot = true;
|
|
}
|
|
|
|
const bool isFresh = everGot && (millis() - lastData < STALE_MS);
|
|
|
|
if (isFresh) {
|
|
updateAlarm(stats.tempC);
|
|
} else {
|
|
alarmActive = false; // без данных о перегреве судить не по чему
|
|
}
|
|
|
|
// Общая фаза для экрана и светодиода, чтобы они моргали синхронно.
|
|
const bool blinkOn = (millis() / ALARM_BLINK_MS) % 2 == 0;
|
|
|
|
// Тревога — мигает, нет данных — горит ровно, норма — погашен.
|
|
bool ledOn;
|
|
if (!isFresh) ledOn = true;
|
|
else if (alarmActive) ledOn = blinkOn;
|
|
else ledOn = false;
|
|
digitalWrite(PIN_LED, ledOn ? LED_ACTIVE_LEVEL : !LED_ACTIVE_LEVEL);
|
|
|
|
// Историю дописываем только при живой связи: пауза не должна рисоваться провалом.
|
|
if (isFresh && millis() - lastSample >= SAMPLE_MS) {
|
|
lastSample = millis();
|
|
uiPushSample(stats.tempC);
|
|
}
|
|
|
|
if (millis() - lastDraw >= DRAW_MS) {
|
|
lastDraw = millis();
|
|
uiRender(isFresh, stats.tempC, stats.loadPct, alarmActive && blinkOn);
|
|
}
|
|
}
|