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
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 ![]()
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 ![]()
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 ![]()
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
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.
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.