I am digging a bit late in the arduino world and currently I am trying to set up a simple system.I have read a lot of post but there is so many that I am not able to find my solution.
Project is simple:
count pulse with Pin 2 and displays total count on an LCD screen
reset the count to zero when pin 7 is HIGH
The count is working well. I increase by +1 each time I get a pulse. Reset is hale OK. If my counter goes to 16 and then I press reset through pin 7, I will get 06. I have not made the test further but I believe that if I go to 124 pulses, reset will give O24.
Here is below my code. If you have any comments or help, I will really appreciate it.
I am using Arduino UNO, LCD screen 20x4 with I2C communication, switch with pull-down resistors.
#include <Wire.h> // Library for I2C communication
#include <LiquidCrystal_I2C.h> // Library for LCD
// Wiring: SDA pin is connected to A4 and SCL pin to A5.
// Connect to LCD via I2C, default address 0x27 (A0-A2 not jumpered)
LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 20, 4); // Change to (0x27,20,4) for 20x4 LCD.
const byte PulsePin = 2; // Input pin for counting
const byte ResetPin = 7; // Reset pin for counting
void setup()
{
// Initiate the LCD:
lcd.init();
lcd.backlight();
// declare pins with names
pinMode(PulsePin, INPUT);
pinMode(ResetPin, INPUT);
}
void loop()
{
static int PulseCount = 0;
static byte PulseState = LOW, ResetPulseState = LOW;
if (digitalRead(PulsePin) != PulseState)
{
if (PulseState == LOW)
{
PulseState = (HIGH);
PulseCount = PulseCount + 1;
lcd.setCursor(0,0);
lcd.print(PulseCount);
lcd.setCursor(0,1);
lcd.print("impulsions");
}
else
PulseState = LOW;
}
if (digitalRead(ResetPin) != ResetPulseState)
{
if (ResetPulseState == LOW)
{
ResetPulseState = (HIGH);
PulseCount = 0;
lcd.setCursor(0,0);
lcd.print(PulseCount);
lcd.setCursor(0,1);
lcd.print("impulsions");
}
else
ResetPulseState = LOW;
}
delay(50); //wait for 5 millisecond(s)
}
vrey strange attempt to evaluate if the button is pressed. I guess you found this code online and you can't explain how it works.
/*
Debounce
***********************************************************************
** **
** The "Bounce" library offers a much easier way to detect changes **
** **
***********************************************************************
Each time the input pin goes from LOW to HIGH (e.g. because of a push-button
press), the output pin is toggled from LOW to HIGH or HIGH to LOW. There's a
minimum delay between toggles to debounce the circuit (i.e. to ignore noise).
The circuit:
- LED attached from pin 13 to ground
- pushbutton attached from pin 2 to +5V
- 10 kilohm resistor attached from pin 2 to ground
- Note: On most Arduino boards, there is already an LED on the board connected
to pin 13, so you don't need any extra components for this example.
created 21 Nov 2006
by David A. Mellis
modified 30 Aug 2011
by Limor Fried
modified 28 Dec 2012
by Mike Walters
modified 30 Aug 2016
by Arturo Guadalupi
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/Debounce
*/
// constants won't change. They're used here to set pin numbers:
const int buttonPin = 2; // the number of the pushbutton pin
const int ledPin = LED_BUILTIN; // the number of the LED pin
// LED_BUILTIN is set to the correct LED pin independent of which board is used
// Variables will change:
int ledState = HIGH; // the current state of the output pin
int buttonState; // the current reading from the input pin
int lastButtonState = LOW; // the previous reading from the input pin
// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
unsigned long debounceDelay = 50; // the debounce time; increase if the output flickers
void setup() {
pinMode(buttonPin, INPUT);
pinMode(ledPin, OUTPUT);
// set initial LED state
digitalWrite(ledPin, ledState);
}
void loop() {
// read the state of the switch into a local variable:
int reading = digitalRead(buttonPin);
// check to see if you just pressed the button
// (i.e. the input went from LOW to HIGH), and you've waited long enough
// since the last press to ignore any noise:
// If the switch changed, due to noise or pressing:
if (reading != lastButtonState) {
// reset the debouncing timer
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
// whatever the reading is at, it's been there for longer than the debounce
// delay, so take it as the actual current state:
// if the button state has changed:
if (reading != buttonState) {
buttonState = reading;
// only toggle the LED if the new button state is HIGH
if (buttonState == HIGH) {
ledState = !ledState;
}
}
}
// set the LED:
digitalWrite(ledPin, ledState);
// save the reading. Next time through the loop, it'll be the lastButtonState:
lastButtonState = reading;
}
by the way, currently you have these lines two times in the code. That's unwanted duplicated code.
You could introduce a simple function doing the lcd print out and call that function wherever you need it. There a other ways to avoid this, but I think in the current stage that might be the easiest for you.
Thanks dr-o !
But then, the issue with lcd.clear() is that it will clear my whole LCD.
Next step of my project is to have other values written in the LCD that I don't want to clear.
Is it possible to clear only one line or a certain numbers of characters ?
Thanks StefanL38 ! yes it's half true. I know it's not the good way to learn but in fact, I am trying to learn by making some tests and when I see it working, I try to understand how. I first made my pulse working on the serial monitor, in this monitor, I was able to reset the count. Then, I set-up the LCD and finally I tried to mix both cases..
What I understood is that I declare my pins in input mode. Then I start something that I called the counter and made it start at 0, and each time an input is high, i do an addition on it. If the other one is high, my counter receive back the original value of 0. And this is done constantly.
barika:
Thanks dr-o !
But then, the issue with lcd.clear() is that it will clear my whole LCD.
Next step of my project is to have other values written in the LCD that I don't want to clear.
Is it possible to clear only one line or a certain numbers of characters ?
Check noiasca His answer and dont forget to Press that add Karma Button for the good man
Next step of my project is to have other values written in the LCD that I don't want to clear.
Is it possible to clear only one line or a certain numbers of characters ?
you have declared your
PulseCount as int
so most digits used will be for a value like
-32768
--> 6 digits.
therefore what you could consider is
Thanks for your help and support ! So it took me more than an afternoon to make some progress.
Here is below my code. Can you please check and confirm if I am right or if I use unecessary code ?
Regarding the reset, on the serial, it works. On the LCD, it does not but I understood why. I am now doing some tests with the printf function to handle the total number on the LCD and reset it completely (in place to just replace the first number by zero). Further step will be to handle an "infinite counter" (at least more than 32768 pulses) with the Nick Gammon library: http://www.gammon.com.au/forum/?id=11519
Here my code so far:
interrupt on pin 2 with debounce for the pulse reading
button on pin 7 with debounce and ezbutton to reset my counter
LCD I2C
factorK: to set the value of my pulse
// WireData - Version: Latest
#include <Wire.h>
// LiquidCrystal I2C - Version: Latest
#include <LiquidCrystal_I2C.h>
// ezButton - Version: Latest
#include <ezButton.h>
LiquidCrystal_I2C lcd(0x27, 20, 4); // I2C address 0x27, 20 column and 4 rows
int counter = 0; //Create a variable named counter, that is an integer (whole number) and has a starting value of 0
int factorK = 1; //set up of the K factor of the flowmeter
const PulseInput(2); //the input will always remain an input
ezButton button(7); // create ezButton object that attach to pin 7;
void setup() {
Serial.begin(9600);
lcd.init(); // initialize the lcd
lcd.backlight(); //start backlight
pinMode(PulseInput, INPUT);
attachInterrupt(digitalPinToInterrupt(PulseInput), count, RISING);
button.setDebounceTime(100); // set debounce time to 100 milliseconds
}
void loop() {
Serial.println(counter);
button.loop(); // MUST call the loop() function first
if(button.isPressed())
counter= 0;
lcd.setCursor(0,0);
lcd.print(counter);
}
void count()
{
static unsigned long lastInterrupt = 0;
unsigned long interruptTime = millis();
if (interruptTime - lastInterrupt > 150)
{
counter+=factorK; //here the counter is incremented by 1 x factorK for each pulse
}
lastInterrupt = interruptTime;
}
If you have any comments or advice that I should take care with that first part of code, I will really appreciate.
Thanks all
++
describe your pulse - what are you measuring in reality?
Because it somehow curious that you use an interrupt to identify the pulse and you do a debounce of 150milliseconds. If this works together - I doubt that you need an interrupt at all.
b) check the
int counter = 0;
will it be ever needed to get negative? Why an signed integer? Wouldn't a uint16_t be more appropriate?
a) in reality, we will count pulses coming from a reed switch. Actually, I don't have the flowmeter wired, so I just use two wires and do my pulses by hand. Step by step, I want to add other feature to this automation. Therefore, I was thinking to use interrupt for the reed switch because I don't want to miss any pulse. If I understood well, interrupt is used to "create an event" outside of the loop. If my loop begin to be long, I can perhaps miss one interrupt ? Right ?
b) I have to check, I don't understand
will it be ever needed to get negative? Why an signed integer? Wouldn't a uint16_t be more appropriate?
It will not be negative, the counter will always increase. I will search about uint_16
Thanks
No an interrupt-service.routine in short isr will not miss any counts because it is what it is an interrupting service routine.
This means 1 microsecond after the attached IO-pin does detect a state-change low-to-high your "standard-code" gets interrupted and the isr is executed. inside the isr you count up a variable. This construction ensures that all pulses get counted. a reed-switch will do some bouncing.
bouncing means contact closes opens again and closes again multiple times but in a very fast sequence
so the isr has to take care of this too.
if your maximum-frequency of pulses comes near to the "debounce"-time this would be a problem.
Then you would have to search for another solution.
There are also possabilitiy to debounce through adding a capacitor of a well chosen value.
So what is the maximum-frequency of the pulses that can occur?
Finally I get my LCD working and clearing totally the value of my counter with the following code. The counter is now limited to 5 digits but first step is done.
Should I set the post solved ?
// WireData - Version: Latest
#include <Wire.h>
// LiquidCrystal I2C - Version: Latest
#include <LiquidCrystal_I2C.h>
// ezButton - Version: Latest
#include <ezButton.h>
LiquidCrystal_I2C lcd(0x27, 20, 4); // I2C address 0x27, 20 column and 4 rows
int counter = 0; //Create a variable named counter, that is an integer (whole number) and has a starting value of 0
int factorK = 1; //set up of the K factor of the flowmeter
char compteur[20] = ""; //define the "size" of the CHAR where we sprintf the specific message
char unitofcounter[6] = "litres"; // set the unit we display for the counter
const PulseInput(2); //the input will always remain an input
ezButton button(7); // create ezButton object that attach to pin 7;
void setup() {
Serial.begin(9600);
lcd.init(); // initialize the lcd
lcd.backlight(); //start backlight
pinMode(PulseInput, INPUT);
attachInterrupt(digitalPinToInterrupt(PulseInput), count, RISING);
button.setDebounceTime(100); // set debounce time to 100 milliseconds
}
void loop() {
Serial.println(counter);
button.loop(); // MUST call the loop() function first
if(button.isPressed())
counter= 0;
sprintf(compteur,"%5d %s",counter, unitofcounter);
lcd.home(); // met le curseur en position (0;0) sur l'écran
lcd.print(compteur); // envoi le message sur l'écran
}
void count()
{
static unsigned long lastInterrupt = 0;
unsigned long interruptTime = millis();
if (interruptTime - lastInterrupt > 150)
{
counter+=factorK; //here the counter is incremented by 1 x factorK for each pulse
}
lastInterrupt = interruptTime;
}
@JimLee: as you keep on advertising your LC_Basetools-library I finally gave myself a tap to look into it.
Seems to be useful. I Usually start with looking at the examples.
As this all is for free of course everybody is free to document as much or less as they want.
Anyway I allow myself to comment on it.
The mechanic-button-beginner-example could have additionally information about how to electrically connect a button.
to ground using the internal pullup or to +Vcc using the an external pull-down and a link to the Arduino-Tutorial
I estimate this link to be stable at least for some years from now
You define a word for pin-number 2 and then use a hardcoded digit in
mechButton button1(2); // Set button one to pin 2.
instead of
mechButton button1(BUTTON1_PIN); // Set button one to defined pin
The intermediate mech-button shows the basic principle.
How about adding an example that does a little more than just printing to the serial monitor
and some additional information that this is a event-driven approach combined with an allday example?
to me personal the name idle() for doing the backround-stuff is confusing. It is not standing by at "low throttle"
it is essential to make it work. The name of this function should reflect what it is doing.
But I'm beginning to hijack this thread. So what would be the best suited place to write some more comments on this and maybe discuss it?
barika: @StefanL38 who is @JimLee ? and where to read more about the library you are talking ?
++
oops I must have chosen the wrong thread for answering
To explain it in short Jim Lee is another user online here who has written a library for timing and buttons and similar things which is called LC_basetools
Whenever you search something google Arduino Github Keyword in 90% of all cases google find relevant information
best regards Stefan