Go Down

Topic: Enter and exit a function with a PIN only. (Read 390 times) previous topic - next topic

antoniok270

Hello friends .

Is it possible for a single player to enter and exit a role?
I can not make my program work.
  I wanted my program to work itself out the following way,

- In the loop function with the PULSET pin I choose in the switch (MOD) the case corresponds to the function

- In the selected function, the LED flashes at the programmed frequency.

-When I want to leave the chosen function, I press the PULSET button and exit the function and return to the loop.

But the code that I did and thought it worked, does not work, when I press the PULSET pin it enters function one, and it does not exit function one anymore, when I press the PULSET pin.

Can someone help me make the code work like I want?

Strong hug

Here is the code I made:

Code: [Select]
//const int PUL_MOD = 2;
//const int PUL_UP = 3;
//const int PUL_DOWN = 4;

#define PULSET  5

const int N=2;
int LEDPIN1=12;
int LEDPIN2=11;
int LEDPIN3=10;
byte MOD = 0;
void BLINK1();
void BLINK2();
void BLINK3();

void setup()
{
  Serial.begin(9600);
 // pinMode(PUL_MOD, INPUT);
  //pinMode(PUL_UP, INPUT);
  //pinMode(PUL_DOWN, INPUT);
  pinMode(PULSET, INPUT_PULLUP);
  pinMode(LEDPIN1, OUTPUT);
  pinMode(LEDPIN2, OUTPUT);
  pinMode(LEDPIN3, OUTPUT);
}
void loop(){

  if(digitalRead(PULSET)==LOW)//we chose the function
    {
    MOD++;
    MOD = MOD % N;
    while(digitalRead(PULSET)==LOW);//while the pin PULSET is pressed, does nothing
    }
  Serial.println(MOD);
  Serial.println("MAIN FUNCTION");

  switch(MOD){
    case 1:
        BLINK1();
        break;
    case 2:
        BLINK2();
        break;
    case 3:
        BLINK3();
        break;
  }
}

void BLINK1()//function one
  {
    while(true)
    {
    digitalWrite(LEDPIN1, HIGH);
    delay(1000);
    digitalWrite(LEDPIN1, LOW);
    delay(1000);
      if(digitalRead(PULSET)==LOW)//if we click the pin PULSET back to the loop
    {
      while(digitalRead(PULSET)==LOW);//while the pin PULSET is pressed, does nothing
      break;
    }
   }
  }
void BLINK2()//function two
  {
    while(true)
    {
    digitalWrite(LEDPIN2, HIGH);
    delay(500);
    digitalWrite(LEDPIN2, LOW);
    delay(500);
   
      if(digitalRead(PULSET)==LOW)//if we click the pin PULSET back to the loop
      {
      while(digitalRead(PULSET)==LOW);//while the pin PULSET is pressed, does nothing
     }
   }
  }

void BLINK3()//function three
  {
      while(true)
    {
    digitalWrite(LEDPIN3, HIGH);
    delay(200);
    digitalWrite(LEDPIN3, LOW);
    delay(200);
   
      if(digitalRead(PULSET)==LOW)//if we click the pin PULSET back to the loop
      {
      while(digitalRead(PULSET)==LOW);//while the pin PULSET is pressed, does nothing
      break;
     
      }
   }
 }

6v6gt

I believe your main problem is that you are using delay() to control the frequency of blinking. During a delay() the buttons are unresponsive. Look at using millis() to conrtol the blink frequency. See the famous "blink without delay" example.

antoniok270

#2
Nov 17, 2018, 06:15 pm Last Edit: Nov 17, 2018, 08:12 pm by antoniok270
Hello,6v6gt  thanks!

I have not yet experience with millis, but I did a google search and found several examples of millis, I tried to adapt with my code but it does not work, the program enters the first function and turns on the LED and does nothing else.
How can I solve this, some idea!

Below the updated code

Code: [Select]
//const int PUL_MOD = 2;
//const int PUL_UP = 3;
//const int PUL_DOWN = 4;

#define PULSET  5
unsigned long previousMillis = 0;
const long interval = 1000;   
const int N=2;
int LEDPIN1=12;
int LEDPIN2=11;
int LEDPIN3=10;
byte MOD = 0;
void BLINK1();
void BLINK2();
void BLINK3();

void setup()
{
  Serial.begin(9600);
 // pinMode(PUL_MOD, INPUT);
  //pinMode(PUL_UP, INPUT);
  //pinMode(PUL_DOWN, INPUT);
  pinMode(PULSET, INPUT_PULLUP);
  pinMode(LEDPIN1, OUTPUT);
  pinMode(LEDPIN2, OUTPUT);
  pinMode(LEDPIN3, OUTPUT);
}
void loop(){

  if(digitalRead(PULSET)==LOW)//we chose the function
    {
    MOD++;
    MOD = MOD % N;
    while(digitalRead(PULSET)==LOW);//while the pin PULSET is pressed, does nothing
    }
  Serial.println(MOD);
  Serial.println("MAIN FUNCTION");
  switch(MOD){
    case 1:
        BLINK1();
        break;
    case 2:
        BLINK2();
        break;
    case 3:
        BLINK3();
        break;
  }
}

void BLINK1()//function one
  {
    while(true)
    {
     static unsigned long currentMillis = millis();
   

   if (currentMillis - previousMillis <= interval) {
       digitalWrite(LEDPIN1, HIGH);
      } else {
      digitalWrite(LEDPIN1, LOW);
      }
     previousMillis = currentMillis;
     
      if(digitalRead(PULSET)==LOW)//if we click the pin PULSET back to the loop
       {
      while(digitalRead(PULSET)==LOW);//while the pin PULSET is pressed, does nothing
      break;
    }
   }
  }
void BLINK2()//function two
  {
    while(true)
    {
    unsigned long currentMillis = millis();
   
    if (currentMillis - previousMillis <= interval) {
       digitalWrite(LEDPIN1, HIGH);
      } else {
      digitalWrite(LEDPIN1, LOW);
      }
     previousMillis = currentMillis;
     
      if(digitalRead(PULSET)==LOW)//if we click the pin PULSET back to the loop
      {
      while(digitalRead(PULSET)==LOW);//while the pin PULSET is pressed, does nothing
     }
   }
  }

void BLINK3()//function three
  {
      while(true)
    {
     unsigned long currentMillis = millis();
     
   if (currentMillis - previousMillis <= interval) {
       digitalWrite(LEDPIN1, HIGH);
      } else {
      digitalWrite(LEDPIN1, LOW);
      }
     previousMillis = currentMillis;
   
      if(digitalRead(PULSET)==LOW)//if we click the pin PULSET back to the loop
      {
      while(digitalRead(PULSET)==LOW);//while the pin PULSET is pressed, does nothing
      break;
     
      }
   }
 }

antoniok270

Hello
As I said, someone can tell me if the use of millis is correct in the function, so I researched I think it's fine, but the code does not work will be the use of the wrong millis
Thanks

MorganS

Quote
Code: [Select]
    while(true)
There's your problem. Let loop() do it's job. Don't get stuck in a sub-function. Then every function needs to know how to read the buttons and that's making your functions much more complex than they need to be.

I also noted that BLINK2() has no break statement, so it can never exit. This is a prime example of the problem with copy-pasting code like this.

Quote
Code: [Select]
      if(digitalRead(PULSET)==LOW)//if we click the pin PULSET back to the loop
      {
      while(digitalRead(PULSET)==LOW);//while the pin PULSET is pressed, does nothing
      break;
     
      }
I don't think you realize how fast the Arduino is, compared to physical things like buttons. When you press a button, two metal pieces inside the button are touched together to make the circuit. There's dust on those metal pieces. Some of the dust conducts electricity. One particle of dust is going to be the first part to make contact. Current will flow and the if() will see that the button was pushed. But the piece of dust is not going to stay still. It will move and stop the flow of current. So the while() sees that the button isn't pushed. Now your program goes back to the similar structure that you put at the top of the loop(). It only takes the Arduino a handful of nanoseconds to do that. But your finger is still descending on the button. It will make contact again, maybe a bit better this time. For the worst switches (like the cheap ones that came in your Arduino kit) this bouncing on and off can continue for tens of milliseconds. One million times longer than the few nanoseconds that it took to run through the code I quoted. Your little counter will go around the block several times for that one button push.

Question for you: How do you know which function it's stuck in since they all attempt to flash the same LED at the same interval? Or is that another copy-pasta mistake?

What is the result of MOD%N when N is 2? I'll give you a clue: it can never be 2 or 3.

Simplify your blink functions. Make only one function which turns an LED on or off using the millis timer (which you seem to have got right, by the way) but it looks at the value of MOD to decide which LED to turn on. Make it always turn all others off. Then you don't need the switch() at all.
"The problem is in the code you didn't post."

6v6gt

Also this is treated in c++ as a one time initialisation only:
static unsigned long currentMillis = millis() ;

You have to do it like this:
static unsigned long currentMillis = 0;
. . .
currentMillis = millis() ;

antoniok270

Hello friends

MorganS
 You are right in everything you have said, but since I am new to arduino programming, I have many doubts in understanding some factors in programming and I thank you for helping me.

Today after what you posted I was updating my code with what you described to me, but unfortunately there are still a lot of things that I still do not understand the logic operation, and so the code does not work.

  below follow the code I did again, if possible I would like you to tell me where are the errors so that the code does not work, mark in red where the error is and also some tips like I should do, so I think I must achieve my success!

Code: [Select]
#define PULSET  5
unsigned long previousMillis = 0;
const long interval = 500;   
const int N=3;
int LEDPIN1=12;
int LEDPIN2=11;
int LEDPIN3=10;
byte MOD = 0;
void BLINK1();
void BLINK2();
void BLINK3();

void setup()
{
  Serial.begin(9600);
 // pinMode(PUL_MOD, INPUT);
  //pinMode(PUL_UP, INPUT);
  //pinMode(PUL_DOWN, INPUT);
  pinMode(PULSET, INPUT_PULLUP);
  pinMode(LEDPIN1, OUTPUT);
  pinMode(LEDPIN2, OUTPUT);
  pinMode(LEDPIN3, OUTPUT);
}
void loop()
   {
    if(digitalRead(PULSET)==LOW)//we chose the function
    {
    MOD++;
    while(digitalRead(PULSET)==LOW);//while the pin PULSET is pressed, does nothing
    }

  if(MOD==1){
     BLINK1();
  }
  if(MOD==2){
     BLINK2();
  }
  if(MOD==3){
     BLINK3();
  }
  if(MOD >3){
  MOD=0;
  }

    Serial.println(MOD);
  Serial.println("MAIN FUNCTION");
 }


void BLINK1()//function one
  {
    int Debounce1=50;
    static unsigned long delay1 = 0;
    static bool stat;
    byte i=0;

    if (millis() - previousMillis < interval) {
     
       digitalWrite(LEDPIN1, HIGH);
      }
     if (millis() - previousMillis > interval) {
     
       digitalWrite(LEDPIN1,LOW);
      }
      if (millis() - previousMillis == 1000) {
     
       previousMillis = millis();
      }
     
  if ( (millis() - delay1) > Debounce1 ) {
       i=(digitalRead(PULSET));
       if (i && (i != stat) )
       {
        delay1 = millis();
        }
   stat = i;
  }
  }
void BLINK2()//function two
{
    int Debounce12=50;
    static unsigned long delay12 = 0;
    static bool stat1;
    byte i1=0;

    if (millis() - previousMillis < interval) {
     
       digitalWrite(LEDPIN2, HIGH);
      }
     if (millis() - previousMillis > interval) {
     
       digitalWrite(LEDPIN2,LOW);
      }
      if (millis() - previousMillis == 1000) {
     
       previousMillis = millis();
      }
     
  if ( (millis() - delay12) > Debounce12 ) {
       i1=(digitalRead(PULSET));
       if (i1 && (i1 != stat1) ) {
        delay12 = millis();
       }
       stat1 = i1;
       }
    }
void BLINK3()//function three
{
    int Debounce13=50;
    static unsigned long delay13 = 0;
    static bool stat2;
    byte i2=0;

    if (millis() - previousMillis < interval) {
     
       digitalWrite(LEDPIN3, HIGH);
      }
     if (millis() - previousMillis > interval) {
     
       digitalWrite(LEDPIN3,LOW);
      }
      if (millis() - previousMillis == 1000) {
     
       previousMillis = millis();
      }
     
  if ( (millis() - delay13) > Debounce13 ) {
       i2=(digitalRead(PULSET));
       if (i2 && (i2 != stat2) ) {
        delay13 = millis();
       }
       stat2 = i2;
      }
   }

Robin2

The demo Several Things at a Time  illustrates the use of millis() to manage timing without blocking. It may help with understanding the technique.

Have a look at Using millis() for timing. A beginners guide if you need more explanation.

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

antoniok270

The demo Several Things at a Time  illustrates the use of millis() to manage timing without blocking. It may help with understanding the technique.

Have a look at Using millis() for timing. A beginners guide if you need more explanation.

...R
Hi .

Robin2 Interesting post about millis, I already read all the content of the post and today I did enough research on millis.

In the code I posted above I think the logic in relation to the buttons is good, but I'm not sure if it is well configured! in the example of the post that posted with the LEDs, it was clear how it works, now in relation to working with functions, I have no idea what I'm doing wrong so that it does not work
Honestly at this moment I do not know what else to do so you can make my code work!
  I accept more ideas or suggestions!
I am grateful for the time you have for me.

Robin2

My first suggestion is to delete all the code in the functions BLINK2 and BLINK3 and concentrate on BLINK1. When you get that working you can easily create the code for the other functions.

My next suggestion is that you tell us exactly what should happen when BLINK1 is called - because it is not clear from your code. Also, I suspect that a lot of the code for the three functions can be shared.

My third suggestion is to use the AutoFormat tool to indent your code consistently as it will make it much easier to read (for you and us).


Separately, I think the line while(digitalRead(PULSET)==LOW); is intended to avoid switch bounce but it is a very crude way to do it as the whole program will be paralysed until you take your finger off the button. The more usual way is to record the state of the button and compare it with the previous state. If it is LOW and previously was HIGH then there was a new button press. Also, only read the button again after a short interval - maybe 50 millisecs using millis() for the timing as in my demo.

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

antoniok270

Hi Robin2
Thanks for the suggestions, yes I think the best is also to start with a little code!

Well I deleted the functions BLINK1 and BLINK2 and I updated the code as you suggested, although the code compiles well, but it does not work!

What I want to do is to do with a single push button (EX; SET) call the functions outside the LOOP function, functions for example increment variables, do some type of update in the code, mathematical calculations, I in this case the example I made for blinking LEDs, when I finish doing what I want to do I press the button again (SET), exit out of this function and return to the loop, and rotate the code that is inside the loop.
If I did not explain well what to do with the code I explain again.

I do not know what I'm doing wrong so it does not work, if possible I can indicate where I'm wrong in the code, it would be a big step.

The modified code

Code: [Select]



#define PULSET  5
unsigned long previousMillis = 0;
const long interval = 500;

byte MOD = 0;
void BLINK1();


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

  pinMode(PULSET, INPUT_PULLUP);
  pinMode(LEDPIN1, OUTPUT);

}
void loop()
{
  static unsigned long delayx;
  static bool x = true;
  static bool i = true;
  x = digitalRead(PULSET);
  if ((!x && i) && ((millis() - delayx) > 50))
  {
    MOD++;
    if (MOD > 2) {
      MOD = 1;
    }
    delayx = millis();
  }
    if (MOD == 1) {
      BLINK1();
    }

 
}

  void BLINK1()//function one
  {
    int Debounce1 = 50;
    static unsigned long delay1 = 0;
    static bool stat;
    byte i = 0;

    if (millis() - previousMillis < interval) {

      digitalWrite(LEDPIN1, HIGH);
    }
    if (millis() - previousMillis > interval) {

      digitalWrite(LEDPIN1, LOW);
    }
    if (millis() - previousMillis == 1000) {

      previousMillis = millis();
    }

    if ( (millis() - delay1) > Debounce1 ) {
      i = (digitalRead(PULSET));
      if (i && (i != stat) )
      {
        delay1 = millis();
      }
      stat = i;
    }
  }

Robin2

#11
Nov 18, 2018, 11:50 pm Last Edit: Nov 18, 2018, 11:51 pm by Robin2
when I finish doing what I want to do I press the button again (SET), exit out of this function and return to the loop,
That is not the right way to think about the problem.

Imagine you have a variable (let's call it runBlink1) and it is normally false. When you press a button it gets changed to true. When you press the button again it changes back to false.

Then envisage how this will work

Code: [Select]
void loop() {
   checkForButtonPress();
   blink1();
}

void checkForButtonPress() {
   // code to read the button and update runBlink1
}

void blink1() {
   if (runBlink1 == true) {
     // do whatever is required
     // but only in small pieces of about a few millisecs so loop() can repeat frequently
  }
}


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

antoniok270

#12
Nov 19, 2018, 07:16 pm Last Edit: Nov 19, 2018, 07:17 pm by antoniok270
Hi Bobin2

I do not know if I understood your logic well, but I made a new code according to your suggestions, but it is still unsuccessful!

Sincerely tested all my little knowledge and the result was zero!

The "checkForButtonPress" function works fine when I press the button the variable "runBlink1" changes state I see by serial!

The program only causes that when I press the button the LED lights and it stays on all the time, even if you press the button again it is still on!

Please correct my code and tell me where I am wrong!
 
I await your understanding and help to achieve my goal.

The new code

Code: [Select]
#define PULSET  5
bool runBlink1 = false;
void blink1();
bool checkForButtonPress();
unsigned long previousMillis = 0;
const long interval = 500;
int LEDPIN1 = 12;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(PULSET, INPUT_PULLUP);
  pinMode(LEDPIN1, OUTPUT);
}


void loop() {
 
  checkForButtonPress();
  blink1();
 
}

bool checkForButtonPress() {
  // code to read the button and update runBlink1
  static unsigned long delayx;
  static bool x = true;
  static bool i = true;
 
  if ((millis() - delayx) > 50)
  {
     x = digitalRead(PULSET);
    if (!x && i){
      runBlink1 = !runBlink1;
      delayx = millis();
    }
    i = x;
  }
  return runBlink1;
}

void blink1() {
  if (runBlink1 == true) {
    // do whatever is required
    if (millis() - previousMillis < interval) {

      digitalWrite(LEDPIN1, HIGH);
    }
     else{
      digitalWrite(LEDPIN1, LOW);
    }
    if (millis() - previousMillis >= 1000) {
    }
    previousMillis = millis();
  }
}

Robin2

I don't have much time now.

I suspect the problem is that you have not designed blink1() with a view to it being called thousands of times. On some of those occasions it will be appropriate to change the state of the LED.  Look at the examples in my earlier link.

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

MorganS

x? i? Variable names are free. The point of using a compiler is you can use long names for variables and those long names don't take up space in the final executable. So make the names longer, something that has meaning to you.

Quote
Code: [Select]
    if (!x && i)
So how do you ever into this when i is false? It turns on but won't turn off.

Quote
Code: [Select]
  return runBlink1;
Why? You never look at the return value. Additionally, it's a global variable, so every other function can see it and doesn't need it returned.

Quote
Code: [Select]
    if (millis() - previousMillis >= 1000) {
    }
    previousMillis = millis();
Oops! That should have been...

Code: [Select]
    if (millis() - previousMillis >= 1000) {
    previousMillis = millis();
    }
"The problem is in the code you didn't post."

Go Up