Hello,
i'm quite new to the whole arduino world and i am currently working on an arduino project. The main goal is to have a stopwatch with displays the following things:
-
How long water has been flowing (from opening the valve to closing), and resetting the number when the valve opens again.
-
How much water flowed through the sensor. Again the display should show me the amount in litres and resetting the value when it starts again.
The hardware works perfectly: water flows through the sensor, my LCD shows the amount of water per second, but i am not able to get my stop to properly work. At the moment i am at a point where the stop watch runs from booting the arduino and stops/resets when water is flowing.
My board is an Arduino nano with the 1602A LCD.
Thank you for your help!
The code i came up with is the following (i did a lot of copy and paste from other code parts):
#include <LiquidCrystal.h>
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
int ledPin = 13; // LED connected to digital pin 13
int buttonPin = 5; // button on pin 2
int value = LOW; // previous value of the LED
int buttonState; // variable to store button state
int lastButtonState; // variable to store last button state
int blinking; // condition for blinking - timer is timing
int frameRate = 10; // the frame rate (frames per second) at which the stopwatch runs - Change to suit
long interval = (1000 / frameRate); // blink interval
long previousMillis = 0; // variable to store last time LED was updated
long startTime ; // start time for stop watch
long elapsedTime ; // elapsed time for stop watch
int fractional; // variable used to store fractional part of Frames
int fractionalSecs; // variable used to store fractional part of Seconds
int fractionalMins; // variable used to store fractional part of Minutes
int elapsedFrames; // elapsed frames for stop watch
int elapsedSeconds; // elapsed seconds for stop watch
int elapsedMinutes; // elapsed Minutes for stop watch
char buf[10]; // string buffer for itoa function
volatile float flow_frequency; // Measures flow meter pulses
float l_sec; // Calculated litres/min
unsigned char flowmeter = 2; // Flow Meter Pin number
unsigned long currentTime;
unsigned long cloopTime;
float totalLiters;
void flow ()
{
flow_frequency++;
}
void setup()
{
lcd.clear();
totalLiters = 0;
lcd.begin(16, 2); // intialise the LCD.
pinMode(ledPin, OUTPUT); // sets the digital pin as output
pinMode(buttonPin, INPUT); // not really necessary, pins default to INPUT anyway
digitalWrite(buttonPin, HIGH); // turn on pullup resistors. Wire button so that press shorts pin to ground.
pinMode(flowmeter, INPUT);
Serial.begin(9600);
attachInterrupt(0, flow, RISING); // Setup Interrupt
// see [...]; // Enable interrupts
currentTime = millis();
cloopTime = currentTime;
}
void loop() {
currentTime = millis(); // Every second, calculate and print litres/hour
if (currentTime >= (cloopTime + 100))
{
cloopTime = currentTime; // Updates cloopTime
// Pulse frequency (Hz) = 6.6Q, Q is flow rate in L/min. (Results in +/- 3% range)
l_sec = (flow_frequency / 60 / 6.6); // (Pulse frequency x 1 min) / 6.6Q = flow rate in L/hour
flow_frequency = 0; // Reset Counter
totalLiters += l_sec ;
lcd.setCursor(0, 1);
lcd.print (l_sec, 3);
lcd.println (" L/Sek ");
}
digitalWrite(ledPin, LOW); // Initiate LED and Step Pin States
buttonState = digitalRead(buttonPin); // Check for button press, read the button state and store
// check for a high to low transition if true then found a new button press while clock is not running - start the clock
if (l_sec == 0 && blinking == false)
{
startTime = millis(); // store the start time
blinking = true; // turn on blinking while timing
lastButtonState = buttonState; // store buttonState in lastButtonState, to compare next time
}
// check for a high to low transition if true then found a new button press while clock is running - stop the clock and report
else if (l_sec > 0 && blinking == true) {
blinking = false; // turn off blinking, all done timing
lastButtonState = buttonState; // store buttonState in lastButtonState, to compare next time
// Routine to report elapsed time
elapsedTime = millis() - startTime; // store elapsed time
elapsedMinutes = (elapsedTime / 60000L);
elapsedSeconds = (elapsedTime / 1000L); // divide by 1000 to convert to seconds - then cast to an int to print
elapsedFrames = (elapsedTime / interval); // divide by 100 to convert to 1/100 of a second - then cast to an int to print
fractional = (int)(elapsedFrames % frameRate); // use modulo operator to get fractional part of 100 Seconds
fractionalSecs = (int)(elapsedSeconds % 60L); // use modulo operator to get fractional part of 60 Seconds
fractionalMins = (int)(elapsedMinutes % 60L); // use modulo operator to get fractional part of 60 Minutes
lcd.clear(); // clear the LDC
if (fractionalMins < 10) { // pad in leading zeros
lcd.print("0"); // add a zero
}
lcd.print(itoa(fractionalMins, buf, 10)); // convert the int to a string and print a fractional part of 60 Minutes to the LCD
lcd.print(":"); //print a colan.
if (fractionalSecs < 10) { // pad in leading zeros
lcd.print("0"); // add a zero
}
lcd.print(itoa(fractionalSecs, buf, 10)); // convert the int to a string and print a fractional part of 60 Seconds to the LCD
lcd.print(":"); //print a colan.
if (fractional < 10) { // pad in leading zeros
lcd.print("0"); // add a zero
}
lcd.print(itoa(fractional, buf, 10)); // convert the int to a string and print a fractional part of 25 Frames to the LCD
}
else {
lastButtonState = buttonState; // store buttonState in lastButtonState, to compare next time
}
// run commands at the specified time interval
// blink routine - blink the LED while timing
// check to see if it's time to blink the LED; that is, the difference
// between the current time and last time we blinked the LED is larger than
// the interval at which we want to blink the LED.
if ( (millis() - previousMillis > interval) ) {
if (blinking == true) {
previousMillis = millis(); // remember the last time we blinked the LED
digitalWrite(ledPin, HIGH); // Pulse the LED for Visual Feedback
elapsedTime = millis() - startTime; // store elapsed time
elapsedMinutes = (elapsedTime / 60000L); // divide by 60000 to convert to minutes - then cast to an int to print
elapsedSeconds = (elapsedTime / 1000L); // divide by 1000 to convert to seconds - then cast to an int to print
elapsedFrames = (elapsedTime / interval); // divide by 40 to convert to 1/25 of a second - then cast to an int to print
fractional = (int)(elapsedFrames % frameRate);// use modulo operator to get fractional part of 25 Frames
fractionalSecs = (int)(elapsedSeconds % 60L); // use modulo operator to get fractional part of 60 Seconds
fractionalMins = (int)(elapsedMinutes % 60L); // use modulo operator to get fractional part of 60 Minutes
lcd.clear(); // clear the LDC
if (fractionalMins < 10) { // pad in leading zeros
lcd.print("0"); // add a zero
}
lcd.print(itoa(fractionalMins, buf, 10)); // convert the int to a string and print a fractional part of 60 Minutes to the LCD
lcd.print(":"); //print a colan.
if (fractionalSecs < 10) { // pad in leading zeros
lcd.print("0"); // add a zero
}
lcd.print(itoa(fractionalSecs, buf, 10)); // convert the int to a string and print a fractional part of 60 Seconds to the LCD
lcd.print(":"); //print a colan.
if (fractional < 10) { // pad in leading zeros
lcd.print("0"); // add a zero
}
lcd.print(itoa((fractional), buf, 10)); // convert the int to a string and print a fractional part of 25 Frames to the LCD
}
else {
digitalWrite(ledPin, LOW); // turn off LED when not blinking
}
}
}
Please ignore the "button" parts. The original code had the possibility to start and stop the stopwatch when pressing a button. I tried to replace the "pressing-button-part" with "water -flowing-through-the-sensor".
Hi there!
If possible, can you tell me what specific water flow sensor you have integrated into your system? I’ve used a flow sensor before and I had similar problems with it, and I wonder if you have the same sensor.
Also, just to clarify, if I understand the issue, the stopwatch keeps time when the flow sensor detects nothing going past it, and the stopwatch stops recording time when the water is flowing. Is this correct?
There are many, many problems with that code, which largely boils down to your "copy & paste without understanding" approach. Don't try to do this all at once. Get one thing working at a time.
-
All times should be declared "unsigned long"
-
Always use subtraction rather than addition. Study the "blink without delay" Arduino example.
if (currentTime >= (cloopTime + 100))
- This won't work, because seconds (declared int) will overflow after part of one day.
elapsedSeconds = (elapsedTime / 1000L); // divide by 1000 to convert to seconds - then cast to an int to print
- Really?
float l_sec; // Calculated litres/min
- This needs to be an unsigned integer (perhaps long), not float, and you have to make sure that interrupts are turned off while you access it in the loop function.
volatile float flow_frequency; // Measures flow meter pulses
- There is so much junk involved in formatting the LCD display that it is impossible to understand your code, and I'll bet you don't either.
I suggest to remove all the LCD stuff and just print seconds to the serial monitor, until you get the button and flowmeter working.
Then worry about formatting the display (all of which, incidentally, could be done in just 4-5 lines using the sprintf() function).
bos1714:
Hi there!
If possible, can you tell me what specific water flow sensor you have integrated into your system? I’ve used a flow sensor before and I had similar problems with it, and I wonder if you have the same sensor.
Also, just to clarify, if I understand the issue, the stopwatch keeps time when the flow sensor detects nothing going past it, and the stopwatch stops recording time when the water is flowing. Is this correct?
The waterflow sensor is yf-b6 waterflow sensor (similiar to yf-s201, it can handle the same code).
Yes, this is absolutely correct
i want it just the other way round. Stopwatch starting when water flowing, and stopping, while showing the time for a couple of seconds, when no flow is detected.
Thank you!
jremington:
There are many, many problems with that code, which largely boils down to your "copy & paste without understanding" approach. Don't try to do this all at once. Get one thing working at a time.
-
All times should be declared "unsigned long"
-
Always use subtraction rather than addition. Study the "blink without delay" Arduino example.
if (currentTime >= (cloopTime + 100))
- This won't work, because seconds (declared int) will overflow after part of one day.
elapsedSeconds = (elapsedTime / 1000L); // divide by 1000 to convert to seconds - then cast to an int to print
- Really?
float l_sec; // Calculated litres/min
- This needs to be an unsigned integer (perhaps long), not float, and you have to make sure that interrupts are turned off while you access it in the loop function.
volatile float flow_frequency; // Measures flow meter pulses
- There is so much junk involved in formatting the LCD display that it is impossible to understand your code, and I'll bet you don't either.
I suggest to remove all the LCD stuff and just print seconds to the serial monitor, until you get the button and flowmeter working.
Then worry about formatting the display (all of which, incidentally, could be done in just 4-5 lines using the sprintf() function).
First of all: thank you very much for your detailed reply. I know that my arduino/python knowledge lacks a lot of basics.
i'll give all your suggestions a try, the idea to use serial_print is very good.
My code, you got it right, is copy-pasted from another stopwatch code and combined with code for this specific sensor somebody had in use.