Thats fine. At this stage of the project the car only needs to turn off and on when the light changes. This can be be done simply with notification leds of red and green. I can add additional functions at a later time but Im on a time crunch so Im trying to finish today. The car doesnt need to react on buttons. The only button feature I wanted to implement is an emergency brake feature. Im looking up software serial and I am having trouble trying to adjust the code for my project. As I stated earlier, I am a programming novice but I need to finish this for a project. I know what I want to do but because of my lack of experience, I am unsure of how to translate that into code.
Here a basic framework using serial
void setup()
{
Serial.begin(9600);
// you can e.g. start the car here
...
...
}
void loop()
{
char lightStatus = 0;
if(Serial.available() >0)
{
lightStatus = Serial.read();
}
switch(lightStatus)
{
case 0:
// nothing received
break;
case 'R':
// put code here to handle red signal
...
...
break;
case 'Y':
// put code here to handle yellow signal
...
...
break;
case 'G':
// put code here to handle green signal
...
...
break;
default:
// unknown light status received
break;
}
}
You need to fill in the dots.
Set the line ending in Serial Monitor to none, baudrate 9600 and send the character R, Y or G.
You will have to decide if the car immediately starts running or wait till a button is pressed (see note in setup) or till it sees a 'G' on the serial port. For the latter, your traffic light can e.g. send the status every second (which will be anyway a good idea in case the car misses some serial data).
Next you need to implement a timeout using millis(); if the car does not receive a command every second (or two), it should stop.
You can read Using millis() for timing. A beginners guide and Demonstration code for several things at the same time to get an idea how to use millis() based timing. You can also look at the blink-without-delay example that comes with the IDE for another example of millis() based timing.
Once you have all this in place, you can concentrate on the traffic light. The car code does not need SoftwareSerial; the traffic light code probably needs it (for now) so you can debug using the serial monitor
Why the pressure to get it done by today?
My project is due today. I have like 10 styles of this project. Every time I send it to my professor he doesn't give me very useful information and wants me to change or add something so I had to start from scratch. Class is over and he doesnt respond well to emails so ive been doing it on my own. You have no idea how helpful this is THANK YOU!!! Ill post what I have when I update it again. Funny enough I just found some code for this but your template is much more useful and easy to understand. I really appreciate it again!!!
#define DEBUG 1
#define CAR_ACTIVE_LED 2
#define CAR_INACTIVE_LED 3
//Motion IN/NotIN Progress
#define CAR_TURNED_OFF 0
#define DRIVING_STATE 1
volatile int StateVariable = 0;
#define DEBOUNCE_DELAY 200000
#define INIT 0 //Gas is pushed
#define RUN 1 //Car is in motion
#define EXIT 2 //Gas is released, brake is pushed, and car is stopped
#define EMERGENCY_BRAKE_BUTTON 4
volatile int PhaseVariable = 0;
unsigned long driving_time = 0; // stores the target time value
unsigned long start_time = 0;
void setup()
{
Serial.begin(9600);
// start the car here
pinMode(CAR_ACTIVE_LED, OUTPUT);
pinMode(CAR_INACTIVE_LED, OUTPUT);
pinMode(EMERGENCY_BRAKE_BUTTON, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(EMERGENCY_BRAKE_BUTTON), do_emergency, FALLING);
#ifdef DEBUG
Serial.begin(9600);
#endif
}
void do_emergency(void) {
// This is an ISR
if (software_debounce(EMERGENCY_BRAKE_BUTTON)) {
detachInterrupt(digitalPinToInterrupt(EMERGENCY_BRAKE_BUTTON));
StateVariable = CAR_TURNED_OFF;
PhaseVariable = INIT;
attachInterrupt(digitalPinToInterrupt(EMERGENCY_BRAKE_BUTTON), do_emergency, FALLING);
}
}
bool software_debounce(int pin) {
//delay(DEBOUNCE_DELAY);
for(long i=0; i<DEBOUNCE_DELAY; i++) {}
if (digitalRead(pin) == LOW) {
return true;
}
else return false;
}
void loop()
{
#ifdef DEBUG
Serial.print("State/Phase: ");
Serial.print(StateVariable);
Serial.print("/");
Serial.println(PhaseVariable);
#endif
char lightStatus = 0;
if(Serial.available() >0)
{
lightStatus = Serial.read();
}
switch(lightStatus);
{
case CAR_TURNED_OFF:
// nothing received
digitalWrite(CAR_ACTIVE_LED, LOW);
digitalWrite(CAR_INACTIVE_LED, LOW);
PhaseVariable = RUN;
break;
case 'R':
// put code here to handle red signal
digitalWrite(CAR_ACTIVE_LED, LOW);
digitalWrite(CAR_INACTIVE_LED, HIGH);
break;
case 'Y':
// put code here to handle yellow signal
digitalWrite(CAR_ACTIVE_LED, HIGH);
digitalWrite(CAR_INACTIVE_LED, HIGH);
// Car is slowing down
break;
case 'G':
// put code here to handle green signal
digitalWrite(CAR_ACTIVE_LED, HIGH);
digitalWrite(CAR_INACTIVE_LED, LOW);
break;
default:
// unknown light status received
digitalWrite(CAR_ACTIVE_LED, LOW);
digitalWrite(CAR_INACTIVE_LED, HIGH);
break;
}
}
This is what I got done so far. I have a few errors that I will look up and need help with but other than that Im feeling a lot better. If you have any suggestions and additional code I should add let me know. Thank you all for your help! Also, did you look at the traffic code. Is there anything I should add to it, especially in order to make it run properly with software serial. The millis thing is kind of confusing so I will come back to it shortly. The traffic code is pretty much done I just need to look and make sure it can connect to the other board. If you would like that code i can post it.
Car
I would get rid of the interrupt. Your loop() code is non-blocking so you can read the button thousands of times per second.
You also should not care about the debounce. At the moment that the button goes LOW, you want to react, not 20 us or 20 ms or 20 s later ![]()
Your ISR should be short; debounce in the ISR does not make it short.
Traffic light
I did look at it when I posted reply #17; see that reply.
Further I mentioned in reply #25 that a timeout on received data should be a good idea in case the communication is interrupted and that you could make the traffic light send the status e.g. every second. You current traffic light code makes that totally impossible due to the delays.
One more comment would be that in the car code you use digitalPinToInterrupt to you know that that function existsl why don't you use it in the traffic light code?
As your traffic light code does not use communication yet, I don't see a need to look futher at that. I will look once you have implemented communication or are having problems implementing it.
PS
You have one error in your car code; there is a semi-colon somewhere where it does not belong.
I have made a few adjustments that you have mentioned to the car code and it compiles. I had some edits to the traffic code but I haven't finished it yet so I will wait on putting it in the chat. How would you have me edit the traffic code and implement the software serial into the traffic code. As to why I didnt add that code to the traffic light. I pretty much restarted my whole project today after talking to my professor so I used some preexisting code. Thanks again for all the help
Create a SoftwareSerial object called car on two pins that are available. Use e.g. car.write('R').
#include <SoftwareSerial.h>
SoftwareSerial Car(2, 3);
int WalkRequest = 0; // Variable used to store the state of the Walk Push Button
const int WalkButton = 2;
const int RedPedLED = 6;
const int WhitePedLED = 7;
// Setup Variables for Station 1 Traffic Light Components
const int Red1LED = 8;
const int Yellow1LED = 9;
const int Green1LED = 10;
// Setup Variables for Station 2 Traffic Light Components
const int Red2LED = 11;
const int Yellow2LED = 12;
const int Green2LED = 13;
// variables that will change:
volatile int buttonState = 0; // variable for monitoring the pushbutton status.
/* A variable should be declared volatile whenever its value can be changed
by something beyond the control of the code section in which it appears,
such as a concurrently executing thread.
In the Arduino, the only place that this is likely to occur is in sections
of code associated with interrupts, called an interrupt service routine (ISR) */
void setup() {
Serial.begin(115200);
Car.begin(4500);
pinMode(12, INPUT_PULLUP);
}
void() {
while (!Car) {
Serial.println(F("wait for serial port to connect."));
}
Car.write("R");
pinMode(RedPedLED, OUTPUT); // Sets all LED's as OUTPUT
pinMode(WhitePedLED, OUTPUT);
pinMode(Red1LED, OUTPUT);
pinMode(Yellow1LED, OUTPUT);
pinMode(Green1LED, OUTPUT);
pinMode(Red2LED, OUTPUT);
pinMode(Yellow2LED, OUTPUT);
pinMode(Green2LED, OUTPUT);
pinMode(WalkButton, INPUT); // Sets Push Button as INPUT
attachInterrupt(0, pin_ISR, CHANGE); // "Watches" in the background for a button press
}
/* Attach an interrupt to the ISR vector to monitor Push Button.
Number 0 (for digital pin 2) or number 1 (for digital pin 3) are used.
Interrupts are useful for making things happen automatically in
microcontroller programs,and can help solve timing problems.
Good tasks for using an interrupt may include reading
a rotary encoder, or monitoring user input */
// Set Initial state of all red LED to HIGH
digitalWrite (Red1LED, HIGH);
digitalWrite (Red2LED, HIGH);
digitalWrite (RedPedLED, HIGH);
void loop() {
// put your main code here, to run repeatedly:
if (digitalRead(12) == 0) {
delay(100);
if (digitalRead(12) == 0)...();
}
delay(25);
}
// Station 1 Timing
delay(2500); // 2.5 Seconds of Red
digitalWrite(Red1LED, LOW); // Sets Red1 OFF Green ON
digitalWrite(Green1LED, HIGH);
delay(15000); // 15 Seconds of Green
digitalWrite(Green1LED, LOW); // Sets Green1 OFF Yellow ON
digitalWrite(Yellow1LED, HIGH);
delay(3500); // 3.5 Seconds of Yellow
digitalWrite(Yellow1LED, LOW); // Sets Yellow1 OFF Red ON
digitalWrite(Red1LED, HIGH);
if (WalkRequest == 1) { // If the button has been pressed
WalkCycle(); // Exit main loop and run WalkCycle () function
}
// Station 2 Timing
{ delay(2500); // 2.5 Seconds of Red
digitalWrite(Red2LED, LOW); digitalWrite(Green2LED, HIGH); // Sets Red2 OFF Green ON
delay(15000); // 15 Seconds of Green
digitalWrite(Green2LED, LOW); digitalWrite(Yellow2LED, HIGH); // Sets Green2 OFF Yellow ON
delay(3500); // 3.5 Seconds of Yellow
digitalWrite(Yellow2LED, LOW); digitalWrite(Red2LED, HIGH); // Sets Yellow2 OFF Red ON
if (WalkRequest == 1) { // If the button has been pressed
WalkCycle(); // Exit main loop and run WalkCycle () function
}
}
void WalkCycle() {
delay(3500); // 3.5 Second delay before "WALK" begins
digitalWrite (WhitePedLED, HIGH); digitalWrite (RedPedLED, LOW); // Turn on White Pedestrian Light
delay (15000); // 15 Second delay to allow crossing street
digitalWrite (WhitePedLED, LOW); digitalWrite(WalkButton, LOW); // Turn off White Pedestrian Light
delay(250);
for (int x = 0; x < 5; x++) { // Flash White Ped LED 5X
digitalWrite(WhitePedLED, HIGH);
delay(250);
digitalWrite(WhitePedLED, LOW);
delay(250);
}
digitalWrite(RedPedLED, HIGH);
WalkRequest = 0; // Reset Push Button
asm volatile (" jmp 0"); // Soft-reset of sketch. Makes sure Station 1 "MAIN" always gets Green after a walk cycle
}
void pin_ISR() {
buttonState = digitalRead(WalkButton);
(WalkRequest = 1); // Walk button has been pressed
// digitalWrite(WhitePedLED, buttonState); // Test Light for Interrupt use only during testing!
}
This is what I got so far in terms of implementing software serial. I still need to understand and change the delays to millis() though. I was a little confused.
Your code does not compile. Somewhere missing a }
Where does that ESP suddenly come from? If you have real SSID/password in there, edit your post and remove it.
What is a station in this context?
I was watching a tutorial on youtube and I think I confused myself and did it wrong. I think this is for something else. Thats what happens when youve been up 28 hrs
That wasnt my info. I edited the code regardless but I still have some errors
[Traffic]
#include <SoftwareSerial.h>
SoftwareSerial Car(2, 3);
int WalkRequest = 0; // Variable used to store the state of the Walk Push Button
const int WalkButton = 4;
const int RedPedLED = 5;
const int WhitePedLED = 6;
// Setup Variables for Station 1 Traffic Light Components
const int Red1LED = 7;
const int Yellow1LED = 8;
const int Green1LED = 9;
// Setup Variables for Station 2 Traffic Light Components
const int Red2LED = 10;
const int Yellow2LED = 11;
const int Green2LED = 12;
// variables that will change:
volatile int buttonState = 0; // variable for monitoring the pushbutton status.
/* A variable should be declared volatile whenever its value can be changed
by something beyond the control of the code section in which it appears,
such as a concurrently executing thread.
In the Arduino, the only place that this is likely to occur is in sections
of code associated with interrupts, called an interrupt service routine (ISR) */
void setup() {
Serial.begin(115200);
Car.begin(4500);
pinMode(12, INPUT_PULLUP);
void(); {
while (!Car)
Serial.println(F("wait for serial port to connect."));
Car.write("R");
}
pinMode(RedPedLED, OUTPUT); // Sets all LED's as OUTPUT
pinMode(WhitePedLED, OUTPUT);
pinMode(Red1LED, OUTPUT);
pinMode(Yellow1LED, OUTPUT);
pinMode(Green1LED, OUTPUT);
pinMode(Red2LED, OUTPUT);
pinMode(Yellow2LED, OUTPUT);
pinMode(Green2LED, OUTPUT);
pinMode(WalkButton, INPUT); // Sets Push Button as INPUT
attachInterrupt(0, pin_ISR, CHANGE); // "Watches" in the background for a button press
/* Attach an interrupt to the ISR vector to monitor Push Button.
Number 0 (for digital pin 2) or number 1 (for digital pin 3) are used.
Interrupts are useful for making things happen automatically in
microcontroller programs,and can help solve timing problems.
Good tasks for using an interrupt may include reading
a rotary encoder, or monitoring user input */
// Set Initial state of all red LED to HIGH
digitalWrite (Red1LED, HIGH);
digitalWrite (Red2LED, HIGH);
digitalWrite (RedPedLED, HIGH);
}
void loop() {
// put your main code here, to run repeatedly:
// Station 1 Timing
delay(2500); // 2.5 Seconds of Red
digitalWrite(Red1LED, LOW); // Sets Red1 OFF Green ON
digitalWrite(Green1LED, HIGH);
delay(15000); // 15 Seconds of Green
digitalWrite(Green1LED, LOW); // Sets Green1 OFF Yellow ON
digitalWrite(Yellow1LED, HIGH);
delay(3500); // 3.5 Seconds of Yellow
digitalWrite(Yellow1LED, LOW); // Sets Yellow1 OFF Red ON
digitalWrite(Red1LED, HIGH);
if (WalkRequest == 1) { // If the button has been pressed
WalkCycle(); // Exit main loop and run WalkCycle () function
}
// Station 2 Timing
delay(2500); // 2.5 Seconds of Red
digitalWrite(Red2LED, LOW); digitalWrite(Green2LED, HIGH); // Sets Red2 OFF Green ON
delay(15000); // 15 Seconds of Green
digitalWrite(Green2LED, LOW); digitalWrite(Yellow2LED, HIGH); // Sets Green2 OFF Yellow ON
delay(3500); // 3.5 Seconds of Yellow
digitalWrite(Yellow2LED, LOW); digitalWrite(Red2LED, HIGH); // Sets Yellow2 OFF Red ON
if (WalkRequest == 1) { // If the button has been pressed
WalkCycle(); // Exit main loop and run WalkCycle () function
}
}
void WalkCycle() {
delay(3500); // 3.5 Second delay before "WALK" begins
digitalWrite (WhitePedLED, HIGH); digitalWrite (RedPedLED, LOW); // Turn on White Pedestrian Light
delay (15000); // 15 Second delay to allow crossing street
digitalWrite (WhitePedLED, LOW); digitalWrite(WalkButton, LOW); // Turn off White Pedestrian Light
delay(250);
for (int x = 0; x < 5; x++) { // Flash White Ped LED 5X
digitalWrite(WhitePedLED, HIGH);
delay(250);
digitalWrite(WhitePedLED, LOW);
delay(250);
}
digitalWrite(RedPedLED, HIGH);
WalkRequest = 0; // Reset Push Button
asm volatile (" jmp 0"); // Soft-reset of sketch. Makes sure Station 1 "MAIN" always gets Green after a walk cycle
}
void pin_ISR() {
buttonState = digitalRead(WalkButton);
(WalkRequest = 1); // Walk button has been pressed
// digitalWrite(WhitePedLED, buttonState); // Test Light for Interrupt use only during testing!
}
[CAR]
#define DEBUG 1
#define CAR_ACTIVE_LED 2
#define CAR_INACTIVE_LED 3
//Motion IN/NotIN Progress
#define CAR_TURNED_OFF 0
#define DRIVING_STATE 1
volatile int StateVariable = 0;
#define INIT 0 //Gas is pushed
#define RUN 1 //Car is in motion
#define EXIT 2 //Gas is released, brake is pushed, and car is stopped
#define EMERGENCY_BRAKE_BUTTON 4
volatile int PhaseVariable = 0;
unsigned long driving_time = 0; // stores the target time value
unsigned long start_time = 0;
void setup()
{
Serial.begin(9600);
// start the car here
pinMode(CAR_ACTIVE_LED, OUTPUT);
pinMode(CAR_INACTIVE_LED, OUTPUT);
pinMode(EMERGENCY_BRAKE_BUTTON, INPUT_PULLUP);
#ifdef DEBUG
Serial.begin(9600);
#endif
}
void do_emergency(void) {
// This is an ISR
detachInterrupt(digitalPinToInterrupt(EMERGENCY_BRAKE_BUTTON));
StateVariable = CAR_TURNED_OFF;
PhaseVariable = INIT;
attachInterrupt(digitalPinToInterrupt(EMERGENCY_BRAKE_BUTTON), do_emergency, FALLING);
}
void loop()
{
#ifdef DEBUG
Serial.print("State/Phase: ");
Serial.print(StateVariable);
Serial.print("/");
Serial.println(PhaseVariable);
#endif
char lightStatus = 0;
if (Serial.available() > 0)
{
lightStatus = Serial.read();
}
switch (lightStatus)
{
case CAR_TURNED_OFF:
// nothing received
digitalWrite(CAR_ACTIVE_LED, LOW);
digitalWrite(CAR_INACTIVE_LED, LOW);
PhaseVariable = RUN;
break;
case 'R':
// put code here to handle red signal
digitalWrite(CAR_ACTIVE_LED, LOW);
digitalWrite(CAR_INACTIVE_LED, HIGH);
break;
case 'Y':
// put code here to handle yellow signal
digitalWrite(CAR_ACTIVE_LED, HIGH);
digitalWrite(CAR_INACTIVE_LED, HIGH);
// Car is slowing down
break;
case 'G':
// put code here to handle green signal
digitalWrite(CAR_ACTIVE_LED, HIGH);
digitalWrite(CAR_INACTIVE_LED, LOW);
break;
default:
// unknown light status received
digitalWrite(CAR_ACTIVE_LED, LOW);
digitalWrite(CAR_INACTIVE_LED, HIGH);
break;
}
}
Latest Update on code
I think it's time that you go to bed
that edit of reply #31 is garbage.
Reply #34 is better
Only thing you have to do now is send the commands to the car when the traffic light changes colours.
I had a little nap. yeah I noticed that so I just took some extra time to think after my nap
. Where do I go from here and how would I do the commands. Is it the same as what was done for the car code?
Would I use something similar to this part of the car code?
char lightStatus = 0;
if (Serial.available() > 0)
{
lightStatus = Serial.read();
}
switch (lightStatus)
{
case CAR_TURNED_OFF:
// nothing received
digitalWrite(CAR_ACTIVE_LED, LOW);
digitalWrite(CAR_INACTIVE_LED, LOW);
PhaseVariable = RUN;
break;
case 'R':
// put code here to handle red signal
digitalWrite(CAR_ACTIVE_LED, LOW);
digitalWrite(CAR_INACTIVE_LED, HIGH);
break;
case 'Y':
// put code here to handle yellow signal
digitalWrite(CAR_ACTIVE_LED, HIGH);
digitalWrite(CAR_INACTIVE_LED, HIGH);
// Car is slowing down
break;
case 'G':
// put code here to handle green signal
digitalWrite(CAR_ACTIVE_LED, HIGH);
digitalWrite(CAR_INACTIVE_LED, LOW);
break;
default:
// unknown light status received
digitalWrite(CAR_ACTIVE_LED, LOW);
digitalWrite(CAR_INACTIVE_LED, HIGH);
break;
}
}
Think logically about it.
Under which condition do you want cars to stop? When the pedestrians can walk. So that's where you need to control the car.
So you can put calls to Car.write() in WalkCycle(); though it might not be te best place, it's the easiest to implement in the current code.
So before you allow the pedestrians to cross, you send a 'R'. Or first a 'Y', a short delay and next a 'R'.
And once pedestrians can no longer cross and cars are allowed to go again, you send a 'G'.
How would I format that in the code? Would I use case and digitalWrite?
void WalkCycle() {
Car.write('R');
delay(3500); // 3.5 Second delay before "WALK" begins
digitalWrite (WhitePedLED, HIGH); digitalWrite (RedPedLED, LOW); // Turn on White Pedestrian Light
Car.write('G');
delay (15000); // 15 Second delay to allow crossing street
digitalWrite (WhitePedLED, LOW); digitalWrite(WalkButton, LOW); // Turn off White Pedestrian Light
delay(250);
for (int x = 0; x < 5; x++) { // Flash White Ped LED 5X
digitalWrite(WhitePedLED, HIGH);
delay(250);
digitalWrite(WhitePedLED, LOW);
delay(250);
}
digitalWrite(RedPedLED, HIGH);
WalkRequest = 0; // Reset Push Button
asm volatile (" jmp 0"); // Soft-reset of sketch. Makes sure Station 1 "MAIN" always gets Green after a walk cycle
}
I think I understand that. You want me to implement the car write so that the car reacts to the pedestrian lights as the colors change.
That's more or less what I was saying in in the post that I deleted.
Except that you give the car the 'G' again before the pedestrians start crossing. Car.write('G'); needs to move to another place in WalkCycle().
And you need to get rid of asm volatile (" jmp 0");. It does not make sense. You can end with a situation where station 2 will never be honoured.
I've deleted a post. I have been concenrtating too much on the pedestrian part and not on the rest of your code; pasrtially because you never explained what stations are.
Thinking about it, you need to instruct your car when the traffic light changes colour.
So when station 1 turns green, you can send a 'G' to the car.
// Station 1 Timing
delay(2500); // 2.5 Seconds of Red
digitalWrite(Red1LED, LOW); // Sets Red1 OFF Green ON
digitalWrite(Green1LED, HIGH);
Car.write('G');
And so on.
Note that there is no way at this stage for the car to know if it's approaching station 1 and has to react on that and ignore station 2 or is approaching station 2 and has to ignore station 1.
// Station 1 Timing
delay(2500); // 2.5 Seconds of Red
digitalWrite(Red1LED, LOW); // Sets Red1 OFF Green ON
digitalWrite(Green1LED, HIGH);
Car.write('G');
delay(15000); // 15 Seconds of Green
digitalWrite(Green1LED, LOW); // Sets Green1 OFF Yellow ON
digitalWrite(Yellow1LED, HIGH);
Car.write('Y');
delay(3500); // 3.5 Seconds of Yellow
digitalWrite(Yellow1LED, LOW); // Sets Yellow1 OFF Red ON
digitalWrite(Red1LED, HIGH);
Car.write('R');
void WalkCycle() {
Car.write('G');
delay(3500); // 3.5 Second delay before "WALK" begins
digitalWrite (WhitePedLED, HIGH); digitalWrite (RedPedLED, LOW); // Turn on White Pedestrian Light
Car.write('R');
delay (15000); // 15 Second delay to allow crossing street
digitalWrite (WhitePedLED, LOW); digitalWrite(WalkButton, LOW); // Turn off White Pedestrian Light
delay(250);
for (int x = 0; x < 5; x++) { // Flash White Ped LED 5X
digitalWrite(WhitePedLED, HIGH);
delay(250);
digitalWrite(WhitePedLED, LOW);
delay(250);
}
digitalWrite(RedPedLED, HIGH);
}
I edited the code in the two places where the car would have to react to the pedestrian traffic and removed the volatile (" jmp "). I see. Sorry I must have missed that with everything else I was working on. Thanks for your help again!