Ventil schaltet ohne Arduino

Hallo miteinander,

ich habe mir eine Hardware zusammen gebaut um Ventile ansteuern zu können.
Ich mache damit Tropfen bildet bzw. ich versuche es :-).

mir ist aufgefallen das wenn ich meine Ventile an der Schaltung habe und das Arduino an den PC Stecke, die Firmware schon mal auf dem Arduino war und noch keinen Start ausgelöst habe kommt schalten alle Ventile Tuch :-(.

Warum schalten meine Ventile denn Tuch?
habe ich in meiner Schaltung was vergessen?

Bildschirmfoto 2013-11-06 um 13.37.58.png

Schaltung ist ok. Evtl. Sketch der reinfunkt?

OK, das ist schon mal gut.

das ist das Sketch

#include "TropfenBox.h"

String commandString;
boolean commandStringReceived = false;  
TropfenBox tropfenBox;

int startPin = 2;

void setup() 
{
  // put your setup code here, to run once:
  Serial.begin(9600);
}

void loop() 
{
  if(commandStringReceived)
  {
    commandStringReceived = false;    
    tropfenBox.ExecuteCommand(commandString); 
    commandString = "";
  }
  
  if(digitalRead(startPin)== HIGH)
  {
    tropfenBox.Run();
  }
}
void serialEvent() 
{
  while (Serial.available()) 
  {
    char inChar = (char)Serial.read(); 
     
    if (inChar == '\n' || inChar == '\r')   
    {  
      commandStringReceived = true;
    }
    else
    {
       commandString += inChar; 
    }
  }
}

und "TropfenBox.h"

#include <Arduino.h> 

#define NAME        "Tropfen Box"
#define FIRMWARE    "1.2.0"
#define ENDLN       "\n"
#define MAXELEMENTS 201
#define STARTPIN    2

class TropfenBox
{
  struct Parameter
  {
    int pin;
    long vorlaufzeit; 
    long dauer;

    Parameter(){
    }
    Parameter(int pin, long vorlaufzeit, long dauer) : 
    pin(pin), vorlaufzeit(vorlaufzeit), dauer(dauer) {
    }
  };    

  struct Step
  {
    int pin;
    long time; 
    boolean state;

    Step(){
    }
    Step(int pin, long time, boolean state) : 
    pin(pin), time(time), state(state) {
    }
  };    

private: 
  Parameter configuration[MAXELEMENTS];
private: 
  Step steps[MAXELEMENTS * 2];
private: 
  int counter;
private: 
  int stepCounter;

public: 
  TropfenBox(): 
  counter(0), stepCounter(0)
  {
    Init();
  }

public: 
  void ExecuteCommand(String command)
  { 
    String response = "";
    int commaPosition;
    int argCounter = 0;
    int maxArgs = 10;
    String args[maxArgs];

    do
    {
      if(argCounter > maxArgs) 
      {
        Serial.println("NOK,Too many arguments");
        return;  
      }

      commaPosition = command.indexOf(',');
      if(commaPosition != -1)
      {
        args[argCounter] = command.substring(0,commaPosition);
        command = command.substring(commaPosition+1, command.length());
        argCounter++;
      }
      else
      {
        if(command.length() > 0)
        {
          args[argCounter] = command;
          argCounter++;  
        }
      }
    }
    while(commaPosition >= 0);

    if(argCounter > 0)
    {
      command =  args[0];
    }

    if(command == "get_name")
    {
      response = "OK," + GetName()+ ENDLN;
    }
    else if(command == "get_firmware")
    {
      response = "OK," + GetFirmware() + ENDLN;
    }
    else if(command == "configure")      //Format:configure,pin,vorlaufzeit,dauer
    {
      int pin = args[1].toInt();
                                         // Nötig?   
      if (pin > STARTPIN && pin < 21)    // && Zeile > -1 && Zeile < 200) 
      {
        InsertParameter(pin, args[2].toInt() * 1000, args[3].toInt() * 1000);
        response = "OK\n";
      }
      else
      {
        response = "NOK, Pin number out of range[2..20]\n";
      }
    }
    else if(command == "print_config")
    {
      PrintConfig();
      response = "OK\n";
    }
    else if(command == "print_steps")
    {      
      PrintSteps();
      response = "OK\n";
    }
    else if(command == "run")
    {
      Run();
      response = response = "OK\n";
    }
    else
    {
      response = "NOK, Unknown command: " + command + ENDLN;
    }

    Serial.println(response);
  }

public: 
  void Run()
  {
    ConfigureOutputPins();

    unsigned long looptime;    
    unsigned long starttime = micros();

    for(int i = 0; i < stepCounter ; i++)
    {
      while ((looptime = micros() - starttime) < steps[i].time);
      digitalWrite(steps[i].pin, steps[i].state);
    }
  }

public: 
  String GetFirmware()
  {
    return FIRMWARE;
  }

public: 
  String GetName()
  {
    return NAME;
  }

private: 
  void Init()
  {
    InsertParameter(21,   10000, 1000000);
    InsertParameter(20,  500000,  400000);
    InsertParameter(19, 1300000,   30000);
  }
private: 
  void PrintConfig()
  {
    String line;    
    for(int i = 0; i < counter; i++)
    {
      line = String(configuration[i].pin, DEC) + "\t";  
      line += String(configuration[i].vorlaufzeit, DEC) + "\t";
      line += String(configuration[i].dauer, DEC) + ENDLN;
      Serial.println(line); 
    }
  }

private: 
  void PrintSteps()
  { 
    String line, flag;       
    for(int i = 0; i < stepCounter; i++)
    {
      if(steps[i].state)
        flag = "true";
      else
        flag = "false";

      line = String(steps[i].pin, DEC) + "\t";  
      line += String(steps[i].time, DEC) + "\t";
      line += flag + ENDLN;
      Serial.println(line); 
    }
  }

  // Neue Konfiguration in das Array einfügen 
private: 
  void InsertParameter(int pin, long vorlaufzeit, long dauer)
  {
    configuration[counter] = Parameter(pin, vorlaufzeit, dauer);

    Step start = Step(pin, vorlaufzeit, true);
    Step stop = Step(pin, vorlaufzeit + dauer, false);

    boolean flag = false; 

    // Zwei Elemente in Steps Liste einsortieren
    if(stepCounter > 1)
    {      
      for(int i = stepCounter -1; i >= 0; i--)
      {
        if(stop.time > steps[i].time)
        {
          steps[i+1] = stop;
          stepCounter++;
          break;          
        }
        else
        {
          steps[i+1] = steps[i];
        }
      }

      for(int i = stepCounter -1; i >= 0; i--)
      { 
        if(start.time > steps[i].time)
        {
          steps[i+1] = start;
          stepCounter++;
          break;          
        }
        else
        {
          steps[i+1] = steps[i];
        }
      }
    }  
    else
    {      
      steps[0] = start;
      steps[1] = stop;
      stepCounter = 2;
    }

    counter++;
  } 

private: 
  void ConfigureOutputPins()
  {
    for(int i = 0; i < counter; i++)
    {
      pinMode(configuration[i].pin, OUTPUT);
    }
  }
};

Dir wurde doch gezeigt wie man von Serial in ein Array einliest. Und es hat funktioniert. Wieso bist du jetzt wieder bei dem ineffizienten, speicherfressenden und unflexiblem String Klassen Müll? Benutzte wenigstens reserve() wenn es denn unbedingt sein muss, damit da nicht ständig Speicher freigegeben und angelegt wird:

Aber generell sollte man auf die String Klasse verzichten und soweit warst du schon.

Und selbst dann hast du noch sowas drin, womit man den Speicher regelrecht vergewaltigt:

    for(int i = 0; i < counter; i++)
    {
      line = String(configuration[i].pin, DEC) + "\t";  
      line += String(configuration[i].vorlaufzeit, DEC) + "\t";
      line += String(configuration[i].dauer, DEC) + ENDLN;
      Serial.println(line); 
    }

Das kann man schön mit einem einzigen Puffer Array und sprintf erledigen, ohne dass ständig auf dem Heap herumgepfuscht wird. Überhaupt ist es Serial vollkommen egal ob das alles in einem String steht oder man mehrmals Serial aufruft. Es ist da zig mal besser einfach in paar Serial hintereinander zu schreiben. Hierfür String Objekte zu verwenden ist Irrsinn.

Das mit deiner eigenen Klasse ist völlig falsch. In den Header gehören nur die Deklarationen der Methoden und die Variablen. Nicht die Implementierung! (es sei denn bei inline Funktionen) Die Implementierung kommt in die .cpp Datei. Außerdem wird nicht für jede Methode "private" oder "public" geschrieben wie z.B. in Java oder C#.

Siehe z.B.:
http://abraham.informatik.fh-lausitz.de/profs/robel/faq/simpleCppProg.html

Wie du da siehst stehen im Header nur zwei Sektionen mit public und private. Und die Methoden haben da lediglich den Namen. Aber keinen Rumpf.

Methoden-Namen groß zu schreiben ist zwar nicht falsch, aber wird in C++ gewöhnlich nicht gemacht. Nur der Konstruktor wird groß geschrieben, da er den gleichen Namen wie die Klasse hat.

Es ist aber auch unsinnig, das in eine eigene Klasse auszulagern. Was sich vielleicht anbietet sind mehrere .ino Dateien/Tabs. Das geht in der Arduino IDE relativ problemlos. Damit kann man den Sketch in verschiedene Dateien aufteilen und die IDE kompiliert das dann zusammen.

Der Starttaster hat einen Pulldown-Widerstand??
Grüße Uwe

Sketch:
ja die Firmware sah änderst aus als ich sie mit euch zusammen gemacht habe,
da ich jedoch das mit dem Programm (WIN) nicht so richtig hin bekommen habe,
habe ich einen Bekannten gefragt ob er mir helfen kann, er wollte eine eigene
Firmware schreiben.

ich habe die Anregungen weitergeleitet und warte auf eine Antwort.

Starttaster:
ja das hat er / Hofe ich zumindest
siehe Bild.

Taster_.png

So:
http://www.honorlevel.com/data/arduino/images/pullDownResistor.jpg

Und Pullups/Pulldowns haben i.d.R. mindestens 10k

Muecke:
Starttaster:
ja das hat er / Hofe ich zumindest
siehe Bild.


Ich hoffe Du hast nur falsch gezeichnet, weil laut Schaltbild ist der Arduino Eingang permanent auf 5V gesetzt ist und damit dauernd HIGH ist.
Der Arduino Eingang muß zwischen Widerstand und Taster angeschlossen sein und wie Serenifly richtig sagt sollte er größer sein etwas um 10kOhm geht gut.

Grüße Uwe

Ihr habt recht ich habe auf der Zeichnung etwas Durcheinander gebracht :frowning:

habe das alles noch mal zusammen gefast, wollte ich eh mal machen das alle Schaltungen die ich verbaut habe auf einem Blatt sind :slight_smile:

Der Vorwiderstand des Optokoplers ist viel zu groß. Nimm einen 470 Ohm Widerstand.
Der MOSFET muß mit einem Arduino-Ausgang angesteuert werden aber nicht mit einem Eingang aber das wird sicher ein Fehler in der Zeichnung sein.
Grüße Uwe

Ups. da hat sich ein Kopierfehler eingeschlichen.
Den Widerstand werde ich gleich mal auswechseln.

Und die Freilaufdiode ist falsch herum. Die gehört in Sperrrichtung.

Tip: Den Strich im 90° Winkel verwendet man eigentlich nur für Masse. Für Anschlüsse gibt es Kringel oder man lässt die Leitung einfach "offen" enden.

Serenifly:
Und die Freilaufdiode ... Die gehört in Sperrrichtung.

Ist sie das nicht? Das Ventil ist an +12V und am MOSFET angeschlossen.

Grüße Uwe

ARG! Ich Idiot. Da hat mich genau das mit dem Strich verwirrt was ich unten gesagt habe :blush:

uh ich dachte schon ich habe einen Kurzen eingebaut, hätte mich gewundert denn die Schaltung tut ja schon :slight_smile:

ich habe das mit den 90° Strichen und Kringeln ausgebessert.

Ok meine Hardware sind wir nun durch gegangen und sind zum Entschluß gekommen das es an dieser nicht liegt.

Ob ich nun die Firmware aus dem Forum oder die von meinem Kumpel nehme macht keinen unterschied ich bekomme die selben Resultate :-(.

was mache ich und was Passiert.

ich habe die Hardware um 9 Ventile vergrößert.
1 Blitz und einen Taster Eingang.

siht dann so aus: (Bild)

  1. ich mache mein Netzteil an.

  2. ich Stecke das Arduino an den PC

  3. ich Spiele die Firmware auf das Arduino
    JETZT schalten alle angeschlossenen Ventile durch bis auf Ventil 1

  4. ich Stecke eins der Ventile auf einen der Freien Ausgänge, das umgesteckte Ventil bleibt geschlossen.

Wenn ich die Firmware laufen lasse werden alle Ventile geschlossen die ich in der Config stehen habe, die anderen bleiben Offen :frowning:

ich bekomme sie nur geschlossen in dem ich Ihren Pin mit in der Config aufrufe.

Woher kommt das verhalten?

ich habe gerade auch getestet es ist egal ob das Netzteil zuerst angeschaltet wird und dann das Arduino oder umgekehrt.

jedoch Öffnen die Ventile nicht wenn das Arduino nicht angeschlossen ist, sprich wenn das Netzteil an ist und das Arduino aus sind die Ventile immer zu !

Hat jemand die woher das kommt?

warum reagieren die Ventile nur dann wenn sie von beging an angesteckt sind?
wenn ich sie später anstecke kommt das Problem nicht.

ich habe Test halber die Firmware durch ein mini Programm ersetzt:
hier habe ich die Probleme nicht, egal ob ich das Ventil in code aufrufe oder nicht.
es schaltet beim Hochfahren vom Arduino kurz alle Ventile auf die schlissen sich dann aber gleich wider.

so jetzt ist die Frage wo kommt der Fehler her und warum?

das ist der Test Code denn ich zum Schluß zum Testen benutzt habe.

int led = 13;
int startPin = 2;
int Ventil_1 = 21;
int Ventil_2 = 20;
int Ventil_3 = 19;

void setup() {                
  pinMode(led, OUTPUT);  

  pinMode(Ventil_1, OUTPUT);  
  pinMode(Ventil_2, OUTPUT);  
//  pinMode(Ventil_3, OUTPUT);    

  pinMode(startPin, INPUT);
}

void loop() 
{
   if(digitalRead(startPin)== HIGH)
    { 
      digitalWrite(led, HIGH);
      digitalWrite(Ventil_1, HIGH);
         delay(1000);
      digitalWrite(led, LOW);
      digitalWrite(Ventil_1, LOW);
         delay(1000);
    }
}