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

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

Related

Timer not stopping at Zero D1 mini

Im currently trying to code a timer on a D1 mini that has three tactile switches and will display on a 64x48 OLED display, switch 1 and 2 will increase and decrease the time and 3 will start the time you have put in.
As of now when as it turns on the timer is in a stopped state and you can set your desired time input with switch 1 and 2 and then start the timer with switch 3 but when the timer counts down I want it to stop at 00:00 for you to then input a new time with switch 1 and 2 and then start it again with switch 3. The timer keeps going and does not appear to stop at 00:00.
Here is the code:
#include <Wire.h>
#include <Adafruit_SSD1306.h>
// SCL GPIO5
// SDA GPIO4
#define OLED_RESET 0 // GPIO0
Adafruit_SSD1306 display(OLED_RESET);
int switch1 = D3;
int switch2 = D4;
int switch3 = D5;
int minutes = 0;
int seconds = 0;
int originalMinutesValue = 0;
int originalSecondsValue = 0;
bool timerRunning = false;
bool isReset = false;
void setup() {
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.display();
delay(2000);
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(4,16);
pinMode(switch1, INPUT);
pinMode(switch2, INPUT);
pinMode(switch3, INPUT);
originalMinutesValue = minutes;
originalSecondsValue = seconds;
}
void loop() {
if(digitalRead(switch1) == LOW) {
if(seconds == 0) {
if(minutes > 0) {
minutes--;
seconds = 59;
}
} else {
seconds--;
}
delay(200);
}
if(digitalRead(switch2) == LOW) {
if(seconds == 59) {
minutes++;
seconds = 0;
} else {
seconds++;
}
delay(200);
}
if(digitalRead(switch3) == LOW) {
timerRunning = !timerRunning;
if(timerRunning && !isReset) {
isReset = true;
}
delay(200);
}
if(timerRunning){
if(seconds==0){
if(minutes>0){
minutes--;
seconds=59;
}else{
if(isReset){
minutes = originalMinutesValue;
seconds = originalSecondsValue;
isReset = false;
}else {
timerRunning = false;
}
}
}else{
seconds--;
}
delay(1000);
}
display.clearDisplay();
display.setCursor(4,16);
if(minutes < 10) {
display.print("0");
}
display.print(minutes);
display.print(":");
if(seconds < 10) {
display.print("0");
}
display.print(seconds);
display.display();
}
I have tried a lot of different workarounds but cannot get it to work. Please let me know if you might know the problem.

how to create condition using ros odom pose data?

I have a mobile autonomous robot that moves using Ros. My goal is to communicate with rosserial via arduino and subscribe to the odom topic. I would like to put some conditions on the exposure data I received after I became a member of Odom. In order to be able to perform some operations at certain points in the coordinates on my map. with a simple example
if (pose_x>2.17 &&pose_x<4.00 &&pose_y<7.6 &&pose_y>9.5 ){
digitalWrite(led_pin, HIGH - digitalRead(13));
}
I want to add conditions like but I don't know how to do that. I'm not very good at software.Below is the code I am trying to do with arduino. I may have been a little silly. I'm still very lacking. I will be grateful for all your help.
#include <ros.h>
#include <std_msgs/String.h>
#include <nav_msgs/Odometry.h>
#include <geometry_msgs/Twist.h>
#include <tf/transform_broadcaster.h>
#include <tf/tf.h>
ros::NodeHandle nh;
ros::Time current_time;
float TIME;
float pose_x, pose_y, angle_z;
geometry_msgs::Quaternion odom_quat;
tf::TransformBroadcaster odom_broadcaster;
std_msgs::String message;
ros::Publisher server_pub("/server_messages", &message);
const int button1_pin = 6;
const int button2_pin = 7;
const int led_pin = 13;
char button1[13] = "2";
char button2[13] = "3";
bool last_reading1;
long last_debounce_time1 = 0;
bool last_reading2;
long last_debounce_time2 = 0;
long debounce_delay = 50;
bool published1 = true;
bool published2 = true;
void odomCallback(const nav_msgs::Odometry & msg) {
nav_msgs::Odometry odom;
odom.header.stamp = current_time;
geometry_msgs::TransformStamped odom_trans;
odom_trans.header.stamp = current_time;
odom_trans.transform.translation.x = pose_x;
odom_trans.transform.translation.y = pose_y;
odom_trans.transform.translation.z = 0.0;
odom_trans.transform.rotation = odom_quat;
odom.pose.pose.position.x = pose_x;
odom.pose.pose.position.y = pose_y;
odom.pose.pose.position.z = 0.0;
odom.pose.pose.orientation = odom_quat;
if (pose_x>-8 && pose_x<10 && pose_y>-8 && pose_y<8) {
digitalWrite(led_pin, HIGH - digitalRead(13));
}
else {
digitalWrite(led_pin, LOW - digitalRead(13));
}
}
ros::Subscriber <nav_msgs::Odometry> sub("/odom", odomCallback);
void setup()
{
nh.initNode();
nh.advertise(server_pub);
nh.subscribe(sub);
//initialize an LED output pin
//and a input pin for our push button
pinMode(led_pin, OUTPUT);
pinMode(button1_pin, INPUT);
pinMode(button2_pin, INPUT);
//Enable the pullup resistor on the button
digitalWrite(button1_pin, HIGH);
digitalWrite(button2_pin, HIGH);
//The button is a normally button
last_reading1 = ! digitalRead(button1_pin);
last_reading2 = ! digitalRead(button2_pin);
}
void loop()
{
bool reading1 = ! digitalRead(button1_pin);
bool reading2 = ! digitalRead(button2_pin);
if (last_reading1 != reading1) {
last_debounce_time1 = millis();
published1 = false;
}
if (last_reading2 != reading2) {
last_debounce_time2 = millis();
published2 = false;
}
//if the button value has not changed for the debounce delay, we know its stable
if ( !published1 == 1 && (millis() - last_debounce_time1) > debounce_delay) {
digitalWrite(led_pin, reading1);
message.data = button1 ;
server_pub.publish(&message);
published1 = true;
}
if ( !published2 == 1 && (millis() - last_debounce_time2) > debounce_delay) {
digitalWrite(led_pin, reading2);
message.data = button2 ;
server_pub.publish(&message);
published2 = true;
}
last_reading1 = reading1;
last_reading2 = reading2;
nh.spinOnce();
}
It seems like you're not using the data from the odomCallback at all.
Looks like pose_x and pose_y values never get set. Try adding this to the beginning of the odomCallback function (not tested):
// set pose_x and pose_y to their most recent values
pose_x = msg.pose.pose.position.x;
pose_y = msg.pose.pose.position.y;

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

Menu Selection WIndow Creation for LCDsheild and arduino Interface

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.

Resources