// https://forum.arduino.cc/t/using-flow-sensor-to-control-dc-motor-for-water-sampling/1019982
// WIP: reduced to implement true debounced pushbutton control
#include <LiquidCrystal.h>
// using Pololu DRV8876 (QFN) Single Brushed DC Motor Driver Carrier
const int rs = 8, en = 9, d4 = 10, d5 = 11, d6 = 12, d7 = 4;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
unsigned long startMillis; // Keeps track of millis() when the pumping cycle starts.
unsigned long currentMillis; // millis() of the current loop.
unsigned long currentMilliss;
// constants for Arduino IO-Pins with SELF-explaining names
const byte samplingBtnPin = 7;
const byte primeBtnPin = 5;
const byte purgeBtnPin = 6;
const byte floatSwitchPin = 3;
const byte DRV8876_IN1_PIN = A0;
const byte DRV8876_IN2_PIN = A1;
// constants for the states with SELF-explaining names
const byte OffState = 0;
const byte PumpState = 1;
const byte PausingState = 2;
const byte ReverseState = 3;
const byte RestState = 4;
const byte FullState = 5;
byte state;
//... let's introduce some tags for the humans
char *tags[] = {
"OffState",
"PumpState",
"PausingState",
"ReverseState",
"RestState",
"FullState",
};
#define pressed HIGH
#define released LOW
#define closed HIGH
#define open LOW
// flow sensor and float switch//
byte statusLed = 13;
byte sensorInterrupt = 0; //0 = digital pin 2
byte sensorPin = 2; //flow sensor input
//byte floatSwitch = 3;
//pulse count and flow settings//
float calibrationFactor = 79; //F=79*Q
volatile byte pulseCount; // counts the pulses of flow sensor
float flowRate;
unsigned int flowMilliLitres; //totaltotalMilliLitres used for the interrupts
unsigned long totalMilliLitres;
unsigned long oldTime;
unsigned long cloopTime; // to count pulses per second
unsigned long vol; //vol tracks total volume throughout loop
void pulseCounter()
{
// Increment the pulse counter
pulseCount++;
}
void setup()
{
//... how do ppl get long without serial i/o? ;-)
Serial.begin(115200);
Serial.println("Hello Flow Sensor States\n");
lcd.begin(16 , 2); // screen size
// lcd.print("Ready ");
pinMode(primeBtnPin, INPUT_PULLUP); // pinMode(5, INPUT);
pinMode(purgeBtnPin, INPUT_PULLUP); // pinMode(6, INPUT);
pinMode(samplingBtnPin, INPUT_PULLUP); // pinMode(7, INPUT);
pinMode(DRV8876_IN1_PIN, OUTPUT); // pinMode(A0, OUTPUT);
pinMode(DRV8876_IN2_PIN, OUTPUT); // pinMode(A1, OUTPUT);
// Set up the status LED line as an output
pinMode(statusLed, OUTPUT);
digitalWrite(statusLed, HIGH);
pinMode(sensorPin, INPUT);
digitalWrite(sensorPin, HIGH);
pinMode(floatSwitchPin, INPUT);
digitalWrite(floatSwitchPin, INPUT);
pulseCount = 0;
flowRate = 0.0;
flowMilliLitres = 0.0;
totalMilliLitres = 0;
vol = 0;
cloopTime = currentMillis;
currentMillis = millis();
// The Hall-effect sensor is connected to pin 2 which uses interrupt 0.
// Configured to trigger on a FALLING state change (transition from HIGH
// state to LOW state)
attachInterrupt(sensorInterrupt, pulseCounter, RISING);
}
void loop()
{
currentMillis = millis(); // Get the current value of millis().
if (digitalRead(samplingBtnPin) == released)
{
if (state > OffState) // Are we already in a pumping cycle?
state = OffState;
else
state = PumpState;
//... track the pushbutton manifestations:
static int bCounter; // just so we can see new lines as they spam
Serial.print(bCounter); bCounter++;
Serial.print(" button activity state = ");
Serial.print(state);
Serial.print(" ");
Serial.println(tags[state]);
}
delay(200); // Small delay to debounce the button.
///////////////////
//flow rate loop//
/////////////////
if (currentMillis >= (cloopTime + 1000))
{
cloopTime = currentMillis;
if (pulseCount != 0) {
flowRate = (pulseCount / calibrationFactor);
//oldTime = millis();
flowMilliLitres = (flowRate / 60) * 1000;
totalMilliLitres += flowMilliLitres;
vol += flowMilliLitres;
//((1000.0 / (millis() - currentMillis)) *
;
lcd.begin(16, 2);
lcd.print("Rate: ");
lcd.setCursor(5, 0);
lcd.print(flowRate);
lcd.setCursor(11, 0);
lcd.print("L/Min");
lcd.setCursor(0, 1);
// print total volume
lcd.print("Vol: ");
lcd.print(totalMilliLitres);
lcd.print(" mL");
pulseCount = 0;
}
else {
lcd.clear();
lcd.setCursor(5, 0);
lcd.print("Rate: ");
lcd.print ( pulseCount); // resets flow rate to 0
lcd.print (" L/m");
lcd.setCursor(0, 1);
lcd.print("Vol:");
lcd.print(vol);
lcd.print(" mL");
}
}
switch (state) // Check which state we are in.
{
case OffState:
while (digitalRead(primeBtnPin) == released) // Prime button being pressed?
PumpForward(); // Turn on the pump.
while (digitalRead(purgeBtnPin) == released) // Purge button being pressed?
PumpReverse(); // Reverse the pump
startMillis = currentMillis; // Keep resetting the start time of the pumping sequence.
pumpOff();
break;
case PumpState: // comment is obsolete code epxlains ITSELF Pumping state
if (totalMilliLitres > 100) /// did we collect 100 mL?
state = PausingState;
else
PumpForward();
lcd.setCursor(0, 0);
lcd.print("PUMP ");
break;
case PausingState:
if (currentMillis - startMillis > 20000) // Have we been in this state too long?
state = ReverseState;
else
pumpOff();
lcd.setCursor(0, 0);
lcd.print("REST ");
break;
case ReverseState:
if (currentMillis - startMillis > 25000) // Have we been in this state too long?
state = RestState;//state++;
else
PumpReverse();
lcd.setCursor(0, 0);
lcd.print("PURGE");
break;
case RestState:
if (currentMillis - startMillis > 50000 && (digitalRead(floatSwitchPin) == closed)) // Have we been in this state too long?
{
state = PumpState;
startMillis = currentMillis; // Reset the start time of the pumping sequence.
totalMilliLitres = 0; //reset totalMilliLitres so it can start counting up from 0 again
}
else
pumpOff();
lcd.setCursor(0, 0);
lcd.print("REST ");
break;
}
}
// senseful SUB-unit of code with a SELF-explaining name
void PumpForward() {
digitalWrite(DRV8876_IN1_PIN, HIGH); // comment is obsolete code epxlains ITSELF Turn on the pump (forward).
digitalWrite(DRV8876_IN2_PIN, LOW);
}
// senseful SUB-unit of code with a SELF-explaining name
void PumpReverse() {
digitalWrite(DRV8876_IN1_PIN, LOW); // comment is obsolete code epxlains ITSELF Reverse the pump.
digitalWrite(DRV8876_IN2_PIN, HIGH);
lcd.setCursor (0, 0);
//lcd.print("Purging");
}
// senseful SUB-unit of code with a SELF-explaining name
void pumpOff()
{
digitalWrite(DRV8876_IN1_PIN, LOW);
digitalWrite(DRV8876_IN2_PIN, LOW);
}
void FullWarning()
{
digitalWrite(DRV8876_IN1_PIN, LOW);
digitalWrite(DRV8876_IN2_PIN, LOW);
//lcd.setCursor (0, 0);
//lcd.print("FULL");
}