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:
//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;
}
}
}
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.
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
//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;
}
}
}
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
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.
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.
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!
#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.
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.
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.
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
#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;
}
}
antoniok270:
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
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
}
}
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.
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.
if (!x && i)
So how do you ever into this when i is false? It turns on but won't turn off.
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.
Maybe when you remove the line with return you also have to change the function definition from
bool checkForButtonPress() {
to
void checkForButtonPress() {
The code in the link I gave you in Reply #7 uses several functions - each using different timing. And there is a more comprehensive example in Planning and Implementing a Program
My previous comment was a bit short because I was typing it on my phone. I've re-read your code and it makes more sense to me. The single-letters were confusing. x is the current value of the digital read and i is the previous value. It will toggle the runBlink1 when the button is currently pressed and previously wasn't, and not more often than once every 50 millseconds.
So this simple single-blink works now? You have it working in a way that you expect? Now you want to go back to the original question of "entering" a function...
When we plan to write a computer program, usually there is some "flowchart" of a linear sequence of actions. "Do A" is followed by "Do B". When we're actually writing the code, we also have a linear sequence of actions. "x = digitalRead(PULSET);" is followed by "if(!x&&i)" and so on. But there's a middle layer in between those two levels which is absolutely not linear. Your project might have an "emergency stop" button. Every box on the flowchart has an invisible arrow leading out of it that would say "stop button pushed". You don't draw those arrows on the chart because the chart would get messy.
Similarly, in the actual code, you don't have every single function check the emergency stop button after every 4 lines of code. That would be unbelievably messy. You must structure your code so that no function ever gets stuck for more than a few milliseconds. Then you can have another function check the emergency-stop button and any other inputs. If you stick to the rule about functions running quickly, you can make it look like it stops "instantly" but really it took a few milliseconds because it was doing something else at the exact moment you pressed the button.
Read and re-read Robin's link above. Then try to ask your question again in a different way.