Geschwindigkeitsmesser für Kegelbahn - Die Zweite

Hallo zusammen.

Vor knapp drei Jahren habe ich hier im Forum viel Hilfe erhalten bei der Konstruktion und Programmierung meiner lasergestützten Geschwindigkeitsmessung für die Kegelbahn.
(https://forum.arduino.cc/index.php?topic=456884.0)

Bei der Vorstellung des Projekts fragte jemand, wieso ich denn keine Großanzeige verwende.
Und genau dies möchte ich jetzt realisieren.

Ich habe mir also 4 in 1 Max7219 LED-Display besorgt und versucht, den Code entsprechend anzupassen, dass die Ausgabe auf dem LED-Display geschieht.
Leider passiert nichts…
Und da ich keine Ahnung von Programmieren habe, finde ich den Fehler nicht.

Kann mir jemand von Euch bei der Lösung des Problems helfen?

Anbei der von mir modifizierte Code für die MAX7219-Anzeige, der nicht funktioniert:

/*
 Quelle: http://www.elektronik-labor.de/Arduino/Speed.html
 von Gerd Sinning
 
 Arduino Speedy
 Measure time and calculate speed
 uses a laserdiode, 2 mirrors and a photodiode for light barrier
 
 Photodiode signal goes to Input Capture Pin on PB0, Arduino pin8
 measures time from falling edge to next falling edge = total time
 first measures time from falling edge to next rising edge = time1 (low time)
 useful to abt 50 us, minimum low time is 4 us
 
 serial output and LCD defined/not used

 GS 3-2014

 Bearbeitet von Emmeff 2019
 
  This is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.
*/


//include the library code:
#include <Wire.h>
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
/**********************************************************/

#ifndef F_CPU
#define F_CPU 16000000L
#endif

#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif

int pinLed=13;         // on board Led
int pinStart=9;        // HIGH to measure, LOW to adjust
int pinTrig=8;         // ICP pin input 

volatile unsigned char p_mlt = 0;       // Timer1 Overflows total
volatile unsigned char p_mlt1 = 0;      // Timer1 Overflows low time
volatile unsigned char p_ready;         // Flag
volatile unsigned int  StartTime = 0;   // ICP pin 1st edge falling
volatile unsigned int  EndTime1 = 0;    // ICP pin next edge rising
volatile unsigned int  EndTime2 = 0;    // ICP pin last edge falling

ISR( TIMER1_CAPT_vect )
{
  static unsigned char edge = 0;
 
   if( edge == 0 )                    // 1st edge falling 
  {
    StartTime = ICR1;
    TIMSK1 = 0;                       // stop Interrupts , Capture & Overflow
    p_mlt = 0;
    p_mlt1 = 0;
    TCCR1B |= (1<<ICES1);             // then change to rising 
    ++edge;       // 
    TIMSK1 = (1<<ICIE1) | (1<<TOIE1); // enable Interrupts , Capture & Overflow
  }

  else if( edge == 1 )                // 2nd edge rising
  {
    EndTime1 = ICR1;                  // time high
    TIMSK1 = 0;                       // stop Interrupts , Capture & Overflow
    p_mlt1 = p_mlt;
    TCCR1B &= ~(1<<ICES1);            // then change ICES1 to falling
    ++edge;       // 
    TIMSK1 = (1<<ICIE1) | (1<<TOIE1); // enable Interrupts , Capture & Overflow
  }

  else if( edge == 2 )                // 3rd edge falling
  {
    EndTime2 = ICR1;                  // total time
    p_ready = TRUE;                   // p_ready to display
    edge = 0;        
  }
}

ISR( TIMER1_OVF_vect )                // count overflow
{
  p_mlt++;
}

// Define the number of devices we have in the chain and the hardware interface
// NOTE: These pin numbers will probably not work with your hardware and may
// need to be adapted
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define CLK_PIN   13
#define DATA_PIN  11
#define CS_PIN    10

// Hardware SPI connection
MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
// Arbitrary output pins
// MD_Parola P = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

void setup()
{
  pinMode(pinLed, OUTPUT);          // on board led
  pinMode(pinStart,  INPUT_PULLUP); // start Input Capture, pin9
  pinMode(pinTrig,  INPUT);         // Input Capture Pin on PB0, pin8

  TCCR1A = 0;                       // 
  TIMSK1 = (1<<ICIE1) | (1<<TOIE1); // 2 Interrupts: Capture & Overflow
  TCCR1B &= ~(1<<ICES1);            // ICES1 trigger on falling
  TIMSK2 &= ~(1<<OCIE2A);           // disable Timer2 Interrupt, millis
  sei();
    P.begin();
}

void loop()
{
  char FString[12];
  double myTime = 0.0;
  double pwpercent = 0.0;
  unsigned long  pwidth;
  unsigned long  pwidth1;

  if (digitalRead(pinStart) == HIGH)          // start ISR else adjust
   {

    if( p_ready )
    {
      TCCR1B = 0;                             // stop Input Capture 

      pwidth1 = (p_mlt1 * 65536) + EndTime1 - StartTime;
      Serial.print("PW low= ");    
      Serial.print(pwidth1);                  // PW1 in counts
     
      pwidth = (p_mlt * 65536) + EndTime2 - StartTime;
      Serial.print("  PWtotal= ");
      Serial.print(pwidth);                   // PW total in counts
      Serial.print("  PW % = ");
      pwpercent = pwidth1*100.0/pwidth; 
      dtostrf( pwpercent, 5, 2, FString );    // 2 digits
      Serial.println(FString);                // PW in counts

      myTime = pwidth/16.0 ;                  // in usec
      dtostrf( myTime, 8, 2, FString );       // 2 digits
      
      Serial.print("Time= ");
      Serial.print(FString);
      Serial.print(" usec  "); 
/*      lcd.print(FString); */
     
      myTime = (p_mlt * 65536) + EndTime2 - StartTime;
      myTime = (F_CPU * 50)/ myTime /36 ;     // 50 cm  / t in km/h
      dtostrf( myTime, 8, 3, FString );       // 3 digits
      
      Serial.print("Speed= ");
      Serial.print(FString);
      Serial.println(" km/h"); 
      
/* Ausgabe */      
     P.print(FString);                           // Print a message to the DotMatrix
     //
      p_ready = FALSE;
      digitalWrite(pinLed,!digitalRead(pinLed));    // blink Led 13 on board
      TCCR1B = (1<<ICES1)  | (1<<CS10);             // enable Input Capture Edge, PreScale 1
      TCCR1B &= ~(1<<ICES1);                        // ICES1 trigger on falling
      
    } //if( p_ready )
    }
    else                                            // stop to adjust 
    {
        TCCR1B = 0;
        digitalWrite(pinLed,digitalRead(pinTrig));  // Led 13 on board shows status       
    }

//  delay(50);
  
}

Es soll der Meßwert mit einer Nachkommastelle angezeigt werden. Ohne Animation, ohne alles.
Außerdem hätte ich gerne, dass beim Start des Arduino ein Text als Laufschrift einmalig durchläuft.
Läßt sich das zusammen machen?

Ich danke Euch schonmal im Voraus für die Hilfe.

Emmeff

Hi

In dem Sketch sehe ich keine Ausgabe via LED oder Ähnlich.
Auch wäre ein Link zu Deiner LED-matrix vll. nicht verkehrt - oder meinst Du 'nur' eine 4x 8x8-Matrix?
Das '4 in 1' passt Da Dafür nämlich nicht so rein - jede 8x8er Matrix hat einen eigenen MAX.
Wenn Es Solche sind - Davon kann man auch 'ein paar Meeeehrrr' zusammen stöpseln ... wenn die Anzeige zu klein erscheint ...
Auch gibt's zu diesen Matrixen Beispiele in der IDE (siehe unter MAX7219) - auch Lauftext.

MfG

Hallo, danke schonmal für die Antworten.

Folgendes Modul habe ich gekauft:

Die Testsketches funktionieren, mittlerweile habe ich auch die Ausrichtung korrekt hinbekommen.
Ich habe mir mein Originalprogramm vorgenommen, habe alles, was für die Ansteuerung des LC-Displays war entfernt und dann die Bestandteile aus den Beispielsketches eingefügt. Dabei bin ich in meinem jugendlichen Leichtsinn davon ausgegangen, dass es keinen Unterschied macht, ob ein vordefinierter Text oder ein in einer Variable gespeicherter Messwert, der ja, wenn ich es richtig verstehe in „FString“ gespeichert ist ausgegeben wird....

Grüße und einen schönen Restsonntag
Emmeff

Emmeff:
Grüße und einen schönen Restsonntag

Gibt es noch eine Frage?

agmue:
Gibt es noch eine Frage?

Naja, die Frage ist die selbe wie im ersten Thread, es läuft nicht und ich bin nicht in der Lage, herauszufinden´ warum.
Meine Antwort war die Entgegnung an die beiden, die geantwortet hatten...

Das Display funktioniert grundsätzlich, aber es gibt meinen Messwert nicht aus.

Grüße
Emmeff

In setup fehlt Serial.begin(9600);

Hier sehe ich einen Konflikt:

int pinLed=13;         // on board Led
...
#define CLK_PIN   13

Wenn ich das ändere, sehe ich was.

Ergänzung: CLK_PIN wird nirgendwo verwendet, aber Hardware-SPI nutzt die Pins 11, 12 und 13.

Vielen Dank für Eure Antworten.

Ich werde Eure Vorschläge heute oder morgen ausprobieren und berichten.

Emmeff

Hallo zusammen,

folgendermaßen sieht der Code jetzt aus:

//include the library code:
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
/**********************************************************/

#ifndef F_CPU
#define F_CPU 16000000L
#endif

#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif

int pinStart = 9;      // HIGH to measure, LOW to adjust
int pinTrig = 8;       // ICP pin input

volatile unsigned char p_mlt = 0;       // Timer1 Overflows total
volatile unsigned char p_mlt1 = 0;      // Timer1 Overflows low time
volatile unsigned char p_ready;         // Flag
volatile unsigned int  StartTime = 0;   // ICP pin 1st edge falling
volatile unsigned int  EndTime1 = 0;    // ICP pin next edge rising
volatile unsigned int  EndTime2 = 0;    // ICP pin last edge falling

ISR( TIMER1_CAPT_vect )
{
  static unsigned char edge = 0;

  if ( edge == 0 )                   // 1st edge falling
  {
    StartTime = ICR1;
    TIMSK1 = 0;                       // stop Interrupts , Capture & Overflow
    p_mlt = 0;
    p_mlt1 = 0;
    TCCR1B |= (1 << ICES1);           // then change to rising
    ++edge;       //
    TIMSK1 = (1 << ICIE1) | (1 << TOIE1); // enable Interrupts , Capture & Overflow
  }

  else if ( edge == 1 )               // 2nd edge rising
  {
    EndTime1 = ICR1;                  // time high
    TIMSK1 = 0;                       // stop Interrupts , Capture & Overflow
    p_mlt1 = p_mlt;
    TCCR1B &= ~(1 << ICES1);          // then change ICES1 to falling
    ++edge;       //
    TIMSK1 = (1 << ICIE1) | (1 << TOIE1); // enable Interrupts , Capture & Overflow
  }

  else if ( edge == 2 )               // 3rd edge falling
  {
    EndTime2 = ICR1;                  // total time
    p_ready = TRUE;                   // p_ready to display
    edge = 0;
  }
}

ISR( TIMER1_OVF_vect )                // count overflow
{
  p_mlt++;
}

// Define the number of devices we have in the chain and the hardware interface
// NOTE: These pin numbers will probably not work with your hardware and may
// need to be adapted
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define CLK_PIN   13
#define DATA_PIN  11
#define CS_PIN    10

// Hardware SPI connection
MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
// Arbitrary output pins
// MD_Parola P = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

void setup()
{
  Serial.begin(9600);
  pinMode(pinStart,  INPUT_PULLUP); // start Input Capture, pin9
  pinMode(pinTrig,  INPUT);         // Input Capture Pin on PB0, pin8

  TCCR1A = 0;                       //
  TIMSK1 = (1 << ICIE1) | (1 << TOIE1); // 2 Interrupts: Capture & Overflow
  TCCR1B &= ~(1 << ICES1);          // ICES1 trigger on falling
  TIMSK2 &= ~(1 << OCIE2A);         // disable Timer2 Interrupt, millis
  sei();
  P.begin();
}

void loop()
{
  char FString[12];
  double myTime = 0.0;
  double pwpercent = 0.0;
  unsigned long  pwidth;
  unsigned long  pwidth1;

  if (digitalRead(pinStart) == HIGH)          // start ISR else adjust
  {

    if ( p_ready )
    {
      TCCR1B = 0;                             // stop Input Capture

      pwidth1 = (p_mlt1 * 65536) + EndTime1 - StartTime;
      Serial.print("PW low= ");
      Serial.print(pwidth1);                  // PW1 in counts

      pwidth = (p_mlt * 65536) + EndTime2 - StartTime;
      Serial.print("  PWtotal= ");
      Serial.print(pwidth);                   // PW total in counts
      Serial.print("  PW % = ");
      pwpercent = pwidth1 * 100.0 / pwidth;
      dtostrf( pwpercent, 5, 2, FString );    // 2 digits
      Serial.println(FString);                // PW in counts

      myTime = pwidth / 16.0 ;                // in usec
      dtostrf( myTime, 8, 2, FString );       // 2 digits

      Serial.print("Time= ");
      Serial.print(FString);
      Serial.print(" usec  ");

      myTime = (p_mlt * 65536) + EndTime2 - StartTime;
      myTime = (F_CPU * 50) / myTime / 36 ;   // 50 cm  / t in km/h
      dtostrf( myTime, 8, 2, FString );       // 3 digits

      Serial.print("Speed= ");
      Serial.print(FString);
      Serial.println(" km/h");

      /* Ausgabe */
      P.print(FString);                           // Print a message to the DotMatrix
      p_ready = FALSE;
      TCCR1B = (1 << ICES1)  | (1 << CS10);         // enable Input Capture Edge, PreScale 1
      TCCR1B &= ~(1 << ICES1);                      // ICES1 trigger on falling

    } //if( p_ready )
  }
  else                                            // stop to adjust
      TCCR1B = 0;
  }

Wenn ich den Laser auf die Fotodiode richte und ihn unterbreche, passiert nichts.
Wenn ich aber das Kabel, dass vom 100k Ohm Widerstand zu Ground geht, kurz aus und wieder einstecke, dann bekomme ich einen Meßwert, sowohl im seriellen Monitor als auch auf dem Display.
Grundsätzlich funktioniert das Programm also.
Mir ist nur noch nicht klar, wieso die eigentliche Messung nicht funktioniert…

berichte genau, was b/c/d bei dir machen

b: 1 kam sofort
c und d: zunächst nichts, aber durch aus- und einstecken kam 2 bzw die Zeit.

Ergänzung: CLK_PIN wird nirgendwo verwendet, aber Hardware-SPI nutzt die Pins 11, 12 und 13.

Das verstehe ich nicht.

Vielen Dank
Emmeff

Hi

Warum eigentlich Interrupt?
Atomares Auslesen sehe ich nicht, wird hier aber nicht das Problem sein.

Mein Ansatz:

// Sketch, um die 'Dunkelzeit' zweier Photo-Transistoren (oder LDR)
// auszumessen und anzuzeigen.

// an welchen Pins hängen die Sensoren?
const byte pinSensor[2] = {3, 4};
const boolean AN=HIGH;    //Zustand des Sensor für Betätigt
const boolean AUS=!AN;

void setup() {
  Serial.begin(115200);
}

void loop() {
  //diverse Variablen vorbereiten - durch static 'überleben' Die das Ende von loop()
  static uint32_t startmicros[2] = {0,0};   //Startbedingung
  static uint32_t stopmicros[2] = {0,0};    //Zeitpunkt, ab wann der Sensor wieder 'frei' war
  static byte t = 0;
  t = ++t % 2;        //zählt 't' um 1 hoch, bricht bei 2 auf 0 um
  if (digitalRead(pinSensor[t])==AN && startmicros[t] == 0) {
    startmicros[t] = micros();  //Startzeit merken, wenn noch keine Startzeit gemerkt wurde UND der Sensor gerade betätigt wird
  }
  if (digitalRead(pinSensor[t])==AUS && startmicros[t] != 0) {
    stopmicros[t] = micros();   //Startzeit, wenn bereits Startzeit UND der Sensor gerade NICHT betätigt wird
  }
  if (startmicros[t] && stopmicros[t]) {
    //Wenn sowohl Start- und Stopzeit eingetragen sind, Zeit ausgeben
    Serial.print(t);
    Serial.print(F(": Differenz:"));
    Serial.print(stopmicros[t] - startmicros[t]);
    Serial.println(F("ns"));
    startmicros[t] = 0;   //Startbedingung wieder herstellen
    stopmicros[t] = 0;    //und 'Nicht' Stop-Bedingung
  }
}

Die Warnung zu Zeile 18 kann - meiner Erfahrung nach - ignoriert werden.
(t = ++t % 2;);
Der Sketch verwendet 2374 Bytes (7%) des Programmspeicherplatzes. Das Maximum sind 32256 Bytes.
Globale Variablen verwenden 207 Bytes (10%) des dynamischen Speichers, 1841 Bytes für lokale Variablen verbleiben. Das Maximum sind 2048 Bytes.
(auf Uno/Nano)
UNGETESTET

Probiere bitte Mal Das - vll. kannst Du Das schon fast so nutzen.

MfG

noiasca:
"kam 2"

da fehlt aber was... fehlt wirklich die Anzeige von den ersten beiden Buchstaben "No" ?

Es kam bei beidem nur die Zahl linksbündig.

Im Grunde schon.

Jetzt werde ich mich erstmal mit dem hardwareseitigen Problem befassen, wieso die Messung nicht funktioniert...

Vielen Dank an alle für die Hilfe.

Einen schönen Tag

Emmeff

Es funktioniert!!!

Wenn man seine eigene Skizze nicht mehr richtig entziffern kann... Eine Leitung war falsch angeschlossen.

Vielen vielen Dank für Eure Hilfe....

Sobald alles fertig ist, werde ich es posten...