Kann gelöscht werden! Danke

Hallo in die Runde,

meine ersten Erfahrungen mit dem Arduino sind gut 10 Jahren her (kauf und Installation der IDE), wirklich angefangen habe ich im November 22, hier ging es darum coole Lichteffekte für das Lightpainting zu bekommen.

Seit langem Spukt mir ein Gerät im Kopf herum, mit dem ich Wassertopfen fotografieren kann. Da mir die am Markt gängigen Produkte nicht zugesagt haben, habe ich versucht es selbst um zu setzen.

Ein Grundprogramm welches über die Arduino IDE steuern lässt, inkl. Stromlaufplan, war schnell gefunden. Soweit läuft das Programm auch ohne "erkennbare" Störung!

Jetzt kam aber der Spieltrieb und der Wunsch das ganze Autark zu betrieben ins Spiel.
Also kamen 6 Encoder inkl. Taster dazu (Einstellen der Tropfengröße & Wartezeiten zw. den Tropfen, Starten des Programms usw.) und noch ein LCD 4x20 (ohne I2C) dazu.
Und damit nahm der Ärger seinen Lauf :frowning: Das ganze läuft auf einem "Mega 2560"

Das Display stürzt immer mit Programmablauf ab, mal beim ersten Durchlauf mal hält es ein paar Durchläufe durch - damit ist dann das Thema "Autark" leider nicht umsetzbar.

Meine E-Technik Kenntnisse sind ähnlich rudimentär, wie die der Programmiersprache. Vielleicht habt ihr einen Blick, für das, was meiner Schaltung / Programm fehlt.

So, der Text ist geschrieben... jetzt muss ich nur noch finden wo und wie ich den Schaltplan & das PRG hochladen kann...

Gruß
Timo

Der Stromlaufplan aus der Vorlage

Der IST-Stromlaufplan mit meinen Anpassungen - der ursprüngliche Stromlaufplan ist cyan-Farben umrandet. Die Pins habe ich dazu geschrieben, da mir beim Anschluss des Boardes die Übersichtlichkeit gefehlt hat. Ebenso sind noch Ergänzungen zu den Bauteilen im Plan enthalten.

```cpp
/*
################################################################################################################################################
###                                                     Tropfengestalter *Halbautomatik*                                                     ###
###                                                   Kamera-, Blitz- und Wassersteuerung                                                    ###
###                       6 Encoder Steuern die Tropfen, sowie die Wartezeit zwischen Tropfen 1, 2 & 3 & die Blitzauslösezeit                ###
###                                                          Version 1.13b / 11.02.23                                                        ###
###                                                               TimothyBK79                                                                ###
################################################################################################################################################
*/
//##############################################################################################################################################
//Kameraversatz wird bei halbautomatik Betrieb benötigt - Kamera per Hand auslösen, Blitz & Tropfen per Tropfengenerator
//Tropfdauer & Verweilzeit wird für das Positionieren einer Schraube benötigt (Fokussierhilfe)

unsigned long Kameraversatz = 120;           
unsigned long Tropfdauer = 20;              //Testtropfenlänge      
unsigned long Verweilzeit = 750;            //Wartezeit zwischen den Testtropfen  
//##############################################################################################################################################

#define ST_Pin  31                           //Starttaster
#define Kamera_Pin 6                        //Kameraanschluss (bei Sony wird Kamera & Blitz gesteuert)
#define Tropfen_Pin 7                       //Magnetventil
#define Blitz_Pin 5                         //Blitzsteuerung (für Leica)
#define LEDGruen 15                         //LED Gruen, zeigt Bereitschaftsstatus
#define LEDRot 16                           //LED Rot - Gerät arbeitet
#define Testtropfen 4                       //Testtropfen zum Fokussieren - 10 Wiederholungen a 500ms (Encoder-PIN 1)
#define Handschalter 44                     //externer Handschalter zum Programmstart
#define Leertaster 30                       //Vorratsbehälter leeren
//#define Taster3 31
//#define Taster5 40
//#define Taster6 17                        
//#define Tropfen_Pin2 43                   //Vorbereitend für 2. Magnetventil
//#define Tropfen_Pin3 45                   //Vorbereitend für 3. Magnetventil

#include <Encoder.h>
Encoder Tropfen1(2, 8);                     //Encoder für die Tropfengröße und die Wartezeiten dazwischen
Encoder Tropfen2(9, 3);
Encoder Tropfen3(20, 12);
Encoder Warte1(18, 10);
Encoder Warte2(19, 11);
Encoder Blitz(14, 21);

#include <LiquidCrystal.h>                  //LCD Einbinden ohne I2C
LiquidCrystal lcd(51, 50, 49, 48, 47, 46);  //Pinanschluesse LCD

void setup() 
{ 
  pinMode(ST_Pin, INPUT_PULLUP);
  pinMode(Testtropfen, INPUT_PULLUP);
  pinMode(Leertaster, INPUT_PULLUP);
  pinMode(Kamera_Pin, OUTPUT);
  pinMode(Tropfen_Pin, OUTPUT);
  pinMode(Blitz_Pin, OUTPUT);
  pinMode(LEDGruen, OUTPUT);
  pinMode(LEDRot, OUTPUT);

 
  lcd.begin(20, 4);                         //LCD hat 20 Zeichen & 4 Zeilen
  lcd.setCursor(0, 0);
  lcd.print("------ Tropfen -----");
  lcd.setCursor(5, 1);
  lcd.print(" |  ");
  lcd.setCursor(12, 1);
  lcd.print(" |  ");
  lcd.print(" ");
  lcd.setCursor(0,2);
  lcd.print("Blitz | Verweilzeit");
  lcd.setCursor(5, 3);
  lcd.print(" |  ");
  lcd.setCursor(12, 3);
  lcd.print(" |  ");
}
                                            //Encoderbereich muss noch definiiert werden - nur wie?!
long oldTropfen1 = -999;
long oldTropfen2 = -999;
long oldTropfen3 = -999;
long oldWarte1 = -999;
long oldWarte2 = -999;
long oldBlitz = -999;

void loop()
{
  digitalWrite(LEDGruen, HIGH);             //Gerätestatus bereit
  long newTropfen1 = Tropfen1.read()/2;
  if (newTropfen1 != oldTropfen1)
  {
    oldTropfen1 = newTropfen1;
  } 
  long newTropfen2 = Tropfen2.read()/4;
  if (newTropfen2 != oldTropfen2)
  {
    oldTropfen2 = newTropfen2;
  }
  
  long newTropfen3 = Tropfen3.read()/4;
  if (newTropfen3 != oldTropfen3)
  {
    oldTropfen3 = newTropfen3;  
  }
  
  long newWarte1 = Warte1.read()/4;
  if (newWarte1 != oldWarte1)
  {
    oldWarte1 = newWarte1;
  }
  
  long newWarte2 = Warte2.read()/4;
  if (newWarte2 != oldWarte2)
  {
    oldWarte2 = newWarte2;
  }  
  
  long newBlitz = Blitz.read()/2;
  if (newBlitz != oldBlitz)
  {
    oldBlitz = newBlitz;
  }
  
  if (digitalRead(Testtropfen) == HIGH)     
  {
    Tropfenlang();
  }

   if (digitalRead(Leertaster) == HIGH)      //Leeren des Vorratsbehälters
  {
    Leeren();
  }
  
  lcd.setCursor(2, 1);
  lcd.print(newTropfen1);
  lcd.print(" ");
  lcd.setCursor(9, 1);
  lcd.print(newTropfen2);
  lcd.print(" ");
  lcd.setCursor(16, 1);
  lcd.print(newTropfen3);
  lcd.print(" ");
  lcd.setCursor(2, 3);
  lcd.print(newBlitz);
  lcd.print(" ");
  lcd.setCursor(9, 3);
  lcd.print(newWarte1);
  lcd.print(" ");
  lcd.setCursor(16, 3);
  lcd.print(newWarte2);
  lcd.print(" ");
 
   if (digitalRead(ST_Pin) == HIGH)
   {
    if ((newWarte1 + newTropfen2 + newWarte2) < newBlitz)
    {
      digitalWrite(LEDGruen, LOW);            //schaltet um von bereit auf in Betrieb      
      digitalWrite(LEDRot, HIGH);
      Kamera();                               //löst Kamera aus
      delay(Kameraversatz);
      Tropfen(newTropfen1);                   //Erster Tropfen wird ausgelöst
      uint32_t millisNow = millis();
      while (millis() < millisNow + newBlitz)
      {
        if (millis() == millisNow + newWarte1)
        {  //Wartezeit bis 2. Tropfen auslöst
          Tropfen(newTropfen2);                   //zweiter Tropfen wird ausgelöst
        }
  
        if (millis() == millisNow + newWarte2 + newTropfen2)
        {
          Tropfen(newTropfen3);
        }
      }
      BlitzSender();      
      delay(2500);                            //Sperrt den Taster gegen Doppelauslösung              
      digitalWrite(LEDRot, LOW);              //schaltet um auf Bereit
      digitalWrite(LEDGruen, HIGH);      
    }
    else 
    {
      digitalWrite(LEDRot, HIGH);              //schaltet um auf Bereit
      digitalWrite(LEDGruen, HIGH);
      delay(1500);
    }
  }
  else
  {
    digitalWrite(LEDRot, LOW);              //schaltet um auf Bereit
    digitalWrite(LEDGruen, HIGH); 
  }

  if (digitalRead(Handschalter) == HIGH)         
  {
    if (!((newWarte1 + newTropfen2 + newWarte2) > newBlitz)) {
      digitalWrite(LEDGruen, LOW);            //schaltet um von bereit auf in Betrieb      
      digitalWrite(LEDRot, HIGH);
      Kamera();                               //löst Kamera aus
      delay(Kameraversatz);
      Tropfen(newTropfen1);                   //Erster Tropfen wird ausgelöst
      uint32_t millisNow = millis();
      while (millis() < millisNow + newBlitz)
      {
        if (millis() == millisNow + newWarte1)
        {  //Wartezeit bis 2. Tropfen auslöst
          Tropfen(newTropfen2);                   //zweiter Tropfen wird ausgelöst
        }
        if (millis() == millisNow + newWarte2 + newTropfen2)
        {
          Tropfen(newTropfen3);
        }
      }          
      BlitzSender();      
      delay(2500);                            //Sperrt den Taster gegen Doppelauslösung              
      digitalWrite(LEDRot, LOW);              //schaltet um auf Bereit
      digitalWrite(LEDGruen, HIGH);      
    }
    else 
    {
      digitalWrite(LEDRot, HIGH);              //schaltet um auf Bereit
      digitalWrite(LEDGruen, HIGH);
      delay(1500);
    }
  }
  else
  {
    digitalWrite(LEDRot, LOW);              //schaltet um auf Bereit
    digitalWrite(LEDGruen, HIGH); 
  }
}

void Kamera()                        
{
  digitalWrite(Kamera_Pin, HIGH);
  delay(5);                                 //Auslöseverzögerung + Reservezeit X (Sony Auslöseverzögerung 100ms) (einmalig)
  digitalWrite(Kamera_Pin, LOW);
}

void Tropfen(int ms)
{
  digitalWrite(Tropfen_Pin, HIGH);
  delay(ms);                                //Zeit wird im LOOP-Teil definiert
  digitalWrite(Tropfen_Pin, LOW);         
}

void BlitzSender()
{
  digitalWrite(Blitz_Pin, HIGH);          
  delay(2);                                 //Zeit muss so angepasst werden, das Blitz auslöst (einmalig)
  digitalWrite(Blitz_Pin, LOW);
}

void Tropfenlang()                          //Testtropfen fällt 6x, in der Zeit springt LED Grün auf Rot
{
  digitalWrite(LEDGruen, LOW);
  digitalWrite(LEDRot, HIGH);
  for (int i = 0; i <6; i++)
  {
  digitalWrite(Tropfen_Pin, HIGH);
  delay(Tropfdauer);
  digitalWrite(Tropfen_Pin, LOW);
  delay(Verweilzeit);
  }
}

void Leeren()                               //leert den Wasservoratsbehälter, solange wie gedrückt wird
{
  digitalWrite(LEDGruen, LOW);
  digitalWrite(LEDRot, HIGH);
  digitalWrite(Tropfen_Pin, HIGH);
  delay(750);
  digitalWrite(Tropfen_Pin, LOW);
  digitalWrite(LEDRot, LOW);
  digitalWrite(LEDGruen, HIGH);
}

Das steht hier. Als neuer User kann es noch Einschränkungen geben.

Gruß Tommy

Vielen Dank dafür :slight_smile:

Beschreibe doch bitte mal genau, wie sich das äußert, wenn dein Display abstürzt.
Und wie lang sind die Kabel zum Display ?

Hallo,
du solltest ein paar Serial.print() einbauen damit Du sehen kannst wo es wann klemmt.
Heinz

@HotSystems
Die Symptome varieren, mal fallen einzelne Zeichen aus, mal sind es Hieroglyphen oder es fällt ganz aus. Sehr selten fängt es sich wieder und zeigt die gewünschte Anzeige an.

Das ganze ist in einem Alukoffer ca. 25x18cm. Alle Kabel sind 10 - 15cm lang. Der Arduino sitzt separat oben links, das Display mittig unten, daneben re/li die Encoder. Die Steuerplatine mit den Optokopplern, Mosfet & Widerständen sitzt mit einem Abstand von ca. 1,5cm hinter dem LCD - allerdings ändert sich das Verhalten nicht, wenn Platine & LCD weiter auseinander sind. Die Klinkenbuchsen für Blitz, Kamera & Magnetventil befinden sich in der Nähe des Arduino.

@Rentner
In wie weit zeigt Serial.Print Fehler an? Ich dachte, es würde analog das anzeigen was auf dem Display stehen soll, bzw. das, was man eben Programmiert hat. Kannst Du das bitte näher erläutern?

Du kannst mit zusätzlichen Printausgaben feststellen, an welcher Stelle der Sketch hängen bleibt, bzw. gestört wird.
Was für ein Netzteil verwendest du und welchen Strom liefert das Netzteil ?
Hast du mal die Spannung (5Volt) gemessen ?

Das mit den Serial.Prints werde ich dann mal wieder einfügen, die hatte ich mit Einzug des LCD entfernt. Das braucht aber sicher ein paar Tage, da ich derzeit anderweitig eingespannt bin :frowning: Ich gehe mal davon aus, das hier das gleiche ausgegeben werden soll wie auf dem LCD?!

Im Test sind 2 Netzteile, 1x 12V 20A & ein einstellbares 16V 30A, das Verhalten ist an beiden das selbe.
Da ich auch schon an Spannungsschwankungen gedacht hatte, hatte ich zwischenzeitlich mal einen Kondensator in die 5V Leitung eingebaut.
Die Steuerung hatte auch noch einen anderer Fehler, daher habe ich das ganze nochmal neu und schöner aufgebaut, mit extra 5V Spannungsregler, falls es dem Arduino einfach zu viel war. Der Fehler blieb allerdings. Und nein, die 5V habe ich nicht nochmals in Betrieb geprüft. Kann ich aber machen, ebenso die 12V.
Die Masse ist miteinander verbunden. Offensichtliche Fehlverbindungen konnte ich mit dem Durchgangsprüfer auch keine feststellen

Sehe ich das richtig, du machst Vergleiche zwischen millis() und signed Long Variablen? Du solltest schon unsigned nutzen. Vielleicht entsteht durch deren Überlauf der Fehler.

a)
Zeitvergleiche macht man wegen dem Überlauf nicht mit addition
while (millis() < millisNow + newBlitz)

sondern immer in dem man die Differenz zweier Zeiten vergleicht!

b)
Zeig mal echte Bilder von deinem Aufbau, besonders würden mich die Lötungen am LCD interessieren, aber auch alle anderen Kabelverbindungen bis zum Mega

@Plumps
Ja, Du siehst richtig. Wie sagte mein Ausbilder seinerzeit immer so zu treffend
"Der Leihe staunt und der Fachmann wundert sich" :wink:

Ich staune, darüber das es was tut, und ihr wundert euch, das es was tut" g

Aus den long habe ich jetzt überall unsigned gemacht - das Ergebnis ist allerdings das gleiche :frowning:

@noiasca
Das man keine Zeitvergleiche machen soll klingt logisch, war aber für mich das naheliegendste - da es gewisse Abhängigkeiten gibt (Erster Tropfen berührt das Wasser, nach Zeit X löst der Blitz aus, alles weitere MUSS dazwischen passieren)

Anbei die Bilder, der Mega ist "nur" von unten fotografiert, da ich die Steckleisten entfernt und die Drähte direkt angelötet habe.
Bei dem Lot handelt es sich um kolophoniumfreies Lot, damit ich überhaupt löten kann. Leider geht es damit nicht ganz so gut / schön.

Um mal alle anderen Komponenten möglichst außen vor zu lassen, habe ich das Grund-Programm um das LCD erweitert. Auch hier tritt der Fehler auf.

```cpp
#define Blitz_Pin 5
#define ST_Pin 31
#define Tropfen_Pin 7

#include <LiquidCrystal.h>                  
LiquidCrystal lcd(51, 50, 49, 48, 47, 46);

unsigned long tropfen1 = 30;
unsigned long delay1 = 0;
unsigned long tropfen2 = 0;
unsigned long delay2 = 45;
  
void setup() {
  pinMode(Tropfen_Pin, OUTPUT);
  pinMode(Blitz_Pin, OUTPUT);
  pinMode(ST_Pin, INPUT_PULLUP);

  lcd.begin(20, 4);                         //LCD hat 20 Zeichen & 4 Zeilen
  lcd.setCursor(0, 0);
  lcd.print("------ Tropfen -----");
  lcd.setCursor(5, 1);
  lcd.print(" |  ");
  lcd.setCursor(12, 1);
  lcd.print(" |  ");
  lcd.print(" ");
  lcd.setCursor(0,2);
  lcd.print("Blitz | Verweilzeit");
  lcd.setCursor(5, 3);
  lcd.print(" |  ");
  lcd.setCursor(12, 3);
  lcd.print(" |  ");
}
 
void loop() {

  lcd.setCursor(2, 1);
  lcd.print(tropfen1);
  lcd.print(" ");
  lcd.setCursor(9, 1);
  lcd.print(tropfen2);
  lcd.print(" ");
  lcd.setCursor(2, 3);
  lcd.print(delay1);
  lcd.print(" ");
  lcd.setCursor(9, 3);
  lcd.print(delay2);
  lcd.print(" ");

  if(digitalRead(ST_Pin) == HIGH){
    tropfen(tropfen1);
    delay(delay1);
    tropfen(tropfen2);
    delay(delay2);
    blitzen();
  }
}
 
void tropfen(int ms) {
    digitalWrite(Tropfen_Pin, HIGH);
    delay(ms);
    digitalWrite(Tropfen_Pin, LOW);
  }

void blitzen() {
  digitalWrite(Blitz_Pin, HIGH);
  delay(10);
  digitalWrite(Blitz_Pin, LOW);
}

Das Programm vom Anfang habe ich um "Serial.print" erweitert, hier wird das Phänomen ebenfalls sichtbar - mit dem Unterschied, das die Werte hier auch danach weiter angezeigt werden, das LCD bleibt dort wo es hängen blieb.

noch mal genau lesen was ich schrieb.
Nicht durch Addition des Intervals sondern durch Subtraktion der alten Zeit!
So wie es im IDE Beispiel "Blink Without Delay" vorgemacht wird!

Bei Millis habe ich noch einen Knoten im Kopf, mit einer Zeit kann ich das noch nachvollziehen, aber danach bin ich relativ schnell raus. Und in meinem Programm sind es ja einige Zeiten die berücksichtigt werden müssen.

Entschuldige, da habe ich mich missverständlich ausgedrückt.

Heuer habe ich mal vor und hinter jeden Befehl des "eigentlichen" Ablaufes ein Serial.println gesetzt.

Was auffällt sind drei Dinge.

  1. das PRG scheint bei dem "Verrechnen Zeiten 2" hängen zu bleiben
  2. das Magnetventil löst nur noch 1x aus, unabhängig von den Zeiten zwischen den Auslösungen 2 & 3
  3. das Display bleibt an (normalerweise fällt es auch aus, wenn nur 1 Tropfen eingestellt ist!)

Desweiteren gibt es im Programm auch noch "void Tropfenlang" hier fallen mehrere Tropfen fest definiert (ohne Verrechnungen und ohne Kamera und Blitz), dieser Ablauf beeinflusst das Display ebenfalls nicht

Irgendwie hat mir das "hängen bleiben" bei der Zeit Verrechnung keine Ruhe gelassen. :thinking:

Das Programm habe ich jetzt nochmals ohne Encoder und der Vergabe fester Zeiten (delay... ja ich weiß, aber mein Knoten im Kopf :face_with_raised_eyebrow:) geschrieben. Hier geht es ohne Auffälligkeiten - auch bei Zeiten, die sonst nicht funktioniert haben.

Bevor ich jetzt weiter an der Elektronik suche, würde ich gerne die Zeiten "ordentlich" verrechnen lassen.
Wäre super, wenn ihr mich auch hier unterstützen könntet :smiling_face:

Der gewünscht Programmablauf sollte sein:

Tropfen1 fällt (keine Zeitvorgabe, er fällt wenn er will)
Blitz wird auf Tropfen 1 eingestellt (zum Einfrieren der Position)
Tropfen2 soll x-ms nach Tropfen1 fallen (jeweils ohne die Blitzzeit zu beeinflussen)
Tropfen3 soll x-ms nach Tropfen2 fallen

Du hast immer überall im Sketch millis() mit dem aktuellen, immer fortlaufenden Zeitstahl zur Verfügung.

Wenn der 1. Tropfen fällt, millis() merken :

tropfenStart = millis()

…. millis() laufen immer weiter

Wenn millis() - tropfenStart >= tropfen2ms dann tue was…

tropfenStart += tropfen2ms (neuer Tropfen-Startzeitpunkt)

Wenn millis - tropfenStart >= tropfen3ms dann tue was…

Ansonsten gilt:

:slight_smile:

Ich sehe was in den Beispielen steht und auch die Nachtwächterregelung ist verständlich erklärt, aber umsetzten / übertragen kann ich es nicht :frowning:

@noiasca @progger
Der Einfachheit halber habe ich das Programm stark zusammen gekürzt und lasse jetzt eine LED blinken. Die LED (TropfenA) blinkt einmal entsprechend der eingestellten Zeit. Aber danach tut sich nichts mehr. Wo bin ich falsch abgebogen? Die IDE meldet zumindest keinen Fehler.

```cpp
#define VENTIL_PIN 5              //LED Gruen
#define SCHALTER_PIN 4

unsigned long Tropfen1 = 200;     //LED Gruen  Eingabe der Werte für "const long"
unsigned long Tropfen2 = 300;     //LED Gelb
unsigned long Warte1 = 160;
unsigned long previousMillis = 0; 
  
const long TropfenA = Tropfen1;   
const long TropfenB = Tropfen2;
const long WarteA = Warte1;


void setup() 
  {
  pinMode(VENTIL_PIN, OUTPUT);
  pinMode(SCHALTER_PIN, INPUT);     //Pullup Widerstaende auf der Platine
  } 
 
void loop() 
{
  if(digitalRead(SCHALTER_PIN) == HIGH)
    {
      tropfen(TropfenA);
      unsigned long tropfenStart = millis();
      if (millis() - tropfenStart >= WarteA) {
      tropfen(TropfenB);
      }
    }
}
 
void tropfen(int ms) {
  digitalWrite(VENTIL_PIN, HIGH);
  unsigned long tropfDauer = millis();
  if (millis()- tropfDauer >= tropfen) {
    digitalWrite(VENTIL_PIN, LOW);
  }
}