Frequenz messen

So hab jetzt die Funktion Wertstabil() auch noch angeglichen und beim seriellen Monitor die Spalte "Sensornummer" ergänzt, um zu sehen, welcher Sensor gerade ausgelesen wird.
Jetzt gibt es nur ein Problem. Irgendwo steckt noch ein Fehler drin. Ich hab zum Testen nämlich nur einen Sensor mal drangehängt. Der Kanal mit dem Sensor müsste ja dann einen anderen Wert haben, als die restlichen 9. Jedoch scheint mir, dass es mir immer nur einen Sensorwert anzeigt.

Zeit[sek] prevVal currVal Delta Sensornummer
5 0 109 109 0
10 0 194 194 1
15 0 261 261 2
20 0 313 313 3
25 0 352 352 4
30 0 383 383 5
35 0 408 408 6
40 0 427 427 7
45 0 440 440 8
50 0 467 467 9
55 109 474 365 0

...

155 506 508 2 0 gueltiger Sensorwert = 508

160 504 506 2 1 gueltiger Sensorwert = 506

165 503 505 2 2 gueltiger Sensorwert = 505

170 502 504 2 3 gueltiger Sensorwert = 504

175 500 503 3 4 gueltiger Sensorwert = 503

180 498 501 3 5 gueltiger Sensorwert = 501

185 497 500 3 6 gueltiger Sensorwert = 500

190 495 499 4 7 gueltiger Sensorwert = 499

195 494 497 3 8 gueltiger Sensorwert = 497

200 509 513 4 9 gueltiger Sensorwert = 513

205 508 511 3 0 gueltiger Sensorwert = 511

...

Berühre ich jetzt den Sensor, verschwinden die gültigen Sensorwerte und alle pegel sich dann auf den neuen Wert ein...

Eigentlich könnte man ja jetzt auch den Abstand der Messungen verkürzen, da ja erst alle Sensoren ausgelesen werden, bevor der aktuelle Wert erneut ausgelesen wird. Setzte ich jetzt const int T_check_Sens_const auf 500 ms runter, müsste ich ja wieder 5sec zwischen den jeweiligen Sensormessungen haben, oder verrechne ich mich da?

hier noch mein abgeänderter Code:

// Definition der Pins
const int Pumpe = 42;                
const int Ventil_1 = 31;

//Mux control pins
const int s0 = 22;
const int s1 = 23;
const int s2 = 24;
const int s3 = 25;

//Mux in "SIG" pin
const int MuxAD = A0;                  // an welchem AD hängt der Ausgang des Mux

// Definition der globalen Variablen
const int AnzahlSensoren = 10;       // Wie viele Sensoren sind am System angeschlossen
  
  int muxChannel (byte _ch){
    PORTA &= 0xF0;
    PORTA |= _ch;
  }
int currVal[AnzahlSensoren];           // globale Variable für den aktuellen gefilterten AD-Wert 
int Sensorwert[AnzahlSensoren];                        // globale Variable für den aktuellen Sensorwert 

// Definition der globalen Konstanten
  const int SensUG = 150;              // untere Fehlergrenze für Sensorwert
  const int SensOG = 800;              // obere Fehlergrenze für Sensorwert
  const int T_check_Sens_const = 5000; // Abstand für Prüfung ob Sensorwert konstant
  const int Sensorgap = 5;             // Fenster für Kriterium Sensor ko
  
 
void setup(){
  Serial.begin(115200);  
  Serial.print("Zeit[sek] \t");  		// Drucken des Spaltenkopfes
  Serial.print("prevVal \t");  
  Serial.print("currVal \t");
  Serial.print("Delta \t");
  Serial.print("Sensornummer \t");
  
  pinMode(s0, OUTPUT); 
  pinMode(s1, OUTPUT); 
  pinMode(s2, OUTPUT); 
  pinMode(s3, OUTPUT); 

  digitalWrite(s0, LOW);
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);
}

void loop(){     
  readsensor();
  Wertstabil();  
}// End loop()



/*************************************************************************************************
**  readsensor											**
**************************************************************************************************
** liesst alle 100ms einen AD-Wert von SPin.							**
** Dieser Wert wird gefiltert (Tiefpaß 1. Ordnung) und in currVal	gespeichert		**
**  												**
**  Input:  SPin										**
**  Output:   Filtwert										**
**  genutzte Globale Variablen: currVal								**
**************************************************************************************************/
void readsensor(){
  static unsigned long lastread = 0;
  static float FiltWert[AnzahlSensoren];
  static int _SNr;                        // Nummer des aktuell auszuwertenden Sensors
  const float FilterFaktor = 20;  
  
  
  if (millis()-lastread < 100) return;    // alle 100ms einen Wert holen.
  lastread = millis();                    // Zeit des letzten Wertes merken
  int AktWert = analogRead(MuxAD);
  if (AktWert < SensUG && AktWert > SensOG){    // prüfen ob AD-Wert gültig.
    currVal[_SNr] = -99;                        // fals nicht, Fehlercode -99 zurückgeben
    return;
  }
  FiltWert[_SNr] = ((FiltWert[_SNr] * FilterFaktor) + AktWert) / (FilterFaktor + 1);  
  currVal[_SNr] = int(FiltWert[_SNr]);
  if(++_SNr >= AnzahlSensoren) _SNr = 0;  // nächsten Sensor anwählen,
  muxChannel(_SNr);                       // und die Muxleitung neu setzen
} // End of readsensor


/*************************************************************************************************
** Wertstabil											**
**************************************************************************************************
** Prüft, ob der eingelesene Sensorwert hinreichend stabil ist.					**
**  												**
**  Input: nix											**
**  Output: nix											**
**  genutzte Globale Variablen: currVal, Sensorwert, Sensorwert_stabil				**
**************************************************************************************************/
void Wertstabil(){
  static unsigned long prevTime = 0;
  static int prevVal[AnzahlSensoren];
  static int _SNr;
    

  if(millis()- prevTime < T_check_Sens_const)return;     // prüfen, ob das nächste Prüffenster erreicht ist
  prevTime = millis();                                   // Zeit des letzten Prüfens merken
  int delta = abs(currVal[_SNr]-prevVal[_SNr]);    
  
// Ausgabe von Debug-Werten:
    Serial.println();
    Serial.print(millis()/1000);      
    Serial.print("\t");
    Serial.print(prevVal[_SNr]);      
    Serial.print("\t");
    Serial.print(currVal[_SNr]);
    Serial.print("\t");
    Serial.print(delta);
    Serial.print("\t");
    Serial.print(_SNr);
// Ende Ausgabe Debugwerte

  if( delta <= Sensorgap){                     // Wenn Änderung kleiner Gap, 
      Sensorwert[_SNr] = currVal[_SNr];        // als Sensorwert speichern
      Serial.print("    gueltiger Sensorwert = ");
      Serial.println(Sensorwert[_SNr]);
   }
   
   prevVal[_SNr] = currVal[_SNr];              // aktuelle Wert als letzten Wert merken.
   
   if(++_SNr >= AnzahlSensoren) _SNr = 0;      // nächsten Sensor anwählen,
   muxChannel(_SNr);                           // und die Muxleitungen neu setzen
}
 // End of wertstabil

Passen meine Adressleitungen so, oder muss ich es umdrehen (also s0 auf pin 25,...)??

Die niederwertigste Leitung muss an den niederwertigsten Pin. Pin 22 ist PA0. Also muss das S0 sein.

Hier ist übrigens ein besseres Pinout:
http://greentechhobby.com/images/Arduino/ArduinoMega.pdf

also hatte ich es richtig gemacht und der fehler muss wo anders liegen... hrm

Ob der Multiplexer geht, kannst du auch statisch testen. Einen Kanal fest schalten und dann den Ausgang auf dem Arduino auf eine LED oder den seriellen Monitor übertragen. Und den Eingang auf Masse oder 5V legen.

Ich vermute auch den Mux als ursache.

Probier doch mal einen Testsketch, in dem du von Hand die Mux-Kanäle durchschaltest und dir den AD-Wert anzeigen läßt.
So was, z.B.:

//Mux control pins
const int s0 = 22;
const int s1 = 23;
const int s2 = 24;
const int s3 = 25;

int Channel;

int muxChannel (byte _ch){
    PORTA &= 0xF0;
    PORTA |= _ch;
  }

void setup() {
  Serial.begin(115200); 
  
  pinMode(s0, OUTPUT); 
  pinMode(s1, OUTPUT); 
  pinMode(s2, OUTPUT); 
  pinMode(s3, OUTPUT); 

  digitalWrite(s0, LOW);
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);
}

void loop() {
  while (Serial.available() > 0) {
    Channel = Serial.parseInt(); 
    muxChannel(byte(Channel));
  }
  
  delay(100);
  int Wert = analogRead(A0);
  Serial.print("Kanal: ");
  Serial.print(Channel);
  Serial.print("\tPortA: ");
  Serial.print(PORTA);
  Serial.print("\tWert: ");
  Serial.println(Wert);
}

Hier kannst du über die Tastatur des PC den Kanal eingeben und in aller Ruhe messen, was wo passiert.

Bei dem Breakout Board:
http://www.exp-tech.de/Shields/Analog-Digital-MUX-Breakout-BOB-09056.html

Du hast hoffentlich EN auf Masse gelegt. Sonst geht das auch nicht

also mit meiner ersten Versuch, den Multiplexer in meine Schaltung zu integrieren hatte ich gerade Erfolg. Auch der drangehängte Sensor hat je nach Berührung die entsprechenden Werte geliefert.

Versuch es jetzt mal mit dem statisch schalten...

So wie es scheint liegt es nicht am Multiplexer. Alle Kanäle pendel Richtung 40 nur der Kanal mit mein Sensor zeigt einen Wert von 165 und reagiert bei Berührung.
Die anderen Känale reagieren auch nicht auf die Berührung vom Sensor und bleiben bei etwa 40. Aslo so wie es sein soll...

Beim Anpassen von Wertstabil() wollte ich eigentlich zuerst delta auch mit [_SNr] versehen. Habe aber dann bei der Kompilierung eine Fehlermeldung bekommen, wesewegen ich es gelassen habe. Liegt da der Fehler?

delta ist nur eine temporäre Variable. Das passt schon.

Aber ich bin ehrlich gesagt ratlos. :blush:
Ich kann den Code aber auch nur trocken durchgehen, weil mir die HW fehlt....

Könnte es sein, dass dein Tiefpass ein so grosses Tau hat, dass sich die Spannung garnicht ändert zwischen zwei Messungen?
Wie lange braucht die Spannung, nach MUX-wechsel, um abzusinken?
Setze doch mal die Zeit von readsensor() von 100ms auf 1000ms.

wie genau sieht deine Schaltung denn jetzt aus?

werde ich morgen gleich als erstes testen.

Zum Aufbau:

Ich habe eine Verteilerstation, in die alle 10 Sensoren eingesteckt werden können. Diese ist über ein mehrpoliges Kabel mit meiner Steuerbox verbunden. Genau gesagt geht jeder Signalausgang vom Sensor zu einem Kanal des Multiplexers. Der Signalausgang vom Multiplexer wiederum läuft über mein Tiefpass und dann zum analogen Pin A0, wo alles ausgelesen wird.

Die zeit bei readsensor() auf 1000ms zu setzen bringt auch nix. der Fehler muss irgendwo anders sein. Momentan ist mein erster Sensor noch nicht auf Kanal 0 sondern Kanal 1. aber das darf ja nix ausmachen. Kanal 0 müsste ja dann eine "leerauswertung" sein und Sensor 10 auf Kanal 10 wird halt nicht berücksichtigt.

muss ich bei readsensor() die Variable AktWert nicht noch mit [_SNr] versehen??? Oder passt noch etwas nicht bei der PORTA vergabe?

also mit meiner Testversion des Codes, der um die Funktion muxChannel erweitert wurde habe ich keine Probleme. Hier kann ich mit mux_Channel_() die Kanäle manuell ansteuern und auslesen. Auf die Weise funtkionieren die Sensoren einwandtfrei und reagieren sofort auf Berührung.

//Pinbelegung des Signaleingangs der Feuchtesensoren
//(alle Sensoren laufen über einen Multiplexer + Tiefpass, bevor sie am Pin A0 ausgelesen werden)
const int MuxAD = A0;
//Adressierpins des Multiplexers
const int s0 = 22;
const int s1 = 23;
const int s2 = 24;
const int s3 = 25;


//_________________________________________________________________________________________________________________________________
// ###################### Definition der globalen Variablen ######################

  int currVal;                          // globale Variable für den aktuellen gefilterten AD-Wert 
  int Sensorwert;                       // globale Variable für den aktuellen Sensorwert 

//_________________________________________________________________________________________________________________________________
// ###################### Definition der globalen Konstanten ######################

  const int SensUG = 150;              // untere Fehlergrenze für Sensorwert
  const int SensOG = 800;              // obere Fehlergrenze für Sensorwert
  const int Pflanze_trocken = 600;     // Wert, ab dem gegossen werden soll
  const int Pflanze_nass = 700;        // Wert, bis dem gegossen werden soll
  const int T_check_Sens_const = 5000; // Abstand für Prüfung ob Sensorwert konstant
  const int Sensorgap = 5;             // Fenster für Kriterium Sensor ko
  const int Bewaesserungsdauer = 5000; // Zeit, die gegossen werden soll (5sec)
  static unsigned long Bewaesserungspause = 7200000;  // Abstand zwischen Bewässerung (2h)

/*
____________________________________________________________________________________________________________________________________
####################################################################################################################################
##################################################################################################################################*/
//                                      
void setup(){
    
  Serial.begin(115200);                 // startet serielle Übertragung mit 115200 Baud
  Serial.print("Zeit[sek] \t");  	// Drucken des Spaltenkopfes
  Serial.print("prevVal \t");  
  Serial.print("currVal \t");
  Serial.println("Delta \t");
  
//_________________________________________________________________________________________________________________________________
// ###################### Deklaration der Pins (Eingang/Ausgang) ######################

  pinMode(MuxAD, INPUT);               //Sensoreingang
  
  pinMode(s0, OUTPUT);                 //Ausgang Adressleitung 0
  pinMode(s1, OUTPUT);                 //Ausgang Adressleitung 1
  pinMode(s2, OUTPUT);                 //Ausgang Adressleitung 2
  pinMode(s3, OUTPUT);                 //Ausgang Adressleitung 3
  
  digitalWrite(s0, LOW);               //setzt Status der 
  digitalWrite(s1, LOW);               //Adressleitungen standartmäßig 
  digitalWrite(s2, LOW);               //auf LOW
  digitalWrite(s3, LOW); 
     
}
// Ende void setup()


/*
____________________________________________________________________________________________________________________________________
####################################################################################################################################
##################################################################################################################################*/

void loop(){     
  readsensor(MuxAD);
  Wertstabil();
  /*Bewaessern();
  Manuelles_Giessen();
  Fensterkontrolle();
  Wasseralarm();
  Wasserstandskontrolle();*/
}// Ende void loop()



/*************************************************************************************************
**  readsensor											**
**************************************************************************************************
** liesst alle 100ms einen AD-Wert von SPin.							**
** Dieser Wert wird gefiltert (Tiefpaß 1. Ordnung) und in currVal	gespeichert		**
**  												**
**  Input:  SPin										**
**  Output:   Filtwert										**
**  genutzte Globale Variablen: currVal								**
**************************************************************************************************/
void readsensor(int SPin){
  muxChannel_3();
  static unsigned long lastread = 0;
  static float FiltWert;
  const float FilterFaktor = 20;  
  
  
  if (millis()-lastread < 100) return;   // alle 100ms einen Wert holen.
  lastread = millis();                   // Zeit des letzten Wertes merken
  int AktWert = analogRead(MuxAD);
  if (AktWert < SensUG && AktWert > SensOG){    // prüfen ob AD-Wert gültig.
    currVal = -99;                              // fals nicht, Fehlercode -99 zurückgeben
    return;
  }
  FiltWert = ((FiltWert * FilterFaktor) + AktWert) / (FilterFaktor + 1);  
  currVal = int(FiltWert);
} // End of readsensor


/*************************************************************************************************
** Wertstabil											**
**************************************************************************************************
** Prüft, ob der eingelesene Sensorwert hinreichend stabil ist.					**
**  												**
**  Input: nix											**
**  Output: nix											**
**  genutzte Globale Variablen: currVal, Sensorwert,             				**
**************************************************************************************************/
void Wertstabil(){
  static unsigned long prevTime = 0;
  static int prevVal;  

  if(millis()- prevTime < T_check_Sens_const)return;     // prüfen, ob das nächste Prüffenster erreicht ist
  prevTime = millis();                      // Zeit des letzten Prüfens merken
  int delta = abs(currVal-prevVal);    
  
// Ausgabe von Debug-Werten:
    Serial.println();
    Serial.print(millis()/1000);      
    Serial.print("\t");
    Serial.print(prevVal);      
    Serial.print("\t");
    Serial.print(currVal);
    Serial.print("\t");
    Serial.print(delta);
// Ende Ausgabe Debugwerte

  if( delta <= Sensorgap){  // Wenn Änderung kleiner Gap, 
      Sensorwert = currVal;            // als Sensorwert speichern.
      Serial.print("    gueltiger Sensorwert = ");
      Serial.println(Sensorwert);
   }
   
   prevVal = currVal;                     // aktuelle Wert als letzten Wert merken.
}
 // End of wertstabil
 
 int muxChannel_1(){
  digitalWrite(s0, HIGH);
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);
}

int muxChannel_2(){
  digitalWrite(s0, LOW);
  digitalWrite(s1, HIGH);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);
}
int muxChannel_3(){
  digitalWrite(s0, HIGH);
  digitalWrite(s1, HIGH);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);
}

int muxChannel_4(){
  digitalWrite(s0, LOW);
  digitalWrite(s1, LOW);
  digitalWrite(s2, HIGH);
  digitalWrite(s3, LOW);
}

int muxChannel_5(){
  digitalWrite(s0, HIGH);
  digitalWrite(s1, LOW);
  digitalWrite(s2, HIGH);
  digitalWrite(s3, LOW);
}

int muxChannel_6(){
  digitalWrite(s0, LOW);
  digitalWrite(s1, HIGH);
  digitalWrite(s2, HIGH);
  digitalWrite(s3, LOW);
}
int muxChannel_7(){
  digitalWrite(s0, HIGH);
  digitalWrite(s1, HIGH);
  digitalWrite(s2, HIGH);
  digitalWrite(s3, LOW);
}

int muxChannel_8(){
  digitalWrite(s0, LOW);
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, HIGH);
}
int muxChannel_9(){
  digitalWrite(s0, HIGH);
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, HIGH);
}

int muxChannel_10(){
  digitalWrite(s0, LOW);
  digitalWrite(s1, HIGH);
  digitalWrite(s2, LOW);
  digitalWrite(s3, HIGH);
}

// Ende Adressierung des analogen/digitalen Multiplexers

Kann man das jetzt nicht ein wenig eleganter machen und dann irgendwie in den Code mit einbauen??
Irgendwie so:

int controlPin[] = {s0, s1, s2, s3};
int muxChannel[10] [4]={
    {1,0,0,0}, //channel 1
    {0,1,0,0}, //channel 2
    {1,1,0,0}, //channel 3
    {0,0,1,0}, //channel 4
    {1,0,1,0}, //channel 5
    {0,1,1,0}, //channel 6
    {1,1,1,0}, //channel 7
    {0,0,0,1}, //channel 8
    {1,0,0,1}, //channel 9
    {0,1,0,1}, //channel 10

Ja. War ja auf der anderen Seite auch so implementiert. Aber definiere das als byte! int hat zwei Bytes pro Wert. Auch wenn du 8kB RAM hast, ist das nicht schön :slight_smile:

und wie kann ich das dann in meine funktionen einfügen, dass es automatisch alle kanäle durchgeht?

Der Teil ist doch auch nicht anders wie vorher. Nur die Art wie die Pins gesetzt werden ist anders (von hinten durch du Brust ins Auge, da man um die Limitationen der Arduino Software herumprogrammiert).

Vollständig ist es so:

void selectChannel(int channel)
{
  const byte controlPin[] = {s0, s1, s2, s3};

  const byte muxChannel[10][4]=
  {
    {0,0,0,0}, //channel 0
    {1,0,0,0}, //channel 1
    {0,1,0,0}, //channel 2
    {1,1,0,0}, //channel 3
    {0,0,1,0}, //channel 4
    {1,0,1,0}, //channel 5
    {0,1,1,0}, //channel 6
    {1,1,1,0}, //channel 7
    {0,0,0,1}, //channel 8
    {1,0,0,1}, //channel 9
  };

  for(int i = 0; i < 4; i ++)
  {
    digitalWrite(controlPin[i], muxChannel[channel][i]);
  }
}

Die Funktion kann man wiederum in einer for-Schleife aufrufen

ich steh grad glaub irgendwie auf dem Schlauch. Wie ich den Kanal auswähle verstehe ich. Ich komm grad einfach nur nicht drauf, wie dies auf gunthers Art in meinen Code integriert werden kann. Also so, dass es automatisch durchläuft.

was ich grad probiere, ich bekomme die Funktion void selectChannel() nicht in meine Code integriert. Bekomme dauernd Fehlermeldungen beim Kompilieren. Könnt ihr mir bitte Helfen, das zum Laufen zu bekommen. Bald ist Abgabe meiner Modulprüfung und ich bekomme meinen Bewässerungscode nicht fertig :~

ich habe versucht, sie wie meine Funktion muxChannel_...() zu integrieren, aber immer ohne erfolg.
Bitte helft mir!

emjay:
...Bekomme dauernd Fehlermeldungen beim Kompilieren.

Es wäre hilfreich zu wissen welche Fehlermeldung.
Und auch der zugehörige Code hilft ungemein bei der Fehlersuche!