Arduino als Zähler - Anzeige per Siebensegment

Guten Abend Liebe Community,

mein Name ist Sandro, ich bin 15 Jahr alt und Anfänger beim Arduino-Coden.

Das Grundlegendste des Codens habe ich schon verstanden, aber jetzt bin ich an eine Grenze gekommen. Ich möchte mit dem Arduino UNO ein Relais ansteuern, dass z.B. einen Motor laufen lässt oder nicht. Daneben möchte ich vier Siebensegmentanzeigen haben, die anzeigen, wie oft der Motor schon gelaufen ist.

Immer wen das Relais auf Durchgang geschalten hat, soll die Anzeige um eine Stelle weiterspringen. Also wenn z.B 1234 auf den Anzeigen steht, das Relais auf Durchgang schaltet, soll die Anziege auf 1235 springen.

Ich hoffe Ihr könnt mir weiterhelfen,
Gruß,
Sandro

Den Sketch fürs Relais habe ich mal angehangen.

Releis__sketch.ino (1000 Bytes)

Warum 7-Segmentanzeige? Der Aufwand ist um einiges größer als ein LCD-Display.
Das Relais wird vom Arduino gesteuert?

Deinen Sketch bitte in Code-Tags </> packen, dann sieht man ihn auch.
Das ist erreichbar, wenn du Preview anwählst.

Hi

Das Multiplexen einer 7-Segment-Anzeige ist nicht ganz trivial und eigentlich auch nicht mehr nötig.
Wenn Dir eine 8-stellige Anzeige reicht, Die gibt's fertig zusammen gelötet beim fC für wenig Geld - und funktioniert direkt ohne größeren Ärger.
Wie 'dick' soll der Motor werden?
Klar kann man auch Relais nehmen - Die haben zumindest den Vorteil, galvanisch aufzutrennen.
Wenn's aber mit Spannung und Strom im unteren Rahmen bleibt, kann man Das auch elektronisch machen - LL-N-FET oder eine H-Brücke.

Dein Sketch ist noch ein 'recht frühes Werk' :slight_smile:
Besonders das delay() am Ende wird Dir binnen kurzer Zeit 'auf die Füße fallen' - in der Zeit macht der Arduino nämlich Nix - ok, gelogen - eigentlich rennt Er die ganze Zeit im Kreis und schaut auf die Uhr, ob Er damit aufhören darf.
Und Du hast keine Chance, Ihn davon zu erlösen!

Heißt: Während des delay() reagiert der Arduino noch nicht Mal auf den Weltuntergang.

Auch ein Relais kannst Du per FET schalten - bei induktiven Artikeln (Alles, was eine Spule beinhaltet - also Motor oder Relais) brauchst Du eine Freilauf-Diode.
Das gibt's ebenfalls schon 'am Stück' und wird, unter Zuhilfenahme des Wortes 'Arduino', auch so verkauft.

Möchtest Du nun nur die Male zählen, Die der Motor eingeschaltet wurde, oder auch die Umdrehungen mitzählen?

MfG

PS: MAX7219 sollte besagte Anzeige zum Vorschein bringen - gibt es auch als 8x8 Punkt Matrix und auch als 4er 8x8-Punkt-Matrix.

Hallo,

na ja , wie Du eventuell richtig vermutest brauchst Du einen Zähler. Dazu kann man eine Variable verwenden und die jedesmal wenn das Relais schaltet um 1 erhöhen. Dazu macht es natürlich Sinn wenn Du die Ansteuerung des Relais schon mal zusammen fasst und so oft im Loop wiederholst wie du das willst. Dazu bietet sich eine If Abfrage in Verbindung mit dem Zähler an.

Erstelle als zunächst einen Ablaufplan, das muss ja nicht nach DIN sein also z.B in der Art.

Wenn Zähler <= 10
Zähler = Zähler +1
Zählerstand anzeigen (z.B mit Serial.print)
Relais einschalten
delay(xxx)
Relais ausschalten
delay(yyy)

Wenn das soweit klappt solltest Du versuchen das delay durch millis zu ersetzen, Dazu gibts das Beispiel blink without delay. Warum das ? weil delay() blokiert. Der Programablauf bleibt stehen , bis das delay abgelaufen ist , und das will man ja eigendlich nicht haben.

Mann könnte es auch mit einer For Schleife machen, aber das führt dann zu dem geichen Problem, solange der Ablauf in der For Schleife ist wird nix anderes gemacht, alles was auserhalb des For steht wird nicht bearbeitet, und es könnte ja sein das Du zwei Motoren völlig unabhängig voneinander laufen lassen willst, oder wenn der Motor läuft soll eine Lampe blinken.

Heinz

Das Relais soll nur auf Durchgang schalten und somit eine etwas ältere Kamera auslösen. Die Anzeige soll nur anzeigen, wie oft dir Kamera ausgelöst hat. Wie könnte man das am besten lösen?

Könnte man das mit den ca. 86 Mio. Millisekunden Wartezeit irgendwie anders lösen?

Hi

Was hast Du vor?
Willst Du diese Zeit warten - also zu einer bestimmten Uhrzeit ein Foto auslösen (denke ich Mal), oder wie soll der Ablauf aussehen?

Wenn ‘nur 1x am Tag’ - eine RTC dran gepackt und Diese einen Alarm auslösen lassen - wenn die RTC den Alarm ausgibt, wird das Foto gemacht, der RTC der neue Alarm mitgeteilt und der Arduino kann wieder sinnvolle Dinge machen - z.B. auch schlafen (was bei einem Arduino, also dem kompletten Board, nicht so viel bringt).

MfG

Hallo,

hab ich nicht verstanden, wenn das Relais die Kamera auslösen soll willt du doch eine Anzahl vorgeben oder ? Warum willst Du anschliessend 86 Mio. ms warten. worauf. ?

Mit einem Taster könntest du alles starten , das Relais z.B 10 mal schalten , danach soll nichts mehr passieren. Wenn dann der Taster anschliessend erneut gedrückt wird gehts wieder bei 1 los .

Sowas in der Art ?

Den Ansatz dazu hab ich Dir schon gegeben. Wenn der Zähler >10 ist passiert halt nix mehr, bis der Taster erneut gedrückt wird. Wenn du keinen Taster drann hast , könntest Du halt den Strom abschalten und neu starten.

schau Dir in der Hilfe die If Anweisung an und spiel was daimt rum.

Heinz

Nachtrag :

ich vermute du willst mehrere Aufnahmen hintereinander machen. z.B 20 Fotos in einer Stunde. von einem Motiv. Zeitraffer heisst das glaube ich .

Nochmal langsam erklärt.

Ich möchte mit einem Relais eine Kamera auslösen, das mittels Arduino gesteuert wird. Das Relais soll für 500 Millisekunden eingeschaltet, dann 8500 Millisekunden ausgeschaltet sein. Das ganze soll neun mal wiederholt werden. Nach den 9 Wiederholungen wird für 86.008.500 Millisekunden gewartet. (Über einen Tag)

Dafür möchte ich einen Sketch schreiben, der ohne delay auskommt.

Zeitgleich soll der Arduino zählen, wie oft das Relais geschalten wurde. Das soll auf einer passenden Siebensegmentanzeige angezeigt werden.

Ich habe jetzt erstmal allein nur das Relais mit einer for - Schleife geschalten, in der aber immer noch delay vorkommt. Wie das mit den millis funktioniert habe ich noch nicht ganz verstanden.

int RelaisPWR = 13;
int RelaisSignal = 12;

void setup()
{
pinMode(13, OUTPUT);
pinMode(12, OUTPUT);
}
void loop(){
digitalWrite(RelaisRWR, HIGH);

for (int i = 0; i<8; i++)
{
digitalWrite(RelaisSignal, HIGH);
delay(500);
digitalWrite(RelaisSignal, LOW);
delay(8500);
}
delay(2000);
}

Ich mache Dir mal einen Vorschlag:

const byte HerzschlagPin = 13;
const byte RelaisSignalPin = 12;
//const uint32_t EIN = 500, AUS = 8500, WARTEN = 86008500UL;
const uint32_t EIN = 500, AUS = 2500, WARTEN = 5000; // kurze Zeiten zum Testen
uint32_t jetzt, vorhin, herz;
uint8_t schritt = 1, aufnahmen = 1;

void setup()
{
  Serial.begin(115200);
  pinMode(HerzschlagPin, OUTPUT);
  pinMode(RelaisSignalPin, OUTPUT);
  digitalWrite(RelaisSignalPin, HIGH);
  Serial.println(aufnahmen);
}

void loop() {
  jetzt = millis();
  switch (schritt)
  {
    case 0:
      if (jetzt - vorhin >= WARTEN)
      {
        vorhin = jetzt;
        schritt = 1;
        digitalWrite(RelaisSignalPin, HIGH);
      }
      break;
    case 1:
      if (jetzt - vorhin >= EIN)
      {
        vorhin = jetzt;
        schritt = 2;
        digitalWrite(RelaisSignalPin, LOW);
      }
      break;
    case 2:
      if (jetzt - vorhin >= AUS)
      {
        vorhin = jetzt;
        aufnahmen++;
        Serial.println(aufnahmen);
        if (aufnahmen % 8)
        {
          schritt = 1;
          digitalWrite(RelaisSignalPin, HIGH);
        } else {
          schritt = 0;
          Serial.println("Pause");
        }
      }
      break;
  }
  if (jetzt - herz >= 100)
  {
    herz = jetzt;
    digitalWrite(HerzschlagPin, !digitalRead(HerzschlagPin));
  }
}

Während der langen Wartezeit zeigt der Herzschlag, daß die Schaltung noch lebt.

geh mal das Beispiel BlinkWithoutDelay durch.

Dann informiere dich wie eine Statemachine aufgebaut ist.
Du kannst z.B. folgende Status definieren:

IDLE, // warten auf Auslösung
ON, // wechselweises ein
OFF, // und ausschalten
LONG // abwarten der langen Pause

Dann definierst du die Übergänge
von ON auf OFF → Zeitablauf
von OFF auf ON → Zeitablauf und noch keine 9 Durchgänge erreicht
von OFF auf LONG → Zeitablauf und 9 Durchgänge erreicht
von LONG auf ON → Zeitablauf

du musst noch was finden um anzufangen, also um aus IDLE in ON zu springen.

All das machst du auf einem kariertem Papier und mit einem Bleistift.

Dann schreibst den Code hin. Als Anregung etwa so:

// https://forum.arduino.cc/index.php?topic=620652.0
// beigesteuert von noiasca

const int relay1 = 13;
// const int relay2 = 12;

uint32_t previousMillis = 0;
const uint16_t intervallOn = 500;              // wenn >60000 umstellen auf uint32_t !!!
const uint16_t intervallOff = 1000;            // wenn >60000 umstellen auf uint32_t !!!
const uint16_t intervallDelay = 2000;          // wenn >60000 umstellen auf uint32_t !!!
//const uint32_t intervallLong = 86008500UL;
const uint32_t intervallLong = 3000UL;
uint8_t runs = 0;                              // Anzahl Durchgänge aktuell
const uint8_t runsMax = 9;                     // Wie viele Durchgänge sollen durchgeführt werden

enum {IDLE,         // warten auf Auslösung
      ON,           // wechselweises ein 
      OFF,          // und ausschalten
      LONG          // abwarten der langen Pause
     } myStatus;                               // Statusvariable für die Statemachine

void doNonblocking()
{
  // eine Statemachine:
  if (myStatus == OFF && millis() - previousMillis >= intervallOff)
  {
    digitalWrite(relay1, HIGH);                               // Relais schalten
    runs++;                                                   // Durchgänge mitzählen
    myStatus = ON;                                           // myStatus weiterdrehen
    previousMillis = millis();                                // Zeitstempel merken
    Serial.print(F("myStatus -> ON  ")); Serial.println(runs); // Debugausgabe, damit wir sehen was das ding macht
  }
  if (myStatus == ON && millis() - previousMillis >= intervallOn)
  {
    digitalWrite(relay1, LOW);
    previousMillis = millis();
    
    if (runs < runsMax)                                       // solange wir das limit nicht erreicht haben bleiben wir im ON/OFF Modus
    {
      myStatus = OFF;

      Serial.print(F("myStatus -> OFF "));  Serial.println(runs);
    }
    else                                                      // ... ansonsten gehts in die Phase LONG
    {
      runs = 0;
      myStatus = LONG;
      Serial.println(F("myStatus -> LONG"));
    }
  }
  if (myStatus == LONG && millis() - previousMillis >= intervallLong)
  {
    digitalWrite(relay1, HIGH);                             // Relais schalten
    runs++;
    myStatus = ON;                                          // myStatus weiterdrehen; Annahme nach der Wartezeit wieder n Auslösungen
    previousMillis = millis();                              // Zeitstempel merken
    Serial.println(F("myStatus == ON"));                    // Debugausgabe, damit wir sehen was das ding macht
  }
}


void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start"));
  pinMode(relay1, OUTPUT);

  //zunächst braucht es einen Startevent/Auslöser du hast nicht definiert, wie es dazu kommen soll
  digitalWrite(relay1, HIGH);
  myStatus = ON;
  runs++;
  previousMillis = millis();
  Serial.print(F("myStatus -> ON  ")); Serial.println(runs);
}


void loop()
{
  doNonblocking();

  // here is where you'd put code that needs to be running all the time.

}

… und wieder mal zu spät :wink:

noiasca:
... und wieder mal zu spät :wink:

Aber dafür schön kommentiert, Qualität vor Quantität!

Danke! Dein Sketch funktioniert nach kleinen Änderungen meinerseits seht gut. Ich habe so ein Arduino-Relais das ich Hintereinander an die Pins GND, 13 und 12 in den Arduino gesteckt habe. Den Herzschlaug habe ich vorerst rausgenommen.

Auch die Serielle Verbindung läuft gut. Jetzt müssen die angezeigten Zahlen (wie oft das Relais ausgelöst hat) noch auf eine Siebensegmentanzeige gebracht werden. Auf so eine Vierstellige, oder auf eine serielle.

Und wenn das dann alles läuft soll auf einer zweiten Anzeige gezeigt werden wie oft der Arduino die ganz lange Pause gemacht hat.

const byte RelaisSignalPin = 12;
const byte RelaisPWR = 13;
//const uint32_t EIN = 500, AUS = 8500, WARTEN = 86008500UL;
const uint32_t EIN = 500, AUS = 8500, WARTEN = 8600; // kurze Zeiten zum Testen
uint32_t jetzt, vorhin, herz;
uint8_t schritt = 1, aufnahmen = 1;

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

  pinMode(RelaisSignalPin, OUTPUT);
  pinMode(RelaisPWR, OUTPUT);
  digitalWrite(RelaisSignalPin, HIGH);
  Serial.println(aufnahmen);
}

void loop() {
  digitalWrite(RelaisPWR, HIGH);
  
  jetzt = millis();
  switch (schritt)
  {
    case 0:
      if (jetzt - vorhin >= WARTEN)
      {
        vorhin = jetzt;
        schritt = 1;
        digitalWrite(RelaisSignalPin, HIGH);
      }
      break;
    case 1:
      if (jetzt - vorhin >= EIN)
      {
        vorhin = jetzt;
        schritt = 2;
        digitalWrite(RelaisSignalPin, LOW);
      }
      break;
    case 2:
      if (jetzt - vorhin >= AUS)
      {
        vorhin = jetzt;
        aufnahmen++;
        Serial.println(aufnahmen);
        if (aufnahmen % 9)
        {
          schritt = 1;
          digitalWrite(RelaisSignalPin, HIGH);
        } else {
          schritt = 0;
          Serial.println("Pause für einen Tag!");
        }
      }
  }
}

Hi

Wenn Du nicht gerade den Pin 13 benutzt, sondern das Relais-Zeug ‘einen rüber setzt’ - kannst Du den HErzschlag auf 13 setzen - ist bei Uno und Nano die ‘L’-LED - dann siehst Du schon von Weitem, daß Da ‘noch was lebt’ - gerade den Herzschlag würde ich drin lassen!

Deine Warterei bis zum nächsten Tag - dazu schrieb ich bereits, daß Dir die Zeit davon läuft - in irgend eine Richtung.
Wenn die Foto’s später ‘Das Stadtleben um 9:00h’ darstellen soll, wäre Es ja schöner, wenn Das nicht auf 6:30h abwandert … Stichwort RTC 3231 und mit Deren Alarm die Foto-Session starten.

Zu Deiner Anzeige: Mir ist davon der Link nicht unter gekommen - was hast Du besorgt?

Zur Ausgabe im Terminal:
oberhalb von setup():
uint16_t fotoknips=0;

Im case 0, hinter dem digitalWrite, schriebst Du
fotoknips++;

Im case 2 bei ‘Pause für einen Tag’
Serial.print(“Ausgelöste Fotos:”);
Serial.println(fotoknips);

MfG

SandroP2019:
Jetzt müssen die angezeigten Zahlen (wie oft das Relais ausgelöst hat) noch auf eine Siebensegmentanzeige gebracht werden. Auf so eine Vierstellige, oder auf eine serielle.

Ich mag ja die 8x8-Matrix-Anzeigen mit MAX7219, wie ich sie bei meinem MP3-Player eingesetzt habe.

die mag ich auch, aber für eine Zahlendarstellung eignen sich die einfachen 8x7 Segment auch gut:

postmaster-ino:
Hi

Wenn Du nicht gerade den Pin 13 benutzt, sondern das Relais-Zeug 'einen rüber setzt' - kannst Du den HErzschlag auf 13 setzen - ist bei Uno und Nano die 'L'-LED - dann siehst Du schon von Weitem, daß Da 'noch was lebt' - gerade den Herzschlag würde ich drin lassen!

Deine Warterei bis zum nächsten Tag - dazu schrieb ich bereits, daß Dir die Zeit davon läuft - in irgend eine Richtung.
Wenn die Foto's später 'Das Stadtleben um 9:00h' darstellen soll, wäre Es ja schöner, wenn Das nicht auf 6:30h abwandert ... Stichwort RTC 3231 und mit Deren Alarm die Foto-Session starten.

Zu Deiner Anzeige: Mir ist davon der Link nicht unter gekommen - was hast Du besorgt?

Zur Ausgabe im Terminal:
oberhalb von setup():
uint16_t fotoknips=0;

Im case 0, hinter dem digitalWrite, schriebst Du
fotoknips++;

Im case 2 bei 'Pause für einen Tag'
Serial.print("Ausgelöste Fotos:");
Serial.println(fotoknips);

MfG

Ich werde jetzt erstmal die Anzeige weglassen. Stattdessen möchte ich die RTC anschließen. Mit dem Zeitstempel im seriellen Monitor merkt mach doch ganz schön die Zeitabweichungen des Arduino.

Wie muss ich den Sketch schreiben wenn ich die RTC mit drin habe? Sie soll, wie du gesagt hast die Auslösungen starten.

Hi

  • RTC-Objekt erstellen
  • Interrupt scharf schalten (der Pin, an Dem der Alarm-Ausgang der RTC hängt)
  • Zeit stellen (Welche ist eigentlich egal)
  • Alarm stellen (ab Jetzt + Zeit x)
  • Schlafen legen

Wenn jetzt die RTC den Alarm auslöst, wacht der Arduino auf.
Du prüfst aber noch, ob Du durch die RTC wach geworden bist und nicht durch 'was Anderes' - z.B. ein schnöder Reset lässt den Arduino auch wieder zum Leben erwecken (wobei Du dann im setup() vorbei kommen solltest - dort also ggf. Lesen, ob die RTC schon gestellt ist und noch ein Alarm aussteht, bevor wir die neue Zeit + Alarm-Zeit einbrutzeln).

Ok, wir sind durch die RTC wieder zum Leben erweckt worden - dann den Status für den Start einstellen und drauf Warten, daß wir wieder pennen gehen dürfen.
Normal sollte der RTC-ALarm bestehen bleiben, also beim nächsten Match wieder feuern - also keine erneute Einstellung an der RTC nötig sein.
Ggf. musst Du den anstehenden Alarm aber vorher quitieren - dazu sollte ein Beispiel zu der verwendeten RTC (empfehle eine DS3231, KEINE 1307) bzw. der von Dir verwendeten Lib was aussagekräftiges sagen.

Beim Pennen wird auch nicht Viel am Terminal ausgegeben ... aber es ist Deine Entscheidung, auf so was Simples wie den Herzschlag verzichten zu wollen.

MfG

SandroP2019:
Wie muss ich den Sketch schreiben wenn ich die RTC mit drin habe? Sie soll, wie du gesagt hast die Auslösungen starten.

Zur DS3231 gibt es verschiedene Bibliotheken, die mich teilweise verwirrt haben. Daher fand ich den Artikel Using DS1307 and DS3231 Real-time Clock Modules with Arduino einfach und hilfreich.

Grundsätzlich stellt sich mir die Frage, ob Du batteriebetrieben, also stromsparend arbeiten möchtest, oder ob die Schaltung an einem Netzteil hängt. Im ersteren Fall ist Schlafen mit Wecken durch Interrupt eine gute Idee, im zweiten kannst Du auch rhythmisch Stunden und Minuten der Ist- mit der Auslösezeit vergleichen.

Ich möchte die gesamte Schaltung per Netzteil versorgen.

Beim einschalten des Arduinos sollen die 9 Auslösungen sofort gemacht werden, dann soll das Bord schlafen gelegt werden, genau 24h nach dem Schlafen legen, sollen dann die nächsten neun Bilder gemacht werden usw. Der Herzschlag wird auch mit drin sein.

Für mich heißt das:

  • 9 Auslösungen
  • 24 Stunden-Timer an der RTC starten
  • Arduino schlafen legen
  • nach 24 Stunden weckt die RTC den Arduino wieder auf, dieser beginnt sofort mit den 9 Auslösungen
  • 24h Timer wieder stellen (wenn Auslösungen beendet sind!)
  • Arduino schlafen legen
  • usw.

Dafür muss ich mir einen Sektch machen. Mein Problem ist nur, dass ich noch richtiger Anfänger dabei bin. Ende des Jahres muss die ganze Schaltung aber laufen.

SandroP2019:
Ich möchte die gesamte Schaltung per Netzteil versorgen.

Dann kannst Du zwischen Schlafenlegen mit Aufwecken und ständig Zeit abfragen wählen.

SandroP2019:
... genau 24h nach dem Schlafen legen ...

Dann hättest Du einen Versatz von 24 h + Zeit für Aufnahmen. Wahrscheinlich willst Du aber immer zur selben Uhrzeit, also beispielsweise um 20:15 Uhr die Aufnahmen starten. Oder?

Wenn Du die Zeit ständig abfragst, vergleichst Du die Stunden, Minuten und Sekunden mit der gewünschten Auslösezeit beispielsweise Stunde=20, Minute=15 und Sekunde=00. Dann startest Du die Aufnahmesequenz.