Zeit zwischen 2 Steigenden Flanken

Hallo!

Bin neu hier und habe leider nur wenig programmier Erfahrung.

Ich möchte die Zeit zwischen zwei steigenden Flanken messen.
Sprich:
Auf Eingang 2 hängt ein Sensor, auf Eingang 3 hängt ein Sensor.
Als erster kommt immer Eingang2 , dann einige Sekunden oder ms später kommt Eingang3, die Zeit möchte ich messen und dann daraus die Geschwindigkeit messen.
Kann mir hier jemand einen Codeansatz machen!?
Danke im Voraus

tschiesi:
Ich möchte die Zeit zwischen zwei steigenden Flanken messen.
Sprich:
Auf Eingang 2 hängt ein Sensor, auf Eingang 3 hängt ein Sensor.
Als erster kommt immer Eingang2 , dann einige Sekunden oder ms später kommt Eingang3, die Zeit möchte ich messen und dann daraus die Geschwindigkeit messen.
Kann mir hier jemand einen Codeansatz machen!?

  1. Du ermittelst den Zeitpunkt, an dem Eingang 2 auf HIGH wechselt
  2. Du ermittels den Zeitpunkt, an dem Eingang 3 auf HIGH wechselt
  3. Zum selben Zeitpunkt wie unter 2. ermittelst Du die Zeitdifferenz aus den beiden Zeitpunkten

Je nach gewünschter zeitlicher Auflösung verwendest Du zur Feststellung von Zeitpunkten die millis() oder die micros() Funktion.

const int LS_1 = 2;
const int LS_2 = 3;

long start;
long ende;
long dauer;

void setup ()
{
  pinMode(LS_1, INPUT);
  pinMode(LS_2, INPUT);
  Serial.begin(9600);
}


void loop ()
{
  while(digitalRead(LS_1) == HIGH)
  {
    start = millis();
  }
  
  while(digitalRead(LS_2) == HIGH)
  {
    ende = millis();
  }
  
  dauer = ende - start;
  Serial.println(dauer);
  
}

So hab ich das jetzt einmal gemacht!

Gibt es noch eine Möglichkeit die Ausgabe zu verschönern bzw. die Zeiten in eine Excel Liste zu schreiben?

tschiesi:
Gibt es noch eine Möglichkeit die Ausgabe zu verschönern bzw. die Zeiten in eine Excel Liste zu schreiben?

Für die loop:

void loop ()
{
  while(digitalRead(LS_1) == HIGH) ;
  start = millis();
  while(digitalRead(LS_2) == HIGH) ;
  dauer = millis()-start;
  Serial.println(dauer);
}

Die Daten kannst Du hinterher aus dem Seriellen Monitor herauskopieren in die Zwischenablage und von dort in anderen Programmen einfügen, oder in eine Textdatei einfügen und abspeichern.

Unter Windows Kopieren in die Zwischenablage:
Gewünschten Bereich mit der Maus markieren, dann Tastenkombination Strg-C

jurs:

  1. Du ermittelst den Zeitpunkt, an dem Eingang 2 auf HIGH wechselt
  2. Du ermittels den Zeitpunkt, an dem Eingang 3 auf HIGH wechselt
  3. Zum selben Zeitpunkt wie unter 2. ermittelst Du die Zeitdifferenz aus den beiden Zeitpunkten

Jurs ???

Wenn schon so ähnlich , dann:

void loop ()
{
  while(digitalRead(LS_1) == LOW) ;
  start = millis(); // LS_1 ist jetzt nicht mehr LOW
  while(digitalRead(LS_2) == LOW) ;
  dauer = millis()-start;
  Serial.print(dauer); Serial.println ( " ms ");
  while ( digitalRead(LS_1) == HIGH ||  digitalRead(LS_2) == HIGH ) { /* warten bis beide wieder LOW sind */ }
}

Danke für euren Tipp!

Gibt es eine Möglichkeit, dass ich die beiden Lichtschranken erst wieder mit einem Tastaturdruck (Enter) "scharf stelle"?

Was das ganze im Endeffekt werden soll ist eine Geschwindigkeitsmessung für ein Radrennen. Dafür möchte ich noch vorher jeweils eine Starnummer hinterlegen, und dann sollten die Daten alle in eine Excel geschrieben werden!?
Ist das möglich?
Wenn ja, könnt ihr mir da etwas helfen?
Danke im Voraus!

tschiesi:
Gibt es eine Möglichkeit, dass ich die beiden Lichtschranken erst wieder mit einem Tastaturdruck (Enter) "scharf stelle"?

Unter Sehr dringend Hilfe für Stoppuhr benötigt - #51 by jurs - Deutsch - Arduino Forum habe ich gerade einen Sketch für eine Lichtschranken-Zeitmessung gepostet, der nach Abschluss der Messung in eine Endlosschleife geht und dann nichts mehr macht. Ein "Reset" des Controllers stellt dann erneut die Messbereitschaft her. Man kann es natürlich auch so machen, dass über ein Kommando von der seriellen Schnittstelle wieder auf Messbereitschaft geschaltet wird.

tschiesi:
Was das ganze im Endeffekt werden soll ist eine Geschwindigkeitsmessung für ein Radrennen. Dafür möchte ich noch vorher jeweils eine Starnummer hinterlegen, und dann sollten die Daten alle in eine Excel geschrieben werden!?
Ist das möglich?

Datenformate, die sich leicht schreiben und von Excel lesen lassen, sind zum Beispiel "CSV" (Comma Seperated Values). Solche Daten sind Textformate, die sich leicht erzeugen lassen.

Du müßtest Dir nur überlegen, wo die Daten gespeichert werden sollen. Dabei stellt sich die Frage, ob Du sehr viele Startnummern und sehr viele Zeiten messen möchtest. Oder vielleicht nur 100 bis 200.

Zum Speichern großer Datenmengen kommen SD-Karten in Frage. Dann müßtest Du den Arduino mit SD-Kartenhardware ausrüsten. Zum Speichern kleiner Datenmengen kommt der im Chip eingebaute EEPROM-Speicher in Frage, der beim UNO 1 KB groß ist. Also wenn Du beispielsweise eine Startnummer zwischen 0 und 255 und eine Zeit in Millisekunden pro Messwert in 5 Bytes abspeicherst, würden ca. maximal 200 Messungen im EEPROM speicherbar sein.

ist auch eine Flankenmessung an einem Pin möglich?
Habe einen Universalencoder mit 8 Polen und würde gerne die Zeit zwischen 2 Flanken messen um die Geschwindigkeit 2 Motoren aneinander anzupassen.

Hast Du mal aufs Datum geschaut?

Gruß Tommy

Hallo,

dennoch die Frage nach einem Eingang ist neu.

den alten Skatch solltest Du nicht nehmen der blokiert alles. Und da Du ja sonst noch was anderes machen willst geht das nicht.

Ich hab hier mal was rausgesucht aus meinen ersten gehversuchen mit dem UNO.

eventuell must Du bei dem lesen des Einganges das invertieren rausnehmen.

Wenn Dein Encoder schnell dreht , und dein übriges Programm lange läuft , kann es sein das Du eventuell mit Interrupt arbeiten must. Da hab ich aber noch keine Ahnung von.

Gruß Heinz

//  Taster angeschlossen zwischen pin2 und 0V
int taster = 2;
unsigned long startzeit;
bool flag;// Hilfsflag
bool s_taster;// Pegel Taster

void setup() {
  pinMode(taster, INPUT_PULLUP);
  Serial.begin(9600);
}

void loop() {
  s_taster = !digitalRead(taster); // Taster invertiert lesen
 
  if (s_taster && !flag) {
    flag = true ;
    startzeit = micros();
    //delay(10);// zum entprellen
  }

  else if ( !s_taster && flag) {
    flag = false ;
    float messung = (micros() - startzeit) / 1000.0;
    Serial.print("Taster war gedrückt für ");
    Serial.print( messung, 3); Serial.println(" ms");
    //delay(10);// zum entprellen
  }
}

Ein eigener Thread wäre aber sinnvoller gewesen.

Gruß Tommy

Hallo,

wenn du dich mit den universellen Pin Interrupt auseinandersetzen möchtest, die Funktion haben viele Pins, an PCINTx erkennbar, nicht verwechseln mit INTx, dann kann ich dir ein Bsp. geben. Dazu µC Manual aufschlagen unter "external interrupts" und lesen. Dann kannste mit Bitmaskierung deine Zustände oder Flanken selbst auswerten und hast mehr Pins zur Verfügung wie nur die zwei INT0 und INT1. Der Vorteil wäre, dass der Zeitpunkt der Feststellung unabhängig von der Programmlaufzeit ist. Wenn dein Programm allerdings nichts weiter macht wäre auch normales Polling ausreichend ohne die Interruptauswertung.

War eine Spielerei von mir um das zuverstehen.

/* 
 * Doc_Arduino - german Arduino Forum
 * IDE 1.6.13
 * Arduino Mega2560
 * 27.01.2017
 * 
 * Einzelauswertung von mehreren PCINTs eines Ports, 
 * auch wenn diese zeitgleich sein sollten.
 */  

 /* 
  * PCINTx ... AVR Port.Pin ... Arduino Pin
  *    0   ...      PB.0    ...     53 
  *    1   ...      PB.1    ...     52
  *    2   ...      PB.2    ...     51  
  *    3   ...      PB.3    ...     50
  *    4   ...      PB.4    ...     10
  *    5   ...      PB.5    ...     11
  *    6   ...      PB.6    ...     12
  *    7   ...      PB.7    ...     13
  *    8   ...      PE.0    ...      0
  *    9   ...      PJ.0    ...     15 
  *   10   ...      PJ.1    ...     14
  *   11   ...      PJ.2    ...     N/A
  *   12   ...      PJ.3    ...     N/A
  *   13   ...      PJ.4    ...     N/A
  *   14   ...      PJ.5    ...     N/A
  *   15   ...      PJ.6    ...     N/A
  *   16   ...      PK.0    ...     A8
  *   17   ...      PK.1    ...     A9  
  *   18   ...      PK.2    ...     A10
  *   19   ...      PK.3    ...     A11
  *   20   ...      PK.4    ...     A12
  *   21   ...      PK.5    ...     A13
  *   22   ...      PK.6    ...     A14
  *   23   ...      PK.7    ...     A15
  *   
  *   PCIE0 ... PCINT7:0
  *   PCIE1 ... PCINT15:8
  *   PCIE2 ... PCINT23:16
  */

#include <util/atomic.h>    // für cli() und sei() mit SREG Sicherung

typedef enum {AUS, AKTIV, DONE} states;    // Steuerzustände
volatile states state_pcint = AUS;

unsigned long temp;
byte port;
volatile unsigned long interrupt_time;
volatile byte PortK;

const byte LED1 = 26;
const byte LED2 = 27;
const byte LED3 = 28;
const byte LED4 = 29;

void setup ()
{  
  // Serial.begin(9600);
  pinMode( A8, INPUT_PULLUP); 
  pinMode( A9, INPUT_PULLUP); 
  pinMode(A10, INPUT_PULLUP); 
  pinMode(A11, INPUT_PULLUP); 
  pinMode(LED1, OUTPUT); 
  pinMode(LED2, OUTPUT); 
  pinMode(LED3, OUTPUT); 
  pinMode(LED4, OUTPUT); 
  set_PCIE2();

}

    
void loop () 
{   
  ATOMIC_BLOCK (ATOMIC_RESTORESTATE) {   // cli & sei mit SREG Sicherung
    temp = interrupt_time; 
    port = PortK; 
  }

  Test_LED(port); 
  
  if ( millis() - temp > 2000) {
    state_pcint = AUS;
  }
  
}


// ****** Funktionen ****** //

ISR(PCINT2_vect)    // Interrupt Handler PCINT2
{  
  PortK = PINK;     // Port.K Zustand sichern
  state_pcint = AKTIV;
  interrupt_time = millis();
}


void Test_LED (byte& port)  // unabhängige Port.Pin Behandlung, auch mehrere zugleich
{
  if (state_pcint == AKTIV) {
    if ( !(port & (1<<PINK0)) )  {  // prüft ob PCINT16 auf Low angesprochen hat 
      digitalWrite(LED1, HIGH);
    }
    if ( !(port & (1<<PINK1)) )  {  // prüft ob PCINT17 auf Low angesprochen hat 
      digitalWrite(LED2, HIGH); 
    }
    if ( !(port & (1<<PINK2)) )  {  // prüft ob PCINT18 auf Low angesprochen hat 
      digitalWrite(LED3, HIGH); 
    }
    if ( !(port & (1<<PINK3)) )  {  // prüft ob PCINT19 auf Low angesprochen hat 
      digitalWrite(LED4, HIGH);    
    }  
    state_pcint = DONE;
  }
  
  if (state_pcint == AUS)  {
    digitalWrite(LED1, LOW);  
    digitalWrite(LED2, LOW);  
    digitalWrite(LED3, LOW);   
    digitalWrite(LED4, LOW);  
  } 
}


void set_PCIE2()
{
  PCICR = (1<<PCIE2);     // PCINT 23:16 Gruppentrigger aktiv
  PCMSK2 = (1<<PCINT16)|(1<<PCINT17)|(1<<PCINT18)|(1<<PCINT19);   // 4 PCINTs der Gruppe PCIE2 aktivieren
}


void del_PCIE2()
{
  PCICR &= ~(1<<PCIE2);   // PCINT 23:16 Gruppentrigger deaktivieren
  PCMSK2 = 0;             // alle PCINTs der Gruppe PCIE2 deaktivieren
}