Skip to content

Commit c43f3d3

Browse files
Add files via upload
1 parent f3c6b3c commit c43f3d3

File tree

4 files changed

+460
-0
lines changed

4 files changed

+460
-0
lines changed

src/SoftPathCalibrator.cpp

Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
// SoftPathCalibrator.cpp
2+
#include "SoftPathCalibrator.h"
3+
4+
SoftPathCalibrator::SoftPathCalibrator() :
5+
_platform(SPK_PLATFORM),
6+
_pin(0),
7+
_numKeys(0),
8+
_tol(8), // empfohlener Standardwert
9+
_debounceAfterZero(false)
10+
{
11+
_keyStr[0] = '\0';
12+
}
13+
14+
/* ---------- öffentlich ---------- */
15+
16+
void SoftPathCalibrator::begin() {
17+
Serial.begin(115200);
18+
while (!Serial) { }
19+
20+
Serial.println(F("SoftPath Keypad Kalibrator v1.3"));
21+
printPlatform();
22+
overridePlatform();
23+
askPin();
24+
askKeys();
25+
askTolerance();
26+
askDebounce();
27+
calibrateKeys();
28+
buildKeyString();
29+
30+
Serial.println();
31+
Serial.println(F("Kalibrierung abgeschlossen. Key-String:"));
32+
Serial.println(_keyStr);
33+
}
34+
35+
/* ---------- generische I/O-Helfer ---------- */
36+
37+
void SoftPathCalibrator::printPlatform() {
38+
Serial.print(F("Erkannte Plattform: "));
39+
Serial.println(_platform == 0 ? F("UNO/AVR") : F("ESP32"));
40+
}
41+
42+
void SoftPathCalibrator::overridePlatform() {
43+
Serial.println(F("Plattform überschreiben? "
44+
"'u' = UNO, 'e' = ESP32 (3 s)…"));
45+
unsigned long t0 = millis();
46+
while (millis() - t0 < 3000) {
47+
if (Serial.available()) {
48+
char c = Serial.read();
49+
if (c == 'u' || c == 'U') { _platform = 0; break; }
50+
if (c == 'e' || c == 'E') { _platform = 1; break; }
51+
}
52+
}
53+
}
54+
55+
void SoftPathCalibrator::readLine(String& out) {
56+
while (!Serial.available()) { delay(10); }
57+
out = Serial.readStringUntil('\n');
58+
out.trim();
59+
}
60+
61+
bool SoftPathCalibrator::askYesNo(const __FlashStringHelper* prompt) {
62+
Serial.println(prompt);
63+
String line; readLine(line);
64+
if (!line.length()) return false;
65+
char c = line[0];
66+
return (c == 'j' || c == 'J' || c == 'y' || c == 'Y');
67+
}
68+
69+
/* ---------- Hilfetexte ---------- */
70+
71+
void SoftPathCalibrator::helpTolerance() {
72+
Serial.println(F("\nToleranz beschreibt, wie stark der gemessene ADC-Wert\n"
73+
"vom Sollwert einer Taste abweichen darf, damit sie noch\n"
74+
"als gedrückt erkannt wird. Ein zu kleiner Wert führt\n"
75+
"zu Fehlschlägen, ein zu großer kann Mehrfach­zuordnungen\n"
76+
"verursachen.\n"
77+
"Beispiel bei 10-Bit-ADC und Sollwert 512:\n"
78+
"Toleranz 8 → gültig 504…520\n"
79+
"Toleranz 20 → gültig 492…532\n"));
80+
}
81+
82+
void SoftPathCalibrator::helpDebounce() {
83+
Serial.println(F("\n„Nach Nullwert entprellen“ sorgt dafür, dass zwischen\n"
84+
"zwei Tastendrücken erst ein eindeutiger Null-ADC-Wert\n"
85+
"erkannt werden muss. Dadurch werden Fehl­erkennungen\n"
86+
"bei sehr schnellen oder über­schneidenden Drücken\n"
87+
"vermieden.\n"
88+
"Aktiviert (j): gedrückt → loslassen (ADC≈0) → nächste Taste\n"
89+
"Deaktiviert (n): jede Taste sofort gültig.\n"));
90+
}
91+
92+
/* ---------- Fragen ---------- */
93+
94+
void SoftPathCalibrator::askPin() {
95+
if (_platform == 0) {
96+
Serial.println(F("Analogen Pin eingeben (A0–A5 oder 0–5):"));
97+
String line; readLine(line); line.toUpperCase();
98+
if (line.startsWith("A")) line.remove(0, 1);
99+
_pin = constrain(line.toInt(), 0, 5);
100+
} else {
101+
Serial.println(F("GPIO-Nummer eingeben (0–39):"));
102+
String line; readLine(line);
103+
_pin = constrain(line.toInt(), 0, 39);
104+
}
105+
}
106+
107+
void SoftPathCalibrator::askKeys() {
108+
Serial.println(F("Anzahl der Tasten (3 / 4 / 6 / 12 / 16):"));
109+
String line; readLine(line);
110+
uint8_t n = line.toInt();
111+
if (n == 3 || n == 4 || n == 6 || n == 12 || n == 16) _numKeys = n;
112+
else _numKeys = 4;
113+
}
114+
115+
void SoftPathCalibrator::askTolerance() {
116+
for (;;) {
117+
Serial.println(F("Toleranz 4–60 (Standard 8, 'h' für Hilfe):"));
118+
String line; readLine(line);
119+
if (!line.length()) { _tol = 8; break; } // Standard
120+
if (line[0] == 'h' || line[0] == 'H') { helpTolerance(); continue; }
121+
uint16_t v = line.toInt();
122+
if (v >= 4 && v <= 60) { _tol = v; break; }
123+
Serial.println(F("Ungültige Eingabe.\n"));
124+
}
125+
}
126+
127+
void SoftPathCalibrator::askDebounce() {
128+
for (;;) {
129+
Serial.println(
130+
F("Nach Nullwert entprellen? (j/n, 'h' für Hilfe):"));
131+
String line; readLine(line);
132+
if (!line.length()) { _debounceAfterZero = false; break; }
133+
char c = line[0];
134+
if (c == 'h' || c == 'H') { helpDebounce(); continue; }
135+
if (c == 'j' || c == 'J' || c == 'y' || c == 'Y') {
136+
_debounceAfterZero = true; break;
137+
}
138+
if (c == 'n' || c == 'N') { _debounceAfterZero = false; break; }
139+
Serial.println(F("Bitte 'j' oder 'n' eingeben.\n"));
140+
}
141+
}
142+
143+
/* ---------- ADC-Helfer ---------- */
144+
145+
uint16_t SoftPathCalibrator::readAnalogOnce() {
146+
#if SPK_PLATFORM == 0
147+
return analogRead(_pin + A0);
148+
#else
149+
return analogRead(_pin);
150+
#endif
151+
}
152+
153+
void SoftPathCalibrator::gatherReadings(uint16_t* buf) {
154+
uint8_t i = 0;
155+
while (i < 6) {
156+
uint16_t v = readAnalogOnce();
157+
if (v > 0) {
158+
buf[i++] = v;
159+
Serial.print('.');
160+
}
161+
delay(8);
162+
}
163+
Serial.println();
164+
}
165+
166+
uint16_t SoftPathCalibrator::medianOfSix(uint16_t* arr) {
167+
uint16_t t[6];
168+
for (uint8_t i = 0; i < 6; ++i) t[i] = arr[i];
169+
for (uint8_t i = 0; i < 5; ++i)
170+
for (uint8_t j = i + 1; j < 6; ++j)
171+
if (t[j] < t[i]) { uint16_t x = t[i]; t[i] = t[j]; t[j] = x; }
172+
return (uint16_t)((t[2] + t[3]) / 2);
173+
}
174+
175+
/* ---------- ASCII-Layout ---------- */
176+
177+
void SoftPathCalibrator::drawLayout(uint8_t highlight) {
178+
uint8_t cols, rows;
179+
switch (_numKeys) {
180+
case 3: cols = 3; rows = 1; break;
181+
case 4: cols = 4; rows = 1; break;
182+
case 6: cols = 3; rows = 2; break;
183+
case 12: cols = 3; rows = 4; break;
184+
default: cols = 4; rows = 4; break;
185+
}
186+
187+
Serial.println();
188+
for (uint8_t r = 0; r < rows; ++r) {
189+
Serial.print('+');
190+
for (uint8_t c = 0; c < cols; ++c) Serial.print(F("----+"));
191+
Serial.println();
192+
193+
Serial.print('|');
194+
for (uint8_t c = 0; c < cols; ++c) {
195+
uint8_t idx = r * cols + c;
196+
char cell[5] = " ";
197+
if (idx < _numKeys) {
198+
char d[4]; sprintf(d, "%u", idx + 1);
199+
if (idx == highlight) cell[0] = '>';
200+
memcpy(cell + 1, d, strlen(d));
201+
}
202+
Serial.print(cell); Serial.print('|');
203+
}
204+
Serial.println();
205+
}
206+
Serial.print('+');
207+
for (uint8_t c = 0; c < cols; ++c) Serial.print(F("----+"));
208+
Serial.println("\n");
209+
}
210+
211+
/* ---------- Kalibrierung ---------- */
212+
213+
void SoftPathCalibrator::calibrateKeys() {
214+
uint16_t buf[6];
215+
216+
Serial.println(F("=== Kalibrierung ==="));
217+
for (uint8_t k = 0; k < _numKeys; ++k) {
218+
bool done = false;
219+
while (!done) {
220+
drawLayout(k);
221+
uint16_t med1 = 0, med2 = 0;
222+
223+
for (uint8_t p = 0; p < 2; ++p) {
224+
Serial.print(F("Taste ")); Serial.print(k + 1);
225+
Serial.print(F(", Durchgang ")); Serial.print(p + 1);
226+
Serial.println(F(": drücken & halten…"));
227+
while (readAnalogOnce() == 0) { delay(5); }
228+
gatherReadings(buf);
229+
(p == 0 ? med1 : med2) = medianOfSix(buf);
230+
Serial.println(F("Loslassen…"));
231+
while (readAnalogOnce() > 0) { delay(5); }
232+
}
233+
234+
uint16_t diff = (med1 > med2) ? (med1 - med2) : (med2 - med1);
235+
if (diff > _tol) {
236+
Serial.print(F("Warnung: Abweichung "));
237+
Serial.print(diff);
238+
Serial.print(F(" > Toleranz "));
239+
Serial.println(_tol);
240+
if (askYesNo(
241+
F("Evtl. falsche Taste? Nochmals versuchen? (j/n):")))
242+
continue;
243+
}
244+
_values[k] = (uint16_t)((med1 + med2) / 2);
245+
Serial.print(F(" → gespeicherter Wert: "));
246+
Serial.println(_values[k]);
247+
done = true;
248+
}
249+
}
250+
}
251+
252+
/* ---------- Key-String ---------- */
253+
254+
void SoftPathCalibrator::buildKeyString() {
255+
char* p = _keyStr;
256+
int n = sprintf(p, "SPK1 %u %u %u %u %u",
257+
_platform, _pin, _numKeys,
258+
_tol, _debounceAfterZero ? 1 : 0);
259+
p += n;
260+
for (uint8_t i = 0; i < _numKeys; ++i) {
261+
n = sprintf(p, " %u", _values[i]); p += n;
262+
}
263+
sprintf(p, "\r\n");
264+
}

src/SoftPathCalibrator.h

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// SoftPathCalibrator.h
2+
#ifndef SOFTPATH_CALIBRATOR_H
3+
#define SOFTPATH_CALIBRATOR_H
4+
5+
#include <Arduino.h>
6+
7+
#if defined(ARDUINO_ARCH_AVR)
8+
#define SPK_PLATFORM 0 // UNO / AVR (10-Bit-ADC)
9+
#elif defined(ESP32)
10+
#define SPK_PLATFORM 1 // ESP32 (12-Bit-ADC)
11+
#else
12+
#error "Nicht unterstützte Plattform"
13+
#endif
14+
15+
/*
16+
* SoftPathCalibrator
17+
* Interaktive Kalibrier-Bibliothek für analoge Keypads.
18+
* Alle Dialoge sind auf Deutsch. Bei den Fragen „Toleranz“ und
19+
* „Nach Nullwert entprellen?“ kann der Benutzer „h“ eingeben,
20+
* um eine kurze Hilfe angezeigt zu bekommen.
21+
*/
22+
class SoftPathCalibrator {
23+
public:
24+
SoftPathCalibrator();
25+
void begin(); // startet den Dialog
26+
const char* getKey() const { return _keyStr; }
27+
28+
private:
29+
uint8_t _platform; // 0 = UNO, 1 = ESP32
30+
uint8_t _pin; // Kanal (UNO) bzw. GPIO (ESP32)
31+
uint8_t _numKeys; // 3,4,6,12,16
32+
uint16_t _tol; // Toleranz
33+
bool _debounceAfterZero; // Debounce-After-Zero
34+
uint16_t _values[16]; // Zielwerte
35+
char _keyStr[192]; // Key-String
36+
37+
/* interne Helfer */
38+
void printPlatform();
39+
void overridePlatform();
40+
void askPin();
41+
void askKeys();
42+
void askTolerance();
43+
void askDebounce();
44+
void calibrateKeys();
45+
void buildKeyString();
46+
47+
uint16_t readAnalogOnce();
48+
void gatherReadings(uint16_t* buf);
49+
uint16_t medianOfSix(uint16_t* arr);
50+
void readLine(String& out);
51+
void drawLayout(uint8_t highlight);
52+
bool askYesNo(const __FlashStringHelper* prompt);
53+
54+
/* Hilfetexte */
55+
void helpTolerance();
56+
void helpDebounce();
57+
};
58+
59+
#endif // SOFTPATH_CALIBRATOR_H

0 commit comments

Comments
 (0)