I'm in quite the same problem as you. I'm trying to make a 2 way traffic light with a push button as an interruption to restart the loop, but everytime I push the button, the interruption occurs, but then resumes from the point it was stopped rather than starting all over again. I've been suggested to use a variable function, but I have no idea how to do it. If anyone can help me, I'll really appreciate it.
NiceArgie:
I'm in quite the same problem as you.
No, you're not.
There is nothing about a traffic light at the level you're at that requires an interrupt.
NiceArgie:
I'm in quite the same problem as you.[...]
If anyone can help me, I'll really appreciate it.
Please don't hijack another person's Thread with your problem. Start your own Thread.
...R
You want a state machine.
Thread split.
The problem is probably the delay() strategy used to program the traffic light.
AWOL:
You want a state machine.
Whether you want it or not, the best way to go is using a state machine.
Hello, I'm a beginner trying to make a simple project work, but I'm rather stuck. I'm trying to make a 2-way traffic light with a pedestarian priority button (as an interruption), meaning that when the interruption is over, the whole loop has to restart from the beginning rather than keep going from where it was stopped. That last bit is causing me a lot of trouble, since I have no idea how to do it. I tried finding a function to help me with that (like goto or something like it) but with no luck. Here's my code so far (disclaimer, I only know how to use "for" and "if" function so far, so my code may look really rowdy):
int led1=1;
int led2=2;
int led3=4;
int led4=5;
int led5=6;
int led6=7;
void interrupt()
{
digitalWrite(led1, HIGH);
}
void setup()
{
digitalWrite(led1, OUTPUT);
digitalWrite(led2, OUTPUT);
digitalWrite(led3, OUTPUT);
digitalWrite(led4, OUTPUT);
digitalWrite(led5, OUTPUT);
digitalWrite(led6, OUTPUT);
digitalWrite(led1, HIGH);
attachInterrupt(1, interrupt, RISING);
}
void loop()
{
if (digitalRead(led1 == HIGH))
{
digitalWrite(led2, LOW);
digitalWrite(led3, LOW);
digitalWrite(led4, LOW);
digitalWrite(led5, LOW);
digitalWrite(led6, HIGH);
delay(3000);
digitalWrite(led1, LOW);
digitalWrite(led2, HIGH);
digitalWrite(led3, LOW);
digitalWrite(led4, LOW);
digitalWrite(led5, LOW);
digitalWrite(led6, LOW);
}
if (digitalRead(led2 == HIGH))
{
digitalWrite(led1, LOW); // asdsad
digitalWrite(led3, LOW);
digitalWrite(led4, LOW);
digitalWrite(led5, HIGH);
digitalWrite(led6, LOW);
delay(1000);
digitalWrite(led1, LOW);
digitalWrite(led2, LOW);
digitalWrite(led3, HIGH);
digitalWrite(led4, LOW);
digitalWrite(led5, LOW);
digitalWrite(led6, LOW);
}
if (digitalRead(led3 == HIGH))
{
digitalWrite(led1, LOW);
digitalWrite(led2, LOW);
digitalWrite(led4, HIGH);
digitalWrite(led5, LOW);
digitalWrite(led6, LOW);
delay(3000);
digitalWrite(led1, LOW);
digitalWrite(led2, HIGH);
digitalWrite(led3, LOW);
digitalWrite(led4, LOW);
digitalWrite(led5, LOW);
digitalWrite(led6, LOW);
}
if (digitalRead(led2 == HIGH))
{
digitalWrite(led1, LOW);
digitalWrite(led3, LOW);
digitalWrite(led4, LOW);
digitalWrite(led5, HIGH);
digitalWrite(led6, LOW);
delay(1000);
digitalWrite(led1, HIGH);
digitalWrite(led2, LOW);
digitalWrite(led3, LOW);
digitalWrite(led4, LOW);
digitalWrite(led5, LOW);
digitalWrite(led6, LOW);
}
}
Any help would be appreciated!
Hi,
Although what you intend (better: the way you intend to solve it) to do it seems clear, the approach is not:
- The use of delay() leads to unsolvable problems (in this case and in many others).
- Just by "looping" a manual button (pedestrian) can be easily detected without using interrupts. Using interrupts for that purpose is, as the spanish proverb says, like "killing fleas by using a cannon ball" (although they may be used -interrupts, I mean- for this purpose).
The "loop" idea is to keep it running continuosly and, desirably, the faster you can. When you want things happening in a sequence (a traffic light system being a good example) the best is to use the millis() function and several variables to check intervals. Have a look to the "blink without delay" example in the forum.
Regards.
With properly written code, there is NO reason to use an interrupt to determine that a switch is pressed.
the whole loop has to restart from the beginning rather than keep going from where it was stopped.
That is NOT how interrupts work. If you are cooking dinner, and the doorbell rings, after answering the door, do you throw away everything that you were preparing for dinner, and start over?
That last bit is causing me a lot of trouble, since I have no idea how to do it.
That's most likely because it can't be done.
digitalWrite(led1, OUTPUT);
digitalWrite(led2, OUTPUT);
digitalWrite(led3, OUTPUT);
digitalWrite(led4, OUTPUT);
digitalWrite(led5, OUTPUT);
digitalWrite(led6, OUTPUT);
Why are you writing OUTPUT to an INPUT pin?
if (digitalRead(led1 == HIGH))
You should print the value of led1 == HIGH to see which pin you are really reading from. Then, you should explain WHY you are doing that.
Your final code will have NO calls to delay(). The blink without delay example doesn't either.
digitalRead(led1 == HIGH)
Can you see what is wrong here?
Instead of reading back your outputs to find out where you are up to, create another variable to keep track of the current position in the cycle. Call it cyclePosition or something that makes sense to you.
Then, when the pedestrian button is pressed, set cyclePosition to the correct position.
Don't use an interrupt for a button. It still has to wait out the period of the current delay before your code can react to that input.
Don't use delay() either. Look at the blink-without-delay example and the sticky post at the top of this sub forum.
Your code could look something like this....
void loop() {
checkTimers();
readInputs();
setOutputs();
}
You just have to write those functions and make the shared variables such as cyclePosition global.
Have a look at how millis() is used to manage timing without blocking in Several Things at a Time.
Note how each function runs very briefly and returns to loop() so the next one can be called. Long running processes are achieved a tiny piece at a time. And there may be dozens of calls to some functions before it is actually time for anything to happen.
For a more extensive example see Planning and Implementing a Program
...R
You shouldn't do anything instantly when the button is pushed. First, you've go to go through the yellow-light sequence and if pedestrians keep coming and pushing the button one-after-another, they would stop the traffic in the other direction forever.
An interrupt is good, but you might want to just set a Button Pushed "flag". That is, make a Boolean (HIGH/LOW) variable and set it high (or TRUE) when the button is pushed.... "Remember" that the button was pushed.
Then, when you get around to the right place in your signal-sequence, use an if-statement to turn-on the "walk" sign, or whatever you want to do. (And, don't forget to reset the flag.)
And, it would be helpful to re-name your LEDs with names that represent the color and direction.
I understand that an interruption may not be the best way to solve this problem. Yet, I've been told to do it this way.
That is NOT how interrupts work.
Yes, I'm aware of that, and I agree with you, but again, this is the way "it has to be done".
Why are you writing OUTPUT to an INPUT pin?
Yes, my mistake, I mistakenly used digitalWrite instead of pinMode.
NiceArgie:
I understand that an interruption may not be the best way to solve this problem. Yet, I've been told to do it this way.Yes, I'm aware of that, and I agree with you, but again, this is the way "it has to be done".
Why is someone telling you to do it wrong?
NiceArgie:
Yes, I'm aware of that, and I agree with you, but again, this is the way "it has to be done".
Well, in fact using or not the interrupt is the second problem ... (Nevertheless, it has to be stated that this is not the correct way to do it, but it can be made using them).
Set a flag (i.e.: "pedestrianRequest") to True when it is pressed; set it to False when the task is accomplished.
¿Have you any idea on how to do the remainder by using millis()?
Regards.
Why is someone telling you to do it wrong?
Cuz, college teacher, who knows what he's thinking.
¿Have you any idea on how to do the remainder by using millis()?
Sadly, no. I've been going the whole semester to class, but I've only learned how to use "for", "if", "delay" functions, and "attachInterrupt" for this project in particular.
NiceArgie:
Cuz, college teacher, who knows what he's thinking.
Fair enough.
Then you’re going to have to get rid of all delay() functions in your code and learn to use millis() for timing. There are plenty of online resources to help do that.
In the ISR set a flag to indicate that the interrupt occurred. Pick up (and reset) that flag in loop() and take the appropriate action. Be sure to declare your flag variable as ‘volatile’. Again, there are numerous examples available online.
You'll also probably need to learn about State Machines. Again, there are numerous examples available online.
Argie,
Perhaps what you have learnt is not what you need ...
To program such a thing you need, at least, to fully understand the "blink without delay" example. Do you?
Regards.
Actually, delay and interrupt are not wrong for this simple assignment.
In the real world however, you can be certain that the requirements will change and locking in delay() now will make it impossible to meet any reasonable change requests.
MorganS:
Actually, delay and interrupt are not wrong for this simple assignment.
Don't think I agree. Sure, pressing the button will trigger the ISR which will then "know" what has happened. But, there's no way for the ISR to tell the main code in loop() to abandon its current task and start at the beginning --- because it's stuck in a delay(). At best, the main code could only check a flag from the ISR after the delay() is over.