Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1febc0b092 | ||
|
|
a84f902f75 | ||
|
|
bcbeea2a17 | ||
|
|
1fe96b70aa | ||
|
|
43517a2c48 | ||
|
|
6a867e54fd |
@@ -1,3 +1,38 @@
|
||||
Version 1.10.4:
|
||||
- Die Maßnahme aus 1.10.3 machte die Delle nach dem Standby länger statt kleiner. Sie
|
||||
hielt beim Umschalten des Standby-Merkers den zuletzt gemeldeten Wert fest - zu diesem
|
||||
Zeitpunkt lag die gestörte Probe aber bereits an. Festgehalten wurde also ausgerechnet
|
||||
die Delle, und das sekundenlang.
|
||||
- Statt einer Sperrfrist tragen die Verlaufskurven jetzt den mittleren Wert der letzten
|
||||
fünf Proben ein (Median). Eine oder zwei verirrte Proben verschwinden damit vollständig,
|
||||
unabhängig davon, wann sie auftreten - beim Standby-Ende ebenso wie beim Bezugsstart.
|
||||
- Echte Temperaturänderungen kommen unverfälscht durch, nur zwei Sekunden später. Das ist
|
||||
die Verzögerung, um die es hier ging.
|
||||
- Die angezeigten Temperaturzahlen bleiben weiterhin ungefiltert.
|
||||
|
||||
Version 1.10.3:
|
||||
- Direkt nach dem Aufwachen aus dem Standby zog die Wasserkurve eine kurze Delle nach
|
||||
unten. Ursache ist die Messung, nicht der Kessel: In genau diesem Moment schalten die
|
||||
Heizungen, und der Wassersensor hängt als NTC am ADC. Ein Kessel kann binnen einer
|
||||
Sekunde nicht um Grade einbrechen.
|
||||
- Die Verlaufskurven halten deshalb rund um jeden Standby-Wechsel sechs Sekunden lang
|
||||
ihren letzten Wert, statt die gestörte Probe einzutragen. Das gilt für die kleinen
|
||||
Kurven im Dashboard und für die große Verlaufsseite.
|
||||
- Die angezeigten Temperaturzahlen bleiben unverändert: Dort steht weiter, was gemessen
|
||||
wird.
|
||||
- Die Versionsanzeige stand seit dem Zurücknehmen von 1.6.11 auf 1.6.10 fest und wurde bei
|
||||
keinem der folgenden Stände mitgezogen. Sie zeigt jetzt wieder den echten Stand.
|
||||
|
||||
Version 1.10.2:
|
||||
- Die Verlaufskurven im Dashboard wurden überhaupt nicht fortgeschrieben. Der Code dafür
|
||||
stand am Ende der Umschaltung „Heizleistung anzeigen" auf der Verlauf-Seite - also im
|
||||
Callback eines Knopfes. Die Kurven wuchsen nur weiter, wenn jemand genau diesen Knopf
|
||||
drückte. Sonst zeigten sie unverändert den Wert, der beim Aufbau der Darstellung gerade
|
||||
anlag: zwei flache, gleich hohe Linien.
|
||||
- Die Fortschreibung sitzt jetzt im sekündlichen Abtaster, dort, wo auch der große Verlauf
|
||||
seine Messwerte nimmt. Damit bewegen sich die Kurven, und die gemeinsame Skala aus 1.10.1
|
||||
kann ihre Arbeit überhaupt erst tun.
|
||||
|
||||
Version 1.10.1:
|
||||
- Die beiden Verlaufskurven teilen sich jetzt eine gemeinsame Skala. In 1.10.0 zoomte jede
|
||||
Kurve auf ihre eigenen Werte - dadurch saß jede mittig in ihrem eigenen Fenster, und
|
||||
|
||||
@@ -126,7 +126,7 @@
|
||||
// -------------------------------------------------------------------------------------
|
||||
// Firmware
|
||||
// -------------------------------------------------------------------------------------
|
||||
#define DISPLAY_FW_VERSION "1.6.10" // Firmware-Stand der P4-Display-Steuerung (Info-Seite)
|
||||
#define DISPLAY_FW_VERSION "1.10.4" // Firmware-Stand der P4-Display-Steuerung (Info-Seite)
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// Protokoll
|
||||
|
||||
+58
-10
@@ -1122,6 +1122,40 @@ static lv_obj_t* tempField(lv_obj_t* parent, const char* title, lv_color_t accen
|
||||
static int32_t g_sparkMin = INT32_MIN; // zuletzt gesetzter Ausschnitt, fuer beide gleich
|
||||
static int32_t g_sparkMax = INT32_MIN;
|
||||
|
||||
// Kurz nach einem Standby-Wechsel sackt die Wassertemperatur fuer einen Sekundenbruchteil
|
||||
// ab. In genau diesem Moment schalten die Heizungen, und der Wassersensor ist ein NTC am
|
||||
// ADC, einmal je Regelzyklus abgetastet - ein Kessel kann binnen einer Sekunde nicht um
|
||||
// Grade einbrechen, die Delle ist also eine Stoerung der Messung, kein Vorgang an der
|
||||
// Maschine.
|
||||
//
|
||||
// In die Kurven geht deshalb nicht die frische Probe, sondern der mittlere Wert der
|
||||
// letzten fuenf (Median). Eine oder zwei verirrte Proben verschwinden damit vollstaendig,
|
||||
// waehrend echte Temperaturaenderungen unverfaelscht durchkommen - nur eben zwei Sekunden
|
||||
// spaeter. Genau diese kleine Verzoegerung ist der Preis.
|
||||
//
|
||||
// Ein erster Anlauf hielt stattdessen beim Standby-Wechsel den zuletzt gemeldeten Wert
|
||||
// fest. Das machte es schlimmer: Beim Umschalten des Merkers lag die gestoerte Probe
|
||||
// bereits an, gehalten wurde also ausgerechnet die Delle - und zwar sekundenlang.
|
||||
// Die angezeigten Zahlen bleiben unangetastet - was gemessen wird, steht dort weiter drin.
|
||||
#define KURVEN_MEDIAN 5
|
||||
static float g_medW[KURVEN_MEDIAN];
|
||||
static float g_medD[KURVEN_MEDIAN];
|
||||
static uint8_t g_medPos = 0;
|
||||
static uint8_t g_medFill = 0;
|
||||
|
||||
// Mittlerer Wert von hoechstens fuenf Proben. Bei so wenigen Werten ist Sortieren durch
|
||||
// Einfuegen das Einfachste, was die Aufgabe loest.
|
||||
static float median_von(const float* quelle, uint8_t anzahl) {
|
||||
float f[KURVEN_MEDIAN];
|
||||
for (uint8_t i = 0; i < anzahl; i++) {
|
||||
float v = quelle[i];
|
||||
int8_t j = (int8_t)i - 1;
|
||||
while (j >= 0 && f[j] > v) { f[j + 1] = f[j]; j--; }
|
||||
f[j + 1] = v;
|
||||
}
|
||||
return f[anzahl / 2];
|
||||
}
|
||||
|
||||
static void spark_scan(lv_obj_t* ch, lv_chart_series_t* ser, int32_t* mn, int32_t* mx) {
|
||||
if (!ch || !ser) return;
|
||||
int32_t* pts = lv_chart_get_y_array(ch, ser);
|
||||
@@ -1727,14 +1761,6 @@ static void chart_duty_btn_cb(lv_event_t*) {
|
||||
else lv_obj_add_flag(g_legDuty, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
chart_redraw();
|
||||
|
||||
// Verlaufskurven des Dashboards (Darstellung "Verlauf") mitfuehren. Beide teilen sich
|
||||
// eine Skala, siehe spark_ranges_fit().
|
||||
if (g_sparkSerW && g_sparkW)
|
||||
lv_chart_set_next_value(g_sparkW, g_sparkSerW, (int32_t)(g_state.tempW * 10.0f));
|
||||
if (g_sparkSerD && g_sparkD)
|
||||
lv_chart_set_next_value(g_sparkD, g_sparkSerD, (int32_t)(g_state.tempD * 10.0f));
|
||||
spark_ranges_fit(); // gemeinsame Skala, damit die Hoehen vergleichbar bleiben
|
||||
}
|
||||
static void build_chart(lv_obj_t* p) {
|
||||
lv_obj_clear_flag(p, LV_OBJ_FLAG_SCROLLABLE);
|
||||
@@ -1959,11 +1985,33 @@ static void chart_redraw() {
|
||||
lv_chart_refresh(g_chart);
|
||||
}
|
||||
static void chart_sample_cb(lv_timer_t*) {
|
||||
// Verlaufskurven des Dashboards (Darstellung "Verlauf") fortschreiben. Das stand
|
||||
// frueher am Ende von chart_duty_btn_cb - also im Callback eines Knopfes auf der
|
||||
// Verlauf-SEITE. Die Kurven wurden dadurch nur fortgeschrieben, wenn jemand genau
|
||||
// diesen Knopf drueckte; sonst zeigten sie unveraendert den Wert, der beim Aufbau
|
||||
// der Darstellung gerade anlag. Beide Linien lagen deshalb flach und identisch.
|
||||
//
|
||||
// Bewusst vor dem Ausstieg unten: Die Kurven im Dashboard haengen nicht daran, ob
|
||||
// die Verlauf-Seite mit ihrem grossen Diagramm schon aufgebaut ist.
|
||||
// Frische Probe einreihen, in die Kurven geht der mittlere der letzten fuenf Werte.
|
||||
g_medW[g_medPos] = g_state.tempW;
|
||||
g_medD[g_medPos] = g_state.tempD;
|
||||
g_medPos = (uint8_t)((g_medPos + 1) % KURVEN_MEDIAN);
|
||||
if (g_medFill < KURVEN_MEDIAN) g_medFill++;
|
||||
const float probeW = median_von(g_medW, g_medFill);
|
||||
const float probeD = median_von(g_medD, g_medFill);
|
||||
|
||||
if (g_sparkSerW && g_sparkW)
|
||||
lv_chart_set_next_value(g_sparkW, g_sparkSerW, (int32_t)(probeW * 10.0f));
|
||||
if (g_sparkSerD && g_sparkD)
|
||||
lv_chart_set_next_value(g_sparkD, g_sparkSerD, (int32_t)(probeD * 10.0f));
|
||||
spark_ranges_fit(); // gemeinsame Skala, damit die Hoehen vergleichbar bleiben
|
||||
|
||||
if (!g_chart || !g_hist) return;
|
||||
// 1-s-Probe in die 60-min-Historie (Ringpuffer); Anzeige zeichnet chart_redraw
|
||||
bool caseOn = g_state.caseSensorEnabled && g_state.hasCaseTemp;
|
||||
g_hist->w[g_histPos] = (int16_t)(g_state.tempW * 10.0f + 0.5f);
|
||||
g_hist->d[g_histPos] = (int16_t)(g_state.tempD * 10.0f + 0.5f);
|
||||
g_hist->w[g_histPos] = (int16_t)(probeW * 10.0f + 0.5f);
|
||||
g_hist->d[g_histPos] = (int16_t)(probeD * 10.0f + 0.5f);
|
||||
g_hist->c[g_histPos] = caseOn ? (int16_t)(g_state.caseTemp * 10.0f + 0.5f) : CHART_HIST_NONE;
|
||||
float dw = g_state.dutyW, dd = g_state.dutyD;
|
||||
g_hist->dutyW[g_histPos] = (uint8_t)(dw < 0.0f ? 0 : (dw > 100.0f ? 100 : (int)(dw + 0.5f)));
|
||||
|
||||
Reference in New Issue
Block a user