Go Down

Topic: Stopuhr mit Max7219 Matrix Display (Read 3524 times) previous topic - next topic

obeis

Hallo zusammen.

Ich bin neu hier. Ich bin beruflich im Bereich 20000V mit 150A unterwegs. Arduino und Co hat mich schon länger gepackt, aber selber programieren habe ich noch nicht endgültig im Griff. Bisher arbeite ich immer noch mit Drag an Drop.
Jetzt habe ich ein Aufgabe, zu der ich noch kein gutes Beispiel gefunden habe.
Ich brauche eine Stopuhr, die ich auf einem oder später vielleicht auch zwei MAX7219 Matrixdisplay mit 32 x 8 Punkten darstellen möchte.
"Start" "Stop" sollte über einen Taster realiesiert werden, mittels eines zweiten Taster sollte der Reset stattfinden.
Einen Lauftext habe ich schon hinbekommen, aber eben nicht als laufende Zeit.
Ich möchte eine Zeit zwischen 20 und 99 sekunden messen, gerne natürlich mit zehnteln .
Hier denke ich allerdings das es ideal währe, wenn die Sekunden dauernd zusehen währen und die Bruchteile erst nach dem Stop angezeigt werden würden. 
Als Hardware habe ich aktuell einen Arduino Nano und das Display.
Nutzen möchte ich das mit einem großen Buzzer für einen Feuerwehr Wettkampf.
Ist das eine lösbare Aufgabe?
Könnt Ihr mir ein Tutorial empfehlen oder sogar ein Lösung?

Mit freundlichen Grüßen vom Weserdeich!

Siebo
   

postmaster-ino

Hi

Jupp, denke, Das ist lösbar.
Willst Du Deine Stop-Uhr als Lauftext?
Wenn Das das Beispiel aus der IDE ist (unter Anderem gibt's Da auch 'Mad Fly'), kannst Du diesen Text einfach vor jeder Ausgabe generieren (bzw. bei Änderung).

Akut habe ich hier einen Mehr-Zeiligen Lauftext, Der seit 959:19:43 (959 Stunden - Arduino Zeit, könnte also etwas ungenau sein) Sein Unwesen treibt ... wäre ja schade, wenn Da die Zeit auf Null geht, nur weil ich Dem den Saft abdrehe ... ;)
(War als Spannungsanzeige in einem LKW gedacht, also per Spannungsteiler die Versorgungsspannung ermitteln und anzeigen - der Rest, eben auch das Einbinden von 'Mad Fly', war eher Spielerei - da das Zeug nicht in den LKW kam (Der dafür in die Werkstatt), fristet die Anzeige jetzt Ihr Dasein bis mir was sinnvolleres einfällt)

MfG

HotSystems

Ja, lösbar ist das schon, hängt aber sehr stark von deinen Programmierkenntnissen ab.
Und jenachdem wie genau die Stopuhr sein muss, solltest du eine RTC in deinem Projekt mit vorsehen.
Der Taktgeber (Quarz bzw. Resonator) auf dem Nano ist nicht sehr genau bzw. stabil.
Gruß Dieter

I2C = weniger ist mehr: weniger Kabel, mehr Probleme. 8)

obeis

@postmaster-ino
ich brauche keine Effekte. Mir reicht es wenn die Zahl einfach umspringt. Wenn es natürlich einfach währe würde ich auch einen WOW Effekt nehmen.
@HotSystems
Meine Programierkenntnisse belaufen sich auf Copy Past mit individueller anpassung. Bei der Genauigkeit kommt es mir nur auf eine vergleichbarkeit am selben Abend an. Ob es nun 25,6 sec. oder 26,1 sec. sind ist eigentlich nebensächlich.
Wenn eine RTC einfach zu realiesieren ist, würde ich das natürlich mit aufnehmen. Was sollte ich da beschaffen?

Ich bedanke mich schon jetzt für die schnellen Antworten.

Siebo

postmaster-ino

Hi

Mit einer RTC (Real Time Clock, z.B. DS3231 mit wenigen Minuten Abweichung im Jahr) kannst Du Dir z.B. 1024Hz (oder mehr) ausgeben lassen und mit dem Arduino 'zählen'.

Mir ging es jetzt nicht um WOW-Effekte, sondern eher darum, wie Dein jetziger Sketch aussieht.
Man muß den Lauftext ja nicht laufen lassen und der Text kann ja auch eine Uhrzeit oder einen Countdown/eine Stop-Uhr anzeigen ;)

Wenn es Dir nur um Messzeiten von wenigen Minuten geht, wirst Du keine höhere Genauigkeit brauchen, da sollte die Arduino-Sekunde ausreichend für sein (aka millis() als System-Uhr in Millisekunden seit Start).

Mittels eines Button für Start (=aktuellen millis()-Wert als Start-Zeitpunkt merken) und einen Button für Stop (... Endzeitpunkt) sowie der Anzeige der vergangenen Zeit seit STart-Zeitpunkt, sofern die Stop-Uhr gerade misst (millis()-StartZeit = vergangene ms - :1000 sind die Sekunden, %1000 sind die 1000stel Sekunden (also 3 Nachkomma-Stellen).

Du solltest also mit Deinem Lauftext-Sketch schon was anfangen können - Du musst nur sehen, Dem das Laufen abzugewöhnen und den Text für Dich anpassen.

Schreibe Dir auf, was in welcher Reihenfolge passieren soll - möglichst kleine Schritte.

MfG

Whandall

Du sagst du kannst Text auf deinen Displays ausgeben?

Dann kann ich dir zur Ergänzung eine simple Stoppuhr mit 1/10 Sekunden Anzeige anbieten.

Code: [Select]
const uint8_t startPin = 4;
const uint8_t resetPin = 5;

bool laeuft = false;

uint32_t start;
uint32_t stop;
uint32_t letzteAnzeige;
uint32_t ergebnis;

bool startState = true;
bool resetState = true;

void setup() {
  Serial.begin(250000);
  pinMode(startPin, INPUT_PULLUP);
  pinMode(resetPin, INPUT_PULLUP);
}

void loop() {
  uint32_t topLoop = millis();
  if (digitalRead(resetPin) != resetState) {
    resetState = !resetState;
    if (!resetState) {
      if (laeuft) {
        laeuft = false;
        Serial.println(F("Abgebrochen"));
      }
    }
  }
  if (digitalRead(startPin) != startState) {
    startState = !startState;
    if (!startState) {
      if (laeuft) {
        stop = topLoop;
        laeuft = false;
        ergebnis = stop - start;
        Serial.print(F("Stop "));
        anzeige(ergebnis);
      } else {
        start = topLoop;
        laeuft = true;
        Serial.print(F("Start"));
        anzeige(0);
      }
    }
    delay(50);
  }
  if (laeuft && topLoop - letzteAnzeige >= 100) {
    letzteAnzeige = topLoop;
    ergebnis = topLoop - start;
    Serial.print(F(" ---"));
    anzeige(ergebnis);
  }
}

void anzeige(uint32_t milliSekunden) {
  Serial.print(F(" - "));
  Serial.print(milliSekunden / 1000);
  Serial.write('.');
  Serial.println((milliSekunden % 1000) / 100);
}
Code: [Select]
Start - 0.0
 --- - 0.0
 --- - 0.1
 --- - 0.2
 --- - 0.3
Stop  - 0.3
Start - 0.0
 --- - 0.0
 --- - 0.1
 --- - 0.2
 --- - 0.3
 --- - 0.4
 --- - 0.5
Abgebrochen
Start - 0.0
 --- - 0.0
 --- - 0.1
 --- - 0.2
 --- - 0.3
Stop  - 0.3

Ausgabe geht hier auf den Monitor, aber das sollte ja leicht übertragbar sein.
Ah, this is obviously some strange usage of the word 'safe' that I wasn't previously aware of. (D.Adams)

obeis

@ postmaster-ino
Es werden nicht mehr als 99 sec werden. Eher 30 bis 50 sec.
der Text läuft aktuell von rechts nach links durchs Bild.
 
Code: [Select]

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Max72xxPanel.h>

int pinCS = 10; // Attach CS to this pin, DIN to MOSI and CLK to SCK
int numberOfHorizontalDisplays = 1;
int numberOfVerticalDisplays = 4;

Max72xxPanel matrix = Max72xxPanel(pinCS, numberOfHorizontalDisplays, numberOfVerticalDisplays);

String tape = "Siebo !";
int wait = 80; // In milliseconds

int spacer = 1;
int width = 5 + spacer; // The font width is 5 pixels

void setup() {

  matrix.setIntensity(5); // Use a value between 0 and 15 for brightness

// Adjust to your own needs
//  matrix.setPosition(0, 0, 0); // The first display is at <0, 0>
//  matrix.setPosition(1, 1, 0); // The second display is at <1, 0>
//  matrix.setPosition(2, 2, 0); // The third display is at <2, 0>
//  matrix.setPosition(3, 3, 0); // And the last display is at <3, 0>
//  ...
//  matrix.setRotation(0, 2);    // The first display is position upside down
 matrix.setRotation(3);    // The same hold for the last display
}

void loop() {

  for ( int i = 0 ; i < width * tape.length() + matrix.width() - 1 - spacer; i++ ) {

    matrix.fillScreen(LOW);

    int letter = i / width;
    int x = (matrix.width() - 1) - i % width;
    int y = (matrix.height() - 8) / 2; // center the text vertically

    while ( x + width - spacer >= 0 && letter >= 0 ) {
      if ( letter < tape.length() ) {
        matrix.drawChar(x, y, tape[letter], HIGH, LOW, 1);
      }

      letter--;
      x -= width;
    }

    matrix.write(); // Send bitmap to display

    delay(wait);
  }

}


ich werde versuchen die serielle Ausgabe der Stopuhr auf "tape" umzulegen.
noch habe ich es nicht hinbekommen den Text einfach nur fest stehend einzublenden.
Gebt Ihr mir einen Tip wo ich nachlesen kann wie ich "matrix.drawchart" passend anpassen kann?

Wie gesagt ich bin starkstromer.

Danke im voraus.

Siebo

Whandall

#7
Jun 25, 2018, 12:09 am Last Edit: Jun 25, 2018, 12:13 am by Whandall
Ich denke hier: adafruit-gfx-graphics-library overview oder genauer hier.

matrix.print() sollte auch wie gewohnt funktionieren.

In der Nähe des zweiten Links steht ein Beispiel für Textausgabe.
Ah, this is obviously some strange usage of the word 'safe' that I wasn't previously aware of. (D.Adams)

Whandall

#8
Jun 25, 2018, 02:08 am Last Edit: Jun 25, 2018, 02:19 am by Whandall
Bei mir funktioniert das auf einem Mega mit anderer Anordnung der Matrixelemente so:

Code: [Select]
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Max72xxPanel.h>

const uint8_t startPin = 4;
const uint8_t resetPin = 5;

bool laeuft = false;

uint32_t start;
uint32_t stop;
uint32_t letzteAnzeige;
uint32_t ergebnis;

bool startState = true;
bool resetState = true;

const uint8_t pinCS = 53; // Attach CS to this pin, DIN to MOSI and CLK to SCK
const uint8_t numberOfHorizontalDisplays = 4;
const uint8_t numberOfVerticalDisplays = 1;

Max72xxPanel matrix = Max72xxPanel(pinCS, numberOfHorizontalDisplays, numberOfVerticalDisplays);

String tape = "Siebo !";
int wait = 80; // In milliseconds

int spacer = 1;
int width = 5 + spacer; // The font width is 5 pixels

void setup() {
  Serial.begin(250000);
  pinMode(startPin, INPUT_PULLUP);
  pinMode(resetPin, INPUT_PULLUP);

  matrix.setIntensity(5); // Use a value between 0 and 15 for brightness

  //  matrix.setPosition(0, 0, 3); // The first display is at <0, 0>
  //  matrix.setPosition(1, 0, 2); // The second display is at <1, 0>
  //  matrix.setPosition(2, 0, 1); // The third display is at <2, 0>
  //  matrix.setPosition(3, 0, 0); // And the last display is at <3, 0>

  matrix.setRotation(0);
  matrix.fillScreen(LOW);
  anzeige(PSTR("Start"));
}

void loop() {
  uint32_t topLoop = millis();
  if (digitalRead(resetPin) != resetState) {
    resetState = !resetState;
    if (!resetState) {
      laeuft = false;
      anzeige(PSTR("Start"));
    }
  }
  if (digitalRead(startPin) != startState) {
    startState = !startState;
    if (!startState) {
      if (laeuft) {
        stop = topLoop;
        laeuft = false;
        ergebnis = stop - start;
        anzeige(ergebnis);
      } else {
        start = topLoop;
        laeuft = true;
        anzeige((uint32_t)0);
      }
    }
    delay(50);
  }
  if (laeuft && topLoop - letzteAnzeige >= 100) {
    letzteAnzeige = topLoop;
    ergebnis = topLoop - start;
    anzeige(ergebnis);
  }
}

void anzeige(uint32_t milliSekunden) {
  float value = milliSekunden / 1000.0;
  uint8_t pos = 2;
  if (value < 100) {
    if (value < 10) {
      pos = 14;
    } else {
      pos = 8;
    }
  }
  matrix.fillScreen(LOW);
  matrix.setCursor(pos, 0);
  matrix.print(value, 1);
  matrix.write();
}

void anzeige(const char* pmData) {
  matrix.fillScreen(LOW);
  matrix.setCursor(0, 0);
  matrix.print((const __FlashStringHelper*) pmData);
  matrix.write();
}
Ah, this is obviously some strange usage of the word 'safe' that I wasn't previously aware of. (D.Adams)

obeis

Coole Nummer.

Das läuft prima.
Gibt es eine Möglichkeit die Tasten Hardcore mässig zu entprellen?. Also für ca. 2 bis 3 sec?
In Phython auf dem Raspberry gibt es da ja einen einfachen Befehl in der Tastendefinition.
Ich möchte dami
 Vermeiden das jemand zweimal auf den Button haut und somit die Zeit löscht.  Fotos vom ersten Aufbau kommen kurzfristig.
Vielen Dank bis hier her.

Siebo

postmaster-ino

Hi

Indem Du einen weiteren 'Zwischenschritt' einbaust.
Bei dem STOP merkst Du Dir die Zeit (millis(); ).
Und beim Start prüfst Du, ob seit dem letzten Stop MINDESTENS schon x Sekunden vergangen sind.
Damit kannst Du dann aber die Uhr das erste Mal auch erst nach x Sekunden starten (oder Du initiierst diese Stop-Zeit auf -x Sekunden, könnte sein, daß der Kompiler Da meckert, wenn Du versuchst einer SIGNED Zahl einen UNSIGNED Wert zuzuweisen.

MfG

obeis

Moin
Das ist mein Ziel. Glaube ich.
Also es ist ein Stopuhr für einen Feuerwehr Wettbewerb. Ich habe jetzt einen großen Buzzer für Start und Stop. jetzt möchte ich nach Rücksprache auch den Reset nutzen. Der Reset könnte die Verzögerungszeit einfach überschreiben(wenn möglich).
Um ein versehentliches Rücksetzen der zu verhindern, währe die Verzögerung für 2 sec überhaupt kein Problem. Allerdings weiß ich nicht wie ich den aktuellen millis einfach abspeichern kann. 4
Kann  mir jemand auf die Sprünge helfen.

Siebo

HotSystems

.....
 Allerdings weiß ich nicht wie ich den aktuellen millis einfach abspeichern kann. 4
Kann  mir jemand auf die Sprünge helfen

Das ist nicht so kompliziert:

Code: [Select]

unsigned long aktuelleZeit = millis();


Oder wie es in den Code-Beispielen von Whandall steht.
Gruß Dieter

I2C = weniger ist mehr: weniger Kabel, mehr Probleme. 8)

postmaster-ino

Hi

Wann und Wo wird man die Stopuhr bewundern können? (bei einem kühlen Blondem?)

Das 'unsigned long' hast Du nur bei der Deklaration der Variable, bei den späteren Wertzuweisungen ist der Typ ja bereits bekannt und wirft somit Fehlermeldungen beim Kompilieren.
Da Du die Stop-Zeit 'über das Ende von loop hinaus' brauchst, musst diese Variable entweder global sein (außerhalb, noch vor setup() stehend, deklariert werden, oder IN der loop() mit dem Zusatz 'static' - Das lässt die Variable 'überleben', wenn loop() beendet wird.

(jede in einer Funktion angelegte Variable wird mit dem Ende der Funktion wieder vernichtet - beim erneuten Anlegen kann somit die gleiche Variable ganz wo anders im Speicher stehen - zusätzlich mit einem undefiniertem Startwert!!)

MfG

obeis

#14
Sep 11, 2018, 11:45 pm Last Edit: Sep 12, 2018, 12:01 am by obeis
Moin Moin

Ich habe leider nicht wirklich verstanden was Ihr meint. Ich habe jetzt mal selber geschaut was ich umsetzen kann.

Mein Ergebnis sieht erstmal so aus als ob es seinen Zweck erfüllt.

einzige Einschrenkung ist das die Wartezeit (aktuell 3000) auch vor dem ersten Start eingehalten werden muss.
Vielleicht kann man das noch als Anzeige Ready  -->   Go als Feature umbauen.

Gefühlt läuft nach dem tasten zum anhalten die Zeit von 3 sec. bis der nächste tastendruck akzeptiert wird.
Meine anpassung ist die folgende

Code: [Select]
if (digitalRead(startPin) != startState) {
    startState = !startState;
    if (!startState && topLoop - stop >= 3000) {
      if (laeuft) {
        stop = topLoop;
        laeuft = false;
       


Wie ist eure Meinung dazu?

Hier noch mal das komplette Programm:

Code: [Select]
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Max72xxPanel.h>

const uint8_t startPin = 4;
const uint8_t resetPin = 5;

bool laeuft = false;

uint32_t start;
uint32_t stop;
uint32_t letzteAnzeige;
uint32_t ergebnis;

bool startState = true;
bool resetState = true;

const uint8_t pinCS = 10; // Attach CS to this pin, DIN to MOSI and CLK to SCK
const uint8_t numberOfHorizontalDisplays = 1;
const uint8_t numberOfVerticalDisplays = 4;

Max72xxPanel matrix = Max72xxPanel(pinCS, numberOfHorizontalDisplays, numberOfVerticalDisplays);

String tape = "Siebo !";
int wait = 80; // In milliseconds

int spacer = 1;
int width = 5 + spacer; // The font width is 5 pixels

void setup() {
  Serial.begin(500000);
  pinMode(startPin, INPUT_PULLUP);
  pinMode(resetPin, INPUT_PULLUP);

  matrix.setIntensity(2); // Use a value between 0 and 15 for brightness

  //  matrix.setPosition(0, 0, 3); // The first display is at <0, 0>
  //  matrix.setPosition(1, 0, 2); // The second display is at <1, 0>
  //  matrix.setPosition(2, 0, 1); // The third display is at <2, 0>
  //  matrix.setPosition(3, 0, 0); // And the last display is at <3, 0>

  matrix.setRotation(3);
  matrix.fillScreen(LOW);
  anzeige(PSTR("Ready"));
}

void loop() {
  uint32_t topLoop = millis();
  if (digitalRead(resetPin) != resetState) {
    resetState = !resetState;
    if (!resetState) {
      laeuft = false;
      anzeige(PSTR("LOS!!"));
    }
  }
  if (digitalRead(startPin) != startState) {
    startState = !startState;
    if (!startState && topLoop - stop >= 3000) {
      if (laeuft) {
        stop = topLoop;
        laeuft = false;
        ergebnis = stop - start;
        anzeige(ergebnis);
      } else {
        start = topLoop;
        laeuft = true;
        anzeige((uint32_t)0);
      }
    }
    delay(50);
  }
  if (laeuft && topLoop - letzteAnzeige >= 100) {
    letzteAnzeige = topLoop;
    ergebnis = topLoop - start;
    anzeige(ergebnis);
    Serial.println(ergebnis);   //anzeige im Display
    }

}
void anzeige(uint32_t milliSekunden) {
  float value = milliSekunden / 1000.0;
  uint8_t pos = 2;
  if (value < 100) {
    if (value < 10) {
      pos = 11;
    } else {
      pos = 5;
    }
  }
  matrix.fillScreen(LOW);
  matrix.setCursor(pos, 0);
  matrix.print(value, 1);
  matrix.write();
}

void anzeige(const char* pmData) {
  matrix.fillScreen(LOW);
  matrix.setCursor(0, 0);
  matrix.print((const __FlashStringHelper*) pmData);
  matrix.write();
}


Mehr Infos die Tage!
schon zu spät.

Gute Nacht

Go Up