you want to add 0.01 to value at 2 different speeds
the fastest you can do this is every loop so the question is shouldn't you be trying to slow down how often 0.01 is added in the first 500ms as the fastest speed is already controlled by the loop speed
I don't think you need to monitor button state. really you just need 2 timers
if button is pressed add 0.01 every 100ms
after 500ms add 0.01 every 0ms
basically this is one timer (500ms) controlling the interval of the second timer (this one adds the 0.01 at either 100ms or 0ms)
I wrote a example using serial print. Is this what you are trying to do?
open serial monitor to see how it works
p.s slow speed is set at 3 seconds and slow count at 100ms per addition.
float value = 0;
#define buttonPin 2
unsigned long interval_1 = 100;
unsigned long interval_2 = 3000;
unsigned long previousMillis1 = 0;
unsigned long previousMillis2 = 0;
void setup() {
Serial.begin(9600);
pinMode(buttonPin, INPUT_PULLUP);
}
void loop() {
unsigned long currentMillis = millis();
byte button = digitalRead(buttonPin);//added this as it assists
//with problem solving e.g i can print state of the button
//below is a timer that only runs when button is pressed
//try to understand that the time stamp is being written
//when the button is high
//every loop in the code so it acts like its being reset
// previousMillis2 = currentMillis;
if (currentMillis - previousMillis2 >= interval_2) {
//timer2 is done
interval_1 = 0;//this is for timer1
} else {
//timer2 not done
interval_1 = 100;//this is for timer1
}
if (button == LOW) {//only do this with button pushed
//add 0.01 based on timer1
if (currentMillis - previousMillis1 >= interval_1) {
value = value + 0.01;
previousMillis1 = currentMillis;
}
} else {//button is high, not pressed
previousMillis2 = currentMillis;
}
Serial.print(interval_1);
Serial.print(" ");
Serial.println(value);
}
made some changes to your original code. It doesn't work as you have said it would (count at 2 different speeds) but the state change seems to works now.
compare to your original code to see the changes made (mainly had to move the time stamp and change the >< as it was changing state from 0 to 2 then after 500ms to 1)
try to understand how the time stamp works when using millis() timers. taken a new time stamp every loop then comparing it on the next line is never going to work.
long prev = 0;
int buttonState = 0; // 0 = not pressed --- 1 = long pressed --- 2 short pressed
float value = 0;
#define button 2
int longpresstime = 3000;
void setup() {
Serial.begin(9600);
pinMode(button, INPUT_PULLUP);
}
void loop() {
buttonState = 0;
if (digitalRead(button) == LOW) {
// prev = millis();
buttonState = 1;
while ((millis() - prev) >= longpresstime) {
if (digitalRead(button == LOW)) {
buttonState = 2;
break;
}
}
} else {
prev = millis();
}
if (!buttonState) {
//do nothing
} else if (buttonState == 1) {
value = value + 0.01;
// TODO button is pressed long
} else if (buttonState == 2) {
value = value + + 0.01;
}
Serial.print(buttonState);
Serial.print(" ");
Serial.println(value);
}
thanks for your help.
Robin, I see your code in linked post.
btnVal = digitalRead(btnPin);
if (btnVal == HIGH) { // assumes btn is LOW when pressed
lastBtnPressMillis = millis(); // btn not pressed so reset clock
}
if (millis() - lastBtnPressMillis > = interval) {
// button has been pressed for longer than interval
}
but I can't understand it.
Please, can you post the entire part of code regarding button short and long press?
Great! Reading your link, I have almost solved my issue.
This is the code
#include <LiquidCrystal.h>
#include <Time.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
#define buttonPin 2 // digital input pin to use as a digital input
#define debounce 20 // ms debounce period to prevent flickering when pressing or releasing the button
#define holdTime 750 // ms hold period: how long to wait for press+hold event
// Button variables
int buttonVal = 0; // value read from button
int buttonLast = 0; // buffered value of the button's previous state
long btnDnTime; // time the button was pressed down
long btnUpTime; // time the button was released
boolean ignoreUp = false; // whether to ignore the button release because the click+hold was triggered
//Value to increment
float value = 0;
//=================================================
void setup(){
lcd.begin(16, 2); //Start Initial Banner
// Set button input pin
pinMode(buttonPin, INPUT_PULLUP);
}
//=================================================
void loop(){
lcd.setCursor(0,0);
lcd.print(value);
// Read the state of the button
buttonVal = digitalRead(buttonPin);
// Test for button pressed and store the down time
if (buttonVal == LOW && buttonLast == HIGH && (millis() - btnUpTime) > long(debounce)){
btnDnTime = millis();
}
// Test for button release and store the up time
if (buttonVal == HIGH && buttonLast == LOW && (millis() - btnDnTime) > long(debounce)){
if (ignoreUp == false) event1();
else ignoreUp = false;
btnUpTime = millis();
}
// Test for button held down for longer than the hold time
if (buttonVal == LOW && (millis() - btnDnTime) > long(holdTime)){
event2();
ignoreUp = true;
btnDnTime = millis();
}
buttonLast = buttonVal;
}
//=================================================
// Events to trigger by click and press+hold
void event1(){
value = value + 0.01;
}
void event2(){
value = value + 0.10;
}
So, now with a Short press the value is incremented by 0.01 while when a press+hold is detected, the value is incremented by 0.10.
I see that holdTime affect the increment speed. So, if the hold time is 750ms, during press+hold the value is incremented by 0.10 every 750 ms.
My goal is:
wait 750ms to start press+hold function
run function every 300 ms in order to get a faster increment
mikseven:
I see the checkbutton() function and tested it.
the main issue is that executes the press+hold function only one time until button is released.
I am not really familiar with that code and I don't understand the exact problem you are dealing with.
Can you explain exactly what you want to happen.
And then explain the shortcomings in that code.
I find it much easier to expand from a known working position than to start with a complex solution.
Press + Hold - wait 750 ms and then increment by 0.10 with a frequency of 350ms until I release the button. For this function also a 0.01 increment with a frequency of 35 ms is accepted
In the first code holdTime affect also the frequency of increments.
#include <LiquidCrystal.h>
#include <Time.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
#define buttonPin 2 // digital input pin to use as a digital input
#define debounce 20 // ms debounce period to prevent flickering when pressing or releasing the button
#define holdTime 350 // ms hold period: how long to wait for press+hold event
// Button variables
int buttonVal = 0; // value read from button
int buttonLast = 0; // buffered value of the button's previous state
long btnDnTime; // time the button was pressed down
long btnUpTime; // time the button was released
boolean ignoreUp = false; // whether to ignore the button release because the click+hold was triggered
//Value to increment
float value = 0;
//=================================================
void setup(){
lcd.begin(16, 2); //Start Initial Banner
// Set button input pin
pinMode(buttonPin, INPUT_PULLUP);
}
//=================================================
void loop(){
lcd.setCursor(0,0);
lcd.print(value);
// Read the state of the button
buttonVal = digitalRead(buttonPin);
// Test for button pressed and store the down time
if (buttonVal == LOW && buttonLast == HIGH && (millis() - btnUpTime) > long(debounce)){
btnDnTime = millis();
}
// Test for button release and store the up time
if (buttonVal == HIGH && buttonLast == LOW && (millis() - btnDnTime) > long(debounce)){
if (ignoreUp == false) event1();
else ignoreUp = false;
btnUpTime = millis();
}
// Test for button held down for longer than the hold time
if (buttonVal == LOW && (millis() - btnDnTime) > long(holdTime)){
event2();
ignoreUp = true;
btnDnTime = millis();
}
buttonLast = buttonVal;
}
//=================================================
// Events to trigger by click and press+hold
void event1(){
value = value + 0.01;
}
void event2(){
value = value + 0.10;
}
in the second code, achieved from link you posted, all function related to button are executed only on button release, so if I press and hold the button the increment will be execute only one time at button release.
I have inserted variuos increment values for any event, in order to monitor behavior.
#include <LiquidCrystal.h>
#include <Time.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
#define buttonPin 2 // analog input pin to use as a digital input
// Button timing variables
int debounce = 20; // ms debounce period to prevent flickering when pressing or releasing the button
int DCgap = 250; // max ms between clicks for a double click event
int holdTime = 750; // ms hold period: how long to wait for press+hold event
int longHoldTime = 1000000; // ms long hold period: how long to wait for press+hold event
// Other button variables
boolean buttonVal = HIGH; // value read from button
boolean buttonLast = HIGH; // buffered value of the button's previous state
boolean DCwaiting = false; // whether we're waiting for a double click (down)
boolean DConUp = false; // whether to register a double click on next release, or whether to wait and click
boolean singleOK = true; // whether it's OK to do a single click
long downTime = -1; // time the button was pressed down
long upTime = -1; // time the button was released
boolean ignoreUp = false; // whether to ignore the button release because the click+hold was triggered
boolean waitForUp = false; // when held, whether to wait for the up event
boolean holdEventPast = false; // whether or not the hold event happened already
boolean longHoldEventPast = false;// whether or not the long hold event happened already
//value to increment
int value = 0;
void setup(){
lcd.begin(16, 2); //Start Initial Banner
// Set button input pin
pinMode(buttonPin, INPUT_PULLUP);
}
void loop(){
lcd.setCursor(0,0);
lcd.print(value);
// Get button event and act accordingly
int b = checkButton();
if (b == 1) clickEvent();
if (b == 2) doubleClickEvent();
if (b == 3) holdEvent();
if (b == 4) longHoldEvent();
}
//=================================================
// Events to trigger by click and press+hold
void clickEvent() {
value++;
}
void doubleClickEvent() {
value = value +2;
}
void holdEvent() {
value = value + 10;
}
void longHoldEvent() {
value = value + 50;
}
int checkButton()
{
int event = 0;
// Read the state of the button
buttonVal = digitalRead(buttonPin);
// Button pressed down
if (buttonVal == LOW && buttonLast == HIGH && (millis() - upTime) > debounce) {
downTime = millis();
ignoreUp = false;
waitForUp = false;
singleOK = true;
holdEventPast = false;
longHoldEventPast = false;
if ((millis()-upTime) < DCgap && DConUp == false && DCwaiting == true) DConUp = true;
else DConUp = false;
DCwaiting = false;
}
// Button released
else if (buttonVal == HIGH && buttonLast == LOW && (millis() - downTime) > debounce) {
if (not ignoreUp) {
upTime = millis();
if (DConUp == false) DCwaiting = true;
else {
event = 2;
DConUp = false;
DCwaiting = false;
singleOK = false;
}
}
}
// Test for normal click event: DCgap expired
if ( buttonVal == HIGH && (millis()-upTime) >= DCgap && DCwaiting == true && DConUp == false && singleOK == true) {
event = 1;
DCwaiting = false;
}
// Test for hold
if (buttonVal == LOW && (millis() - downTime) >= holdTime) {
// Trigger "normal" hold
if (not holdEventPast) {
event = 3;
waitForUp = true;
ignoreUp = true;
DConUp = false;
DCwaiting = false;
//downTime = millis();
holdEventPast = true;
}
// Trigger "long" hold
if ((millis() - downTime) >= longHoldTime) {
if (not longHoldEventPast) {
event = 4;
longHoldEventPast = true;
}
}
}
buttonLast = buttonVal;
return event;
}
I can see now why there is a limitation in the other guy's code.
All I can suggest is a few more hours thinking about the problem and its solution.
Maybe the answer is as simple as recording millis() when the button is pressed (after being released) and doing various things at intervals thereafter.
When the button is released and if the time was short do whatever is appropriate for a short press.
gpop1:
did you ever test the code I posted in reply#2
ops, I totally missed your post.
Just Tried (added some changes and display). Yes now I'm almost near the target.
With short press i have 0.01 increments.
If i hold the button it increments by 0.01 at frequency of 200 until it reach the interval 2. Then it increments by 0.01 at frequency of 30.
It's almost ok, but i see some debouncing on short press.
I'm thinking a solution to avoid it
#include <LiquidCrystal.h>
#include <Time.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
float value = 0;
#define buttonPin 2
unsigned long interval_1 = 30;
unsigned long interval_2 = 1000;
unsigned long previousMillis1 = 0;
unsigned long previousMillis2 = 0;
void setup() {
lcd.begin(16, 2); //Start Initial Banner
Serial.begin(9600);
pinMode(buttonPin, INPUT_PULLUP);
}
void loop() {
unsigned long currentMillis = millis();
byte button = digitalRead(buttonPin);//added this as it assists
//with problem solving e.g i can print state of the button
//below is a timer that only runs when button is pressed
//try to understand that the time stamp is being written
//when the button is high
//every loop in the code so it acts like its being reset
//previousMillis2 = currentMillis;
if (currentMillis - previousMillis2 >= interval_2) {
//timer2 is done
interval_1 = 30;//this is for timer2
} else {
//timer2 not done
interval_1 = 200;//this is for timer1
}
if (button == LOW) {//only do this with button pushed
//add 0.01 based on timer1
if (currentMillis - previousMillis1 >= interval_1) {
value = value + 0.01;
previousMillis1 = currentMillis;
}
} else {//button is high, not pressed
previousMillis2 = currentMillis;
}
Serial.print(interval_1);
Serial.print(" ");
Serial.println(value);
lcd.setCursor(0,0);
lcd.print(value);
}