How to reset total counter on LCD

Hi from France !

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)
}

Thanks

Yeah the Thing with

lcd.setCursor(0,0);
      lcd.print(PulseCount);

Is, it Just writes the necessary characters and move on. Try using lcd.clear()

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;
}

best regards Stefan

Is, it Just writes the necessary characters and move on. Try using lcd.clear()

this, or (because lcd.clear() is quite slow,) write some blanks after your number. This will delete eventually digits from the last print.

      lcd.setCursor(0, 0);
      lcd.print(PulseCount);
      lcd.print("        ");
      lcd.setCursor(0, 1);
      lcd.print("impulsions");

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.

I guess you are facing the floating input issue due to not use pull-up or pull-down for reset pin 7. See this button tutorial for more detail.

Moreover, I recommend to debounce for button without using delay() function. All will become easy if you use the ezButton library

Thanks all, will give a try this afternoon and make you know.

Thanks for your inputs.

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 :wink:

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

lcd.setCursor(yourPosition, yourRow);
lcd.print(" "); // 6 blanks
lcd.setCursor(yourPosition, yourRow);
lcd.print(yourValue);

only the positions of your value will be deleted.

By the way ... if you think about your pulse count ... to you really think it will ever get negative?

@dr-o: thank you for reading my posts ^^, Karma++

FYI, see post #4.

https://forum.arduino.cc/index.php?topic=717760.msg4821839#msg4821839

Hi all,

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
++

two comments:

a)

count pulse with Pin 2

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?

Thanks.

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?

best regards Stefan

Hi Stefan,

I already use the ISR for the reedswitch and it's working well. I debounce it with the code and it looks to be working.

At least, I can have a pulse every 0,2 seconds, 5Hz. I think it will be ok.

Thanks Stefan

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;
}

Thanks for all your great help.

you can edit the header of your entry post to something like

How to reset total counter on LCD [solved]

@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?

best regards Stefan

@StefanL38 who is @JimLee ? and where to read more about the library you are talking ?

++

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