Ein Sensor an zwei Ardiuno möglich?

Hallo.

Kann man einen Sensor an zwei Arduino betreiben, also gleichzeitig?
Beide haben die gleiche Spannungsversorgung.

Es handelt sich um eine Durchflussmesser der einen Wert von 0-5V ausgibt

Es wäre sinnvoller den Wert von einem Arduino zum nächsten zu übergeben, z.b. seriell oder I²C,....

Das geht leider nicht.
Ich habe mal vor längerer Zeit eine Kaffeemaschine umgebaut, um den Wasserstand zu überwachen.
Das habe ich mit der Laufzeit der Pumpe realisiert.
Leider hat der Hersteller die Kapseln verändert. Ein Kaffee braucht nun erheblich länger als z. B. ein Tee.
In der Maschine ist aber ein Durchflussmesser mit 3 Kontakten.
Wenn das stimmt was ich gemessen habe GND, 5V und Ausgang 0-5V
In der Maschine ist ein AttinyXxXx irgend eine 4 Stellige Nummer. Weiß ich jetzt nicht mehr.
Deshalb die Frage mit zwei Arduinos.

Da der Sensor ja nur eine Spannung ausgibt, sollten sich die zwei ja eigentlich nicht in die Quere kommen... oder?

im Durchflusssensor sitzt ein Attiny? Ich kenne nur Sensoren die Pulse ausgeben.

Die analogen Eingänge sind eigentlich hochohmig genug, es könnte so gehen. Teste es doch einfach aus, und mache eine Vergleichsmessung mit nur einem Arduino.

Gruß

Das auslesen des Signals vom Durchflusssensor an zwei µC gleichzeitig sollte problemlos gehen, tu ich ebenfalls bei meinem Kaffeeautomaten. Der µC der Maschine liest den Sensor aus, was ich ebenfalls parallel dazu mache.

Der Attiny steuert die ganze Kaffeemaschine :slight_smile:
Es ist ein Attiny 861a

Denke auch mal das sollte funktionieren.
Werde den mal anzapfen und schauen.

Also was da wirklich raus kommt, weiß ich noch nicht. Hoffe das ist nur eine Spannung, keine Pulse.
Wird sich zeigen.

Danke schon mal für eure Antworten !

Meinst du eine analoge Spannung? Das fände ich umständlicher, dann müsstest du ja die Spannung und die Zeit messen und daraus dir die Menge errechnen. Andernfalls einfach nur Pulse zählen....

Gruß

Scherheinz:
Andernfalls einfach nur Pulse zählen....

Ja analogRead hat nicht wirklich was gebracht. Aufgefallen ist mir, das wenn die Pumpe stoppt entweder 5V oder 0V anliegen.
Also war klar, das hier Pulse raus kommen.
Habe per Interrupt und CHANGE das ganze mal getestet.
Zählen funktioniert ! Wenn kein Wasser mehr da ist, hört das Zählen auf.
Also denke ich, das wenn wenig Wasser durchläuft der Zähler langsamer läuft.

Damit kann ich nun arbeiten.
Leider habe ich bereits alle PINS belegt, zwei LED, ein Restet Taster, eine Lichtschranke für die Kapsel und eben eine LDR/LED Kombination um die Pumpe "abzufragen".
Natürlich habe ich genau den Interrupt Pin 2 nicht für die Wasserpumpe verwendet :smiley:
Na ja, kurz umlöten dann sollte das funktionieren.
Ach so, ich verwende einen Attiny85 !

Wen es interessiert:

Die "bessere" Version der Kaffemaschine (im übrigen eine Expressi, Aldi) soll wohl eine Wasserstandsanzeige haben.
Wenn da schon ein Durchflussmesser drin ist, hätte man da auch direkt ab Werk was machen können, eben mit dem Zählen der Pulse so wie ich es vorhabe.

Na ja, aber dann hätte ich ja nichts mehr zu tun...auch doof :wink:

EDIT: Hallo ??? Editieren != neuer Beitrag !
Warum gibt es hier eine Begrenzung für Fehlerbeseitigungen ?
Dieser Zähler sollte mal schnell erhöht werden !

Also denke ich, das wenn wenig Wasser durchläuft der Zähler langsamer läuft.

genauso ist es, die Zeit spielt keine Rolle, du zählst nur die Pulse und hast deine Menge an Wasser

Wenn da schon ein Durchflussmesser drin ist, hätte man da auch direkt ab Werk was machen können, eben mit dem Zählen der Pulse so wie ich es vorhabe.

Naja dann weiß die Maschine wieviel Wasser verbraucht wurde, aber sie weiß nicht ob du den Wasserbehälter vorher auch ganz voll gemacht hast oder zwischendurch noch was nachgefüllt hast.

Gruß

Ok das stimmt allerdings.

Ich habe da aber ein (Verständnis) Problem mit dem Interrupt.

void pulsZahl()
{
  noInterrupts();
  wasser++;    
  tapdrin = true;
  pumpean = true;
  interrupts();  
}

Was passiert hier genau ? Bleibt das Programm hier in der Schleife hängen ?
Am Interrupt Pin wird ja ein Puls abgefragt. Kommt das Programm dann gelegentlich in seine LOOP Schleife ?
Ich habe nämlich gerade ein Problem. So lange die Pumpe läuft, soll eine LED aus bleiben. Die Stört dann.
Dafür die beiden Variablem taprin=true und pumpean=true.
In der LOOP steht dann, wenn beide true dann LED aus. Das funktioniert so aber nicht mehr, da der interrupt den normalen Programmablauf verändert.

Wie kann man so was umgehen ?

Wenn das Gezeigte deine Interruptroutine ist, dann ist sie falsch (unnötiges disablen, aber gefährlicher noch - enablen der Interrupts).

Ohne dein ganzes Programm zu sehen kann ich nicht mehr sagen.

Wie wäre es denn richtig ?
Habe das aus einem Forum, woher weiß ich nicht mehr.
Ich hatte vermutet, das abgeschaltet wird, damit der Interrupt nicht die Berechnung wasser++ stört bzw. unterbricht.

Kannst du mir kurz erklären, wie die interrupt Funktion funktioniert ?

Achtung ! Lesen auf eigene Gefahr !

/*

ATTINY 85 mit 1Mhz 

kleine Tasse = 296 
große Tasse = 740
spülen = 390
Tankinhalt = 5300
Neue Werte mit Durschflussmesser 

*/

int tapsmax = 8;  // Kapseln im Behälter
int wassermax = 4200;  // Ermittelt mit Durschflussmesser
int empfindlich = 980;  // Empfindlichkeit der Kapsel Lischtchranke
int tapdrinzeit = 4000;  // Zeit für Blinken wenn Kapsel vergessen

int led2blink = 40;  // Blinkgeschwindigkeit, da ohne DELAY !

// PINs
int led1 = 0; // Wasser LED PIN - PWM 
int led2 = 1; // Taps LED PIN - PWM 
int resetPin = 4;
int wasserPin = 0;  // INT 0 - Pin 2/Analog1
int lichtsensorPin = 3; //Lichtschranke - Analog Pin 3 = Digital PIN3 !
// PINs 


int wasser = 0;
int taps = 0;
int tapzeit = 0;  // Zähler für Kapsel Zeit vergessen
int lichtwert = 0;
int reset = 0;
int led2zaehler=0;
volatile boolean tapdrin = false;
volatile boolean pumpean = false;
volatile boolean led2stat = LOW;

void setup() {                
  delay(2000);    // Einschaltpause 

  pinMode(resetPin, INPUT);  

  for (int i=0; i<=255; i+=1){           // LEDs langsam hell werden lassen
    analogWrite (led1,i);
    analogWrite (led2,i);
    delay(10);
  }
  analogWrite (led1,0);
  analogWrite (led2,0);

  pinMode(led1, OUTPUT);             // erst dann als digitalport definieren
  pinMode(led2, OUTPUT);  

  attachInterrupt(wasserPin, pulsZahl, CHANGE);   //Interrupt 0 = PIN 2, Attiny85 hat nur einen Interrupt 
  // pulsZahl = Unterprogramm
}


void loop() {
 
  lichtwert = analogRead(lichtsensorPin);  // Kapsel
  reset = digitalRead(resetPin);
  

// Lichtschranke Kapsel
  if (lichtwert <= empfindlich ) 
  {
    taps++;
    tapdrin = false;
  
   digitalWrite(led2, HIGH);   // Kontrollblinken wenn Kapsel durch fällt
   delay(30);
   digitalWrite(led2, LOW);
   delay(100);
  }


// Wasser MAX
  if (wasser >= wassermax) {
   digitalWrite(led1, HIGH);
   delay(50);
   digitalWrite(led1, LOW);
   delay(50);
   }

  else
   { digitalWrite(led1, LOW); 
   }
   

// Kapsel noch drin ?

  if (tapdrin == false) {
    led2stat = LOW;
    tapzeit = 0;
    led2zaehler=0;
   }
   
   else if (tapdrin == true && pumpean == false)  //LED nur an wenn Pumpe ein mal gelaufen ist, aber nicht mehr läuft !
   {
    
   if (tapzeit <= tapdrinzeit){
   led2stat = HIGH;
   }
   
    else if (tapzeit >= tapdrinzeit){    //Blinken wenn Tap drin ist ohne DELAY damit schnell auf Lichtschranke reagiert werden kann
      
      if(led2zaehler >= led2blink){
        if(led2stat == HIGH){
        led2stat = LOW;
         }
        else {
        led2stat = HIGH;
        }
     
      led2zaehler=0; // Zähler wieder auf Null
      }
      
      led2zaehler++;
      tapzeit = tapdrinzeit;  // auf Maximalwert stellen, damit kein Variablen Überlauf erfolgt
     
     }  // else if
   
   tapzeit++;

   } // else if
// Kapsel noch drin ENDE


// LED immer aus wenn Pumpe an !
   if (pumpean == true)  //LED aus wenn Pumpe läuft...bleibt trotzdem an :-(
   {
    digitalWrite(led2, LOW);
    led2stat = LOW;
    tapzeit = 0;
    led2zaehler=0;
   }
// LED ......Ende


  
// Kapselbehälter voll
  
  if (taps >= tapsmax) {
   digitalWrite(led2, HIGH);
   delay(50);
   digitalWrite(led2, LOW);
   delay(50);
   }

 
 
 // RESET
 
  if (taps >= tapsmax && reset == LOW) {
  taps = 0;
  tapdrin = false;  //eingefügt 23.11.2014
  tapzeit = 0; 
  led2zaehler=0;
  }
  
 
  if (tapdrin == true && reset == LOW) {
  taps++;   //eingefügt 23.11.2014 
  tapdrin = false;  
  tapzeit = 0;
  led2zaehler=0;
  delay(2000);   // Pause sonst wird direkt tapps auf 0 gesetzt wenn taps max in diesem Moment erreicht wurde !
  }
  
  if (wasser>= wassermax && reset == LOW) {
  wasser = 0;  
  tapzeit = 0;
  led2zaehler=0;
  }
  

digitalWrite(led2, led2stat);
delay(10);  

}


// Wasserper Interrupt und Durschflussmesser
void pulsZahl()
{
  noInterrupts();
  wasser++;    
  tapdrin = true;
  pumpean = true;
  digitalWrite(led2, LOW);
  led2stat = LOW;
  tapzeit = 0;
  led2zaehler=0;
  interrupts();  
  pumpean = false;
}

Habe zusätzlich digitalWrite(led2,LOW) in die Interrupt Funktion eingebaut, damit die LED aus geht, ansonsten wird diese durch led2stat entweder auf LOW oder HIGH gesetzt und am ende von LOOP per digitalWrite geschaltet...funktioniert so aber nicht.
Ich denke ich habe da irgend wo anders eine Fehler.

Also ich denke das ganze ist recht verwirrend :slight_smile: Ich blick da grad selber nicht wirklich durch.
Ich glaube ich habe im Abschnitt "Kapsel noch drin?" nicht gerade gut gelöst.
Da es aber vor dem Interrupt funktioniert hatte, hab ich es so gelassen.
Nun wird das ganze immer komplizierter.

Zu Interrupts lies bitte Gammon Forum : Electronics : Microprocessors : Interrupts, das will ich nicht 'kurz erklären'.

Wenn du danach noch Fragen hast, kann ich gerne noch versuchen Unklarheiten ausräumen.

void pulsZahl()
{
  //noInterrupts(); // sind schon disabled, streichen
  wasser++;         // nicht volatile 
  tapdrin = true;
  pumpean = true; 
  digitalWrite(led2, LOW);
  led2stat = LOW;
  tapzeit = 0;      // nicht volatile 
  led2zaehler = 0;  // nicht volatile 
  //interrupts();   // werden automatisch wieder enabled, streichen
  pumpean = false;  // huch, eben solle es noch true sein
}

Dann wird das bei mir mit Sicherheit an den Variablen liegen die nicht volatile deklariert wurden !
Also werden die vom LOOP und ISR als verschiedene Variablen angesehen ?
Das letzte pumpean = false; war nur weil ich dachte, ok, ab hier ist der interrupt an, also wird es ab hier weiter im normalen Programm gehen...war natürlich Unsinn.

Werde deine Änderungen mal übernehmen.

Bedanke mich schon mal !

Du musst zusätzlich auch noch alle (auch lesende) Zugriffe auf Variablen von mehr als einem Byte gegen Interrupts schützen.

Ein Beispiel das zeigt wie und welche Fehler auftreten:

void setup() {
  Serial.begin(115200);
  Serial.println(F("Warte auf Fehler...\r\n\r\nvon - auf - Differenz"));
  // set up Timer 1
  TCCR1A = 0;                        // normal operation
  TCCR1B = bit(WGM12) | bit(CS10);   // CTC, no pre-scaling
  OCR1A =  7999;                     // compare A register value for 2 kHz
  TIMSK1 = bit (OCIE1A);             // interrupt on Compare A Match
}
volatile unsigned long Counter;

ISR(TIMER1_COMPA_vect)
{
  Counter++;
}

void loop() {
  static unsigned long before;
  static unsigned long current;

  // Counter wird mit 2 kHz incrementiert
  //  noInterrupts(); // ohne gibt es den Fehler
  current = Counter;
  //  interrupts();   // ohne gibt es den Fehler

  unsigned long differenz = current - before;

  // loop ist so schnell, der Unterschied zwischen zwei Counter-Werten
  // sollte niemals 1 übersteigen

  if (differenz > 1) {
    Serial.print(before, HEX);
    Serial.write(' ');
    Serial.print(current, HEX);
    Serial.print(F(" - "));
    Serial.println(differenz, HEX);
  }
  before = current;
}
Warte auf Fehler...

von - auf - Differenz
14FF 15FF - 100
15FF 1501 - FFFFFF02
1501 1503 - 2
27FF 28FF - 100
28FF 2801 - FFFFFF02
2801 2803 - 2
40FF 41FF - 100
41FF 4101 - FFFFFF02
4101 4103 - 2
5FFF 60FF - 100
60FF 6001 - FFFFFF02
6001 6003 - 2
90FF 91FF - 100
91FF 9101 - FFFFFF02

Sorry, da verstehe ich leider nicht so viel.
Diese TCCR1A usw. sagen mir gar nichts.
Mit dem 2Khz Signal simulierst du praktisch ein Signal an einem Eingang ?

Wie im code angegeben erhalte ich bei

noInterrupts();
current = Counter;
interrupts();

keine Fehler.
Also muss der interrupt mit noInterrupts(); im Code auch abgeschaltet und dann wieder eingeschaltet werden.

Aber wie oft muss man das machen und wo ?
Ich kann doch nicht in jeder Schleife oder überall dort wo irgend was zugewiesen oder berechnet wird den interrupt abschalten. Dann nützt der mir ja gar nichts.

Ich habe gestern noch einiges versucht, erst wenn ich den LOOP mit einem delay(100) oder 200 verlangsame, bleibt die LED die aus sein soll, wenn die Pumpe läuft, auch aus.
Das ist mir aber zu langsam, da die Lichtschranke möglichst ob abgefragt werden soll.
Sonst ist das Programm gerade im delay und dann fällt die Kapsel durch. Das hatte ich vorher schon mal.

Also werden die vom LOOP und ISR als verschiedene Variablen angesehen ?

Das zwar nicht, aber: volatile verhindert, dass der Compiler falsch optimiert und eine Variable eventuell vorübergehend nur in einem Register hält, statt sie immer an der definierten Speicherstelle zu aktualisieren.
Das von Whandall eindrucksvoll gezeigte Problem mit Variablen die mehr als 1 byte groß sind, liegt daran, dass selbst eine Anweisung wie   unsigned long  current = Counter;
in loop während des Übertragens der 4 Bytes durch eine ISR unterbrochen werden kann.

noInterrupts(); 
// ... wird nicht durch ISR unterbrochen
interrupts();

ist für loop und funktionen die von dort aufgerunfen werden, Interrupt-Routinen selbst laufen schon unter geschlossenen Interrupts. In ISR wäre noInterrupts();unnötig undinterrupts(); schlecht.

Wie der Timer1 in setup eingerichtet wird, ist erstmal nur dafür da, dass die ISR recht oft drankommt.
Soll dich nicht weiter verwirren.
Mit selteneren Interrupts passiert der Fehler auch nur sehr selten. Wodurch das Problem aber eher schlimmer wird, weil es kaum zu reproduzieren ist.

@michael_x

Ok, soweit klar, aber wo setze ich nun dieses noInterrups() ein ?
Mein sketch habe ich ja hier gepostet. Dort sind ja schon einige IF abfragen.
Ich kann ja nicht die ganze LOOP in ein noInterrups() einschließen...oder doch ?

Werde morgen mal einige versuche durchführen...

Ich kann ja nicht die ganze LOOP in ein noInterrups() einschließen...oder doch ?

Normalerweise eine schlechte Idee.
Innerhalb von noInterrupts() kann man nichts machen, was auch in Interruptroutinennicht geht:
( delay() z.B. )
Man sollte daher auch keine "fremden" Funktionen aufrufen, bei denen man nicht weiss was sie machen.

Genauso wie bei Interruptroutinen sollte man die Aktionen auf ein Minimum beschränken.

Also optimalerweise nur die Variablen umkopieren und rücksetzen:

unsigned int _wasser;
noInterrupts();
_wasser = wasser;
wasser = 0;
interrupts();  
// wasser kann jetzt wieder neu gezählt werden, wir arbeiten mit _wasser weiter

Was das mit  pumpean = true/false;  überhaupt soll weiss ich nicht, inwieweit andere Merker (tapdrin) mit dem Wert vonwassersynchron sein müssen, ist mir auch nicht ganz klar.

pumpean = true ist gedacht gewesen ob die Pumpe ein mal an war.
tapdin = true bedeutet Kapsel ist in der Maschine
Synchron mit wasser muss da gar nichts sein.

Eigentlich funktioniert soweit auch alles. Nur will ich diese eine LED aus haben, wenn eben die Pumpe läuft. Das läuft über den interrupt. Aber egal was ich versucht habe, die LED blinkt.
Mit delay kann ich das beheben, dadurch verliere ich aber an Geschwindigkeit um die Lichtschranke abzufragen.
Die ganze Interrupt Sache gefällt mir gar nicht...

Ich werde aber jetzt erst mal selber noch mal ausprobieren.