Go Down

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

obeis

Moin Moin.

Heute habe ich endlich "eure" Stopuhr vorgestellt.
Jetzt gibt es Änderungswünsche:
Die Uhr soll 100stel anzeigen.
Ich habe von millis auf micros umgestellt und den Faktor habe ich auch schon verstellt. Ich zeige jetzt also nur noch die hunderstel an. Jetzt geht mir aber irgendwie der Platz aus. Ich brauche Zeiten bis zu 180 sec. also 18000 hundertstel.
Ich bekomme 5 Stellen auf dem Display (4St 8x8) dargestellt. Allerdings stört mich der Punkt. Den habe ich  über den Faktor ja schon weg geschoben. Allerdings brauche ich den Punkt. Kann ich den Punkt einfach als einzelnen Pixsel in die untere Zeile positionieren? dafür müsste ich die Zahlen der Zeit natürlich an einer Stelle "fixieren" das klappt auch bis die fünfte Zahl dazu kommt. Kann ich eigentlich in die If else abfrage eine drtte ebene einbauen? Oder kann ich einen kleinen Abstand für einen Punkt zwischen der 3ten und 4ten Stelle einfügen.
Alternativ würde eine schmalerer Schrift auch helfen. Aber da bin ich völlig aufgeschmissen.

Ich hoffe auf eure Hilfe.

Siebo

Whandall

#16
Nov 23, 2018, 10:05 am Last Edit: Nov 23, 2018, 10:40 am by Whandall Reason: So sieht es noch besser aus
Ich habe von millis auf micros umgestellt
Warum das? Millis sollten für 1/100 Sekunden ausreichend genau sein.

Und warum hast du deinen aktuellen Kode nicht gepostet?

Du hättest nur die Anzeige ändern müssen,

Code: [Select]
void anzeige(uint32_t milliSekunden) {
  uint32_t value = (milliSekunden + 5) / 10;
  uint16_t seconds = value / 100;
  uint16_t hundertstel = value % 100;
  uint8_t pos = 0;
  matrix.fillScreen(LOW);
  if (seconds >= 100) {
    matrix.setCursor(0, 0);
    matrix.print((seconds / 100) % 10);
    matrix.setCursor(5, 0);
    matrix.print((seconds / 10) % 10);
    matrix.print(seconds % 10);
    seconds -= 100 * (seconds / 100);
  } else {
    if (seconds < 10) {
      pos = 11;
    } else {
      pos = 5;
    }
    matrix.setCursor(pos, 0);
    matrix.print(seconds);
  }
  matrix.setCursor(15, 0);
  matrix.print('.');
  matrix.setCursor(20, 0);
  matrix.print(hundertstel / 10);
  matrix.setCursor(26, 0);
  matrix.print(hundertstel % 10);
  matrix.write();
}

sowie deren Aufrufhäufigkeit.

Code: [Select]

  if (laeuft && topLoop - letzteAnzeige >= 10) {

Ich habe die ersten beiden Ziffern direkt aneinander geklebt, da die erste Stelle aber laut Vorgabe
nur leer oder eine 1 sein soll, sieht das dennoch akzeptabel aus.
Ah, this is obviously some strange usage of the word 'safe' that I wasn't previously aware of. (D.Adams)

obeis

Moin.

Danke für die Hilfe. Ich werde das heute Abend testen.
Ich habe meinen Code nicht mehr gepostet weil mein Wecker um 5:10 wieder geläutet hat und ich einfach nicht mehr dran gedacht habe das das gut sein könnte.
Wenn es klappt werde ich wieder berichten. Wenn nicht weiter fragen und testen.

Schönes Wochenende

Siebo

obeis

Moin Moin

Jetzt noch mal in richtig wach.
Die Stopuhr funktioniert und sieht auch echt gut aus.
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);

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.setRotation(1);
  matrix.fillScreen(LOW);
  anzeige(PSTR("Start"));
}

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 >= 10) {
    letzteAnzeige = topLoop;
    ergebnis = topLoop - start;
    anzeige(ergebnis);
    Serial.println(ergebnis);   //anzeige im Display
    }

}
void anzeige(uint32_t milliSekunden) {
  uint32_t value = (milliSekunden + 5) / 10;
  uint16_t seconds = value / 100;
  uint16_t hundertstel = value % 100;
  uint8_t pos = 0;
  matrix.fillScreen(LOW);
  if (seconds >= 100) {
    matrix.setCursor(0, 0);
    matrix.print((seconds / 100) % 10);
    matrix.setCursor(5, 0);
    matrix.print((seconds / 10) % 10);
    matrix.print(seconds % 10);
    seconds -= 100 * (seconds / 100);
  } else {
    if (seconds < 10) {
      pos = 11;
    } else {
      pos = 5;
    }
    matrix.setCursor(pos, 0);
    matrix.print(seconds);
  }
  matrix.setCursor(15, 0);
  matrix.print('.');
  matrix.setCursor(20, 0);
  matrix.print(hundertstel / 10);
  matrix.setCursor(26, 0);
  matrix.print(hundertstel % 10);
  matrix.write();
}

Allerdings kommen meine beiden Textmeldungen nicht mehr durch.
beim einschalten sollte eigentlich "READY" im Display stehen, beim Reset "LOS!!".
Jetzt steht da beim einschalten "1.42" und beim Reset "1.43". Das verstehe ich jetzt garnicht.
Liegt das daran das die Pos. der Buchstaben verschoben ist?
Gibt es auch dafür eine Lösung?
Danke im voraus.

Siebo

Whandall

Du hast eine Funktion entfernt und Warnungen ausgeschaltet oder ignoriert.

Code: [Select]

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

Danke.
Das war ja irre schnell.

Copy Past will auch gelernt sein.

Jetzt läuft es gut.

Projekt Abschnitt 1 erldigt. Jetzt kommt die Kür. Ich versuche jetzt noch die Zeit auf dem PC Terminal darzustellen.  Da werde ich eich bestimmt noch mal belästigen

Vielen Dank

Siebo

Whandall

Ich versuche jetzt noch die Zeit auf dem PC Terminal darzustellen.
Was auch immer das heißen soll...

Die Zeit?

  Uhrzeit? Stopzeit? Laufende Zeit? Wenn letzteres wie oft pro Sekunde?

PC Terminal?

  Putty? Serial Monitor? Ein Programm? Wenn ja welches?

Und mal ganz allgemein: wenn du etwas geändert hast, den gesamten Kode neu posten.

Ah, this is obviously some strange usage of the word 'safe' that I wasn't previously aware of. (D.Adams)

obeis

Ahoi

Ich muss noch viel lernen.
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);

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

  matrix.setIntensity(15); // 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(1);
  matrix.fillScreen(LOW);
  anzeige(PSTR("LkCUX"));
}

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 && 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 >= 10) {
    letzteAnzeige = topLoop;
    ergebnis = topLoop - start;
    anzeige(ergebnis);
    Serial.println(ergebnis);   //anzeige im Display
    }

}
void anzeige(uint32_t milliSekunden) {
  uint32_t value = (milliSekunden + 5) / 10;
  uint16_t seconds = value / 100;
  uint16_t hundertstel = value % 100;
  uint8_t pos = 0;
  matrix.fillScreen(LOW);
  if (seconds >= 100) {
    matrix.setCursor(0, 0);
    matrix.print((seconds / 100) % 10);
    matrix.setCursor(5, 0);
    matrix.print((seconds / 10) % 10);
    matrix.print(seconds % 10);
    seconds -= 100 * (seconds / 100);
  } else {
    if (seconds < 10) {
      pos = 11;
    } else {
      pos = 5;
    }
    matrix.setCursor(pos, 0);
    matrix.print(seconds);
  }
  matrix.setCursor(15, 0);
  matrix.print('.');
  matrix.setCursor(20, 0);
  matrix.print(hundertstel / 10);
  matrix.setCursor(26, 0);
  matrix.print(hundertstel % 10);
  matrix.write();
}

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



Anzeige:


Die erste Anzeige habe ich mit dem IDE Seriell Monitor erreicht.
Da läuft aktuell die laufende Zeit als tausendstel in einem rasenden Tempo durch.

Mein Traum währe der folgende:
Ein extra Program das am ende des Tages eine gefüllte Tabelle hinterlässt.
Der Bediener gibt den Namen der aktuellen Startgruppe am Laptop ein und betätigt den "Reset" Knopf am Gerät.
Die lafende Zeit, vielleicht mit zehnteln, wird zusammen mit dem aktuellen Namen der Startgruppe wird formatfüllend angezeigt. Nach betätigen der "Start" Knopfes bleibt die gestoppte Zeit stehen und wird mit dem Namen zusammen in einer Datei abgespeichert.

Realistisch währe wohl folgendes:
Ein für jedermann zugängliches Tool (früher gab es Hyperterm), das einfach zu bedienen sein sollte zeigt die Zeit auf einer festen Position (zehntel währen gut). Nach betätigen der Start Taste wird die Zeit mit hundersteln angezeigt, bis die Reset Taste wieder gedrückt wird.

Was da für mich umsetztbar ist wird sich noch zeigen.

Siebo

obeis

Oder sollte ich eher versuchen auf einen ESP8266/D1mini umzusteigen um das ganze per HTML Seite zu lösen?
Ich habe jetzt "auf die schnelle" keinen Befehl gefunden der mir einen Rücksprung im Terminal erlaubt.

Die Anzeige und das Programm sollten an einen ESP ja genausogut laufen.

Siebo

Whandall

Wenn der Rechner danebensteht würde ich ein Anzeigeprogramm in Processing benutzen,
das über die serielle Schnitstelle mit dem Arduino kommuniziert.

Klar geht das auch mit einem ESP, erhöht aber doch sehr die Komplexität.
Ah, this is obviously some strange usage of the word 'safe' that I wasn't previously aware of. (D.Adams)

obeis

Irre diese Geschwindigkeit.

Ja der Rechner steht ca. 5m daneben. Also noch USB Abstand.

Processing sagt mir aktuell garnichts. Ich werde morgen mal Google quälen.
Für heute bin ich raus.

Siebo

Schuppeste

#26
Nov 25, 2018, 07:28 pm Last Edit: Nov 25, 2018, 07:36 pm by Schuppeste
Nicht zu vergessen..

bei einer Messzeit von 180 Sekunden könnte die Arduino Zeit auch mal eben 0,5-1 Sekunde neben einer Profistoppuhr liegen.. da bräuchte man eine etwas bessere Zeitreferenz wenn man am Ende schon in 100stel/10tel anzeigen möchte.

EDIT: andere Idee.. Wieso nicht alles mit dem Rechner machen und aus dem Arduino eine USB Anzeige basteln..

Whandall

#27
Nov 25, 2018, 08:10 pm Last Edit: Nov 25, 2018, 08:15 pm by Whandall

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

const uint8_t startPin = 37;
const uint8_t resetPin = 36;

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);

//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(1); // a value between 0 and 15
  matrix.setRotation(0);
  matrix.fillScreen(LOW);
  anzeige(PSTR("Ready"));
  Serial.println(F("*Setup"));
}

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

void anzeige(uint32_t milliSekunden) {
  uint32_t value = (milliSekunden + 5) / 10;
  uint16_t seconds = value / 100;
  uint16_t hundertstel = value % 100;
  uint8_t pos = 0;
  matrix.fillScreen(LOW);
  if (seconds >= 100) {
    matrix.setCursor(0, 0);
    matrix.print((seconds / 100) % 10);
    matrix.setCursor(5, 0);
    matrix.print((seconds / 10) % 10);
    matrix.print(seconds % 10);
    seconds -= 100 * (seconds / 100);
  } else {
    if (seconds < 10) {
      pos = 11;
    } else {
      pos = 5;
    }
    matrix.setCursor(pos, 0);
    matrix.print(seconds);
  }
  matrix.setCursor(15, 0);
  matrix.print('.');
  matrix.setCursor(20, 0);
  matrix.print(hundertstel / 10);
  matrix.setCursor(26, 0);
  matrix.print(hundertstel % 10);
  matrix.write();
}

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

Processing
Code: [Select]
import processing.serial.*;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.util.Date;

Serial myPort;
int whichKey = -1;
String inData;
String selectedTeam = "";
String team = "";
PFont stdFont, bigFont, giantFont;
int currMillis;
int rounded;
boolean debugDisplay = false;

void setup() {
  size(1024, 640);

  stdFont = createFont("DejaVu Sans", 16);
  bigFont = createFont("DejaVu Sans Bold", 64);
  giantFont = createFont("DejaVu Sans Bold", 200);

  //printArray(PFont.list());
  printArray(Serial.list());

  // I know that the first port in the serial list on my mac
  // is always my  FTDI adaptor, so I open Serial.list()[0].
  // In Windows, this usually opens COM1.
  // Open whatever port is the one you're using.
  String portName = Serial.list()[1];
  myPort = new Serial(this, portName, 250000);
  myPort.bufferUntil('\n');
}

void draw() {
  background(0);
  textFont(stdFont);
  text("Team: " + team, 10, height-20);
  if (debugDisplay) {
    text("Key: " + whichKey, width-100, height-20);
    text("Data: '" + inData +"'", width-280, height-20);
  }
  textFont(bigFont);
  text("Team " + selectedTeam, 10, 70);
  textFont(giantFont);
  text(makeTime(), makePos(120), height-250);
}

void serialEvent(Serial myPort) {
  inData = myPort.readString().trim();
  if (inData.charAt(0) >= '0' && inData.charAt(0) <= '9') {
    currMillis = int(inData);
  } else if (inData.startsWith("*Stop")) {
    currMillis = int(inData.substring(6));
    if (selectedTeam != "") {
      Date date = new Date();
      appendTextToFile(sketchPath() + "\\ergebnisse.txt",
        "\"" + selectedTeam + "\", " + currMillis + ", " + makeTime() + ", \"" + date.toString() + "\"");
    }
  }
}

int makePos(int basePos) {
  if (rounded > 9999) {
    return basePos;
  }
  if (rounded > 999) {
    return basePos + 140;
  }
  return basePos + 279;
}

String makeTime() {
  String mt;
  rounded = (currMillis+5)/10;
  int highPart = rounded / 100;
  int lowPart = rounded % 100;
  mt = highPart + ".";
  if (lowPart<10) {
    mt = mt + "0";
  }
  mt = mt + lowPart;
  return mt;
}

void keyPressed() {
  myPort.write(key);
  whichKey = key;
  if (whichKey != 65535) {
    if (whichKey == 10) {
      selectedTeam = team;
      team = "";
    } else if (whichKey == 8) {
      if (team.length()>0) {
        team = team.substring(0, team.length()-1);
      }
    } else {
      team = team + char(whichKey);
    }
  }
}

void appendTextToFile(String filename, String text) {
  try {
    File f = new File(filename);
    if (!f.exists()) {
      if (!f.createNewFile()) {
        println("could not create " + filename);
      }
    }
    PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(f, true)));
    out.println(text);
    out.close();
  }
  catch (IOException e) {
    e.printStackTrace();
  }
}

Datei
Code: [Select]
"abcdefg", 1836, 1.84, "Sun Nov 25 20:05:54 CET 2018"
"abcdefg", 1640, 1.64, "Sun Nov 25 20:07:07 CET 2018"
"abcdefg", 2602, 2.60, "Sun Nov 25 20:07:15 CET 2018"
"abcdefg", 1829, 1.83, "Sun Nov 25 20:07:24 CET 2018"
"abcdefg", 2141, 2.14, "Sun Nov 25 20:07:31 CET 2018"
Ah, this is obviously some strange usage of the word 'safe' that I wasn't previously aware of. (D.Adams)

agmue

Dieser Beitrag gehört gedanklich vor die #26.

Zur Darstellung eines Wertes könnte man auch SerialComInstruments probieren, erspart man sich das selber Programmieren.
Die Vorstellungskraft ist wichtiger als Wissen, denn Wissen ist begrenzt. (Albert Einstein)

obeis

Ihr / Du bist Irre

Das sieht verdammt grandios aus.

Allerdings läuft es bei mir nicht so einfach.
Ich habe den Arduino Sketch mit den Pins angepasst und so übernommen.
Das läuft am Powerpack auch prima.
Die Zeitabweichung sehe ich nicht als Problematisch, da immer nur das eine Zeitnahmegerät im Einsatz sein wird, und wenn sich das Klima nicht derbe ändert wird die Abweichung sicher sehr ähnlich bleiben.
Das "Problem" ist mir aber bekannt.
Der PC soll nur on Top sein wenn es doch mal mehr menschen sehen sollen. Eigentlich ist der Hauptnutzen Stand alone an der Powerbank.
Wenn ich jetzt Processing runterlade und den Sketch einkopiere bekomme ich ein graues Fenster, und der Arduino stopt nach ca. 1 bis 3sec. selbstständig und führt einen neustart durch.
Es ist keine Eingabe möglich. Das Fenster bleibt nach kurzer Zeit einfach hängen.
Ich habe den CH340 Treiber auch Com1 gestellt.
Kein Erfolg.
Muss ich den Processing Sketch noch irgendwie auf meine Umgebung anpassen?

Ich befürchte es hängt an mir und meinem COM Port.

Siebo

Go Up