Files
Arduino/CPU_temp/CPU_temp.ino
T
oskarvitaliiandClaude Opus 5 bd0a87ea49 feat(ui): тревога по перегреву и config.h со всеми настройками
Настройки собраны в 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>
2026-09-14 22:32:31 +07:00

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);
}
}