Go Down

Topic: [SOLVED] Menu Structure - returning to main loop from submenu (Read 601 times) previous topic - next topic

Robin2

after the compile neither button works not the encoder just outs what i've posted in Post#6.
Thanks that worked. So back to the built.
Is everything working fine now?

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

anishkgt

Is everything working fine now?

...R
I mean back to the menu structure. :) i was stuck halfway through the process of the menu structure and cattledog's suggestion helped me move on with it.

Robin2

So ... once again ... Please post the latest version of the program and tell us how it is misbehaving and what YOU think may be the cause of that problem.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

anishkgt

So far.....
Code: [Select]

#include <PinChangeInterrupt.h>
#include <Wire.h>

const int buttonPin  = 9;  // Weld button
const int ENC_SW     = 11; // Push button on Encoder
const int ENC_PinB   = 12; // PIN B of Encoder
const int ENC_PinA   = 13; // PIN A of Encoder
const int noEvent = 0;
const int shortPress = 1;
const int longPress = 2;
const int longerPress = 3;
const int shortTime = 500; //if equal longTime there is no unrecorded press
const int longTime = 500;
const int longerTime = 2000;

boolean startTimeout = false;
int InMenu = 0;
int ENC_PinAState = LOW;
int ENC_PinALastState = LOW;
int Counter1 = 0;


unsigned long buttonPressStartTimeStamp;
unsigned long buttonPressDuration;

void setup()
{
  pinMode (ENC_PinA, INPUT_PULLUP);
  pinMode (ENC_PinB, INPUT_PULLUP);
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(ENC_SW, INPUT_PULLUP);
  attachPCINT(digitalPinToPCINT(13), rotaryEncoder, CHANGE);
  Serial.begin(9600);
}

int rotaryEncoder()
{
  ENC_PinAState = digitalRead(ENC_PinA);
  if (ENC_PinAState != ENC_PinALastState)
  {
    if (digitalRead(ENC_PinB) != ENC_PinAState) {
      Counter1++;
    } else {
      Counter1--;
    }
    Serial.println(Counter1 >> 1);
  }
  ENC_PinALastState = ENC_PinAState;
  if (Counter1 <= 0)
  {
    Counter1 = 0;
  }
  if (Counter1 >= 500)
  {
    Counter1 = 500;
  }
  return (Counter1 >> 1);
}

void configMenu()        // End configuration mode.
{
  int menuFlag;
  Serial.println("Start");
  Serial.println("End");
  Serial.println("Test");
  Serial.println("W1");
}

void loop()
{
  byte menuFlag = false;
  switch (checkButton())
  {
    case shortPress:
      Serial.println("Mode: Manual Weld");
      break;

    case longPress:
      Serial.println("Mode: Automatic Weld");
      break;

    case longerPress:
      Serial.println("CONFIGURATION MODE");
      menuFlag = true;
      break;
  }

  while (menuFlag == true)
  {
    noInterrupts();
    int select = map(rotaryEncoder(), 0, 4, 1, 4);
    interrupts();

    switch (select)
    {
      case 1:
        Serial.println("> Start");
        if ((digitalRead(ENC_SW) == LOW) && select == 1)
        {
          Serial.println("> Start_Menu");
          InMenu = 1;
        }
        break;

      case 2:
        {
          Serial.println("> End");
          if ((digitalRead(ENC_SW) == LOW) && select == 1)
          {
            Serial.println("> End_Menu");
            InMenu = 2;
          }
          break;
        }
    }
    switch (InMenu)
    {
      case 1:
        {
          if (Counter1 == 1)
          {
            Serial.println("Start_Menu: 2");
          }
          if (digitalRead(ENC_SW) == LOW)
          {
            Serial.println("Start_Menu: 1-Saved");
          }
        }
      case 2:
        {
          Serial.println("End_Menu: 2");
        }
        if (digitalRead(ENC_SW) == LOW)
        {
          Serial.println("End_Menu: 1-Saved");
        }
    }
  }
}

byte checkButton()
{
  static int buttonState = HIGH;
  static int previousButtonState = HIGH;
  byte event = noEvent;
  buttonState = digitalRead(buttonPin);

  //button pressed
  if (buttonState == LOW && previousButtonState == HIGH)
  {
    delay(20);   //blocking debounce routine
    buttonState = digitalRead(buttonPin);//read button again
    if (buttonState == LOW && previousButtonState == HIGH)
    {
      buttonPressStartTimeStamp = millis();
      startTimeout = true;
    }
  }

  //button released
  if (buttonState == HIGH && previousButtonState == LOW)
  {
    delay(20);//blocking debounce routine
    buttonState = digitalRead(buttonPin);//read button again
    if (buttonState == HIGH && previousButtonState == LOW)
    {
      buttonPressDuration = (millis() - buttonPressStartTimeStamp);
      startTimeout = false;//duration determined no timeout required
    }
  }

  if (buttonPressDuration > 0 && buttonPressDuration <= shortTime)
  {
    event = shortPress;
    buttonPressDuration = 0;
  }

  if (buttonPressDuration > longTime && buttonPressDuration <= longerTime)
  {
    event = longPress;
    buttonPressDuration = 0;
  }

  //button not released and still timing
  if (buttonState == LOW && startTimeout == true && (millis() - buttonPressStartTimeStamp) > longerTime)
  {
    event = longerPress;
    startTimeout = false;
  }

  buttonPressDuration = 0;
  previousButtonState = buttonState;
  return event;
}

Just a note, tho this is a "project thread" and most members here maybe a pro in programming but i am not so much into electronics but i can work around things wish to learn more and pickup where i left of 10years back with electronics. i now work in the IT industry.

hence these questions and slow to come up with the code though i have the idea in mind.

cattledog

#19
Jul 17, 2017, 11:54 pm Last Edit: Jul 17, 2017, 11:57 pm by cattledog
 
When you changed your encoder reading from polled to interrupt driven, you have gotten muddled up in how you are reading it and how you are treating the interrupt service routine (ISR). You should be doing some more background reading on interrupts.

First thing is that the main global variable modified in the ISR and used by the program needs to be declared as volatile.
Code: [Select]
//int Counter1 = 0;
volatile int Counter1 = 0;


Second the ISR should not need a return value. It is called by the interrupt (when the pin changes state) and there is nothing to read a return.

Code: [Select]
//int rotaryEncoder()
 rotaryEncoder()
{
  ENC_PinAState = digitalRead(ENC_PinA);
  if (ENC_PinAState != ENC_PinALastState)
  {
    if (digitalRead(ENC_PinB) != ENC_PinAState) {
      Counter1++;
    } else {
      Counter1--;
    }
    //Serial.println(Counter1 >> 1); //Don't serial print within an ISR.
  }
  ENC_PinALastState = ENC_PinAState;
  if (Counter1 <= 0)
  {
    Counter1 = 0;
  }
  if (Counter1 >= 500)
  {
    Counter1 = 500;
  }
  //return (Counter1 >> 1); //no return value
}


Third, when you access the value of Counter1 you don't do it by calling the function like you do here

Code: [Select]
int select = map(rotaryEncoder(), 0, 4, 1, 4);

With the Counter1 value as an int, you need to make the protected copy and use that. If the Counter1 can go to 500, I'm not seeing why you are mapping like you are.
Code: [Select]

noInterrupts()
int reading = Counter1;
interrupts();
int select = map(reading, 0, 4, 1, 4);

 

Robin2

Sorry, I don't want to sound unkind, but there is no easy way to say that this is nonsense
Code: [Select]
    noInterrupts();
    int select = map(rotaryEncoder(), 0, 4, 1, 4);
    interrupts();


You should not be calling that function from your main code. That function is only called when an interrupt happens and you don't need to know when that is.

Your code just needs to check the value that the function has updated - the variable counter. And this is all the code that should be in that function
Code: [Select]
void rotaryEncoder()
{
  ENC_PinAState = digitalRead(ENC_PinA);
  if (ENC_PinAState != ENC_PinALastState)
  {
    if (digitalRead(ENC_PinB) != ENC_PinAState) {
      Counter1++;
    } else {
      Counter1--;
    }
  }
}


...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Robin2

@anishkgt, you are committing the cardinal sin of trying to figure out two things at once - learning to use an encoder and learning to get a menu to work.

Separate that learning into two separate programs and you will make progress a lot faster. When you can do the two things separately then it will be time to create a combined program.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

anishkgt

actually i got the encoder part working earlier.

Now got the menu structure as well

Code: [Select]
switch (checkButton())
  {
    case shortPress:
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Mode: Manual Weld    ");
      lcd.setCursor(0, 2);
      lcd.print("W1:");
      lcd.print(pre);
      //lcd.print(char(0xE4));
      lcd.print("ms");
      lcd.setCursor(9, 2);
      lcd.print("P:");
      lcd.print(pause);
      lcd.print("ms");
      lcd.setCursor(0, 3);
      lcd.print("W2:");
      lcd.print(WeldTime);
      lcd.print("ms ");
      lcd.backlight();
      Weld();
      break;

    case longPress:
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Mode: Automatic Weld");
      continousWeld();
      break;

    case longerPress:
      configMenu();
      break;
  }
  zeroCrossingFlag = false;
  rotaryEncoder();

  while (menuFlag == true) // stay in config mode
  {
    currentRotaryValue();
    noInterrupts();
    int S1 = rotaryEncoder();
    interrupts();
    select = map(S1, 1, 4, 1, 4);
    Serial.println(select);
    switch (select)
    {
      case 1:
        lcd.setCursor(0, 1);
        lcd.print(">");
        lcd.setCursor(7, 1);
        lcd.print(" ");
        digitalRead(ENC_SW);
        delay(100);
        if ((digitalRead(ENC_SW) == LOW) && select == 1)
        {
          menuFlag = false; // exit config mode
          InMenu = 1;       // enter submenu
          stayInMenu = 3;     // got to submenu in Menu 1
          lcd.clear();
        }
        break;

      case 2:
        lcd.setCursor(0, 1);
        lcd.print(" ");
        lcd.setCursor(7, 1);
        lcd.print(">");
        digitalRead(ENC_SW);
        delay(100);
        if ((digitalRead(ENC_SW) == LOW) && select == 2)
        {
          InMenu = 2;
          lcd.clear();
        }
        break;

      case 5:
        lcd.setCursor(0, 1);
        lcd.print(" ");
        lcd.setCursor(7, 1);
        lcd.print(">");
        digitalRead(ENC_SW);
        delay(100);
        if ((digitalRead(ENC_SW) == LOW) && select == 2)
        {
          InMenu = 2;
          lcd.clear();
        }
        break;
    }
    switch (InMenu)
    {
      select = 0;
        while (stayInMenu == 3)
        {
          currentRotaryValue();
        case 1:
          int startSrv = map(rotaryEncoder(), 0, 160, 24, 160);
          if  (startSrv < 25)
          {
            startSrv = 0;
          }
          if  (startSrv >= 160)
          {
            startSrv = 160;
          }
          lcd.setCursor(3, 0);
          lcd.print("Set Start Point");
          lcd.setCursor(3, 2);
          lcd.print("Set Start:");
          lcd.print(startSrv);
          lcd.print(char(223));
          lcd.setCursor(3, 3);
          lcd.print("Stored   :");
          lcd.print(SrvPotMap2);
          lcd.print(char(223));
          myServo.attach(servoPin);
          myServo.write(startSrv);
          delay(200);
          if ((digitalRead(ENC_SW) == LOW) && SrvPotMap2 != startSrv)     // Display message only if current value is different from the stored value
          {
            SrvPotMap2 = startSrv;
            //EEPROM.update(startSrvAddr, startSrv); lcd.setCursor(0, 2);
            myServo.detach();
            lcd.clear();
            lcd.setCursor(2, 2);
            lcd.print("SAVE SUCCESSFULL");
            lcd.setCursor(0, 3);
            lcd.print("value changed: ");
            lcd.print(startSrv);
            lcd.print(char(223));
            menuFlag = 0;
            stayInMenu = 0;
            InMenu = 0;
            digitalWrite(bzr, HIGH);
            delay(100);
            digitalWrite(bzr, LOW);
            delay(100);
            digitalWrite(bzr, LOW);
            delay(2500);
            lcd.clear();
            lcd.setCursor(1, 0);
            lcd.print("CONFIGURATION MODE");
            configMenu();
          }
          else if (digitalRead(ENC_SW) == LOW)
          {
            myServo.detach();
            menuFlag = true;
            stayInMenu = 0;
            InMenu = 0;
            configMenu();
          }
        }
    }
  }
}

int rotaryEncoder()
{
  ENC_PinAState = digitalRead(ENC_PinA);
  if (ENC_PinAState != ENC_PinALastState)
  {
    if (digitalRead(ENC_PinB) != ENC_PinAState) {
      Counter1++;
    } else {
      Counter1--;
    }
    //Serial.println(Counter1);
  }
  ENC_PinALastState = ENC_PinAState;
  return (Counter1 >> 1);
}


Not the best but gets the job done. Let me know if there is something better. How can i reset the encoder value to zero ? i see it is zero when using the map command. i even tried counter = 0 but nope it would not change. Basically when i try to return to another function the value remains unchanged from the previous. It is the rotary encoder function that stores the counter value.

anishkgt

This bit info was helpful. i use the rotary button for other functions as well and do not wish to reset whenever i press it.

anishkgt

so setting a variable to detect if it was true solve the problem

Code: [Select]
void loop()
{
  byte InMenu = 0;
  byte select;
  int prevWeldTime = 0;
  noInterrupts();
  int W1 = rotaryEncoder();
  interrupts();

  WeldTime = W1 * 2;
  unsigned long startTime = millis(); // start timer for LCD time-out
  while (!zeroCrossingFlag && (millis() - startTime < timeCheck))
  {
    /* hang inside while loop until either zeroCrossFlag or timeout occurs
       both conditions need to be met to stay in while loop
    */

  }
  if (zeroCrossingFlag)//exit while loop due to flag set
  {
    digitalWrite(rdy, HIGH);
    lcd.setCursor(9, 3);
    lcd.print("*READY*");
    zeroCrossingFlag = false;
  }
  else //exit while loop due to time out error
  {
    Serial.println("ZC Sense ERROR");
    lcd.setCursor (0, 2);
    lcd.print("ZC Sense Error  ");
    digitalWrite(rdy, HIGH);
    delay(50);
    digitalWrite(rdy, LOW);
    delay(100);
    digitalWrite(rdy, HIGH);
    delay(50);
    digitalWrite(rdy, LOW);
    delay(500);
  }

  if (prevWeldTime != WeldTime)
  {
    if (WeldTime <= 0)
    {
      WeldTime = 0;
    }
    prevWeldTime = WeldTime;
    lcd.setCursor(0, 3);
    lcd.print("W2:");
    lcd.print(WeldTime);
    lcd.print("ms ");
  }
  //Start debug
  /*if (OldWeldStepValue != WeldStep())
    {
    lcd.backlight();
    Serial.print("Set weld time(W2): ");
    Serial.print(WeldStep());
    Serial.println("ms");
    OldWeldStepValue = WeldStep();
    digitalWrite(bzr, HIGH);
    delay(3);
    digitalWrite(bzr, LOW);
    }*/
  //end debug
  backLightStart = millis();
  if (backLightStart - previousTime >= backLightOff)
  {
    previousTime = backLightStart;

    lcd.noBacklight();
  }
  switch (checkButton())
  {
    case shortPress:
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Mode: Manual Weld    ");
      lcd.setCursor(0, 2);
      lcd.print("W1:");
      lcd.print(pre);
      //lcd.print(char(0xE4));
      lcd.print("ms");
      lcd.setCursor(9, 2);
      lcd.print("P:");
      lcd.print(pause);
      lcd.print("ms");
      lcd.setCursor(0, 3);
      lcd.print("W2:");
      lcd.print(WeldTime);
      lcd.print("ms ");
      lcd.backlight();
      Weld();
      break;

    case longPress:
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Mode: Automatic Weld");
      continousWeld();
      break;

    case longerPress:
      configMenu();
      break;
  }
  zeroCrossingFlag = false;
  rotaryEncoder();

  while (menuFlag == true) // stay in config mode
  {
    currentRotaryValue();
    noInterrupts();
    int S1 = rotaryEncoder();
    interrupts();
    select = map(S1, 1, 4, 1, 4);

    switch (select)
    {
      case 1:
        lcd.setCursor(0, 1);
        lcd.print(">");
        lcd.setCursor(7, 1);
        lcd.print(" ");
        resetFlag = true;
        ENC_SWstate = digitalRead(ENC_SW);
        if ((ENC_SWstate == LOW) && select == 1)
        {
          delay(200);
          ENC_SWstate = digitalRead(ENC_SW);
          if ((ENC_SWstate == LOW) && select == 1)
          {
            menuFlag = false; // exit config mode
            InMenu = 1;       // enter submenu
            stayInMenu = 3;     // got to submenu in Menu 1
            lcd.clear();
          }
        }
        resetFlag = false;
        break;

      case 2:
        lcd.setCursor(0, 1);
        lcd.print(" ");
        lcd.setCursor(7, 1);
        lcd.print(">");
        digitalRead(ENC_SW);
        delay(100);
        if ((digitalRead(ENC_SW) == LOW) && select == 2)
        {
          InMenu = 2;
          lcd.clear();
        }
        break;

      case 5:
        lcd.setCursor(0, 1);
        lcd.print(" ");
        lcd.setCursor(7, 1);
        lcd.print(">");
        digitalRead(ENC_SW);
        delay(100);
        if ((digitalRead(ENC_SW) == LOW) && select == 2)
        {
          InMenu = 2;
          lcd.clear();
        }
        break;
    }
    switch (InMenu)
    {
        while (stayInMenu == 3)
        {
          currentRotaryValue();
        case 1:
          int startSrv = map(rotaryEncoder(), 1, 160, 24, 160);
          if  (startSrv < 25)
          {
            startSrv = 0;
          }
          if  (startSrv >= 160)
          {
            startSrv = 160;
          }
          lcd.setCursor(3, 0);
          lcd.print("Set Start Point");
          lcd.setCursor(3, 2);
          lcd.print("Set Start:");
          lcd.print(startSrv);
          lcd.print(char(223));
          lcd.setCursor(3, 3);
          lcd.print("Stored   :");
          lcd.print(SrvPotMap2);
          lcd.print(char(223));
          myServo.attach(servoPin);
          myServo.write(startSrv);
          resetFlag = true;
          ENC_SWstate = digitalRead(ENC_SW);
          if ((ENC_SWstate == LOW) && SrvPotMap2 != startSrv)     // Display message only if current value is different from the stored value
          {
            delay(200);
            ENC_SWstate = digitalRead(ENC_SW);
            if ((ENC_SWstate == LOW) && SrvPotMap2 != startSrv)
            {
              SrvPotMap2 = startSrv;
              //EEPROM.update(startSrvAddr, startSrv); lcd.setCursor(0, 2);
              myServo.detach();
              lcd.clear();
              lcd.setCursor(2, 2);
              lcd.print("SAVE SUCCESSFULL");
              lcd.setCursor(0, 3);
              lcd.print("value changed: ");
              lcd.print(startSrv);
              lcd.print(char(223));
              menuFlag = 0;
              stayInMenu = 0;
              InMenu = 0;
              resetFlag = false;
              digitalWrite(bzr, HIGH);
              delay(100);
              digitalWrite(bzr, LOW);
              delay(100);
              digitalWrite(bzr, LOW);
              delay(2500);
              lcd.clear();
              lcd.setCursor(1, 0);
              lcd.print("CONFIGURATION MODE");
              configMenu();
            }
            else if (digitalRead(ENC_SW) == LOW)
            {
              myServo.detach();
              menuFlag = true;
              stayInMenu = 0;
              InMenu = 0;
              resetFlag = false;
              configMenu();
            }
          }
        }
    }
  }
}

int rotaryEncoder()
{
  ENC_PinAState = digitalRead(ENC_PinA);
  if (ENC_PinAState != ENC_PinALastState)
  {
    if (digitalRead(ENC_PinB) != ENC_PinAState) {
      Counter1++;
    } else {
      Counter1--;
    }
    //Serial.println(Counter1);
  }
  ENC_PinALastState = ENC_PinAState;
  return (Counter1 >> 1);
}

Robin2

so setting a variable to detect if it was true solve the problem

Whatever "it" refers to?

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

anishkgt

missed that part here it is which includes the ISR for resetting the counter to 0

Code: [Select]

void configMenu()        // End configuration mode.
{

  myServo.detach();
  lcd.clear();
  lcd.setCursor(1, 0);
  lcd.print("CONFIGURATION MODE");
  lcd.setCursor(1, 1);
  lcd.print("Start");
  lcd.setCursor(8, 1);
  lcd.print("End");
  lcd.setCursor(13, 1);
  lcd.print("Test");
  lcd.setCursor(1, 2);
  lcd.print("W1");
  lcd.setCursor(5, 2);
  lcd.print("Exit");
  currentRotaryValue();
  menuFlag = true;
  resetFlag = false;
}

void currentRotaryValue()
{
  lcd.setCursor(17, 3);
  lcd.print(rotaryEncoder());
  lcd.print("   ");
}

void resetENC()
{
  if (resetFlag == false)
  {
    Counter1 = 0;
  }
}

void loop()
{................
...................
.............}

Go Up