Menu Selection WIndow Creation for LCDsheild and arduino Interface - c

I am trying to create Menu Selection process.if SELECT button pressed once should display the Display parameter and if select button pressed twice should goes to Set_parameter window(Where we set parameter). once it is display parameter using up and down arrow Choose the Display window .But problem i am facing here is It enter the Display parameter but comes out Menu window directly .
Circuit diagram for LCD is given here
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
// Pin configuration of the buttons
#define btnRIGHT 0 // Okay
#define btnUP 1 // inc
#define btnDOWN 2 // dec
#define btnLEFT 3 // Select
#define btnSELECT 4 // Menu
#define btnNONE 5
#define beeper A1 // Alarm buzzer
#define shortBeep 100
#define longBeep 500
int button_counter=0;
void setup()
{
Serial.begin(9600);
}
void loop()
{
Select_Menu();
}
void Select_Menu()
{
lcd.begin(16,2);
lcd.setCursor(0,0);
lcd.print("MENU");
int button=read_LCD_buttons();
if(button==btnSELECT)
{
button_counter=button_counter+1
}
if(button_counter==1)
{
Display_function();
}else if((button_counter==2))
{
Set_function();
}else
{
button_counter=0;
}
}
void Display_function()
{
int button = read_LCD_buttons();
if(button==btnUP)
{
button_counter=button_counter+1;
Serial.print("button_counter");
Serial.println(button_counter);
}else if(button==btnDOWN)
{
button_counter=button_counter-1;
Serial.println(button_counter);
}
if (button_counter>5)
{
button_counter=1;
}else
while(button_counter<5)
{
int button = read_LCD_buttons();
if(button != prev_button && button != btnNONE)
{
prev_button = button;
//timedBeep(shortBeep,2);
}
if ((((button ==btnUP )||(button_counter==1))||((button ==btnDOWN )))&&(prev_button==btnUP)
{
digitalClockDisplay();//timedBeep(200,1);
}else if((((button ==btnUP )||(button_counter==2))||((button ==btnDOWN )))&&(prev_button==btnUP))
{
Display_angle();//timedBeep(200,1);
}else if((((button ==btnUP )||(button_counter==3))||((button ==btnDOWN )))&&(prev_button==btnUP))
{
Display_coordinate();//timedBeep(200,1);
}else if((((button ==btnUP )||(button_counter==4))||((button ==btnDOWN )))&&(prev_button==btnUP))
{
button_loop();//timedBeep(500,4);
}else if((((button ==btnUP )||(button_counter==5))||((button ==btnDOWN )))&&(prev_button==btnUP))
{
Display_Wind();//timedBeep(200,1);
}
}
}
void Display_Wind()
{
lcd.setCursor(0,0);
lcd.print("WS kmph:");
lcd.print(Wind_Kmph);
lcd.setCursor(0,1);
lcd.print("WS m/s:");
lcd.print(Wind_Speed);
}
void button_loop()
{
lcd.begin(16,2);
lcd.setCursor(0,0);
lcd.print("Welcome");
}
void Display_coordinate()
{
lcd.begin(16,2);
lcd.setCursor(0,0);
lcd.print("Latitude:");
lcd.print(latitude);
lcd.setCursor(0,1);
lcd.print("Longitude:");
lcd.print(longitude);
}
void Display_angle()
{
lcd.begin(16,2);
lcd.setCursor(0,0);
lcd.print("DESIRED: ");
lcd.print(tracker_des_angle,DEC);
lcd.setCursor(0,1);
lcd.print("ACTUAL: ");
lcd.print(tracker_actual_pos,DEC);
}
void digitalClockDisplay()
{
lcd.begin(16,2);
lcd.setCursor(0,0);
lcd.print("Date:");
lcd.print(local_day);
lcd.print("/");
lcd.print(local_month);
lcd.print("/");
lcd.print(local_year);
lcd.setCursor(0,1);
lcd.print("Time:");
lcd.print(local_h);
lcd.print(":");
lcd.print(local_m);
lcd.print(":");
lcd.print(local_s);
lcd.print(" ");
}
int read_LCD_buttons()
{
adc_key_in = analogRead(0); // read the value from the sensor
// my buttons when read are centered at these valies: 0, 131, 307, 481, 722
// we add approx 50 to those values and check to see if we are close
// No button pressed should be 1023
if (adc_key_in > 1000) return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result
if (adc_key_in < 50) return btnRIGHT;
if (adc_key_in < 195) return btnUP;
if (adc_key_in < 380) return btnDOWN;
if (adc_key_in < 555) return btnLEFT;
if (adc_key_in < 790) return btnSELECT;
return btnNONE; // when all others fail, return this...
}

You have a flow control problem.
Your main loop runs SelectMenu() in there you enter Display_function() which contains no loop so it reaches the end and returns to SelectMenu() which then returns to loop() which again calls SelectMenu() redrawing your menu and overwriting the display with the menu again.
There are many ways to solve this, but as this is an arduino environment where resources are anything other than endless I would suggest you make each "page" its own loop breaking out of it when needing to move on. Do not switch pages inside the loops or you will build up quite the callstack.
Pseudo code:
loop():
#print and handle input
if (navigate)
Display_function()
Display_function():
while(true)
# print and do whatever
if (nav_angle)
Display_angle()
else if (nav_coord)
Display_coordinate()
#... etc.
if (nav_back)
return
Display_angle():
while(true)
#do stuff
if (nav_back)
return
This should give you the idea, it will work as long as you don't have too deep of a structure and run out of memory.

Related

How to return back to the initial screen when button is pressed?

I have three screens in the LCD connected to the 8051-microcontroller that scroll to the different screen when the button is pressed but I want to return back to the initial screen when again button is pressed. How can I do that, thank you?
#include <stdio.h>
#include <string.h>
#include <stdint.h>
void change_screen(void);
int count = 0;
void change_screen(void)
{
if (modebutton == 1) { // when button is pressed
if (count == 0) {
count++;
delay(100);
display_screen1();
modebutton=0;
}
else if (count == 1) {
count++;
delay(100);
display_screen2();
modebutton=0;
}
else if (count == 2) {
display_screen3();
count = 0;
}
}
}
You can use the remainder operator % for this.
Example:
void change_screen(void) {
static unsigned count = 0;
if(modebutton) {
delay(100);
modebutton = 0;
switch(count) {
case 0: display_screen1(); break; // first fourth ...
case 1: display_screen2(); break; // second fifth
case 2: display_screen3(); break; // third sixth
}
count = (count + 1) % 3; // 0,1,2 then 0,1,2 etc...
}
}

7Digit Display counting bug

I am trying to fix the bug in my code - I have 7Digit display, which must count up from 0 to 99 when button is not pressed, or count down from 99 to 0 when button is pressed.
I have the issue with counting up, the issue happens, when the display must show numbers as 10,20,30 etc. While countin it up, after number 09 there is 00 instead of 10, after 19 there is 10 instead of 20 etc.
I am attching below a fragment of code responsible for counting up and down:
void Refresh_Display() {
AT91C_BASE_PIOB->PIO_CODR = A|B|C|D|E|F|G;
}
void set_Number(int number) {
AT91C_BASE_PIOB->PIO_SODR = LEFTDIGIT;
AT91C_BASE_PIOB->PIO_CODR = RIGHTDIGIT;
Refresh_Display();
Display_Number(number%10);
delay(5000);
AT91C_BASE_PIOB->PIO_SODR = RIGHTDIGIT;
AT91C_BASE_PIOB->PIO_CODR = LEFTDIGIT;
Refresh_Display();
Display_Number(number/10);
delay(5000);
}
void countdown(int i) {
while(1) {
if(i<=0) {
i = 99;
}
set_Number(i);
i--;
if(!BP1_Status) {
counter = i;
break;
}
}
}
void countup(int i) {
while(1) {
i++;
if(i>=99) {
i = 0;
}
set_Number(i);
if(BP1_Status) {
counter = i;
break;
}
}
}
int main(void){
Port_init();
Button_init();
while(1) {
for (volatile int i=0;i<100;i++) {
if(BP1_Status) {
countdown(counter);
} else if (!BP1_Status) {
countup(counter);
}
}
}
}
I have a solution for that problem:
In the ARM processor AT91SAM9263 there are registers PIO_CODR and PIO_SODR. The first one register is refreshing data, the second one Sets the data to be driven on the I/O line.
I have swapped the method of display the numbers on two 7Segment Displays. On the left, there are displayed, the decimal numbers are displayed as number/10 and the units as numbers%10to receive 0 digit on second display while showing 10 or 20 value.
void set_Number(int number) {
AT91C_BASE_PIOB->PIO_CODR = LEFTDIGIT;
AT91C_BASE_PIOB->PIO_SODR = RIGHTDIGIT;
Refresh_Display();
Display_Number(number/10);
delay(5000);
AT91C_BASE_PIOB->PIO_CODR = RIGHTDIGIT;
AT91C_BASE_PIOB->PIO_SODR = LEFTDIGIT;
Refresh_Display();
Display_Number(number%10);
delay(5000);
}

RPi 4 GPIO Interrupt on Rising and Falling trigger not working in C

Beginner here learning to code linux kernel modules.
I want to write a kernel module for my RPi 4 in C language.
I want to use interrupts to light on a LED when I push a button. As long as the button is pushed, the LED is on and when I release it, the LED is supposed to turn off.
I use the function request_irq() so that my function handling the interrupt is called on the rising edge and on the falling edge of my button by indicating "IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING". I formerly used the function gpio_to_irq(BUTTON_PIN).
request_irq(button_irq, button_ih, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "button_irq", NULL);
The function is called when I push the button but not when I release it. It is coded as seen below :
static irqreturn_t button_ih(int irq, void *data)
{
int state;
state = gpio_get_value(BUTTON_PIN);
printk(KERN_INFO "Actual state of the button : %d", state);
//Debounce condition
if(jiffies - last_interrupt_time > msecs_to_jiffies(200))
{
if(state)
{
gpio_set_value(LED_PIN, 1);
}else
{
gpio_set_value(LED_PIN, 0);
}
}
last_interrupt_time = jiffies;
return IRQ_HANDLED;
}
I check whether the value of the button is 1 (pressed) or 0 (released) and want to turn on/off the LED accordingly.
When I try different GPIOs, sometimes, the value of my button is 1 even though I haven't pushed it yet(by printing a message from the init function) and sometimes it's 0. So I don't understand if I'm doing something wrong. I don't think the GPIOs are already used cause I can request them with the function gpio_request_one().
So when the button already has the value 1, the LED turn on but won't switch off when I release the button.
And when the value is already 0, the button value doesn't change to become 1 when I enter the interrupt handler function (and the LED obviously doesn't turn on).
Could you tell me what's wrong with it please?
Form simple C program, not kernel module
This minimal to see how I'm doing.
main.h
typedef struct s_Data {
int exitFlag;
struct {int value; int bcmPin;} In01; //<--- Stock actual GPIO Value
struct {int value; int bcmPin;} In02;
....
struct {int value; int bcmPin;} Out01;
struct {int value; int bcmPin;} Out02;
....
} t_Data;
#define NO_Click 0
#define SimpleClick 1
#define LongClick 2
#define MultiClick 3
typedef struct s_Button {
pthread_t button_thread;
int *exitFlag;
int * input; //Button
int * output;
int old_state;
int new_state;
struct timeval t0;
struct timeval t1;
struct timeval pressedTime;
struct timeval releasedTime;
int clickType;
//float debounce = 0.020; // ms debounce period to prevent flickering when pressing or releasing the button
// debounce not necessary while thread have time to take a coffee
float DCgap; // max ms between clicks for a double click event
float holdTime; // ms hold period: how long to wait for press+hold event
} t_Button;
main.c
#include "main.h"
#include <wiringPi.h>
#include <pthread.h>
// initial state
static t_Data data = {
.exitFlag = 0,
.In01.value = 0, .In01.bcmPin = 4,
.In02.value = 0, .In02.bcmPin = 17,
.Out01.value = 0, .Out01.bcmPin = 4,
.Out02.value = 0, .Out02.bcmPin = 17,
}
static _Data data_prev;
static void *inputRead_threadFn(void *p_Data) {
pinMode(Data.In01.bcmPin, INPUT);
pullUpDnControl(Data.In01.bcmPin, PUD_UP);
pinMode(Data.In02.bcmPin, INPUT);
pullUpDnControl(Data.In02.bcmPin, PUD_UP);
while (!Data.exitFlag) {
Data.In01.value = !digitalRead(Data.In01.bcmPin);
Data.In02.value = !digitalRead(Data.In02.bcmPin);
if (Data.In01.value != Data_old.In01.value) {
Data_old.In01.value = Data.In01.value;
}
if (Data.In02.value != Data_old.In02.value) {
Data_old.In02.value = Data.In02.value;
}
usleep(50)
}
}
static void *outputWrite_threadFn(void *p_Data) {
pinMode(Data.In01.bcmPin, OUTPUT);
pinMode(Data.In02.bcmPin, OUTPUT);
while (!Data.exitFlag) {
digitalWrite(Data.Out01.bcmPin, !Data.Out01.value);
digitalWrite(Data.Out02.bcmPin, !Data.Out02.value);
}
usleep(50)
}
static void *button_threadFn(void *p_Data) {
t_Button *button = (t_Button *)p_data;
LOG("Button[%s] thread initialized\r\n", button->name);
button->old_state = 0;
button->new_state = 0;
button->clickType = NO_Click;
int clickCount = 0;
while(*(button->exitFlag) == 0) {
button->new_state = *(button->input) || *(button->web_input); //*((int *)
if( button->old_state == 0 && button->new_state == 1 ) {
//printf("front montant\r\n"); fflush(stdout);
// *****************************
// traitement sur front montant
// rising edge
// *****************************
button->old_state = 1;
gettimeofday(&button->pressedTime, 0);
//Button pressed
} else if( (button->old_state == 1) && (button->new_state == 0) ) {
//printf("front descendant\r\n"); fflush(stdout);
// *****************************
// traitement sur front descendant
// falling edge
// *****************************
button->old_state = 0;
gettimeofday(&button->releasedTime, 0);
if (my_timedifference_msec(button->releasedTime, button->pressedTime ) < button->DCgap) {
clickCount++;
button->clickType = MultiClick;
}
//Button released
} else if( (button->old_state == 0) && (button->new_state == 0) ) {
// printf("front bas\r\n"); fflush(stdout);
// *****************************
// pas de changement d'état : front bas
// no state change : edge down
// *****************************
gettimeofday(&button->t0, 0);
*(button->output) = 0; //<--- here in your case
//Attendre DC_Gap pour connaitre le nombre de click
// Wait for DC_Gap to know click count
if (my_timedifference_msec(button->t0, button->releasedTime) > button->DCgap) {
if (clickCount == 1) {
LOG("SimpleClick");
//Simple Click
} else if ( clickCount > 1 ) {
//Multiclicks
}
button->clickType = NO_Click;
clickCount = 0;
}
} else if( (button->old_state == 1) && (button->new_state == 1) ) {
// printf("front haut\r\n"); fflush(stdout);
// *****************************
// pas de changement d'état : front haut
// no state change : edge up
// *****************************
gettimeofday(&button->t1, 0);
*(button->output) = 1; //<--- here in your case
//long click
if (my_timedifference_msec(button->t1, button->pressedTime) >= button->holdTime) {
LOG("LongClick");
button->clickType = LongClick;
//do what you want while not released
usleep(30*1000);
}
}
usleep(100);
}
printf("Light Loop::exiting...\r\n"); fflush(stdout);
}
int main(int argc, char** argv) {
wiringPiSetup();
wiringPiSetupGpio();
data_prev = data;
//start input thread
//start output thread
int DCGap = 250; //ms
int HoldTime = 600;
t_Button Buttons[] = {
{ //WC
.exitFlag = &Data.exitFlag,
.DCgap = DCGap,
.holdTime = HoldTime,
.input = &Data.In01.value,
.output = &Data.Out01.value,
},
{ //chambre
.exitFlag = &Data.exitFlag,
.DCgap = DCGap,
.holdTime = HoldTime,
.input = &Data.In02.value,
.output= &Data.Out02.value,
}
}
//start buttons threads
for (i = 0; i < (sizeof(Buttons) / sizeof(t_Button)) ; i++) {
ret = pthread_create (&Buttons[i].button_threadFn, NULL, fn_Button, &Buttons[i]);
if (ret) {
fprintf (stderr, "%s", strerror (ret));
}
}
//threads join
return (EXIT_SUCCESS);
}
Ok so thanks for all the comments/answers.
It was indeed because I wasn't using any pull-up or pull-down resistor properly.
So I changed my circuit as following:
Circuit

SDL/C EventHandler continuous key

I'm trying to develop an event handler in C using SDL.
I wanted to be able to detect the following things: Key pressed, key released and key held down.
The problem is that keyboard auto-repeat spams pressed keys after a certain delay and at a given interval. To mitigate this I tried using SDL_EnableKeyRepeat(0, 0); which according to documentation should disable it?
As that failed I tried mapping SDL_GetKeyboardState(NULL); and it sort of works. But I'm having the issue that if i hold down a key for X seconds, it will spam ghost events for the same amount of time.
An example output from pressing esc, holding it down for a bit, and then releasing it is:
Pressed
HELD
HELD
HELD
...
RELEASED {it breaks down after first proper release}
PRESSED
RELEASED
HELD
PRESSED
RELEASED
HELD
...
RELEASED // it always ends on released.
The result from above is:
Pressed: 18;
Released: 21;
Held: 39.
Should be:
Pressed 1;
Released 1;
Held: say 20.
Not sure if I'm messing up my logic somehow, or if it's something with the actual built in mechanics of keyboard events.
Here is the code:
/**
Program Interface
void ev_handle_start() // Starts the Event Handler.
void ev_handle_stop() // Pauses the Event Handler.
**/
#include <stdio.h>
#include <SDL2/SDL.h>
#include <SDL/SDL.h>
#include "ev_handler.h"
#define PRESSED 1
#define RELEASED 0
#define TMR_FREQ 33
#define MOUSE_RIGHT 1
#define MOUSE_LEFT 3
#define EV_LEFT_CLICK 0
#define EV_LEFT_RELEASE 1
#define EV_RIGHT_CLICK 2
#define EV_RIGHT_RELEASE 3
#define EV_MOUSE_MAX 4
#define MAX_SCANCODES SDL_SCANCODE_MODE
#define EV_DELAY 70
//********************************************************************************************//
// VARIABLES
//********************************************************************************************//
SDL_Event e;
Uint8* keyboardState;
SDL_TimerID ev_timer = NULL; // Timer to callback the search of the code
bool ev_handler_active = false; // Used to determine if the ev_handler() is enabled or not
bool buttonState[EV_MOUSE_MAX]; // Button Stats, either pressed or released
bool evMouseEvent[EV_MOUSE_MAX]; // Used to flag if a mouse events
int evKeyEventStatus[MAX_SCANCODES];
bool evKeyStatePrev[MAX_SCANCODES]; //
bool evKeyStateCur[MAX_SCANCODES]; //
//********************************************************************************************//
// 1 FRONTEND
//********************************************************************************************//
//********************************************************************************************//
// 1.1 MOUSE
// Can only handle left and right mouse buttons.
//********************************************************************************************//
bool evButtonPressed(int button)
{ bool flag = button == SDL_BUTTON_RIGHT || button == SDL_BUTTON_LEFT;
if (!flag) {
printf("ERROR: isButtonPressed(int) received parameter of invalid type.\n");
return false;
}
return buttonState[button];
}
bool evLeftClick()
{
return evMouseEvent[EV_LEFT_CLICK];
}
bool evLeftRelease()
{
return evMouseEvent[EV_LEFT_RELEASE];
}
bool evRightClick()
{
return evMouseEvent[EV_RIGHT_CLICK];
}
bool evRightRelease()
{
return evMouseEvent[EV_RIGHT_RELEASE];
}
//********************************************************************************************//
// 1.2 KEYBOARD
//********************************************************************************************//
bool evKeyHeld(SDL_Scancode sc)
{
return evKeyEventStatus[sc] == 1 || evKeyEventStatus[sc] == 3;
}
bool evKeyPressed(SDL_Scancode sc)
{
return evKeyEventStatus[sc] == 1;
}
bool evKeyReleased(SDL_Scancode sc)
{
return evKeyEventStatus[sc] == 2;
}
//********************************************************************************************//
// 1.3 MANAGE
//********************************************************************************************//
void evSetup()
{
for (int i = 0; i < MAX_SCANCODES; i++) {
evKeyStatePrev[i] = 0;
}
evClearEvents();
}
int j;
void evClearEvents()
{
evMouseEvent[EV_LEFT_CLICK] = false;
evMouseEvent[EV_LEFT_RELEASE] = false;
evMouseEvent[EV_RIGHT_CLICK] = false;
evMouseEvent[EV_RIGHT_RELEASE] = false;
}
//********************************************************************************************//
// 2 BACKEND
//********************************************************************************************//
void ev_handler()
{
while(SDL_PollEvent(&e))
{
switch (e.type)
{
/*Skip unnecessary events*/
case SDL_KEYDOWN:
break;
case SDL_KEYUP:
break;
case SDL_MOUSEMOTION:
break;
case SDL_MOUSEBUTTONDOWN:
buttonState[e.button.button] = PRESSED;
if (e.button.button == SDL_BUTTON_LEFT) {
evMouseEvent[EV_LEFT_CLICK] = true;
}
else if (e.button.button == SDL_BUTTON_RIGHT) {
evMouseEvent[EV_RIGHT_CLICK] = true;
}
break;
case SDL_MOUSEBUTTONUP:
buttonState[e.button.button] = RELEASED;
if (e.button.button == SDL_BUTTON_LEFT) {
evMouseEvent[EV_LEFT_RELEASE] = true;
}
else if (e.button.button == SDL_BUTTON_RIGHT) {
evMouseEvent[EV_RIGHT_RELEASE] = true;
}
break;
case SDL_QUIT:
exit(0);
printf("Quit\n");
break;
default:
break;
}
keyboardState = SDL_GetKeyboardState(NULL);
for (int i = 0; i < MAX_SCANCODES; i++)
{
evKeyStateCur[i] = keyboardState[i];
int sum = evKeyStateCur[i] + evKeyStatePrev[i]*2;
switch (sum) {
case 0:
break;
case 1:
evKeyEventStatus[i] = 1;
break;
case 2:
evKeyEventStatus[i] = 2;
break;
case 3:
evKeyEventStatus[i] = 3;
break;
default: evKeyEventStatus[i] = 0; break;
}
evKeyStatePrev[i] = evKeyStateCur[i];
}
}
}
The problem was that SDL 2.0.4 had a bug where holding down a key sent key releases in-between key presses instead of continuous key presses. Downloading the latest version fixed the issue.

How to detect how long a button was pressed in Arduino?

How can I detect how long a button was pressed / released in Arduino and then print some custom output after that?
Arduino can only detect the state of your button (pressed OR unpressed).
You could use a timer variable (based on this example from their docs) to save the exact time when you pressed or released the button, so you can check the difference between both variables to calculate how long it is on hold or idle.
The code could look like this:
const int buttonPin = 2;
int buttonState = 0; // current state of the button
int lastButtonState = 0; // previous state of the button
int startPressed = 0; // the moment the button was pressed
int endPressed = 0; // the moment the button was released
int holdTime = 0; // how long the button was hold
int idleTime = 0; // how long the button was idle
void setup() {
pinMode(buttonPin, INPUT); // initialize the button pin as a input
Serial.begin(9600); // initialize serial communication
}
void loop() {
buttonState = digitalRead(buttonPin); // read the button input
if (buttonState != lastButtonState) { // button state changed
updateState();
}
lastButtonState = buttonState; // save state for next loop
}
void updateState() {
// the button has been just pressed
if (buttonState == HIGH) {
startPressed = millis();
idleTime = startPressed - endPressed;
if (idleTime >= 500 && idleTime < 1000) {
Serial.println("Button was idle for half a second");
}
if (idleTime >= 1000) {
Serial.println("Button was idle for one second or more");
}
// the button has been just released
} else {
endPressed = millis();
holdTime = endPressed - startPressed;
if (holdTime >= 500 && holdTime < 1000) {
Serial.println("Button was held for half a second");
}
if (holdTime >= 1000) {
Serial.println("Button was held for one second or more");
}
}
}
However, if you want to trigger an event while the button is still pressed (or maybe you want to increment a counter in some display), you can still do the same math.
Change your condition in the loop function to be like this:
if (buttonState != lastButtonState) {
updateState(); // button state changed. It runs only once.
} else {
updateCounter(); // button state not changed. It runs in a loop.
}
And then implement your new function like this:
void updateCounter() {
// the button is still pressed
if (buttonState == HIGH) {
holdTime = millis() - startPressed;
if (holdTime >= 1000) {
Serial.println("Button is held for more than a second");
}
// the button is still released
} else {
idleTime = millis() - endPressed;
if (idleTime >= 1000) {
Serial.println("Button is released for more than a second");
}
}
}
for your interest here's an example of code using 2 arrays to store button states of arduino pin given to the corresponding input button. During the loop you can do a simple check with the wanted repeat:
if(button_down(But1_pin, BTN_LOOP_DELAY_MS))
{
// code here repeated if the button is either clicked or maintained
}
button_down() also defers the first repeat by DELAY_WAIT_BEFORE_REPEAT ms.
Here the full tested example:
#define BTN_LOOP_DELAY_MS 100
#define DELAY_WAIT_BEFORE_REPEAT 500
#define NB_MAX_PIN_INPUT 13
#define But1_pin 7
#define But2_pin 6
// array to check status change
bool prev_button[NB_MAX_PIN_INPUT];
unsigned long button_last_down[NB_MAX_PIN_INPUT];
// macro : our read init with prev_button storage
#define READ_INIT_BUTTON(pin) \
do{ \
pinMode(pin, INPUT); \
prev_button[pin] = digitalRead(pin); \
} while(false)
// function at the end of the code
bool button_down(byte pin_num, unsigned int delay_repeated);
void setup() {
READ_INIT_BUTTON(But1_pin);
READ_INIT_BUTTON(But2_pin);
Serial.begin(115200);
}
void loop() {
if(button_down(But1_pin, BTN_LOOP_DELAY_MS))
{
Serial.print("new inpulse");
Serial.print(millis());
Serial.println();
}
if(button_down(But2_pin, BTN_LOOP_DELAY_MS))
{
Serial.println("button2");
}
}
bool button_down(byte pin_num, unsigned int delay_repeated)
{
bool b = digitalRead(pin_num);
bool r = false;
unsigned long currentMillis = millis();
if(prev_button[pin_num] != HIGH && b == HIGH)
{
r = true;
button_last_down[pin_num] = currentMillis + DELAY_WAIT_BEFORE_REPEAT;
}
else if(b == HIGH
&& prev_button[pin_num] == HIGH
&& currentMillis > button_last_down[pin_num]
&& currentMillis - button_last_down[pin_num] > delay_repeated
)
{
// save the last time we give a button impusle at true
button_last_down[pin_num] = currentMillis;
r = true;
}
// store button state, if changed
if(prev_button[pin_num] != b)
{
prev_button[pin_num] = b;
}
return r;
}
This following steps works:
If the button state satisfies.
Then read the millis() values one time(Using flag) and find the
duration by comparing with current millis() value.
void buttonLongPress() {
uint32_t duration = 0;
if (digitalRead(button_pin) == LOW) {
if (pressReadLimit == 0) {
pressTime = millis();
pressReadLimit = 1;
}
duration = millis() - pressTime;
if (duration >= 3000) {
Serial.println("Long press");
}
Serial.println(duration);
} else {
duration = 0;
pressReadLimit = 0;
}
}
Serial monitor result

Resources