Go Down

Topic: Neuaufbau meiner Modellbahngeschwindigkeitsmessung (Read 908 times) previous topic - next topic

MicroBahner

#15
Jul 23, 2018, 10:55 am Last Edit: Jul 23, 2018, 11:02 am by MicroBahner
Hallo Jan,
wenn ein Moba-Kollege ein Problem hat, muss ich mich doch auch mal zu Wort melden  ;)

Zerrissen wird hier keiner  :) . Aber dein Sketch ist schon noch eine rechte Bauruine.
Kommentare sind zwar gut und wichtig ( an einigen Stellen könnten es durchaus auch ein paar mehr sein ). Aber sie sollten auch zum Programm passen! Kommentare, die was anderes sagen als der kommentierte Code, tragen sehr zur Verwirrung bei.

Dass es keine gute Idee ist, für die Abfrage eines mechanischen Tasters einen Interrupt herzunehmen, wurde ja schon gesagt. Das ist besser im loop aufgehoben. Dass der loop dann aber nicht mit delay lange blockiert werden darf, wurde ja auch schon gesagt.
Wichtig für das Entprellen ist eigentlich nur, dass der Taster nicht zu oft abgefragt wird. Die Libs, die es dafür gibt, sind m.M. nach nur Ressourcenvernichter und überflüssig. Definier dir eine Statusvariable für den Taster. Die aktualisierst Du dann am Anfang von loop, wenn seit der letzten Aktualisierung mindestens 10ms vergangen sind. Das kann man sehr schon und einfach mit millis machen und mehr braucht es dafür nicht. Im loop wird dann nur die Statusvariable verwendet.

Aufpassen muss man, wenn mit dem Taster 'getoggelt' werden soll ( bei dir die Umschaltung von Modus zwischen -1 und 1 ). Da darfst Du nicht den statischen Zustand des Tasters abfragen. Sonst wird während der Taster gedrückt ist, ständig zwischen -1 und 1 hin- und hergeschaltet, und welcher Zustand dann beim Loslassen herrscht ist rein zufällig. Da musst Du das 'Drücken'  also den Statuswechsel erkennen. Dazu musst Du dir bei jedem loop-Durchlauf auch den vorherigen Status merken, und nur wenn sich der Tasterstatus von 'nicht gedrückt' auf 'gedrückt'  ändert, darfst Du den Modus umschalten.

Dinge, die nur beim Programmstart ausgeführt werden sollen, gehören in  setup(), das mit dem modus==0 ist unnötig.

Die lcd-Aufrufe sind zeitintensiv. Deshalb - wie schon geschrieben wurde - das LCD wirklich nur bei Bedarf aktualisieren.

Ist deine Messtrecke wirklich variabel? Bei einer festen Messtrecke kannst Du die Werte als const im Programm eintragen, und brauchst deinen speziellen 'Strecken-Definiton-Mode' gar nicht. Es macht auch keinen Sinn, die Strecke in 1/10 mm anzugeben. So genau wirst Du das gar nicht ausrichten können.

So, das mal meine ersten Gedanken dazu.

Das kleine Prijekt ist auch eine wunderbare Gelegenheit, sich mal mit dem Thema 'endlicher Automat' auseinanderzusetzen. Da gibt's auch hier im Forum Beispiele dazu.



Gruß, Franz-Peter

Tommy56

Eine Frage noch zum Taster. Du fragst auf HIGH ab, d.h. Dein Taster schaltet nach 5V. Hast Du an dem Eingang einen Pulldownwiderstand von ca. 10 kOhm nach GND? Sonst wirkt der Eingang wie eine Antenne und fängt alles (un)mögliche ein.

Dass die delay aus dem Loop raus müssen, wurde Dir ja schon gesagt.

Gruß Tommy
"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)

Jan999

#17
Jul 23, 2018, 11:49 am Last Edit: Jul 23, 2018, 11:52 am by Jan999 Reason: Habe jetzt erst die anderen Postings von heute gesehen! :-(
Moin!

ich habe den Code einmal reduziert und auch den Interrupt herausgenommen.

Dann alles (bis auf den Kopf) reduziert. Über den Monitor lasse ich mir das Betätigen des Tasters dokumentieren.

Aber wenn ich auf den Taster drücke kommt folgendes:

Quote
1
          ----------
1
++++++++++          
-1
++++++++++          
1
++++++++++          
-1
++++++++++          
1
          ----------
1
Es wurde zwar einmal etwas von Bounce2 geschrieben - aber das habe ich mit meinem englisch Kenntnissen nicht verstanden.

Hier der Code:
Code: [Select]

// Lichtschranke für Zugeschwindigkeit in Verbindung mit Seriellen Monitor
//
// Einbinden der LCD-Funktionen derzeit noch inaktiv
// #include <LiquidCrystal_I2C.h>
// LiquidCrystal_I2C lcd(0x27, 16,2) // ?????
//
#include <Wire.h>  // Comes with Arduino IDE
#include <LiquidCrystal_I2C.h>

/*-----( Declare Constants )-----*/
/*-----( Declare objects )-----*/
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address
/*-----( Declare Variables )-----*/
//NONE

unsigned long start, finished, elapsed;
int modus=-1;      // Programmstart 0 / Def der Strecke =-1 / Messung = 1
int act=0;         // Messung läuft 1 / beendet oder nicht gestartet 0
int tstatus=0;     // Tasterstatus
int T1=7;          // 1. IR #7
int T2=8;          // 2. IR #8
int T3=9;          // 1. Taster für Modi-Wechsel
int P1=A1;         // ANALOG für Poti
// Werteabfrage
// IR
// aktueller Status
int cT1=-1;        // Status IR 1
int cT2=-1;        // Status IR 2
// vorheriger Status
int oT1=-1;        // Status IR 1
int oT2=-1;        // Status IR 2
int maxTime=0;     // Kennung für die Zeitüberschreitung
// Poti
int cP=0;          // Wert am Poti
// Werte für die Messstrecke (1/10mm)
int Svon = 3500;    // 50 cm
int Sbis = 4500;    // 60cm
int oDist =0;       // alter Streckenwert
char text[5];

void setup() {
  // Hier fehlt die Initalisierung des LCD
  Serial.begin(9600);    // öffnen der Seriellen Schnittstelle für die Überwachung
  pinMode(T1,INPUT);     // EINGANGSpin für den IR-#1
  pinMode(T2,INPUT);     // EINGANGSpin für den IR-#2
  pinMode(T3,INPUT);     // EINGANGSpin für den Taster
  
  lcd.setCursor(0,0); //Start at character 4 on line 0
  lcd.print("Lichtschranke");
  lcd.setCursor(0,1); //Start at character 4 on line 0
  lcd.print("bereit ...");
  delay(2000);
}

void loop() {
  // Abfrage des Tasters für Modus
  //Serial.println("Taster-Abfrage");
  if (digitalRead(T3)==HIGH){
    Serial.println("++++++++++          ");
    modus=modus*-1;
  }else{
    Serial.println("          ----------");
 }

Serial.println(modus);
  
  // Definition der Strecke
  if (modus==-1) {
//    Serial.println("Streckendefinition");
  }else{
//    Serial.println("Messung");
 }
  
}//end-loop


Kann mir zumindest für diese Stelle einer schon mal weiterhelfen??

Gruß Jan

Habe jetzt erst die anderen Postings von heute gesehen! :-(

MicroBahner

#18
Jul 23, 2018, 11:53 am Last Edit: Jul 23, 2018, 12:21 pm by MicroBahner
Hallo Jan,
das Ganze erstmal abzuspecken, und mit der Tasterabfrage zu beginnen ist ja schonmal gut. Aber hast Du dir durchgelesen, was ich geschrieben habe? Du machst in deinem Programm nichts davon - weder entprellen, noch die Flanke erkennen. So wie es jetzt ist, kann das nichts werden.


mal auf die reine Tastererkennung reduziert:
Code: [Select]
int modus=-1;      // Programmstart 0 / Def der Strecke =-1 / Messung = 1
const int T3=9;          // 1. Taster für Modi-Wechsel
bool T3State, T3oldState;
unsigned long lastAktT3;
const unsigned long prellZeit = 20;

void setup() {
  // Hier fehlt die Initalisierung des LCD
  Serial.begin(9600);    // öffnen der Seriellen Schnittstelle für die Überwachung
  pinMode(T3,INPUT);     // EINGANGSpin für den Taster
}

void loop() {
  // Abfrage des Tasters für Modus
  T3oldState = T3State;
  if ( millis() - lastAktT3 > prellZeit ) {
    lastAktT3 = millis();
    T3State = digitalRead(T3);
  }
  if (T3State && ! T3oldState){
    Serial.println("++++++++++          ");
    modus=modus*-1;
    Serial.println(modus);
  }

 
}//end-loop
Gruß, Franz-Peter

Jan999

#19
Jul 23, 2018, 12:51 pm Last Edit: Jul 23, 2018, 12:58 pm by Jan999 Reason: Anmerkung zu Beispielen im Netz
Hallo Franz-Peter,

ich habe mir das jetzt gerade durchgelesen.

Ist deine Messtrecke wirklich variabel? Bei einer festen Messtrecke kannst Du die Werte als const im Programm eintragen, und brauchst deinen speziellen 'Strecken-Definiton-Mode' gar nicht. Es macht auch keinen Sinn, die Strecke in 1/10 mm anzugeben. So genau wirst Du das gar nicht ausrichten können.

hatte ich so vorgesehen, dass diese nicht verbaut ist. Außerdem möchte ich nicht ein Rechner mitschleppen. Auf den 1/10 kann man verzichten.  8)

Nebensächlich - ich wundere mich, dass in diesem Code die LCD nicht reagiert! Habe ich versehentlich etwas gelöscht was erforderlich ist? Defekt und falsch angeschlossen ist ausgeschlossen, da in einem anderen Sketch es angesprochen wird.

Was die Frage nach der Steckung betrifft habe ich meine erste Skizze mit Fritzing erstellt:



Helfen diese Angaben weiter?

Ein Beispiel für eine Geschwindigkeitsmessung habe ich gefunden - https://forum.arduino.cc/index.php?topic=396341.0. Aber das ist nicht mein Ziel ich möchte es schrittweise mir selber erarbeiten. Eine Messung ohne den Taster und die Umschaltung hat schon einmal funktioniert.

Anmerkung zum Beispiel von Franz-Peter: das würdest Du dann in eine Void legen?

Gruß Jan


combie

#20
Jul 23, 2018, 01:27 pm Last Edit: Jul 23, 2018, 01:29 pm by combie
Quote
ich habe mir das jetzt gerade durchgelesen.
Ich mir deinen Code auch....

Aufgefallen ist mir, dass du, obwohl du eine Statemachine (oder auch mehrere) baust, dich dennoch nicht an die üblichen Verfahren hältst.
Das mach es für mich schwer zu lesen.

Beispiel:
> modus=modus*-1;
Magische Zahlen...
Hier würde ich dir einen kleinen, aber feinen, endlichen Automaten, empfehlen
Mit klar definierten Zuständen.

----


Es gibt mehrere Möglichkeiten/Verfahren Tasten auszulesen und zu entprellen.
1. Interrupts und in Hardware entprellen
2. in loop() pollen und mit Zeiten rechnen
3. in einem TimerTick und Ticks zählen

Alle 3 Verfahren haben ihren Reiz
Und ihre Anwendungen


Da die I2C Kommunikation doch recht lange blockiert, wie auch ein (kurzes) delay() es tun würde, möchte ich dir schon fast Weg 3 empfehlen. Der Weg ist hier im Forum nicht sonderlich weit verbreitet, zählt aber doch zu den üblichen.

---

Quote
das würdest Du dann in eine Void legen?
"Void" heißt "unbestimmt", "nicht vorhanden", oder sogar "egal"

> das würdest Du dann in eine unbestimmt legen?
> das würdest Du dann in eine nicht vorhanden legen?
Passt irgendwie nicht...
Ein Frosch, der im Brunnen lebt, beurteilt das Ausmaß des Himmels nach dem Brunnenrand.

Jan999

#21
Jul 23, 2018, 01:34 pm Last Edit: Jul 23, 2018, 01:43 pm by Jan999
Moin!

mit void wollte ich Funktion sagen - die Wärme macht etwas zu schaffen!

Quote
Nebensächlich - ich wundere mich, dass in diesem Code die LCD nicht reagiert! Habe ich versehentlich etwas gelöscht was erforderlich ist? Defekt und falsch angeschlossen ist ausgeschlossen, da in einem anderen Sketch es angesprochen wird.
Hier habe ich den Fehler gefunden!

LCD.Beginn fehlte!!!  ;D

Jan

combie

#22
Jul 23, 2018, 01:46 pm Last Edit: Jul 23, 2018, 01:48 pm by combie
Ja, die Wärme!

Und die Automaten?

Natürlich könnte ich dir meine Tastenabhandlungen und Entpreller zukommen lassen ... wenn du willst...
(evtl kommst du sogar dahinter, wie sie funktionieren...)

CombieLib.zip
Ein Frosch, der im Brunnen lebt, beurteilt das Ausmaß des Himmels nach dem Brunnenrand.

Jan999

#23
Jul 23, 2018, 01:52 pm Last Edit: Jul 23, 2018, 02:06 pm by Jan999
Moin!

für Wissen bin ich immer dankbar.

Habe jetzt die Tasterabfrage erst einmal in eine Sub gepackt.

Code: [Select]

// Tasterabfragen
void getTaster(){
  // Abfrage des Tasters für Modus
  T3oldState = T3State;
  if ( millis() - lastAktT3 > prellZeit ) {
    lastAktT3 = millis();  
    T3State = digitalRead(T3);
  }
  if (T3State && ! T3oldState){
    Serial.println("++++++++++          ");
    modus=modus*-1;
    Serial.println(modus);
  }  
}



Lässt sich sicherlich noch optimieren, dass man bei mehreren Tastern (Zukunft und andere Projekte) nur eine Funktion für mehrere Taster haben kann.

Gruß Jan

MicroBahner

Hallo Jan,
Du hättest es auch erstmal einfach am Anfang von loop stehen lassen können. Wenn man das lesen der Taste(n) in eine Funktion auslagert, sollte das Auswerten da aber eigentlich nicht mit rein.

Lässt sich sicherlich noch optimieren, dass man bei mehreren Tastern (Zukunft und andere Projekte) nur eine Funktion für mehrere Taster haben kann.
Die millis-Abfrage brauchst Du auch bei mehreren Tastern nur einmal. Innerhalb des millis-Blocks kannst Du beliebig viele Taster/Schalter abfragen, die werden dann alle mit entprellt.
Wenn Du es schon in eine Funktion auslagerst, würde es Sinn machen, die globalen Variablen zu reduzieren, und das Ergebnis der Tastenabfrage als Funktionswert zurückzugeben.
Gruß, Franz-Peter

Jan999

Quote
Wenn Du es schon in eine Funktion auslagerst, würde es Sinn machen, die globalen Variablen zu reduzieren, und das Ergebnis der Tastenabfrage als Funktionswert zurückzugeben.
Darüber muss ich mir noch ein anderes mal Gedanken machen. So wird der Hauptcode aber einfacher zu lesen - weil kürzer.

Nun muss ich erst ein schauen, ob meine Lichtschranken (IR-Hinderniserkenner) im Eimer sind. Alle Kontroll-LCD leuchten permanent und nicht nur, wenn ich die Hand davor bewege. Vermute, dass mir die irgendwie bei einer Fehlpolung abgeraucht sind.  :(

Jan


Tommy56

Die Frage nach dem Anschluß des Tasters (PullDown-Widerstand) wurde noch nicht beantwortet.

Gruß Tommy
"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)

Jan999

Hallo Thommy,

ich hatte doch die Grafik eingebunden. Oder ist das nicht die Info welche Du gesucht hattest. Mit der Lösung von Frank-Peter bin ich auch schon einen Schritt weiter.

Gruß Jan

MicroBahner

#28
Jul 23, 2018, 02:41 pm Last Edit: Jul 23, 2018, 02:47 pm by MicroBahner
Ja, in dem Fritzing-Bild sieht man den Widerstand. Über den Wert könnte man noch reden - scheint ein wenig hochohmig (falls das Bild dem tatsächlichen Widerstand entspricht), sollte aber prinzipiell funktionieren.
Wenn Du den Taster nach Gnd anschließt und den Eingang im Mode INPUT_PULLUP betreibst, könntest Du den Widerstand einsparen. Du musst dann nur die Abfrage rumdrehen:
Code: [Select]
T3State = !digitalRead(T3);
Gruß, Franz-Peter

Tommy56

Ich sehe kein Bild. Externer Server ohne Https?

Gruß Tommy
"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)

Go Up