Stuck in void loop, not sure how to get out

hi guys, its me again.

i have a simple sketch for a clock, with encoder used to set up the alarm, the procedure goes like this:

  1. If i keep the encoder button pressed for 3 seconds i get into the setup menu “encoder_alarm”, this is ok
  2. i can toggle “select” boolean to be able to chose digits to set (select = true) and to adjust the values of digits (select = false)
  3. one thing i do not know how to do is how to exit the “encoder_alarm” loop once i have finished setting up the alarm.

as i have 4 groups of digits to set: hour start, minute start, hour end and minute end, each 2 digit groups I have set up the 5th “menu item” which when selected, and button clicked, should exit the loop, but not sure how to do that.

full code below, keep in mind this code is test WIP and a bit messy:

#include <EEPROM.h>
#include <ezButton.h>
#include <LedControl.h>

#include <TimeLib.h>
#include <RTClib.h>
#include <OneWire.h>
#include <DS1307RTC.h>
#include <SPI.h>


#define MAXIMCCLD 10         // output - CS/LOAD
#define MAXIMCCCLK 11        // output - CLOCK
#define MAXIMCCDATA 9       // output - DATA    
#define DS1307_I2C_ADDRESS 0x68 // define the RTC I2C address

#define ENCODER_SW 8

ezButton button(8);  // create ezButton object that attach to pin 7;
LedControl MaximCC=LedControl(MAXIMCCDATA, MAXIMCCCLK, MAXIMCCLD, 1); // Define pins for Maxim 72xx and how many 72xx we use

int LED = 4;
int LED2 = 444;



volatile signed int counter_hour_start = EEPROM.read(2);
volatile signed int counter_minute_start = EEPROM.read(3);
volatile signed int counter_hour_end = EEPROM.read(4);
volatile signed int counter_minute_end = EEPROM.read(5);
volatile signed int counter;


// usually the rotary encoders three pins have the ground pin in the middle
enum PinAssignments {
  encoderPinA = 3,   // right DT
  encoderPinB = 2,   // left CLK
};

  // a counter for the dial
signed int lastReportedPos_hour_start = 1;   // change management
signed int lastReportedPos_minute_start = 1;   // change management
signed int lastReportedPos_hour_end = 1;   // change management
signed int lastReportedPos_minute_end = 1;   // change management
signed int lastReportedPos_brightness_count = 1;   // change management

// interrupt service routine vars
boolean A_set = false;
boolean B_set = false;

int previousSecond = 0;
int tensofhours, singlehours, tensofminutes, singleminutes,tensofhours1, singlehours1, tensofminutes1, singleminutes1,singlecounts,tensofcounts;

const int SHORT_PRESS_TIME = 1000; // 1000 milliseconds
const int LONG_PRESS_TIME  = 1000; // 1000 milliseconds

unsigned long pressedTime  = 0;
unsigned long releasedTime = 0;
bool isPressing = false;
bool isLongDetected = false;

unsigned long count0 = true;
unsigned long count1;
unsigned long count2;
unsigned long count3;
unsigned long count4;
unsigned long count5;
unsigned long count6;
unsigned long largerThanZero;

int period = 20;
unsigned long time_now = 0;

signed int lastReportedPos_setupMenuCounter = 1;
signed int setupMenuCounter = 1; // counter goes from 1 to 3 or whatever the number of menu items is. Counter cycles so after 3 we get 1 or if we go to less than 1 we get 3
signed int lastReportedPos_sleepWakeCounter = 1;
signed int sleepWakeCounter = 1;

int oldEncoderButtonState = LOW;
int encoderButtonState = LOW;

bool selectVar = false;

volatile unsigned int encoderPos = 0;  // a counter for the dial
unsigned int lastReportedPos = 1;   // change management
static boolean rotating = false;    // debounce management

//==============================================================================
// SETUP
//==============================================================================

void setup() {
  Serial.begin(9600);

  pinMode(LED, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(53, OUTPUT);
  pinMode(ENCODER_SW, INPUT);

  pinMode(encoderPinA, INPUT);
  pinMode(encoderPinB, INPUT);
  
  // Initialize RTC and set as SyncProvider.
  // Later RTC will be synced with DCF time
  setSyncProvider(RTC.get); // the function to get the time from the RTC
  // check if RTC has set the system time
  if (timeStatus() != timeSet)
  { // Unable to sync with the RTC - activate RTCError LED  
  }
  
  MaximCC.shutdown(0,false);
  MaximCC.setIntensity(0,15);
  MaximCC.clearDisplay(0);
  button.setDebounceTime(10); // set debounce time to 50 milliseconds
  button.setCountMode(COUNT_FALLING);

     // turn on pullup resistors
  digitalWrite(encoderPinA, HIGH);
  digitalWrite(encoderPinB, HIGH);

  // encoder pin on interrupt 0 (pin 2)
  attachInterrupt(0, doEncoderB, CHANGE);
  // encoder pin on interrupt 1 (pin 3)
  attachInterrupt(1, doEncoderA, CHANGE);

  tensofhours = counter_hour_start / 10;
  singlehours = counter_hour_start % 10;
  tensofminutes = counter_minute_start / 10;
  singleminutes = counter_minute_start % 10;
  tensofhours1 = counter_hour_end / 10;
  singlehours1 = counter_hour_end % 10;
  tensofminutes1 = counter_minute_end / 10;
  singleminutes1 = counter_minute_end % 10; 
}

//==============================================================================
// LOOP
//==============================================================================

void loop() {

  tasksEverySecond();
 
  // check if there was a short or a long press of a bottom // 
  button.loop(); // MUST call the loop() function first

  if(button.isPressed()){
    pressedTime = millis();
    isPressing = true;
    isLongDetected = false;
  }

  if(button.isReleased()) {
    isPressing = false;
    releasedTime = millis();

    long pressDuration = releasedTime - pressedTime;
    
    if( pressDuration < SHORT_PRESS_TIME ) // on short button press, keep resetting the counter to zero so it does not count before long press
      if (count0 == true){
      button.resetCount();
      }
  }

  if(isPressing == true && isLongDetected == false) {
    long pressDuration = millis() - pressedTime;
    if( pressDuration > LONG_PRESS_TIME ) {
      isLongDetected = true;
    }
  }
   
  if (count0 == true){ 
    if(millis() > time_now + period){
        time_now = millis();
    manual_brightness_control();
    } 
  } else {
    if(millis() > time_now + period){
        time_now = millis();
    encoder_alarm ();
  }
  }
  
  if (isLongDetected == true){
    button_press();
  }
}


//==============================================================================
// tasksEverySecond
//==============================================================================
void tasksEverySecond()
{
  if (second() != previousSecond)
  {
    previousSecond = second();
    displayRtcTime(); 
    ledTest();
  }
}

//==============================================================================
// ENCODER INTERRUP ROUTINE
//==============================================================================
// Interrupt on A changing state
void doEncoderA() {

  if ( digitalRead(encoderPinA) != A_set ) { // debounce once more
    A_set = !A_set;
    // adjust counter + if A leads B
    if ( A_set && !B_set )
    if (count0 == true)
        counter +=1;
      else if (selectVar == true)
        sleepWakeCounter ++;
      else if ((sleepWakeCounter == 0) && (selectVar == false))
        counter_hour_start +=1; 
      else if ((sleepWakeCounter == 1) && (selectVar == false))
        counter_minute_start +=1;
      else if ((sleepWakeCounter == 2) && (selectVar == false))
        counter_hour_end +=1;
      else if ((sleepWakeCounter == 3) && (selectVar == false))
        counter_minute_end +=1;
    }
}

// Interrupt on B changing state, same as A above
void doEncoderB() {
  if ( digitalRead(encoderPinB) != B_set ) {
    B_set = !B_set;
    //  adjust counter - 1 if B leads A
    if ( B_set && !A_set )
      if (count0 == true)
        counter -=1;
      else if (selectVar == true)
        sleepWakeCounter --;
      else if ((sleepWakeCounter == 0) && (selectVar == false))
        counter_hour_start -=1;
      else if ((sleepWakeCounter == 1) && (selectVar == false))
        counter_minute_start -=1;
      else if ((sleepWakeCounter == 2) && (selectVar == false))
        counter_hour_end -=1;
      else if ((sleepWakeCounter == 3) && (selectVar == false))
        counter_minute_end -=1;
  }
}

//==============================================================================
// button_press
//==============================================================================
void button_press (){

  unsigned long count = button.getCount();
  
  if (count == 0) {
    count0 = true;
    } else {
      count0 = false;
    }  
}


//==============================================================================
// ENCODER ALARM
//==============================================================================

void encoder_alarm(){

  button.loop(); // MUST call the loop() function first
  unsigned long count = button.getCount();

  // toggle boolean state to choose between cycling the setup positions and changing the values
  encoderButtonState = digitalRead(ENCODER_SW);
  if (( encoderButtonState != oldEncoderButtonState ) && (encoderButtonState == HIGH) ) {
     selectVar = !selectVar;
     Serial.println(selectVar);
    }
    oldEncoderButtonState = encoderButtonState;

  //--------------------- HOURS alarm STARTS at ------------------------//
  
    if (lastReportedPos_hour_start != counter_hour_start) {
      if (counter_hour_start>23) {(counter_hour_start = 0);}
      if (counter_hour_start<0) {(counter_hour_start = 23);}

      tensofhours = counter_hour_start / 10;
      singlehours = counter_hour_start % 10; 

      lastReportedPos_hour_start = counter_hour_start;
  }
      EEPROM.update(2,counter_hour_start);


  //--------------------- MINUTES alarm STARTS at ------------------------//

    if (lastReportedPos_minute_start != counter_minute_start) {
      if (counter_minute_start>59) {(counter_minute_start = 0);}
       if (counter_minute_start<0) {(counter_minute_start = 59);}

       tensofminutes = counter_minute_start / 10;
       singleminutes = counter_minute_start % 10; 

      lastReportedPos_minute_start = counter_minute_start;

       EEPROM.update(3,counter_minute_start);
  } 
  
  //--------------------- HOURS alarm ENDS at ------------------------// 

    if (lastReportedPos_hour_end != counter_hour_end) {
      if (counter_hour_end>23) {(counter_hour_end = 0);}
      if (counter_hour_end<0) {(counter_hour_end = 23);}

      tensofhours1 = counter_hour_end / 10;
      singlehours1 = counter_hour_end % 10; 

      lastReportedPos_hour_end = counter_hour_end;
  }
      EEPROM.update(4,counter_hour_end);

  
  //--------------------- MINUTES alarm ENDS at ------------------------//
  
    if (lastReportedPos_minute_end != counter_minute_end) {
      if (counter_minute_end>59) {(counter_minute_end = 0);}
       if (counter_minute_end<0) {(counter_minute_end = 59);}

       tensofminutes1 = counter_minute_end / 10;
       singleminutes1 = counter_minute_end % 10; 

      lastReportedPos_minute_end = counter_minute_end;

       EEPROM.update(5,counter_minute_end);
  } 

  
  //--------------------- 7 Segment display  ------------------------//

    MaximCC.setChar(0,7,tensofhours,false);
    MaximCC.setChar(0,6,singlehours,false);
    MaximCC.setChar(0,5,tensofminutes,false);
    MaximCC.setChar(0,4,singleminutes,false);
    MaximCC.setChar(0,3,tensofhours1,false);
    MaximCC.setChar(0,2,singlehours1,false);
    MaximCC.setChar(0,1,tensofminutes1,false);
    MaximCC.setChar(0,0,singleminutes1,false);

  if (selectVar == true) {

    if (lastReportedPos_sleepWakeCounter != sleepWakeCounter) {
      if (sleepWakeCounter>4) {(sleepWakeCounter = 0);}
       if (sleepWakeCounter<0) {(sleepWakeCounter = 4);}
    
       lastReportedPos_sleepWakeCounter = sleepWakeCounter;
    
    }
  }

  if ((sleepWakeCounter == 0) || (sleepWakeCounter == 1) || (sleepWakeCounter == 2) || (sleepWakeCounter == 3)) { 
    if(button.isPressed()) {
      selectVar = false;
      }
  }

  
    if (sleepWakeCounter == 4) {
      
      count0 = true;
      
  }
   

  
  if (sleepWakeCounter == 0) {
    MaximCC.setChar(0,7,tensofhours,false);
    MaximCC.setChar(0,6,singlehours,true); 
  } else {
    MaximCC.setChar(0,6,singlehours,false); 
  }

  if (sleepWakeCounter == 1) {
    MaximCC.setChar(0,5,tensofminutes,false);
    MaximCC.setChar(0,4,singleminutes,true); 
  } else {
    MaximCC.setChar(0,4,singleminutes,false); 
  }

  if (sleepWakeCounter == 2) {
    MaximCC.setChar(0,3,tensofhours1,false);
    MaximCC.setChar(0,2,singlehours1,true); 
  } else {
    MaximCC.setChar(0,2,singlehours1,false); 
  }

  if (sleepWakeCounter == 3) {
    MaximCC.setChar(0,1,tensofminutes1,false);
    MaximCC.setChar(0,0,singleminutes1,true); 
  } else {
    MaximCC.setChar(0,0,singleminutes1,false); 
  }
}

//==============================================================================
// manual_brightness_control
//==============================================================================

void manual_brightness_control()
{
  
  if (lastReportedPos_brightness_count != counter) {
      if (counter>15) {(counter = 15);}
       if (counter<0) {(counter = 0);}

       singlecounts = counter / 10;
       singlecounts = counter % 10; 

      lastReportedPos_brightness_count = counter;
      MaximCC.setIntensity(0,counter);
  }  
}
//==============================================================================
// displayRtcTime
//==============================================================================

void displayRtcTime()
{
  if (count0 == true){
  MaximCC.setChar(0, 7, (hour() / 10), false);
  MaximCC.setChar(0, 6, (hour() % 10), false);
  
  MaximCC.setChar(0, 5, '-', false);
  MaximCC.setChar(0, 4, (minute() / 10), false);
  MaximCC.setChar(0, 3, (minute() % 10), false);

  MaximCC.setChar(0, 2, '-', false);
  MaximCC.setChar(0, 1, (second() / 10), false);
  MaximCC.setChar(0, 0, (second() % 10), false);
  
  }
}

//==============================================================================
// ledTest
//==============================================================================
void ledTest(){
  int midnight;
  int powersaving;
  int startTime = counter_hour_start * 100 + counter_minute_start;
  int endTime = counter_hour_end * 100 + counter_minute_end;
  int timeNow = hour() * 100 + minute();
  

  if (endTime == 0000 && startTime != 0000){
    endTime = 2359;
  }
  
    
   if (timeNow >= startTime && timeNow < endTime)  {
    powersaving = true;
   } else {
    powersaving = false;
   }
  
  if (powersaving == true){
    digitalWrite(LED2, HIGH);
  } else {
    digitalWrite(LED2, LOW);
  }
}

many thanks for any help,
Alek

Pease edit your post, and put the code in CODE TAGS as per the instructions.

but my code IS in code tags

1 Like

Thanks

Exit any function with “return;”.
Paul

One approach is that if no button is pressed, for example in five seconds, exit the function.

Hint: the keyword “void” in front of a function name means that the function returns no result.

Related thread: https://forum.arduino.cc/t/rotary-encoder-increment-decrement/

If you’re trying to implement what’s outlined in this post: Rotary encoder increment/decrement you’re making it more difficult.

It would work better, and the idea was, to toggle select outside the function then only call the function if select is in the ‘adjust times’ mode

ok, i have sorted out the exit routine, based on dougp ideas:

if (sleepWakeCounter == 4) { // EXIT MENU option is at sleepWakeCounter 4
      MaximMATRIX.setRow(MENUdisplay,1,B11111111);
      MaximMATRIX.setRow(MENUdisplay,0,B11111111);
      // once we press the button from digit selection boolean togles to "false", this then executes everything below
      if(select == false) {
        // turn off LED matrix rows showing EXIT MENU
        MaximMATRIX.setRow(MENUdisplay,1,B00000000);
        MaximMATRIX.setRow(MENUdisplay,0,B00000000);
        sleepWakeCounter = 0;         // set sleepWakeCounter to 0 so that when we are back in the setup menu our selection is at position 0 - counter_hour_start
        setSleepWakeDisplay = false;  // set setSleepWakeDisplay to "false" so that when we are back in the setup menu last alarm setup is displayed on the display ONCE
        count0 = true;                // once we set count0 to "true" we are exiting "encoder_alarm" loop
        } 
      } else {
        MaximMATRIX.setRow(MENUdisplay,1,B00000000);
        MaximMATRIX.setRow(MENUdisplay,0,B00000000);
      }

this works great now. i am still a long way away from being done, the next step in to implement a MAIN MENU where we will be present with two choices

  1. set time and date
  2. set sleep/wake alarm
  3. EXIT MENU

Then thorough code cleaning as i am dragging this sketch for a full year now, lots of things to remove, optimize…

many thanks,
Alek

Image of my project, at the top is my prototype PCB with two 4-digits displays at the right hand side, showing 06.300200… sleep/wake alarm, with decimal point marking that we are changing first two digits.
bottom part of the image is test rig for testing out parts of the code.

DCF77 signal syncs both clocks from main DCF receiver, via nrf24l01 transceivers.

1 Like