Entering programming mode

Hi
I'm doing a project making a turntable for my model railroad.
I'm using a rotary encoder to set the exact placement of the turntable bridge for each track. But I would like only to enter the programming mode (set the exact track placement) when pushing the button on the rotary encoder for ex 5 sec.
The button is connected via INT1.

I suppose it's quite simple to do, but haven't found a solution to my problem yet.

I hope, some brilliant mind can help me out :slight_smile:

It is most implausible that anything on a model railroad layout would require use of an interrupt.

I won't get into the lecture on what interrupt are and are not (unless challenged), but you may care to study an example of full de-bounce and action timing code:

// Blink without "delay()" - multi!  With button de-bounce.
// Note that this code is immediately extensible to *many* buttons.

const int led1Pin =  13;    // LED pin number
const int led2Pin =  10;
const int led3Pin =  11;
const int button1 =  4;     // buttons & switches always connect from input to ground

int led1State = LOW;        // initialise the LED
int led2State = LOW;
int led3State = LOW;
char bstate1 = 0;

unsigned long count1 = 0;   // will store last time LED was updated
unsigned long count2 = 0;
unsigned long count3 = 0;
unsigned long bcount1 = 0; // button debounce timer.  Replicate as necessary.

// Have we completed the specified interval since last confirmed event?
// "marker" chooses which counter to check 
boolean timeout(unsigned long *marker, unsigned long interval) {
  if (millis() - *marker >= interval) { 
    *marker += interval;    // move on ready for next interval
    return true;       
  } 
  else return false;
}

// Deal with a button read; true if button pressed and debounced is a new event
// Uses reading of button input, debounce store, state store and debounce interval.
boolean butndown(char button, unsigned long *marker, char *butnstate, unsigned long interval) {
  switch (*butnstate) {               // Odd states if was pressed, >= 2 if debounce in progress
  case 0: // Button up so far, 
    if (button == HIGH) return false; // Nothing happening!
    else { 
      *butnstate = 2;                 // record that is now pressed
      *marker = millis();             // note when was pressed
      return false;                   // and move on
    }

  case 1: // Button down so far, 
    if (button == LOW) return false; // Nothing happening!
    else { 
      *butnstate = 3;                 // record that is now released
      *marker = millis();             // note when was released
      return false;                   // and move on
    }

  case 2: // Button was up, now down.
    if (button == HIGH) {
      *butnstate = 0;                 // no, not debounced; revert the state
      return false;                   // False alarm!
    }
    else { 
      if (millis() - *marker >= interval) {
        *butnstate = 1;               // jackpot!  update the state
        return true;                  // because we have the desired event!
      }
      else 
        return false;                 // not done yet; just move on
    }

  case 3: // Button was down, now up.
    if (button == LOW) {
      *butnstate = 1;                 // no, not debounced; revert the state
      return false;                   // False alarm!
    }
    else { 
      if (millis() - *marker >= interval) {
        *butnstate = 0;               // Debounced; update the state
        return false;                 // but it is not the event we want
      }
      else 
        return false;                 // not done yet; just move on
    }
  default:                            // Error; recover anyway
    {  
      *butnstate = 0;
      return false;                   // Definitely false!
    }
  }
}

void setup() {
  pinMode(led1Pin, OUTPUT);      
  pinMode(led2Pin, OUTPUT);      
  pinMode(led3Pin, OUTPUT);      
  pinMode(button1, INPUT);      
  digitalWrite(button1,HIGH);        // internal pullup all versions
}

void loop() {
  // Toggle LED if button debounced
  if (butndown(digitalRead(button1), &bcount1, &bstate1, 10UL )) {
    if (led1State == LOW) {
      led1State = HIGH;
    }
    else {
      led1State = LOW; 
    } 
    digitalWrite(led1Pin, led1State);
  } 

  // Act if the latter time (ms) has now passed on this particular counter,
  if (timeout(&count2, 300UL )) {
    if (led2State == LOW) {
      led2State = HIGH;
    }
    else {
      led2State = LOW; 
    } 
    digitalWrite(led2Pin, led2State);
  } 

  if (timeout(&count3, 77UL )) {
    if (led3State == LOW) {
      led3State = HIGH;
    }
    else {
      led3State = LOW; 
    } 
    digitalWrite(led3Pin, led3State);
  } 
}

Easily tried as an exercise with a button and three LEDs with resistors. :grinning:

You should have a variable that is read every time through the loop that tells the sketch if it is in 'programming mode' or not. If it is, take one path and if not take another. A simple if statement can do this if there are only 2 modes (programming and running), but if there are more modes (say, programming, normal running, maintenance, weekend, rush hour, etc.) then a switch function would be the way to go.

It rather depends on how many parts are common to alternate modes, and how different steps are to be ordered.

It may be more effective to have a single principal loop thread, with various "if" statements along the way.

Give we have little or no idea what the OP is doing, all this is moot. :roll_eyes:

Tomas_:
when pushing the button on the rotary encoder for ex 5 sec.

This is a a nice idea but pressing a button for 5 seconds will seem like an age to a human. And it certainly won't need an interrupt.

I suggest you settle for a button-press of about 500 millisecs and have an LED that turns on to show that the system is in programming mode.

To detect if a button is pressed continuously for a period of time you need code like this - note especially how it is actually testing for when the button is NOT pressed.

void loop() {
   buttonState = digitalRead(buttonPin);
   if (buttonState == HIGH) {   // assumes LOW when pressed and HIGH when not-pressed
       lastTimeButtonWasHigh = millis();
   }

   if (millis() - lastTimeButtonWasHigh >= requiredTime) {
       // input has been LOW throughout the required time
       // do whatever needs to be done
   }
}

...R

Hi folks
Thanks for all your help.
I will look into that :slight_smile:
I just want to make sure a misplaced long push on the rotary encoder isn't going to put bad values into the eeprom - therefor the 5 sec.
But using millis() is of course a use of interrupt and a fine way to do it :slight_smile:

Thanks again!

Tomas_:
But using millis() is of course a use of interrupt

Technically speaking that is not correct. Interrupts have a very specific meaning in the microprocessor world. Humans tend to use the word "interrupt" very loosely.

...R

I presume Tomas_ understands that millis() is based on reading a value that is updated by a timer interrupt but the millis() function itself does not involve an interrupt or the need to set up anything in advance as the underlying system has been already set up.

Did you study my code?