Hallo, ich habe ein Metronom mit Vibrationsmotor für das Handgelenk gebaut. der Controller ist ein XIAO ESP32 C3. Es gibt 2 Modi: Modus 0 ist ESPNOW Empfang von einem anderen ESP und im Modus 1 generiert das Gerät selbst einen Tempopuls.
Nachdem es mit voreingestelltem Tempo (int bpm) lief, wollte ich nun die Tempoveränderung progarmmieren. Dabei hab ich wohl einen Fehler gemacht. Meine SerialMonitor-Ausgabe zeigt mir, dass das Tempo ohne das ich irgendeinen Touchsensor berühre auf den Mindestwert (minBPM) herunterrauscht. Der Ausdruck dürfte eigentlich nur einmal erfolgen, da er nur erfolgt, wenn der Wert geändert wurde: if( bpm != bpm_Old) ...
Die Ermittlung der anderen selbstgeschriebenen Funktionen (Voids) hat eigentlich funktioniert. Die Ermittlung von "statTouch" (bedeutet den Status der beiden Touchsensoren).
Ich weiß, es ist eine Zumutung solch laienhaften Code durchzuschauen. Aber "bpm" kann man ja mit der Suchfunktion "strg F" finden, denn nur im Zusammenhang mit "bpm" kann doch diese Integer verändert werden, oder nicht? Aber ich sehe da nichts, was automatisch, ohne Berührung von der Touchsensoren den Wert: "aktuell bpm: 30" verursacht.
Dann muss es ja woanders sein. Aber wo?
Also wenn mir da jemand weiterhelfen könnte, wäre das echt super. Oder auch eine Idee, was ich probieren / checken soll ...
Hier der Code:
const int Mot = D6; // VibrMotor
int play;
const int stark = 255; const int mittel = 150; const int leicht = 75; // Vibrationsstärke
const int tacet = 0; // Vibrationsstärke 0 = no Vibration
bool statMot;
// debug
bool statMot_old;
int bpm = 80;
const int minBPM = 30;
const int maxBPM = 270;
// debug
int bpm_Old;
int microTime;
int microTLaenge; // gleichbedeutend mit TaktArt
int taktLaenge = 1;
const int maxTL = 8;
bool changeTL;
const int Led = D10;
bool statLed;
int Rpt = 3;
int T = 225; // T = Time für Argument in Blitz()
const int Touch1 = D7, Touch2 = D8;
bool statTouch1, statTouch2; // in statTouchAll() ???
bool statTouch1_old, statTouch2_old;
int statTouch, statTouch_old;
long touch1Hold, touch2Hold;
const int touchWait = 1000; // = 1 Sekunde in ms
int IncrDecrTime; // kleiner zeitl Abstand bei TouchHold ( ==> gr Sprünge Incr/Decr)
// wird nicht verwendet???
int touchDelay = 2000; // in ms zur Entprellung und Two-Touchkombi
int sec = 1000; // in ms
int inTerval;
long past, present;
float voltKorr = 0.18; // Wert durch Testung ermittelt (bq)
int voltCounter; // hier als Anzahl Pulse für Batterie-Voltage
int Modus; // 0 = Reciever (default), 1 = Metronom, 2 = Charge, 3 wäre noch mögl. (noch nicht definiert)
// nur debug
int count;
void setup() {
pinMode(Mot, OUTPUT);
pinMode(Led, OUTPUT);
pinMode(Touch1, INPUT);
pinMode(Touch2, INPUT);
//pinMode(A0, INPUT); // für Voltage Messung -> braucht man nicht? -> Konflikt? wird so zu digitalEingang ???
digitalWrite(Mot, LOW); // evntl überflüssig ???
//Blitz(3, 225);
//delay(sec / 2); // zeitl. Abstand zur "Mod-ChoosingLed"
//############# SERIAL ###################################
Serial.begin(115200);
delay(50); // Zeit geben um Serial zum starten
Serial.println("Setup");
//########################################################
//??????????? Voltage Messung ????????????????????????????????????
voltMess(); // voltage Messung wird ausgelöst
showResult(Rpt, T); // Ergebnis wird gezeigt
//???????????????????????????????????????????????????????????
//!!!!!!!!!!!! A L A R M & DeepSleep !!!!!!!!!!!!!!!!!!!!!!!!!!
if (voltCounter < 2) { // dauert 1sec showResult() + delay(sleep) = 128sec + 34,7min < 37 min
doBattAlarm(Rpt, T); // am Ende von doBAttAlarm() nochmalige voltMess(), wenn nicht Volt erhöht ==> deepSleep()
} //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// wenn BattVolt OK dann einfach weiter
/////////// Mod-Choice-LED //////////////////////////////////////
digitalWrite(Led, HIGH);
delay(sec * 2); // jetzt Modus wählen (Touch 1 od 2 od no Touch)
digitalWrite(Led, LOW);
/////////////////////////////////////////////////////////////////
statTouchAll();
delay(sec / 2); // zeitl. Abstand zum Beginn showChooseResult
// Modus ermitteln & anzeigen (3 od. 4 Modi mögl. statTouch 0 - 2, evntl. 3 od. 4)
//////// Reciever - Modus: 3x Blink /////////////////////
if (statTouch == 0) {
Modus = 0; // Reciever
showResult(3, sec/4);
}
//////// internes Metronom - Modus: 5x Blink ////////////
if (statTouch != 0) {
Modus = 1; // internes Metronom
showResult(5, sec/4);
}
/* //////// Lademodus: 7x Blink ////// Lademod im RecieverMod includiert ///////////
if (statTouch == 2) {
Modus = 2; // Chargemode
for (int i = 0; i < 7; i++) {
digitalWrite(Led, HIGH);
delay(sec / 8);
digitalWrite(Led, LOW);
delay(sec / 2);
}
}
*/
// Reset
statTouch = 0;
// Serial.print("Modus: "); Serial.println(Modus);
// Serial.print("statTouch: "); Serial.println(statTouch);
// Serial.println("Reset Touch done");
}
void statTouchAll() {
statTouch1_old = statTouch1;
statTouch2_old = statTouch2;
statTouch_old = statTouch;
statTouch1 = digitalRead(Touch1);
statTouch2 = digitalRead(Touch2);
if ((statTouch1 == 0) && (statTouch2 == 0)) { // nix berührt
statTouch = 0;
}
/* ERLÄUTERUNG "statTouch" - Zustände (bei Berührung):
nur Touch1 = 1, Touch1 + (danach) Touch2 = 3 (= ungerade Zahlen)
nur Touch2 = 2, Touch2 + (danach) Touch1 = 4 (= gerade Zahlen) */
if (statTouch1 == 1) { // Touch1 berührt
if (statTouch1 != statTouch1_old) {
Blitz(1, sec/4); // Feedback: "Touch1 wurde berührt"
}
if (statTouch2 != statTouch2_old) {
if (statTouch2 == 1) { // zusätzlich Touch2 berührt
statTouch = 3;
}
}
else if (statTouch2 == 0) { // nur Touch1 berührt
statTouch = 1;
}
}
if (statTouch2 == 1) { // Touch2 berührt
if (statTouch2 != statTouch2_old) {
Blitz(1, sec/4); // Feedback: "Touch2 wurde berührt"
}
if (statTouch1 != statTouch1_old) {
if (statTouch1 == 1) { // zusätzlich Touch1 berührt
statTouch = 4;
}
}
else if (statTouch1 == 0) { // nur Touch2 berührt
statTouch = 2;
}
}
}
void voltMess() {
uint32_t Vbatt = 0;
for (int i = 0; i < 16; i++) {
Vbatt = Vbatt + analogReadMilliVolts(A0); // ADC with correction
}
float Vbattf = 2 * Vbatt / 16 / 1000.0; // attenuation ratio 1/2, mV --> V
float volBatt = Vbattf + voltKorr;
// voltage counter change
if (volBatt >= 4.1) {
voltCounter = 5;
} // => voll aufgeladen
if (volBatt >= 3.8 && volBatt < 4.1) {
voltCounter = 4;
} // => fast voll
if (volBatt >= 3.5 && volBatt < 3.8) {
voltCounter = 3;
} // => mittelvoll
if (volBatt >= 3.2 && volBatt < 3.5) {
voltCounter = 2;
} // => hält noch ein wenig (wie lange?)
if (volBatt < 3.2) {
voltCounter = 1;
} // => dringend aufladen!
Rpt = voltCounter;
}
void showResult(int Repeat, int Time) {
/* Ergebniscode: Blink 5x = Batt voll, 4x = fast voll, 3x = halbleer, 2x = bald leer,
Blink 1x = DRINGEND AUFLADEN !!! */
for (int i = 0; i < Repeat; i++) {
delay(Time); // startet mit delay() wg zeitl Abstand zu vorherig LedON
digitalWrite(Led, HIGH);
delay(Time);
digitalWrite(Led, LOW);
}
delay(sec/2);
}
void doBattAlarm(int Repeat, int Time) {
int sleep;
for (int i = 0; i < 64; i++) { // delay(sleep) = 2080 sec /60 = 34,6667 min
showResult(Repeat, Time);
Blitz(2, sec/4);
sleep = sleep++;
delay(sleep);
}
voltMess(); // vielleicht wurde inzwischen aufgeladen ...
// >>>>>>>>>>>> go to SLEEP >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
if (voltCounter < 2) {
esp_deep_sleep_start();
} // wird hoffentlich noch rechtzeitig geladen bevor Akku unter 3V ...
else {
sleep = 0; // reset sleep
};
}
void Blitz(int Repeat, int Time) { // Rpt = Anz. Wdh. Blitz; alarmTime = Pause zw Blitzen
for (int y = 0; y < Repeat; y++) {
//delay(Time); // delay() steht am Anfang für zeitl. Abstand zum vorherigen LedON
digitalWrite(Led, HIGH);
delay(25); // immer nur ultrakurzer Blitz
digitalWrite(Led, LOW);
delay(Time); // steht am Ende für zeitl. Abstand zur nachfolgenden LedON
}
}
void createBeat() {
/* TaktArt (= taktLaenge)
* TA 0 = alles 4tel (PWM: mittel); TA 1 = alles 4tel (Einsen - PWM: stark)
* TA 2 = 2/4; TA 3 = 3/4; TA 4 = 4/4; TA 5 = 5/4; TA 6 = 6/8;
* TA 7 = 7/4 (223); TA 8 = 4/4 m offBeats;
*/
if (microTime % 2 == 0) { //also bei microTime = 2; 4; 6; 8; 10; 12; 14; 16
play = tacet;
}
if (taktLaenge < 6) {
switch (microTime) {
case 1: if (taktLaenge == 0) {play = mittel;}
else play = stark; break; // Beat 1
case 3: play = mittel; break; // Beat 2
case 5: play = mittel; break; // Beat 3;
case 7: play = mittel; break; // Beat 4
case 9: play = mittel; break; // Beat 5;
// case 11; 13; 15 nur im 6/8 & 7/4 & 4/4offBeats möglich
}
}
if (taktLaenge == 6) { // Betonung: 3|3
switch (microTime) {
case 1: play = stark; break; // Beat 1
case 3: play = leicht; break; // Beat 2
case 5: play = leicht; break; // Beat 3
case 7: play = stark; break; // Beat 4
case 9: play = leicht; break; // Beat 5
case 11: play = leicht; break; // Beat 6
} // case 13; 15 nur im 7/4 & 4/4offBeats möglich
}
if (taktLaenge == 7) { // Betonung: 2|2|3
switch (microTime) {
case 1: play = stark; break; // Beat 1
case 3: play = mittel; break; // Beat 2
case 5: play = stark; break; // Beat 3
case 7: play = mittel; break; // Beat 4
case 9: play = stark; break; // Beat 5
case 11: play = mittel; break; // Beat 6
case 13: play = mittel; break; // Beat 7
} // case 15 nur im 4/4offBeats möglich
}
if (taktLaenge == 8) { //4/4 mit offBeats
switch (microTime) {
case 1: play = stark; break; // Beat 1
case 3: play = leicht; break; // offBeat
case 5: play = mittel; break; // Beat 2
case 7: play = leicht; break; // offBeat
case 9: play = stark; break; // Beat 3
case 11: play = leicht; break; // offBeat
case 13: play = mittel; break; // Beat 4
case 15: play = leicht; break; // offBeat
}
}
}
void showTL() {
digitalWrite(Mot, LOW); // evntl überflüssig ???
statMot = false; // überfrlüssig?
for (int i = 0; i < taktLaenge; i++) {
Blitz(2, sec/8);
delay(sec/4);
}
statMot = true; // überfrlüssig?
}
void loop() {
present = millis();
statTouchAll();
if (statTouch != 0) { // bei Touch - Eingabe kein Motor
statMot = false;
}
else statMot = true;
//########### debug ################################
if (statTouch != statTouch_old) {
Serial.print("statTOUCH: "); Serial.println(statTouch);
}
if (bpm != bpm_Old) {
Serial.print("aktuell BPM: "); Serial.println(bpm);
bpm = bpm_Old;
}
if (statMot != statMot_old) {
Serial.print("statMot: "); Serial.println(statMot);
statMot_old = statMot;
} //################################################
if (Modus == 0) { ///////// RECIEVER (Baustelle) /////////////////////////////////////
// hier kommt noch der Reciever-Block hin
//??????????? Voltage Messung ????????????????????????????????????
if (statTouch == 4) {
statMot = false;
voltMess(); // voltage Messung wird ausgelöst
showResult(Rpt, T); // Ergebnis wir gezeigt
//???????????????????????????????????????????????????????????
//!!!!!!!!!!!! A L A R M & DeepSleep !!!!!!!!!!!!!!!!!!!!!!!!!!
if (voltCounter < 2) { // dauert 1sec showResult() + delay(sleep) = 128sec + 34,7min < 37 min
doBattAlarm(Rpt, T);
} //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
} //???????????????????????????????????????????????????????????
// wenn BattVolt OK dann einfach weiter
statMot = true;
} /////////////////////// END RECIEVER /////////////////////////////////////////////
if (Modus == 1) { ///////// internMETRONOM //////////////////////////////////////////
microTLaenge = taktLaenge * 2; // ungerade Beats sind Pulse, gerade Beats sind Pausen
inTerval = 60000 / bpm / 2; // ungerade Beats sind Pulse, gerade Beats sind Pausen
//!!!!!!!!! Erzeugung Microtiming & MotorPuls !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
if (present >= past + inTerval) {
microTime++;
if (microTime > microTLaenge) { // microTLaenge: = taktLaenge * 2;
microTime = 1;
}
if (statMot == true) {
createBeat();
analogWrite(Mot, play); // play = Stärke PWM (stark, mittel od. leicht)
}
past = present;
} //!!!!!!!!!!!!!END MicroTIMING & MotorPULS !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!! +/- changeTEMPO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
if (statTouch_old == 0) {
if (statTouch == 1) {
bpm++; // = bpm wird höher (schneller)
//debug #########################################
Serial.println("bpm INcrease");
touch1Hold = present;
}
if (statTouch == 2) {
bpm--; // = bpm wird niedriger (langsamer)
//debug #########################################
Serial.println("bpm DEcrease");
touch2Hold = present;
}
}
if (statTouch == 1) {
if (present > touch1Hold + touchWait + IncrDecrTime) {
bpm = bpm + 5;
//debug #########################################
Serial.println("bpm INcrease + 5");
Blitz(1, 125); // 1x kurzBlink - Anzeige für Hochzälen
IncrDecrTime + 500; // nach 500 ms nächste +/- 5 IncreDecrement
}
}
if (statTouch == 2) {
if (present > touch2Hold + touchWait + IncrDecrTime) {
bpm = bpm - 5;
//debug #########################################
Serial.println("bpm DEcrease + 5");
Blitz(1, 125); // 1x kurzBlink - Anzeige für Runterzälen
IncrDecrTime + 500; // nach 500 ms nächste +/- 5 IncreDecrement
}
}
if (bpm < minBPM) {
bpm = minBPM;
}
if (bpm > maxBPM) {
bpm = maxBPM;
}
// reset nach Loslassen Touch1 od Touch2
if (statTouch == 0) {
IncrDecrTime = 0;
}
//!!!!!!!!!!!!!! END changeTEMPO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!! ++ takt LAENGE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
if (statTouch != statTouch_old) {
if (statTouch == 3) { // Touch1 gehalten, Touch2 neu berührt
taktLaenge++;
changeTL = true;
if (taktLaenge > maxTL) { // maxTL = 8 (in Header)
taktLaenge = 0;
}
}
// statTouch == 4 soll Tab-Tempo werden ==> Baustelle
//++++++++++++++++++ Baustelle TAB - TEMPO ++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
}
if (statTouch != statTouch_old && changeTL == true) {
if (statTouch == 0) {
delay(sec/2); // Abstand zum Loslassen, um showTL() besser zu erkennen
showTL();
changeTL = false;
}
} //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// //??????????? Voltage Messung ????????????????????????????????????
// if (statTouch == 4) {
// statMot = false;
// voltMess(); // voltage Messung wird ausgelöst
// showResult(Rpt, T); // Ergebnis wir gezeigt
// //???????????????????????????????????????????????????????????
// //!!!!!!!!!!!! A L A R M & DeepSleep !!!!!!!!!!!!!!!!!!!!!!!!!!
// if (voltCounter < 2) { // dauert 1sec showResult() + delay(sleep) = 128sec + 34,7min < 37 min
// doBattAlarm(Rpt, T);
// } //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// } //???????????????????????????????????????????????????????????
// // wenn BattVolt OK, dann einfach weiter
// statMot = true;
} //////////////////// END internMETRONOM ////////////////////////////////
}