Dosieranlage auf Tastendruck starten

Hallo zusammen,
beschäftige mich gerade mit dem erlernen der Arduino-Programmierung.
Ich habe mir bisher immer Programmschnipsel oder fertige Sketches aus dem www besorgt und diese dann nach meinen Wünschen geändert (für mich eine Art learning by doing).
Jetzt hänge ich aber total, bei zwei Dingen.
Erstmal zu meinem Vorhaben: Ich möchte eine Dosieranlage für Flüssigwaschmittel bauen. Arduino Uno, Schlauchpumpe und Durchflusssensor vorhanden, verkabelt und funktioniert auch soweit. Die Pumpe hängt übrigens an einem 1-Kanal-Relaysmodul mit Optokoppler.
Logischerweise läuft der Sketch durch, sobald der Arduino Strom bekommt oder Reset gedrückt wird. Und genau das möchte ich erst, wenn ich eine Taste drücke (vom Shield wäre die "Select" Taste noch frei).
Zu meinem anderen Problem komme ich unten nach dem Code.
Hier mein Sketch:

#include <LiquidCrystal.h>

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

int lcd_key     = 0;
int adc_key_in  = 0;
float current_volume = 0;                //Current total volume passed though flow meter
float target_volume = 0.5;                //Total desired volume
float adjustment_volume = 0;             //Adjustment volume to take into account delays in solenoid closing. Subtracted from the current volume.

#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5

#define hltSIZE   0.6                       //Size of the Hot Liquor Tun in litres

#define SOLENOIDPIN 13                      //Solenoid relay on Pin 13
#define FLOWSENSORPIN 12                    //Flow sensore on Pin 2

// count how many pulses
volatile uint16_t pulses = 0;
// track the state of the pulse pin
volatile uint8_t lastflowpinstate;
// you can try to keep time of how long it is between pulses
volatile uint32_t lastflowratetimer = 0;
// and use that to calculate a flow rate
volatile float flowrate;
// Interrupt is called once a millisecond, looks for any pulses from the sensor!
SIGNAL(TIMER0_COMPA_vect) {
 uint8_t x = digitalRead(FLOWSENSORPIN);
 
 if (x == lastflowpinstate) {
   lastflowratetimer++;
   return; // nothing changed!
 }
 
 if (x == HIGH) {
   //low to high transition!
   pulses++;
 }
 lastflowpinstate = x;
 flowrate = 1000.0;
 flowrate /= lastflowratetimer; // in hertz
 lastflowratetimer = 0;
}

void useInterrupt(boolean v) {
 if (v) {
   // Timer0 is already used for millis() - we'll just interrupt somewhere
   // in the middle and call the "Compare A" function above
   OCR0A = 0xAF;
   TIMSK0 |= _BV(OCIE0A);
 } else {
   // do not call the interrupt function COMPA anymore
   TIMSK0 &= ~_BV(OCIE0A);
 }
}

void setup()
{
   
 Serial.begin(9600);
 Serial.print("Flow sensor test!");
 
 digitalWrite(SOLENOIDPIN,LOW);           //ACTIVE HIGH RELAY PUT THIS FIRST TO ENSURE PIN IS IN CORRECT STATE BEFORE WE INIT IT
 digitalWrite(FLOWSENSORPIN, HIGH);

 pinMode(SOLENOIDPIN, OUTPUT);
 pinMode(FLOWSENSORPIN, INPUT);

 
 lcd.begin(16, 2);                        // start the library

 printBanner(3000);                       // show banner for 2 seconds
 
 lcd.clear();
 
 printLabels();
 
 lastflowpinstate = digitalRead(FLOWSENSORPIN);
 useInterrupt(true);

}
void loop()
{

 while(current_volume < (target_volume - adjustment_volume))
 { 
   dowork();
 }
 
 digitalWrite(SOLENOIDPIN,HIGH);          //Close solenoid //normal low!!

 lcd.setCursor(0,0);
 lcd.print("Waschm. dosieren");
 lcd.setCursor(0,1);
 lcd.print(" Start druecken ");
 
 //Debug Messaging
 Serial.println("  VALVE CLOSED  ");
 Serial.println("   TARGET HIT   ");

}

void printBanner(int bannerdelay)
{
 lcd.setCursor(0,0);                     
 lcd.print("  Waschmittel   ");
 lcd.setCursor(0,1);  
 lcd.print("  wird dosiert  ");
 delay(bannerdelay);
}

void printLabels()
{
 lcd.setCursor(0,0);
 lcd.print("Ziel: ");
 lcd.setCursor(0,1);
 lcd.print("Aktuell: ");
}

// read the buttons
int read_LCD_buttons()
{
 adc_key_in = analogRead(0);
 /*  OLD BUTTONS at 3.3V
 if (adc_key_in > 1000) return btnNONE;
 if (adc_key_in < 50)   return btnRIGHT; 
 if (adc_key_in < 195)  return btnSELECT;
 if (adc_key_in < 380)  return btnUP;
 if (adc_key_in < 555)  return btnDOWN;
 if (adc_key_in < 790)  return btnLEFT; 
*/

if (adc_key_in > 1000) return btnNONE;  
if (adc_key_in < 50)   return btnRIGHT; 
if (adc_key_in < 195)  return btnUP;
if (adc_key_in < 380)  return btnDOWN;
if (adc_key_in < 555)  return btnLEFT;
if (adc_key_in < 790)  return btnSELECT; 

 return btnNONE;
}

void dowork()
{

 //Serial.print("Freq: "); Serial.println(flowrate);        //Uncomment these two lines to monitor the freq/pulses
 //Serial.print("Pulses: "); Serial.println(pulses, DEC);
 float liters = pulses;
 liters /= 7.5;
 liters /= 60.0;
 
 current_volume = liters;
 
 //Debug Messaging
 Serial.print("Cur: "); Serial.println(current_volume);
 Serial.print("Tar: "); Serial.println(target_volume);
 
 //Print the target volume value in litres
 lcd.setCursor(11,0);
 lcd.print(target_volume,2);
 lcd.setCursor(15,0);
 lcd.print("L");

 //Print the current volume value in litres
 lcd.setCursor(11,1);            
 lcd.print(current_volume,2);
 lcd.setCursor(15,1);
 lcd.print("L");

 lcd_key = read_LCD_buttons();    // read the buttons
 

 switch (lcd_key)               // depending on which button was pushed, we perform an action
 {
 case btnRIGHT:
   {
    if (digitalRead(SOLENOIDPIN == HIGH))
    {
            digitalWrite(SOLENOIDPIN,LOW);       //STOP FLOW
    }
     

     Serial.println("Solenoid Closed");
     break;
   }

 case btnLEFT:
   {
    if (digitalRead(SOLENOIDPIN == LOW))
    {
            digitalWrite(SOLENOIDPIN,HIGH);       //START FLOW
    }
     

     Serial.println("Solenoid Open");
     
     break;
   }

 case btnUP:
   {
     if (target_volume >= hltSIZE)  //don't go larger than the size of the vessel
     {
       target_volume = hltSIZE;
       break;
     }
     else
     {
       target_volume += 0.01;
       break;
     }

     break;
   }

 case btnDOWN:
   {
     if (target_volume <= 0)      //don't go below zero
     {
       target_volume = 0;
       break; 
     }
     else
     {
       target_volume -= 0.01;
     }
     break;
   }
  

 case btnNONE:
   {
     break;
   }
 }

}

Mein anderes Problem wäre, dass der Pin 13 an dem meine Pumpe hängt, nach Reset oder Energiezuführung kurz in undefinierten Zuständen "flackert" und dann erst low bleibt. Gibts dafür Abhilfe?
Besten Dank im Voraus!
Gruß
Bonsai

Hallo,
den Pin 13 würde ich nicht nehmen, ist Arduino LED.
Den verwendeten DigitalPin würde ich mit einem 10k Widerstand gegen Masse ziehen.
Schaue Dir einmal while an.
Damit bekommst Du alles zum Stillstand.
Gruß und Spaß
Andreas

bonsai308:
Logischerweise läuft der Sketch durch, sobald der Arduino Strom bekommt oder Reset gedrückt wird. Und genau das möchte ich erst, wenn ich eine Taste drücke (vom Shield wäre die "Select" Taste noch frei).

Bau eine entsprechende Tastenabfrage in setup() ein.

bonsai308:
Mein anderes Problem wäre, dass der Pin 13 an dem meine Pumpe hängt, nach Reset oder Energiezuführung kurz in undefinierten Zuständen "flackert" und dann erst low bleibt. Gibts dafür Abhilfe?

Eine Möglichkeit ist eine separate Einschaltverzögerung, eine andere der Einsatz eines UND-Gliedes (das ist am Ausgang erst HIGH, wenn beide Eingänge HIGH sind).

Gruß

Gregor

bonsai308:
Logischerweise läuft der Sketch durch, sobald der Arduino Strom bekommt oder Reset gedrückt wird. Und genau das möchte ich erst, wenn ich eine Taste drücke (vom Shield wäre die "Select" Taste noch frei).

Aber genau das ist der Sinn der Loop.
Wenn du es anders machst, bekommst du doch dein Menü (Displayanzeige) nicht zu sehen.
Du musst also deinen Sketch so aufbauen, dass er auf den ersten Tastendruck des Menüs wartet.

Hallo,
"so aufbauen, dass er auf den ersten Tastendruck des Menüs wartet"

An was Du alles denkst... :wink:

Gruß und Spaß
Andreas

SkobyMobil:
An was Du alles denkst... :wink:

Wichtig ist, das der TO es auch versteht.

Ok. Danke erst mal für Eure Antworten.
stimmt. Dann klemme ich von Pin 13 mal auf Pin10.

Könnte es mit dem warten auf Tastendruck evtl. damit gehen?

{

  while(current_volume < (target_volume - adjustment_volume && btnSELECT >0))
 {
    dowork();

Funktionieren tut's zwar noch nicht. Aber wäre dies ein Ansatz?

Gruß
bonsai

In Deiner While Schleife müsstest Du btnSELECT auch
nochmal abfragen, damit die Schleife auch wieder verlassen wird.
Natürlich auch die ganzen anderen Variablen die Du in Deiner Verknüpfung nutzt.

Mach Dir doch einfach ne getrennte "Mausefalle"
à la

while (btnSELECT <=1) // bzw >=1022 oder was auch immer als "nichts" ausgegeben wird
{ btnSELECT = analogRead(A0);}

Rest des Programmloops