//John Guarnieri 06/11/2020 Simplified USA Traffic light system just using 5 led's 3 for traffic 2 for Pedestrian crossing. // I am relativly new to arduino and electronics, just a hobby, I like to learn new things. //My simplified USA Traffic Light System using 5 led's works as follows: //Red traffic immediatly to green traffic - green traffic to Yellow traffic - yellow traffic back to red traffic - repeat //this script uses button array - sizeof() - Debounce - millis - machine state. I feel this sketch will be a good learning experience //for anyone who is interested in Arduino coding and how it works. //I did not write this code from scratch, I did edit it and added blocks form other google code and Arduino forum //credits //larryd Arduino forum original code/John Guarnieri edit 05/30/2020 // TrafficLightStateMachinePedSwitch.ino //hsiboy/MultiButton.ino multi button with debounce https://gist.github.com/hsiboy/f55a0911c7e8553092ea //revision hsiboy created this gist on Jan 30, 2015. //I can't find what was changed in the revision #define DEBOUNCE 20 // button debouncer, how many ms to debounce, 5+ ms is usually plenty // here is where we define the buttons that we'll use. button "1" is the first, button "6" is the 6th, etc //byte buttons[] = {4, 9, 12, A0}; // the analog 0-5 pins are also known as 14-19 //my add or edit //************************************************************************************************************** byte buttons[] = {2, 3}; // the analog 0-5 pins are also known as 14-19 //************************************************************************************************************** // This handy macro lets us determine how big the array up above is, by checking the size //original Clément Lansmarie says below line is wrong //it still works in your case because buttons is an array of bytes //but it wouldn't work as intended with another type. //If button is an array of integers, then the sizeof () that would be 8 //since each button is 2 bytes. Your original statement only works //because button is a byte. The second form below is considered safer. //#define NUMBUTTONS sizeof(buttons) //recomended by facebook should be below line Clément Lansmarie #define NUMBUTTONS (sizeof(buttons) / sizeof(buttons[0])) // we will track if a button is just pressed, just released, or 'currently pressed' volatile byte pressed[NUMBUTTONS], justpressed[NUMBUTTONS], justreleased[NUMBUTTONS]; //my add or edit //************************************************************************************************************** // Traffic Light code //my add or edit enum STATES {STARTUP, RED, GREEN, YELLOW, CROSSING, REDdontWalk}; STATES mState = STARTUP; //my add or edit unsigned long redMillis; unsigned long greenMillis; unsigned long yellowMillis; unsigned long REDdontWalkMillis; unsigned long currentMillis; unsigned long heartbeatMillis; unsigned long switchMillis; unsigned long pedMillis; unsigned long flashingMillis; const unsigned long switchDelay = 25; //25ms //my add or edit #define ENABLED true #define DISABLED false //my add or edit bool walkFlag = DISABLED; bool pedFlag = DISABLED; bool REDdontWalkFlag = DISABLED; bool flashingFlag = DISABLED; //my add or edit //realistic times 1 minute on red and green 12 seconds on yellow /* //Change as needed #define redInterval 60 * 1000ul //ON time in seconds #define greenInterval 60 * 1000ul //ON time in seconds #define yellowInterval 12 * 1000ul //ON time in seconds #define flashingDelay 40 * 1000ul //Time at which the flashing starts #define pedInterval 50 * 1000ul //Time at which the walk light goes off #define REDdontWalkInterval 3 * 1000ul //wait 3 seconds before the "Don't Walk" comes on #define flashingInterval 200ul #define minHoldTime 500ul */ //my add or edit //testing speed times 3 seconds //my edit alter times for testing speed #define redInterval 3 * 1000ul //ON time in seconds #define greenInterval 3 * 1000ul //ON time in seconds #define yellowInterval 3 * 1000ul //ON time in seconds #define flashingDelay 10 * 1000ul //Time at which the flashing starts this has to be smaller than pedInterval #define pedInterval 20 * 1000ul //Time at which the walk light goes off #define REDdontWalkInterval 3 * 1000ul //wait 3 seconds before the "Don't Walk" comes on #define flashingInterval 200ul #define minHoldTime 500ul const byte redLED = 5; //+5V----[>|]----[220R]----GND const byte greenLED = 7; const byte yellowLED = 6; const byte walk_green_LED = 9; //look here study this original code const byte walk_red_LED = 8; const byte heartbeatLED = 13; #define LEDon HIGH #define LEDoff LOW //original code //************************************************************************************************************** void setup() { byte i; // set up serial port Serial.begin(9600); Serial.print("Button checker with "); Serial.print(NUMBUTTONS, DEC); Serial.println(" buttons"); //my add or edit //************************************************************************************************************* pinMode(redLED, OUTPUT); pinMode(greenLED, OUTPUT); pinMode(yellowLED, OUTPUT); pinMode(walk_red_LED, OUTPUT); pinMode(walk_green_LED, OUTPUT); pinMode(heartbeatLED, OUTPUT); //pinMode (walkSwitch.pin, INPUT_PULLUP); //walkSwitch.lastState = digitalRead(walkSwitch.pin); //pinMode (otherSwitch.pin, INPUT_PULLUP); //otherSwitch.lastState = digitalRead(otherSwitch.pin); //************************************************************************************************************* // pin13 LED pinMode(13, OUTPUT); // Make input & enable pull-up resistors on switch pins for (i=0; i < NUMBUTTONS; i++) { pinMode(buttons[i], INPUT); digitalWrite(buttons[i], HIGH); } // I am not clear on how this TCCR2A works not using it for now //************************************************************************************************************* // Run timer2 interrupt every 15 ms //TCCR2A = 0; //TCCR2B = 1< millis()) { // not enough time has passed to debounce return; } // ok we have waited DEBOUNCE milliseconds, lets reset the timer lasttime = millis(); for (index = 0; index < NUMBUTTONS; index++){ currentstate[index] = digitalRead(buttons[index]); // read the button /* Serial.print(index, DEC); Serial.print(": cstate="); Serial.print(currentstate[index], DEC); Serial.print(", pstate="); Serial.print(previousstate[index], DEC); Serial.print(", press="); */ if (currentstate[index] == previousstate[index]) { if ((pressed[index] == LOW) && (currentstate[index] == LOW)) { // just pressed justpressed[index] = 1; } else if ((pressed[index] == HIGH) && (currentstate[index] == HIGH)) { // just released justreleased[index] = 1; } pressed[index] = !currentstate[index]; // remember, digital HIGH means NOT pressed } //Serial.println(pressed[index], DEC); previousstate[index] = currentstate[index]; // keep a running tally of the buttons } } //end void check_switches void loop() { //save current time //my add currentMillis = millis(); // to run traffic lights automatically call checkTrafficLight() here in void loop //******************************** //to help show if there is any blocking code, this LED toggles every 500ms //BEGIN: substitute // Run timer2 interrupt every 15 ms here use millis if (currentMillis - heartbeatMillis >= 1000) { Serial.print("Time = "); Serial.println(currentMillis / 1000ul); //start this TIMER heartbeatMillis = currentMillis; digitalWrite(heartbeatLED, !digitalRead(heartbeatLED)); } //END: substitute // Run timer2 interrupt every 15 ms here use millis check_switches(); checkTrafficLight(); for (byte i = 0; i < NUMBUTTONS; i++){ if (justpressed[i]) { justpressed[i] = 0; Serial.print(i, DEC); Serial.println(" Just pressed"); // remember, check_switches() will CLEAR the 'just pressed' flag } if (justreleased[i]) { //do work here //my add or edit if (buttons[i] == 2) { // Do the thing for pin 2 // to run traffic lights manually call checkTrafficLight() here //each button press on button 2 will go thru the traffic lights //based on millis times //my add //call function here if you want manual traffic light sequence using button 2 //checkTrafficLight(); } //PROBLEM AREA if (buttons[i] == 3) { // Do the thing for pin 3 //my add or edit fix for Pedestrian button firing off if pressed and released "again" during Pedestrian Crossing if ((currentMillis - REDdontWalkMillis > REDdontWalkInterval) && (pedFlag == DISABLED)) { REDdontWalkFlag = DISABLED; walkFlag = ENABLED; } } justreleased[i] = 0; Serial.print(i, DEC); Serial.println(" Just released"); // remember, check_switches() will CLEAR the 'just pressed' flag } if (pressed[i]) { Serial.print(i, DEC); Serial.println(" pressed"); // is the button pressed down at this moment } } } //end void loop //my add or edit //************************************************************************************************************* void checkTrafficLight() { switch (mState) { //***************** case STARTUP: { digitalWrite(redLED, LEDon); digitalWrite(greenLED, LEDoff); digitalWrite(yellowLED, LEDoff); digitalWrite(walk_red_LED, LEDon); digitalWrite(walk_green_LED, LEDoff); //start the TIMER redMillis = currentMillis; //next State mState = RED; Serial.print("Red Traffic ON = "); Serial.println(currentMillis / 1000ul); } break; //***************** case RED: { if (currentMillis - redMillis >= redInterval) { Serial.print("Red Traffic OFF = "); Serial.println(currentMillis / 1000ul); digitalWrite(redLED, LEDoff); //this is ok here //begin my edit 05_30_2020 works. Had to set a flag here. This condition "if NOT walkFlag" is here to stop green traffic led from doing a //short unnecessary milli second blink when the Pedestrian button is pushed if (!walkFlag == ENABLED) { digitalWrite(greenLED, LEDon); } //end my edit 05_30_2020 //testing end 05/30 //start the TIMER greenMillis = currentMillis; Serial.print("Green Traffic ON = "); Serial.println(currentMillis / 1000ul); if (walkFlag == ENABLED) { digitalWrite(walk_red_LED, LEDoff); digitalWrite(walk_green_LED, LEDon); //start the TIMER pedMillis = currentMillis; walkFlag = DISABLED; pedFlag = ENABLED; Serial.print("Walk Green ON = "); Serial.println(currentMillis / 1000ul); } //next State mState = GREEN; } } break; //***************** case GREEN: { if (pedFlag == ENABLED) { mState = CROSSING; } if (REDdontWalkFlag == ENABLED) { mState = REDdontWalk; } if (REDdontWalkFlag == DISABLED && pedFlag == DISABLED && currentMillis - greenMillis >= greenInterval) { Serial.print("Green Traffic OFF = "); Serial.println(currentMillis / 1000ul); //testing 05/30 ok leave it digitalWrite(greenLED, LEDoff); digitalWrite(yellowLED, LEDon); //start the TIMER yellowMillis = currentMillis; //next State mState = YELLOW; Serial.print("Yellow Traffic ON = "); Serial.println(currentMillis / 1000ul); } } break; //***************** case CROSSING: { //next State //look here study this original code //mState = GREEN; //my edit turn this mState = GREEN; off //mState = GREEN; //my edit digitalWrite(redLED, LEDon); //digitalWrite(walk_red_LED, LEDoff); //testing here this is ok leave it digitalWrite(greenLED, LEDoff); //time to toggle LED ? if (flashingFlag == ENABLED && currentMillis - flashingMillis >= flashingInterval) { //start the TIMER flashingMillis = currentMillis; //toggle LED //look here study this original code digitalWrite(walk_green_LED, !digitalRead(walk_green_LED)); } //is it time to start flashing the walk light ? if (flashingFlag == DISABLED && currentMillis - pedMillis >= flashingDelay) { flashingFlag = ENABLED; //start the TIMER flashingMillis = currentMillis; Serial.print("Walk Green Flashing = "); Serial.println(currentMillis / 1000ul); } //has walking time expired ? if (currentMillis - pedMillis >= pedInterval) { pedFlag = DISABLED; flashingFlag = DISABLED; digitalWrite(walk_green_LED, LEDoff); Serial.print("Walk Green OFF = "); Serial.println(currentMillis / 1000ul); REDdontWalkFlag = ENABLED; //start TIMER REDdontWalkMillis = currentMillis; //next State mState = REDdontWalk; } } break; //***************** case YELLOW: { if (currentMillis - yellowMillis >= yellowInterval) { Serial.print("Yellow Traffic OFF = "); Serial.println(currentMillis / 1000ul); Serial.print("Red Traffic ON = "); Serial.println(currentMillis / 1000ul); digitalWrite(yellowLED, LEDoff); digitalWrite(redLED, LEDon); //start the TIMER redMillis = currentMillis; //next State mState = RED; } } break; //***************** //look here study this original code case REDdontWalk: { //next State //look here study this original code //mState = GREEN; //my edit turn this mState = GREEN; off //mState = GREEN; digitalWrite(walk_red_LED, LEDon); if (currentMillis - REDdontWalkMillis > REDdontWalkInterval) { REDdontWalkFlag = DISABLED; //look here study this original code //digitalWrite(walk_red_LED, LEDon); //Just my fussy idea to keep the red traffic red led on for N seconds for cosmetic effect //instead of shooting directly to greenled after pedestrian green walk led goes out //and Pedestrian redled comes on digitalWrite(redLED, LEDon); Serial.print("Walk Red ON = "); Serial.println(currentMillis / 1000ul); //my edit mState = RED; } } break; } //END of switch(mstate) } //END of checkTrafficLight() //*************************************************************************************************************