Sensoren hintereinander auslesen ohne Delay

Hallo,

normalerweise finde ich im Forum immer etwas was mir weiterhilft aber nun stehe ich völlig auf dem Schlauch. Daher wende ich mich mal an euch. Vorne weg sollte ich noch sagen, dass ich im Grunde völlig fachfremd bin und immer nach dem Trial and Error Prinzip programmiere.

Worum es geht:

Ich möchte fünf Feuchtigkeitssensoren hintereinander auslesen. Das ganze soll dann in ein größeres Projekt einfließen.

Zum auslesen soll der Strom eingeschaltet und nach 500ms die Werte ausgelesen sowie der Strom wieder ausgeschaltet werden. Danach soll der nächste Sensor angesprochen werden. Die 500ms ergeben sich daraus, dass bei einem kürzeren Stromfluss die Werte ungenau sind. Hintereinander auslesen ist mir daher wichtig, da ich das Ganze später über so wenig Leitungen wie möglich verbinden möchte.

Mit verschiedenen Anleitungen und Delay habe ich die Sache zum laufen bekommen aber da Delay in einem solchen Code nichts zu suchen hat, würde ich das Problem gerne mit Millis lösen. Aber daran scheitert es. In meiner Schleife oder davor Millis einzubauen führt nur dazu, dass alle Sensoren gleichzeitig ausgelesen werden. Was auch irgendwie logisch erscheint.

Könnte sich jemand erbarmen und mir einen Tipp geben? Es wird sicher was ganz simples sein.

Schon einmal vielen Dank im Voraus.

Anbei der derzeit funktionierende Code mit Delay.

 unsigned long current_millis = 0;
 unsigned long previous_millis = 0;
 unsigned long FS_intervall = 10000;
 int FS_Schleifenzaehler = 0;

 int saveDR[5];
 int saveAR[5];

// Feuchtigkeitssensor 1
 #define FS_1_P  22
 #define FS_1_DR  24
 #define FS_1_AR  A14

// Feuchtigkeitssensor 2
 #define FS_2_P  23
 #define FS_2_DR  25
 #define FS_2_AR  A15

// Feuchtigkeitssensor 3
 #define FS_3_P  24
 #define FS_3_DR  26
 #define FS_3_AR  A4

// Feuchtigkeitssensor 4
 #define FS_4_P  27
 #define FS_4_DR  29
 #define FS_4_AR  A5

// Feuchtigkeitssensor 5
 #define FS_5_P  28
 #define FS_5_DR  30
 #define FS_5_AR  A6
 
void setup() {

Serial.begin(9600);

// Feuchtigkeitssensor 1
 pinMode (FS_1_P, OUTPUT);
 pinMode (FS_1_DR, INPUT);
 pinMode (FS_1_AR, INPUT);
 
// Feuchtigkeitssensor 2
 pinMode (FS_2_P, OUTPUT);
 pinMode (FS_2_DR, INPUT);
 pinMode (FS_2_AR, INPUT);

// Feuchtigkeitssensor 3
 pinMode (FS_3_P, OUTPUT);
 pinMode (FS_3_DR, INPUT);
 pinMode (FS_3_AR, INPUT);
 
 // Feuchtigkeitssensor 4
 pinMode (FS_4_P, OUTPUT);
 pinMode (FS_4_DR, INPUT);
 pinMode (FS_4_AR, INPUT);

 // Feuchtigkeitssensor 5
 pinMode (FS_5_P, OUTPUT);
 pinMode (FS_5_DR, INPUT);
 pinMode (FS_5_AR, INPUT);
}

void loop() {
  
  current_millis = millis();

  int FS_P[] = {FS_1_P, FS_2_P, FS_3_P, FS_4_P, FS_5_P};
  int FS_DR[] = {FS_1_DR, FS_2_DR, FS_3_DR, FS_4_DR, FS_5_DR};
  int FS_AR[] = {FS_1_AR, FS_2_AR, FS_3_AR, FS_4_AR, FS_5_AR};

  if (current_millis - previous_millis >= FS_intervall) { // Wenn Intervall überschritten, soll gemessen werden.

    for (int i = 0; i < 5; i++) {
        digitalWrite(FS_P[i], HIGH);       // Strom für den Sensor an
        delay(500); 
        
        saveDR[i] = digitalRead(FS_DR[i]); //legt den Wert 1 oder 0 ins Array
        saveAR[i] = analogRead(FS_AR[i]);  // legt den Wert 0 bis 1023 ins Array
        digitalWrite(FS_P[i], LOW);        // Strom für den Sensor aus
        FS_Schleifenzaehler++;
    }

    if (FS_Schleifenzaehler >= 5) {       // Nachdem alle 5 Sensoren ausgelesen wurden sollen die Werte ausgegeben werden. 
        FS_Schleifenzaehler = 0;          // Nur in der Testphase wichtig.
        previous_millis = current_millis;
            
        for (int i = 0; i < 5; i++) {
        Serial.println(saveDR[i]);
        Serial.println(saveAR[i]);  
        }
    }
  }
}

Du könntest auch schön mit Objekten arbeiten, das würde deinen Kode übersichtlicher und flexibler machen.

const uint32_t FS_intervall = 10000;
const uint32_t powerTime = 500;
const uint8_t noSensor = 0xFF;

class FSensor {
    const uint8_t powerPin;
    const uint8_t digitalPin;
    const uint8_t analogPin;
    uint32_t lastAction;
  public:
    uint8_t digitalValue;
    uint16_t analogValue;
    FSensor(const uint8_t pPin, const uint8_t dPin, const uint8_t aPin) : powerPin(pPin), digitalPin(dPin), analogPin(aPin) {}
    void begin() {
      pinMode (powerPin, OUTPUT);
    }
    void print() {
      Serial.print(F("D "));
      Serial.print(digitalValue);
      Serial.print(F(", A "));
      Serial.println(analogValue);
    }
    void start() {
      lastAction = millis();
      digitalWrite(powerPin, HIGH);
    }
    bool process() {
      if (millis() - lastAction >= powerTime) {
        digitalValue = digitalRead(digitalPin);
        analogValue = analogRead(analogPin);
        digitalWrite(powerPin, LOW);
        return true;
      }
      return false;
    }
} sensors[] = {{22, 24, A14}, {23, 25, A15}, {24, 26, A4}, {27, 29, A5}, {28, 30, A6}};

const uint8_t numberOfSensors = sizeof(sensors) / sizeof(sensors[0]);

void setup() {
  Serial.begin(250000);
  for (auto sensor : sensors) {
    sensor.begin();
  }
}

void loop() {
  static uint32_t previous_millis;
  static uint8_t aktuellerSensor = noSensor;
  uint32_t current_millis = millis();

  if (current_millis - previous_millis >= FS_intervall) {
    previous_millis = current_millis;
    aktuellerSensor = 0;
    sensors[aktuellerSensor].start();
  }
  if (aktuellerSensor != noSensor) {              // irgend ein Sensor?
    if (sensors[aktuellerSensor].process()) {     // ist der fertig geworden?
      if (++aktuellerSensor >= numberOfSensors) { // war es der letzte?
        aktuellerSensor = noSensor;
        for (uint8_t i = 0; i < numberOfSensors; i++) {
          Serial.print(F("Sensor "));
          Serial.print(i);
          Serial.print(F(": "));
          sensors[i].print();
        }
      } else {
        sensors[aktuellerSensor].start();
      }
    }
  }
}

Ja, Whanddall, das würde es ganz bestimmt. Lies dir aber doch nochmal den Eingangspost durch und schließe dann auf den Kenntnissstand des TE.

Vielleicht bringt ihn das ja auf die Idee sein Wissen zu vergrößern,
Trial und Error ist IMHO keine Entwicklungsstrategie.

Hallo,

vielen Dank für eure Tipps. Für was neues bin ich immer offen. Man möchte schließlich seinen Horizont stetig erweitern und Trial und Error ist nun wirklich keine Methode.

Ich werde mich demnächst wieder an die Sache heran setzen, denn gestern hat sich der Motor von meinem Wagen verabschiedet und das hat erst einmal Vorrang.

Rückmeldung folgt.

ElEspanol:
Ja, Whanddall, das würde es ganz bestimmt. Lies dir aber doch nochmal den Eingangspost durch und schließe dann auf den Kenntnissstand des TE.

Hmm...
Das liest sich, wie die Aufforderung, die bessere Lösung verbergen zu sollen.
Diese Tendenz kann ich nicht unterstützen.
Ganz im Gegenteil

Eine Antwort die nah an der Frage bleibt, hat den großen Vorteil, evtl. verstanden zu werden.
Komplett andere Ansätze haben natürlich auch ihren Reiz.

Was nun besser ist, kann auch von Leser zu Leser unterschiedlich sein.

Hallo,

ich möchte noch mal die Frage nach dem Sinn für das Abschalten der Stromversorgung für die Sensoren stellen. Die Stromaufnahme der Sensoren kann doch nicht so groß sein. Den von Dir angegebene Grund um damit die Verkabelung einfacher zu machen kann ich nicht sehen. Was hast Du denn vor wenn die 5 Sensoren alle einmal gemessen haben, soll dann sofort wieder mit Sensor 1 angefangen werden. ?

Heinz

Was nun besser ist, kann auch von Leser zu Leser unterschiedlich sein.

Hmmm....

Der Mensch an sich, kann Informationen, welche ihn überfordern, ausblenden.
Der Mensch kann was neues sehen, und sich dafür interessieren, sich das Verständnis erarbeiten.

Schaue ich mir die Frage an, dann sehe ich dass der TO mit seinem delay() nicht weiter kommt.
Er was neues wissen will.

Dann kann man ihm doch nicht so kommen:

Ich weiß wie es VIEL besser geht, aber ich sage es dir nicht, weil du zu blöd dafür bist.
Und ihr anderen habt euch auch gefälligst zurückzuhalten mit der Information

ich möchte noch mal die Frage nach dem Sinn für das Abschalten der Stromversorgung für die Sensoren stellen.

Hallo,

bei den Sensoren handelt es sich um Feuchtigkeitssensoren für die Erde. Es sind leider keine kapazitiven Sensoren, sodass sie bei ständigem Stromfluss schneller korrodieren. Daher werden diese später alle 15min unter Spannung gesetzt. Dabei ist mir auch schon aufgefallen, dass die Messungen ungenau werden, wenn alle Sensoren gleichzeitig messen. Daher auch der Ansatz Sie hintereinander einzuschalten.

Mein zweiter Gedanke ist auch, diesen Code später für die Ventilsteuerung zu verwenden um auch hier dann nacheinander zu bewässern.

Mfg

combie:
Dann kann man ihm doch nicht so kommen:

Ich weiß wie es VIEL besser geht, aber ich sage es dir nicht, weil du zu blöd dafür bist.
Und ihr anderen habt euch auch gefälligst zurückzuhalten mit der Information

ich bezog das eher auf den objektorientierten Lösungsansatz mit Klassen. Glaub mir, das dauert, bis man das drauf hat oder wenigstens so weit durch steigt, es nur auch zu verstehen.
Eine Lösung mit einer state machine und arrays, evtl. noch structs ist inho für Beginner wesentlich einfacher zu verstehen und zu erlernen.

ich bezog das eher auf den objektorientierten Lösungsansatz mit Klassen.

Das war klar.

Glaub mir, das dauert, bis man das drauf hat oder wenigstens so weit durch steigt, es nur auch zu verstehen.

Dass du damit Schwierigkeiten hast, oder hattest, ist möglich.
Das glaube ich dir.
Aber deine Probleme auf andere zu projizieren, ist mindestens ungerecht.

deine Probleme auf andere zu projizieren, ist mindestens ungerecht

Nein. Das kann man auch Empathie nennen.

In der Richtung fehlt dir zwar einiges, lieber Combie, aber das stört mich meist nicht. :wink:

Das kann man auch Empathie nennen.

Ich nenne es ein Urteil über eine Person, welche man nicht kennt.
Ein auf eigenen Erfahrungen beruhendes Vorurteil.

In der Richtung fehlt dir zwar einiges, lieber Combie,

Mag sein, ....

Anders betrachtet:
Arduino ist C++
C++ ist OOP
In Arduino steckt viel OOP

Welchen Sinn mag es haben Arduino Anfänger von der OOP fern halten zu wollen?
Im Sinne, oder zum Vorteil, des lernen wollenden, kann es nicht sein.


Denkt man das konsequent weiter, dann darf man hier im Forum niemandem etwas erzählen/vorschlagen, von dem man glaubt/vermutet dass er/sei/es dieses noch nicht kennt.
Ich halte das für das recht exakte Gegenteil von "beim lernen unterstützen".
Und darum werde ich mich mit allem was ich habe, gegen einen solchen Zensurversuch stemmen.

Hallo,

Die obigen Beiträge mögen ja richtig sein, bringen Dich aber leider keinen Millimeter weiter. Eigendlich ist das eine schöne Aufgabe für eine Schrittkette bzw. Ablaufsteuerung. Sketch Gerüste für eine State-Mashine gibt auch reichlich, sowas könnte man also auch nehmen. Kannst Du Dir ja auch mal ansehen und eventuell verwenden.

Dein Ansatz mit einem Array zu arbeiten war ja schon mal gut. Deine Deklaration der Pin´s fand ich allerdings etwas umständlich.

Ich hab da mal einen Ansatz gemacht den Du noch etwas anpasen musst. Ich hab nur drei Messstellen verwendet und das mit drei LED getestet. Zusätzlich gibts einen Schritt für die Pausenzeit.

Heinz

/* Hardware UNO
 *  
*/
byte Messstelle = 0;// index aktuelle Messstelle
uint32_t altzeit;// Hilfsgrösse für Zeiten

const byte led[] = {2, 3, 4}; // Pins für die Ausgänge;
const byte D_pin[] = {7, 8, 9}; // Pin für Digital Input;
const int A_pin[] = {A0, A1, A2}; // Pins für die Analog Messwerte

int messwert[3];// Array für die Messwerte
byte digInput[3];// Array für die Digital Eingänge des Sensors

void setup() {
  // put your setup code here, to run once:
  for ( byte i = 0; i <= 2; i++ ) { // pin´s setzen
    pinMode(led[i], OUTPUT);
    pinMode(D_pin[i],INPUT_PULLUP);
  }
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  messen();
}


void messen() {
  if (Messstelle >2) { // Pausenzeit zwischen dem Messzyklus
    if (millis() - altzeit > 10000) { // Wenn Pause abgelaufen
      altzeit = millis();
      Messstelle = 0;   // neu anfangen
    }
    return; // Wenn Pause dann nix mehr machen
  }
  if (millis() - altzeit >= 2000) { // Wartezeit ist abgelaufen
    altzeit = millis();
    // jetzt messen
    digInput[Messstelle] = digitalRead(D_pin[Messstelle]);
    messwert[Messstelle] = analogRead(A_pin[Messstelle]);

    Serial.print("Messstelle "); Serial.print(Messstelle);
    Serial.print("\t"); Serial.print(messwert[Messstelle]);
    Serial.print("\t");Serial.println(digInput[Messstelle]);
    digitalWrite(led[Messstelle], LOW);// Ausgang abschalten

    Messstelle++;   // nexte Messtelle
  }
  else {
    digitalWrite(led[Messstelle], HIGH); // Ausgang einschalten
  }

}

Nachtrag Sketch geändert nach Hinweis:

int messwert[2];
.
.
if (Messstelle >= 3)
.
.
messwert[Messstelle]

Böse Falle

ElEspanol:

int messwert[2];

.
.
if (Messstelle >= 3)
.
.
messwert[Messstelle]




Böse Falle

Hallo,

stimmt, danke für den Hinweis, besser das Array eins grösser machen und die Abfrage auf

if (Messstelle >2)

ändern , obwohl da eigendlich nichts passieren kann. Wenn Messstelle den Wert >=3 hat trifft ja der Fall return ein bis die Pause angelaufen ist und dann wird Messstelle 0 gesetzt. Er kommt also nie in den unteren Teil rein.

Heinz

int messwerte[2];
const byte anzmesswerte=sizeof(messwerte)/sizeof(messwerte[0]);
...
if (Messstelle>=anzmesswerte){
...
... oder ...
Messstelle=(Messstelle+1)%anzmesswerte;  //begrenzt auf <abzmesswerte

Dann ist's auch egal, wenn Du oben zwölf Elemente erstellst - die Abfrage passt dann trotzdem noch.

MfG

Böse Falle.

Das Array hat 2 Elemente
Bei >2 hast du schon über das Array hinaus geschrieben, nämlich auf 0,1 und 2.