Es soll ein Übungsbeispiel mit mehreren Hardware-Interrupts entstehen, eine Stoppuhr mit 5 Sensoren (erstmal mit Tastern simuliert), die jeweils einen Interrupt auslösen. Ziel ist, bei hohen Geschwindigkeiten einen hinreichend weit entfernten Sensor als Stoppzeitgeber auszuwerten.
Da der Uno nur 2 Interrupts anbietet, fiel die Wahl auf einen ESP32 Wroom32 von AZDelivery, bei dem theoretisch jeder GPIO für einen Hardwareinterrupt genutzt werden kann. Praktisch wohl nicht ohne weiteres, wegen anderweitiger boardseitiger Nutzung.
Das aktuelle Problem besteht derzeit darin, dass die serielle Ausgabe bei allen angebotenen und ausprobierten Baudraten den ersten String, wenn überhaupt, verkrüppelt herausbringt. Weitere serielle Ausgaben erfolgen nicht. Allerdings scheint etwas zu funktionieren: Die interne LED reagiert wie erwartet. Sie wird beim Betätigen des ersten Knopfes eingeschaltet und kann mit einem anderen ausgeschaltet werden.
Was kann die Ursache sein, dass die serielle Ausgabe während des Loops nichts ausgibt? Vertragen sich die Interrupts mit der seriellen Ausgabe vielleicht nicht? Oder ist das Board-spezifisch? Oder sollte ein anderes Board in der IDE eingestellt werden?
Verwendet wird die Arduino IDE 2.0.3., eingestelltes Board: ESP32 Dev Module.
Hier der Sketch (bei dem es erstmal nur um die Funktion an sich geht):
// Zeit messen mit 5 Tastern (Simulation mit 5 Gebern, z.B. Lichtschranken)
// ******
// Ziel ist es, in Abhängigkeit von der Geschwindigkeit, die Messung mit dem Taster zu beenden, der hinreichend weit genug vom Einschalttaster entfernt ist.
// Je höher die Geschwindigkeit, desto größer sollte der Messweg für einen brauchbaren Messwert sein.
// Board: ESP32 WROOM32 (AZ-Delivery)
// Struktur anlegen, die die Eigenschaften der Signaleingänge enthält
struct Button {
const uint8_t PIN; // Pin am Board
bool aktiv; // Zustandsflag des Eingangs
long t; // Zeitstempel
};
// Struktur vorbelegen
Button button1 = { 15, false, 0 };
Button button2 = { 2, false, 0 };
Button button3 = { 0, false, 0 };
Button button4 = { 4, false, 0 };
Button button5 = { 5, false, 0 };
// Messtimervariablen
bool messtimerFlag = false; // Flag ist HIGH während der Messung
bool ausgabeFlag = false; // Flag ist HIGH, wenn etwas auszugeben ist
long merk = millis(); // zum Merken der aktullen Zeit
// Variablen für Berechnungen
long messstart = 0; // Messtart
long messende = 0; // Messende
long messdauer = 0; // Messdauer
int stoptaster = 0; // Zustandsvariable, damit in der Ausgabe angegeben werden kann, welcher Eingang die Messung beendet hat
// interne LED
const uint8_t ledPin = 1; // Ausgabe-PIN der internen LED des Boards
void setup() {
Serial.begin(115200); // Serielle Ausgabe starten
Serial.println("Zeitmesser");
// Interrupt-Pins initialisieren
pinMode(button1.PIN, INPUT_PULLUP);
pinMode(button2.PIN, INPUT_PULLUP);
pinMode(button3.PIN, INPUT_PULLUP);
pinMode(button4.PIN, INPUT_PULLUP);
pinMode(button5.PIN, INPUT_PULLUP);
// Interrupts initialisieren
attachInterrupt(button1.PIN, isr1, FALLING);
attachInterrupt(button2.PIN, isr2, FALLING);
attachInterrupt(button3.PIN, isr3, FALLING);
attachInterrupt(button4.PIN, isr4, FALLING);
attachInterrupt(button5.PIN, isr5, FALLING);
// Indikator-LED initialisieren
pinMode(ledPin, OUTPUT); // Pin auf Ausgabe legen
digitalWrite(ledPin, HIGH); // Led AUS
}
void loop() {
if (button1.aktiv && (!messtimerFlag)) { // Wenn 1. Eingang und keine Messung im Gang, dann "Messung starten"
messtimerFlag = true; // Messtimerflag setzen
ausgabeFlag = false; // Berechnung und Ausgabe unterdrücken
Serial.println("1. Eingang ausgelöst "); // Monitoring
digitalWrite(ledPin, LOW); // Monitoring: LED ein
button1.aktiv = false; // Eingang 1 freigeben
// delay(100);
}
if (button2.aktiv && (messtimerFlag)) { // Wenn 2. Eingang und Messung aktiv, dann prüfen, ob Messung zu beenden ist
if ((button2.t - button1.t > 10000)) { // Wenn Zeit überschritten, Messung beenden
messdauer = button2.t - button1.t; // Berechnung
messtimerFlag = false; // Ende der Messung setzen
ausgabeFlag = true; // Ausgabe setzen
stoptaster = 2; // Monitoring
digitalWrite(ledPin, HIGH); // Monitoring: LED aus
}
button2.aktiv = false; // Eingang 2 "freigeben"
}
if (button3.aktiv && (messtimerFlag)) { // Wenn 3. Eingang und Messung aktiv, dann prüfen, ob Messung zu beenden ist
if ((button3.t - button1.t < 10000) && (button3.t - button1.t > 2500)) { // Wenn Zeitfenster überschritten, Messung beenden
messdauer = button3.t - button1.t; // Berechnung
messtimerFlag = false; // Ende der Messung setzen
ausgabeFlag = true; // Ausgabe setzen
digitalWrite(ledPin, HIGH); // Monitoring: LED aus
stoptaster = 3; // Monitoring
}
button3.aktiv = false; // Eingang 3 "freigeben"
}
if (button4.aktiv && (messtimerFlag)) { // Wenn 4. Eingang und Messung aktiv, dann prüfen, ob Messung zu beenden ist
if ((button4.t - button1.t < 2500) && (button2.t - button1.t > 1250)) { // Wenn Zeitfenster überschritten, Messung beenden
messdauer = button4.t - button1.t; // Berechnung
messtimerFlag = false; // Ende der Messung setzen
ausgabeFlag = true; // Ausgabe setzen
digitalWrite(ledPin, HIGH); // Monitoring: LED aus
stoptaster = 4; // Monitoring
}
button4.aktiv = false; // Eingang 4 "freigeben"
}
if (button5.aktiv && (messtimerFlag)) { // Wenn 5. Eingang und Messung aktiv, dann Messung beenden
messdauer = button5.t - button1.t; // Berechnung
messtimerFlag = false; // Ende der Messung setzen
ausgabeFlag = true; // Ausgabe setzen
digitalWrite(ledPin, HIGH); // Monitoring: LED aus
stoptaster = 5; // Monitoring
button5.aktiv = false; // Eingang 5 freigeben
}
// Ausgabe
if (ausgabeFlag) {
ausgabeFlag = false; // Ausgabeflag löschen
Serial.print("Stop-Taste: ");
Serial.print(String(stoptaster));
Serial.print(", Messdauer: ");
Serial.println(String(messdauer));
delay(3000); // 3 Sekunden anhalten
}
}
// ISR
void ICACHE_RAM_ATTR isr1() {
long zeitstempel = millis();
if (zeitstempel - button1.t > 25) { // Entprellen: Der letzte Aufruf der ISR muss älter als 25 ms sein
button1.aktiv = true; // Zustandsflag von Eingang 1 setzen
button1.t = zeitstempel; // Zeitstempel wird gespeichert
}
}
void ICACHE_RAM_ATTR isr2() {
long zeitstempel = millis();
if (zeitstempel - button2.t > 25) { // Entprellen: Der letzte Aufruf der ISR muss älter als 25 ms sein
button2.aktiv = true; // Zustandsflag von Eingang 2 setzen
button2.t = zeitstempel; // Zeitstempel wird gespeichert
}
}
void ICACHE_RAM_ATTR isr3() {
long zeitstempel = millis();
if (zeitstempel - button3.t > 25) { // Entprellen: Der letzte Aufruf der ISR muss älter als 25 ms sein
button3.aktiv = true; // Zustandsflag von Eingang 2 setzen
button3.t = zeitstempel; // Zeitstempel wird gespeichert
}
}
void ICACHE_RAM_ATTR isr4() {
long zeitstempel = millis();
if (zeitstempel - button4.t > 25) { // Entprellen: Der letzte Aufruf der ISR muss älter als 25 ms sein
button4.aktiv = true; // Zustandsflag von Eingang 2 setzen
button4.t = zeitstempel; // Zeitstempel wird gespeichert
}
}
void ICACHE_RAM_ATTR isr5() {
long zeitstempel = millis();
if (zeitstempel - button5.t > 25) { // Entprellen: Der letzte Aufruf der ISR muss älter als 25 ms sein
button5.aktiv = true; // Zustandsflag von Eingang 2 setzen
button5.t = zeitstempel; // Zeitstempel wird gespeichert
}
}