Hackster is hosting Hackster Holidays, Finale: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Tuesday!Stream Hackster Holidays, Finale on Tuesday!
Lucky_G
Published © GPL3+

Intersection with Traffic Lights

Teaching kids how traffic lights work.

AdvancedShowcase (no instructions)12,062
Intersection with Traffic Lights

Things used in this project

Hardware components

Arduino Nano R3
Arduino Nano R3
×1
Terminal Adapter Board For Arduino Nano 3.0
×1
DC-DC adjustable step-down voltage regulator with LM2596
×2
PCF8575 IO Expander Module I2C To 16 IO
×1
TF card U disk MP3 player / decoder module
×1
12V relay (A12W-K)
×1
Transistor NPN (BC547 or similar)
×1
Diode BA159
×1
Buzzer, Piezo
Buzzer, Piezo
×1
PCF8574T (SMD)
×4
Red 1206 SMD LED
×24
Yellow 1206 SMD LED
×12
Green 1206 SMD LED
×16
White (cold) 1206 SMD LED
×4
SX1509 IO expander module
×2
4 channel I2C Logic Level Converter Bi-Directional Module 5V to 3.3V
×1
200 ohm 1206 SMD resistor
There are actually 4 different values used as current limiting resistors for LEDs ranging from 200 to 1K ohms.
×56
DC jack female panel mount
×1
Illuminated tactile switch Blue
×1
Illuminated tactile switch Green
×1
Illuminated tactile switch Red
×1
12V/1A power adapter
×1
Plastic plate 2mm thick, 93x73cm
×1
Plastic pipe 10mm diameter
×1
Electrical installation boxes
×24

Hand tools and fabrication machines

Drill, Screwdriver
Drill, Screwdriver
Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Schematics

Schematic

Complete schematic

Schematic of main traffic light with 7 LEDs and PCF8574T

Schematic of main traffic light with 7 LEDs and PCF8574T

PCB of main traffic light with 7 LEDs and PCF8574T

PCB of main traffic light with 7 LEDs and PCF8574T

Schematic of pedestrian traffic light with 2 LEDs

Schematic of pedestrian traffic light with 2 LEDs

PCB of pedestrian traffic light with 2 LEDs

PCB of pedestrian traffic light with 2 LEDs

Schematic of railway traffic light with 3 LEDs

Schematic of railway traffic light with 3 LEDs

PCB of railway traffic light with 3 LEDs

PCB of railway traffic light with 3 LEDs

Code

Main code

Arduino
#include <Wire.h>
#include <SparkFunSX1509.h> // Include SX1509 library

const int SX_RESET = 16; // reset pins of SX1509s
const int RAILWAY_SOUND = 6; // control pin of relay for mp3 power
const int PCF_INT = 2; // interrupt from PCF8575

// D4 & D5 = software serial for level shifter / ESP8266; not implemented yet

// SX1509 I2C address (set by ADDR1 and ADDR0 (00 by default):
const byte SX1509_0 = 0x3E;  // SX1509 I2C address
const byte SX1509_1 = 0x70;  // SX1509 I2C address
SX1509 io0; // Create an SX1509 object to be used throughout
SX1509 io1; // Create an SX1509 object to be used throughout

// SX1509_0 Pin definition:
const byte SX1509_0_RWL0 = 6; // rail red left
const byte SX1509_0_RWR0 = 5; // rail red right
const byte SX1509_0_RWW0 = 7; // rail white
const byte SX1509_0_RWL1 = 14; // rail red left
const byte SX1509_0_RWR1 = 15; // rail red right
const byte SX1509_0_RWW1 = 13; // rail white

const byte SX1509_0_PEDR0 = 10; //pedestrian red #3a
const byte SX1509_0_PEDG0 = 11; //pedestrian green #3a
const byte SX1509_0_PEDR1 = 9; //pedestrian red #3b
const byte SX1509_0_PEDG1 = 8; //pedestrian green #3b
const byte SX1509_0_PEDR2 = 1; //pedestrian red #4a
const byte SX1509_0_PEDG2 = 0; //pedestrian green #4a
const byte SX1509_0_PEDR3 = 2; //pedestrian red #4b
const byte SX1509_0_PEDG3 = 3; //pedestrian green #4b

// SX1509_1 Pin definition:
const byte SX1509_1_RWL0 = 6; // rail red left
const byte SX1509_1_RWR0 = 5; // rail red right
const byte SX1509_1_RWW0 = 7; // rail white
const byte SX1509_1_RWL1 = 14; // rail red left
const byte SX1509_1_RWR1 = 13; // rail red right
const byte SX1509_1_RWW1 = 15; // rail white

const byte SX1509_1_PEDR0 = 8; //pedestrian red #1a
const byte SX1509_1_PEDG0 = 9; //pedestrian green #1a
const byte SX1509_1_PEDR1 = 10; //pedestrian red #1b
const byte SX1509_1_PEDG1 = 11; //pedestrian green #1b
const byte SX1509_1_PEDR2 = 0; //pedestrian red #2a
const byte SX1509_1_PEDG2 = 1; //pedestrian green #2a
const byte SX1509_1_PEDR3 = 3; //pedestrian red #2b
const byte SX1509_1_PEDG3 = 2; //pedestrian green #2b



// addresses of PCF8574 IC
const byte PCF8574[] = {0x39, 0x3b, 0x3d, 0x3f};

#define PCF8575 (0x20) //address of PCF8575 (button input, illuminated buttons LED output)


const byte RED = 10;
const byte YLW = 20;
const byte GRN = 30;

unsigned long previousMillis = 0;
const long interval = 20;
byte blink_int = 0;
byte sec20 = 0;
boolean blink_state = false;

const byte numChars = 64;
char recChars[numChars];   // an array to store the received data
boolean newData = false;

byte cur_light = 0;
byte b;
String s;
boolean pcf_int_trigger = false;
byte dbnc = 0;
boolean sound = false;

boolean red_btn = false; // LED of red button
boolean grn_btn = false; // LED of green button
boolean blu_btn = false; // LED of blue button

byte mode = 1; // 0 = orange lights blink, 1 - program, 2 - test
byte rail_mode = 1; // 0 = off, 1 - white, 2 - red
byte prog_step = 0;
byte next_step = 1;



void setup()
{
  pinMode(RAILWAY_SOUND, OUTPUT);
  digitalWrite(RAILWAY_SOUND, LOW);
  pinMode(SX_RESET, OUTPUT);
  digitalWrite(SX_RESET, HIGH);

  pinMode(PCF_INT, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(PCF_INT), PCF_INT_ISR, FALLING); //interrupt when any of buttons is pressed
  
  Wire.begin();

  pcf8575_write(word(B11111111,B11111111)); //set all IOs as inputs

  Serial.begin(9600);
  while (!Serial);
  Serial.println("\nI2C Scanner");


  if (!io0.begin(SX1509_0, SX_RESET)) {
    Serial.println("SX1509_0 not found");
  }

  if (!io1.begin(SX1509_1, SX_RESET)) {
    Serial.println("SX1509_1 not found");
  }

  sx_init();

  set_rail();
}




void sx_init() {
  // Use the internal 2MHz oscillator.
  // Set LED clock with divider (2MHz / (2^(divider-1)):
  // divider = 2 means 1MHz LED clock (2MHz / (2^(2-1))
  // divider = 3 means 500kHz LED clock (2MHz / (2^(3-1))
  // divider = 4 means 250kHz LED clock (2MHz / (2^(4-1))
  
  // 0x1-0xE: fOSCout = Fosc / 2 ^ (outputFreq - 1) Hz

  const byte divider = 4;
  
  io0.init();
  io1.init();

  io0.clock(INTERNAL_CLOCK_2MHZ, divider, INPUT, 1); //250kHz clock
  io1.clock(INTERNAL_CLOCK_2MHZ, divider, INPUT, 1); //250kHz clock

  //set IOs for pedestrian lights as digital outputs
  //IOs for railway lights will be set as analogue outputs with breath funcion later
  io0.pinMode(SX1509_0_PEDR0, OUTPUT);
  io0.pinMode(SX1509_0_PEDG0, OUTPUT);
  io0.pinMode(SX1509_0_PEDR1, OUTPUT);
  io0.pinMode(SX1509_0_PEDG1, OUTPUT);
  io0.pinMode(SX1509_0_PEDR2, OUTPUT);
  io0.pinMode(SX1509_0_PEDG2, OUTPUT);
  io0.pinMode(SX1509_0_PEDR3, OUTPUT);
  io0.pinMode(SX1509_0_PEDG3, OUTPUT);
  
  io1.pinMode(SX1509_1_PEDR0, OUTPUT);
  io1.pinMode(SX1509_1_PEDG0, OUTPUT);
  io1.pinMode(SX1509_1_PEDR1, OUTPUT);
  io1.pinMode(SX1509_1_PEDG1, OUTPUT);
  io1.pinMode(SX1509_1_PEDR2, OUTPUT);
  io1.pinMode(SX1509_1_PEDG2, OUTPUT);
  io1.pinMode(SX1509_1_PEDR3, OUTPUT);
  io1.pinMode(SX1509_1_PEDG3, OUTPUT);
}




void loop()
{
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {//every 20ms / 50x sec
    previousMillis = currentMillis;

    sec20++;
    if (dbnc > 0) {
      dbnc --;
    }

    if (sec20 == 50) { // 50 x 20 miliseconds elapsed, i.e. new second
      // ****************************  NEW SECOND  ****************************
      sec20 = 0;

      if (next_step > 0) {next_step--;}   //counter for traffic lights program
      if (next_step == 0 || mode == 0 || mode == 2) { //when counter reaches zero, it's time for next program step. In mode=0 and mode=2 it's every second.
        program_step();
      }
    }

    blink_int++;
    if (blink_int == 34) {
      blink_state = true;
      if (mode == 0) { // mode = 0 means only orange lights are flashing with cca. 700ms ON / 700ms OFF interval
        set_leds(0, 5*32 + 5*4);
        set_leds(1, 5*32 + 5*4);
        set_leds(2, 5*32 + 5*4);
        set_leds(3, 5*32 + 5*4);
      }
    }

    if (blink_int == 69) {
      blink_state = false;
      blink_int = 0;
      if (mode == 0) {
        set_leds(0, 5*32 + 5*4);
        set_leds(1, 5*32 + 5*4);
        set_leds(2, 5*32 + 5*4);
        set_leds(3, 5*32 + 5*4);
      }
    }

    if (blink_int == 1) {
      digitalWrite(LED_BUILTIN, HIGH);
    } else {
      digitalWrite(LED_BUILTIN, LOW);
    }
  }

  //check if any of buttons was pressed
  if (pcf_int_trigger) {
    pcf_int_trigger = false;
    b = pcf8575_read();
    b = b | B11101010; // mask only for the buttons
    if (b != 255 && dbnc == 0) { //some button was pressed
      Serial.println(b, BIN);
      dbnc = 8; //set debounce period
      //blue.0
      //red.4
      //grn.2
      if (bitRead(b, 4) == 0) { //RED button pressed, change railway lights mode
        rail_mode++;
        if (rail_mode > 2) {
          rail_mode = 1;
        }
        set_rail();
      } else if (bitRead(b, 2) == 0) {//GREEN button pressed, change traffic lights mode
        mode++;
        next_step = 1;
        prog_step = 0;
        if (mode > 2) {
          mode = 0;
        }
        Serial.print("Mode changed: ");
        Serial.println(mode);
      } else if (bitRead(b, 0) == 0) {//BLUE button pressed, it does nothing so far
        //nothing yet
      }
    }
  }

  //check serial port input buffer
  CheckSerial();
}



void button_lights() {
  //sets illuminated buttons LEDs according to variables red_btn, grn_btn and blu_btn
  byte lights;
  lights = pcf8575_read();
  if (red_btn) {
    bitClear(lights, 3);
  } else {
    bitSet(lights, 3);
  }

  if (grn_btn) {
    bitClear(lights, 5);
  } else {
    bitSet(lights, 5);
  }

  if (blu_btn) {
    bitClear(lights, 1);
  } else {
    bitSet(lights, 1);
  }
  lights = lights | B00010101; //set button input IOs always as inputs
  pcf8575_write(word(0xFF,lights));
}







void set_ped_group(byte group, byte color) {
  //there are 4 groups of LEDs for pedestrian signals
  //in every group the signals change simultaneously
  
  boolean rval;
  boolean gval;
  if (color == RED) {
    rval = 0; // RED lights on
    gval = 1; // GRN lights off
  } else {
    rval = 1;
    gval = 0;
  }

    
  if (group == 0) {
    io1.digitalWrite(SX1509_1_PEDR1, rval);
    io1.digitalWrite(SX1509_1_PEDG1, gval);
    io1.digitalWrite(SX1509_1_PEDR2, rval);
    io1.digitalWrite(SX1509_1_PEDG2, gval);
  } else if (group == 1) {
    io1.digitalWrite(SX1509_1_PEDR3, rval);
    io1.digitalWrite(SX1509_1_PEDG3, gval);
    io0.digitalWrite(SX1509_0_PEDR0, rval);
    io0.digitalWrite(SX1509_0_PEDG0, gval);
  } else if (group == 2) {
    io0.digitalWrite(SX1509_0_PEDR1, rval);
    io0.digitalWrite(SX1509_0_PEDG1, gval);
    io0.digitalWrite(SX1509_0_PEDR2, rval);
    io0.digitalWrite(SX1509_0_PEDG2, gval);
  } else if (group == 3) {
    io0.digitalWrite(SX1509_0_PEDR3, rval);
    io0.digitalWrite(SX1509_0_PEDG3, gval);
    io1.digitalWrite(SX1509_1_PEDR0, rval);
    io1.digitalWrite(SX1509_1_PEDG0, gval);
  }
}

void ped_off() {
  //turn off all pedestrian signals
  io0.digitalWrite(SX1509_0_PEDR0, 1);
  io0.digitalWrite(SX1509_0_PEDG0, 1);
  io0.digitalWrite(SX1509_0_PEDR1, 1);
  io0.digitalWrite(SX1509_0_PEDG1, 1);
  io0.digitalWrite(SX1509_0_PEDR2, 1);
  io0.digitalWrite(SX1509_0_PEDG2, 1);
  io0.digitalWrite(SX1509_0_PEDR3, 1);
  io0.digitalWrite(SX1509_0_PEDG3, 1);
  io1.digitalWrite(SX1509_1_PEDR0, 1);
  io1.digitalWrite(SX1509_1_PEDG0, 1);
  io1.digitalWrite(SX1509_1_PEDR1, 1);
  io1.digitalWrite(SX1509_1_PEDG1, 1);
  io1.digitalWrite(SX1509_1_PEDR2, 1);
  io1.digitalWrite(SX1509_1_PEDG2, 1);
  io1.digitalWrite(SX1509_1_PEDR3, 1);
  io1.digitalWrite(SX1509_1_PEDG3, 1);
}






void CheckSerial() {
  //serial port input routine, used only for debugging
    static byte ndx = 0;
    char endMarker = '\n';
    char endMarker2 = '\r';
    char rc;
    byte pgroup, pcolor;
   
    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();
 
        if (rc != endMarker && rc != endMarker2) {
            recChars[ndx] = rc;
            ndx++;
            if (ndx >= numChars) {
                ndx = numChars - 1;
            }
        }
        else {
            recChars[ndx] = '\0'; // terminate the string
            ndx = 0;
            newData = true;
        }
    }

    if (newData == true) {
      int slen = strlen(recChars);
      if (slen > 1) {
      String usbreply = recChars;

      usbreply.trim();
      slen = usbreply.length();
        
      if (usbreply == "TRED") {
        rail_mode = 2;
        set_rail();
      } else if (usbreply == "TREDB") {
        rail_mode = 3;
        set_rail();
      } else if (usbreply == "WHITE") {
        rail_mode = 1;
        set_rail();
      } else if (usbreply == "RED") {
        set_leds(cur_light, 32 + 4);
      } else if (usbreply == "YLW") {
        set_leds(cur_light, 4*32 + 4*4 + 0);
      } else if (usbreply == "GRN") {
        set_leds(cur_light, 3*32 + 3*4 + 1);
      } else if (usbreply == "REDYLW") {
        set_leds(cur_light, 2*32 + 2*4 + 0);
      } else if (usbreply.startsWith("CL")) {
        usbreply = usbreply.substring(2);
        cur_light = usbreply.toInt();
        Serial.println("CURRENT LIGHT: " + String(cur_light));
      } else if (usbreply == "SXRST") {
        digitalWrite(SX_RESET, LOW);
        delay(2); //2ms RESET
        digitalWrite(SX_RESET, HIGH);
        sx_init();
        Serial.println("SXs were RESET");
      } else if (usbreply == "SX0READ") {
        SX1509_print_regs(SX1509_0);
      } else if (usbreply == "SX1READ") {
        SX1509_print_regs(SX1509_1);
      } else if (usbreply.startsWith("PG")) {
        s = usbreply.substring(2,3);
        pgroup = s.toInt();
        s = usbreply.substring(3,4);
        pcolor = s.toInt();
        pcolor = pcolor * 10;
        Serial.println("PED GROUP: " + String(pgroup) + ", color: " + String(pcolor));
        set_ped_group(pgroup, pcolor);
      }
      
    }
    newData = false;
  }
}




void set_rail() {
  if (rail_mode == 0) {
    //nothing yet
  } else if (rail_mode == 1) {

    //set railway lights as GO - white lights blinking/breathing, red lights off
    
    red_btn = false;
    button_lights();
    digitalWrite(RAILWAY_SOUND, LOW);
    io0.pinMode(SX1509_0_RWL0, OUTPUT);
    io0.pinMode(SX1509_0_RWR0, OUTPUT);
    io0.digitalWrite(SX1509_0_RWL0, HIGH);
    io0.digitalWrite(SX1509_0_RWR0, HIGH);
    io0.pinMode(SX1509_0_RWL1, OUTPUT);
    io0.pinMode(SX1509_0_RWR1, OUTPUT);
    io0.digitalWrite(SX1509_0_RWL1, HIGH);
    io0.digitalWrite(SX1509_0_RWR1, HIGH);
    io0.pinMode(SX1509_0_RWW0, ANALOG_OUTPUT);
    io0.breathe(SX1509_0_RWW0, 600, 700, 5, 5); // Breathe interval: 600ms LOW, 700ms HIGH, 5ms to rise from low to high, 5ms to fall from high to low
    io0.pinMode(SX1509_0_RWW1, ANALOG_OUTPUT);
    io0.breathe(SX1509_0_RWW1, 600, 700, 5, 5);
    io1.pinMode(SX1509_1_RWL0, OUTPUT);
    io1.pinMode(SX1509_1_RWR0, OUTPUT);
    io1.digitalWrite(SX1509_1_RWL0, HIGH);
    io1.digitalWrite(SX1509_1_RWR0, HIGH);
    io1.pinMode(SX1509_1_RWL1, OUTPUT);
    io1.pinMode(SX1509_1_RWR1, OUTPUT);
    io1.digitalWrite(SX1509_1_RWL1, HIGH);
    io1.digitalWrite(SX1509_1_RWR1, HIGH);
    io1.pinMode(SX1509_1_RWW0, ANALOG_OUTPUT);
    io1.breathe(SX1509_1_RWW0, 600, 700, 5, 5);
    io1.pinMode(SX1509_1_RWW1, ANALOG_OUTPUT);
    io1.breathe(SX1509_1_RWW1, 600, 700, 5, 5);
  } else if (rail_mode == 2) {

    //set railway lights as STOP - white lights off, red lights blinking/breathing
    
    red_btn = true;
    button_lights();
    
    io0.sync();
    io1.sync();
    digitalWrite(RAILWAY_SOUND, HIGH);
    io0.pinMode(SX1509_0_RWW0, OUTPUT);
    io0.digitalWrite(SX1509_0_RWW0, HIGH);
    io0.pinMode(SX1509_0_RWW1, OUTPUT);
    io0.digitalWrite(SX1509_0_RWW1, HIGH);
    io0.pinMode(SX1509_0_RWL0, ANALOG_OUTPUT);
    io0.breathe(SX1509_0_RWL0, 500, 500, 40, 40); // Breathe interval: 500ms LOW, 500ms HIGH, 40ms to rise from low to high, 40ms to fall from high to low
    io0.pinMode(SX1509_0_RWL1, ANALOG_OUTPUT);
    io0.breathe(SX1509_0_RWL1, 500, 500, 40, 40);
    io1.pinMode(SX1509_1_RWW0, OUTPUT);
    io1.digitalWrite(SX1509_1_RWW0, HIGH);
    io1.pinMode(SX1509_1_RWW1, OUTPUT);
    io1.digitalWrite(SX1509_1_RWW1, HIGH);
    io1.pinMode(SX1509_1_RWL0, ANALOG_OUTPUT);
    io1.breathe(SX1509_1_RWL0, 500, 500, 40, 40);
    io1.pinMode(SX1509_1_RWL1, ANALOG_OUTPUT);
    io1.breathe(SX1509_1_RWL1, 500, 500, 40, 40);
    delay(650);
    io0.pinMode(SX1509_0_RWR0, ANALOG_OUTPUT);
    io0.pinMode(SX1509_0_RWR1, ANALOG_OUTPUT);
    io1.pinMode(SX1509_1_RWR0, ANALOG_OUTPUT);
    io1.pinMode(SX1509_1_RWR1, ANALOG_OUTPUT);
    io0.breathe(SX1509_0_RWR0, 500, 500, 40, 40);
    io0.breathe(SX1509_0_RWR1, 500, 500, 40, 40);
    io1.breathe(SX1509_1_RWR0, 500, 500, 40, 40);
    io1.breathe(SX1509_1_RWR1, 500, 500, 40, 40);
  } else if (rail_mode == 3) {

    //test mode, just to show how lights work without breathe function
    red_btn = true;
    button_lights();
    io0.sync();
    io1.sync();

    io0.pinMode(SX1509_0_RWW0, OUTPUT);
    io0.digitalWrite(SX1509_0_RWW0, HIGH);
    io0.pinMode(SX1509_0_RWW1, OUTPUT);
    io0.digitalWrite(SX1509_0_RWW1, HIGH);
    io1.pinMode(SX1509_1_RWW0, OUTPUT);
    io1.digitalWrite(SX1509_1_RWW0, HIGH);
    io1.pinMode(SX1509_1_RWW1, OUTPUT);
    io1.digitalWrite(SX1509_1_RWW1, HIGH);

    io0.pinMode(SX1509_0_RWL0, OUTPUT);
    io0.pinMode(SX1509_0_RWL1, OUTPUT);
    io1.pinMode(SX1509_1_RWL0, OUTPUT);
    io1.pinMode(SX1509_1_RWL1, OUTPUT);
    io0.pinMode(SX1509_0_RWR0, OUTPUT);
    io0.pinMode(SX1509_0_RWR1, OUTPUT);
    io1.pinMode(SX1509_1_RWR0, OUTPUT);
    io1.pinMode(SX1509_1_RWR1, OUTPUT);
    io0.blink(SX1509_0_RWL0, 600, 600);
    io0.blink(SX1509_0_RWL1, 600, 600);
    io1.blink(SX1509_1_RWL0, 600, 600);
    io1.blink(SX1509_1_RWL1, 600, 600);
    delay(600);
    io0.blink(SX1509_0_RWR0, 600, 600);
    io0.blink(SX1509_0_RWR1, 600, 600);
    io1.blink(SX1509_1_RWR0, 600, 600);
    io1.blink(SX1509_1_RWR1, 600, 600);
  }
}







void program_step() {
  if (rail_mode == 2) {   //whaen railway lights are red, all car traffic in every direction is set to RED signals, all pedestrian signals are GREEN
    set_leds(0, 1*32 + 1*4);
    set_leds(1, 1*32 + 1*4);
    set_leds(2, 1*32 + 1*4);
    set_leds(3, 1*32 + 1*4);
    set_ped_group(0, GRN);
    set_ped_group(1, GRN);
    set_ped_group(2, GRN);
    set_ped_group(3, GRN);
    return;
  }
  
  if (mode == 1) {
    if (prog_step == 0) {
      set_leds(0, 4*32 + 4*4);
      set_leds(1, 4*32 + 4*4);
      set_leds(2, 4*32 + 4*4);
      set_leds(3, 4*32 + 4*4);
      set_ped_group(0, RED);
      set_ped_group(1, RED);
      set_ped_group(2, RED);
      set_ped_group(3, RED);
      next_step = 5;
    } else if (prog_step == 1) {
      set_leds(0, 1*32 + 2*4);
      set_leds(1, 1*32 + 1*4);
      set_leds(2, 1*32 + 2*4);
      set_leds(3, 1*32 + 1*4);
      next_step = 3;
    } else if (prog_step == 2) {
      set_leds(0, 1*32 + 3*4 + 1);
      set_leds(1, 1*32 + 1*4);
      set_leds(2, 1*32 + 3*4 + 1);
      set_leds(3, 1*32 + 1*4);
      set_ped_group(0, GRN);
      set_ped_group(1, RED);
      set_ped_group(2, GRN);
      set_ped_group(3, RED);
      next_step = 12;
    } else if (prog_step == 3) {
      set_ped_group(0, RED);
      set_ped_group(1, RED);
      set_ped_group(2, RED);
      set_ped_group(3, RED);
      next_step = 8;
    } else if (prog_step == 4) {
      set_leds(0, 1*32 + 4*4);
      set_leds(1, 1*32 + 1*4);
      set_leds(2, 1*32 + 4*4);
      set_leds(3, 1*32 + 1*4);
      next_step = 3;
    } else if (prog_step == 5) {
      set_leds(0, 1*32 + 1*4);
      set_leds(1, 2*32 + 1*4);
      set_leds(2, 1*32 + 1*4);
      set_leds(3, 2*32 + 1*4);
      next_step = 3;
    } else if (prog_step == 6) {
      set_leds(0, 1*32 + 1*4);
      set_leds(1, 3*32 + 1*4);
      set_leds(2, 1*32 + 1*4);
      set_leds(3, 3*32 + 1*4);
      next_step = 15;
    } else if (prog_step == 7) {
      set_leds(0, 1*32 + 1*4);
      set_leds(1, 4*32 + 2*4);
      set_leds(2, 1*32 + 1*4);
      set_leds(3, 4*32 + 2*4);
      next_step = 3;
    } else if (prog_step == 8) {
      set_leds(0, 1*32 + 1*4);
      set_leds(1, 1*32 + 3*4 + 1);
      set_leds(2, 1*32 + 1*4);
      set_leds(3, 1*32 + 3*4 + 1);
      set_ped_group(0, RED);
      set_ped_group(1, GRN);
      set_ped_group(2, RED);
      set_ped_group(3, GRN);
      next_step = 12;
    } else if (prog_step == 9) {
      set_ped_group(0, RED);
      set_ped_group(1, RED);
      set_ped_group(2, RED);
      set_ped_group(3, RED);
      next_step = 8;
    } else if (prog_step == 10) {
      set_leds(0, 1*32 + 1*4);
      set_leds(1, 1*32 + 4*4);
      set_leds(2, 1*32 + 1*4);
      set_leds(3, 1*32 + 4*4);
      set_ped_group(0, RED);
      set_ped_group(1, RED);
      set_ped_group(2, RED);
      set_ped_group(3, RED);
      next_step = 3;
    } else if (prog_step == 11) {
      set_leds(0, 1*32 + 1*4);
      set_leds(1, 1*32 + 1*4);
      set_leds(2, 1*32 + 1*4);
      set_leds(3, 1*32 + 1*4);
      next_step = 3;
    } else if (prog_step == 12) {
      set_leds(0, 2*32 + 1*4);
      set_leds(1, 1*32 + 1*4);
      set_leds(2, 2*32 + 1*4);
      set_leds(3, 1*32 + 1*4);
      next_step = 3;
    } else if (prog_step == 13) {
      set_leds(0, 3*32 + 1*4);
      set_leds(1, 1*32 + 1*4);
      set_leds(2, 3*32 + 1*4);
      set_leds(3, 1*32 + 1*4);
      next_step = 15;
    } else if (prog_step == 14) {
      set_leds(0, 4*32 + 1*4);
      set_leds(1, 1*32 + 1*4);
      set_leds(2, 4*32 + 1*4);
      set_leds(3, 1*32 + 1*4);
      next_step = 3;
    }
    
    prog_step++;
    if (prog_step > 14) {
      prog_step = 1;
    }


    
  } else if (mode == 2) {
    if (prog_step == 1) {
      set_leds(0, 0);
      set_leds(1, 0);
      set_leds(2, 0);
      set_leds(3, 0);
      ped_off();
    } else if (prog_step == 2) {
      set_leds(0, 1*32 + 1*4);
      set_leds(1, 1*32 + 1*4);
      set_leds(2, 1*32 + 1*4);
      set_leds(3, 1*32 + 1*4);
      set_ped_group(0, RED);
      set_ped_group(1, RED);
      set_ped_group(2, RED);
      set_ped_group(3, RED);
    } else if (prog_step == 3) {
      set_leds(0, 4*32 + 4*4);
      set_leds(1, 4*32 + 4*4);
      set_leds(2, 4*32 + 4*4);
      set_leds(3, 4*32 + 4*4);
      set_ped_group(0, GRN);
      set_ped_group(1, GRN);
      set_ped_group(2, GRN);
      set_ped_group(3, GRN);
    } else if (prog_step == 4) {
      set_leds(0, 3*32 + 3*4);
      set_leds(1, 3*32 + 3*4);
      set_leds(2, 3*32 + 3*4);
      set_leds(3, 3*32 + 3*4);
      set_ped_group(0, RED);
      set_ped_group(1, RED);
      set_ped_group(2, RED);
      set_ped_group(3, RED);
    } else if (prog_step == 5) {
      set_leds(0, 1);
      set_leds(1, 1);
      set_leds(2, 1);
      set_leds(3, 1);
      set_ped_group(0, GRN);
      set_ped_group(1, GRN);
      set_ped_group(2, GRN);
      set_ped_group(3, GRN);
    }
    prog_step++;
    if (prog_step > 5) {
      prog_step = 1;
    }


    
  } else { // mode = 0, orng blinking
    ped_off();
    set_leds(0, 5*32 + 5*4);
    set_leds(1, 5*32 + 5*4);
    set_leds(2, 5*32 + 5*4);
    set_leds(3, 5*32 + 5*4);
    next_step = 10;
  }
}



void SX1509_print_regs(byte devAdd) {
  //only for debug
  b = SX1509_readB(devAdd, 0x1e);
  Serial.print("RegClock (1E): ");
  print_val(b);
  
  b = SX1509_readB(devAdd, 0x1f);
  Serial.print("RegMisc (1F): ");
  print_val(b);

  b = SX1509_readB(devAdd, 0x21);
  Serial.print("RegLEDDriverEnableA (21): ");
  print_val(b);
  
  b = SX1509_readB(devAdd, 0x20);
  Serial.print("RegLEDDriverEnableB (20): ");
  print_val(b);

  b = SX1509_readB(devAdd, 0x44);
  Serial.print("REG_T_ON_7 (44): ");
  print_val(b);

  b = SX1509_readB(devAdd, 0x45);
  Serial.print("REG_I_ON_7 (45): ");
  print_val(b);

  b = SX1509_readB(devAdd, 0x46);
  Serial.print("REG_OFF_7 (46): ");
  print_val(b);

  b = SX1509_readB(devAdd, 0x47);
  Serial.print("REG_T_RISE_7 (47): ");
  print_val(b);

  b = SX1509_readB(devAdd, 0x48);
  Serial.print("REG_T_FALL_7 (48): ");
  print_val(b);
}

void print_val(byte b) {
  Serial.println(b);
  Serial.println(b, HEX);  
  Serial.println(b, BIN);  
}







void set_leds(byte pole, byte pattern) {
  byte Pleds;
/*
  LEFT:
  0 - off
  1 - RED
  2 - RED+ORNG
  3 - GRN
  4 - ORNG
  5 - ORNG blink
  
  RIGHT:
  0 - off
  1 - RED
  2 - RED+ORNG
  3 - GRN
  4 - ORNG
  5 - ORNG blink
  
  PEDESTRIAN CROSSING WARNING ORANGE LIGHT:
  0 - off
  1 - on
  2 - blink
  
  LLLRRRPP
  LLLx32 + RRRx4 + PP
*/

  //Left
  b = pattern & B11100000;
  b = b >> 5;

  if (b == 0) {
    Pleds = 0;
  } else if (b == 1) {
    Pleds = 16; //red
  } else if (b == 2) {
    Pleds = 16+64; // red+orng
  } else if (b == 3) {
    Pleds = 32; //grn
  } else if (b == 4) {
    Pleds = 64;
  } else if (b == 5) {
    if (blink_state) {
      Pleds = 64;
    } else {
      Pleds = 0;
    }
  }

  //Right
  b = pattern & B00011100;
  b = b >> 2;

  if (b == 0) {
    //Pleds += 0;
  } else if (b == 1) {
    Pleds += 8; //red
  } else if (b == 2) {
    Pleds += 8+1; // red+orng
  } else if (b == 3) {
    Pleds += 2; //grn
  } else if (b == 4) {
    Pleds += 1;
  } else if (b == 5) {
    if (blink_state) {
      Pleds += 1;
    } else {
      //Pleds += 0;
    }
  }

  //Pedestrian warning orng
  b = pattern & B00000011;

  if (b == 0) {
    //Pleds += 0;
  } else if (b == 1) {
    Pleds += 4; //pedestrian
  } else if (b == 2) {// blink
    if (blink_state) {
      Pleds += 4;
    }
  }

  Pleds = ~Pleds;

  pole = constrain(pole, 0, 3);
  Wire.beginTransmission(PCF8574[pole]);
  Wire.write(Pleds);
  Wire.endTransmission();
}


// Function for writing two Bytes to the I2C expander device
void pcf8575_write(uint16_t data)
{
  Wire.beginTransmission(PCF8575);
  Wire.write(lowByte(data));
  Wire.write(highByte(data));
  Wire.endTransmission();
}



//uint16_t pcf8575_read()
byte pcf8575_read()
{
  byte dataReceived[2]; //a two byte array to hold our data
  uint16_t dat_rec;
  Wire.beginTransmission(PCF8575);
  Wire.endTransmission();
  Wire.requestFrom(PCF8575, 2); //request two bytes of data
  if (Wire.available()){
      dataReceived[0] = Wire.read(); //read byte 1
      dataReceived[1] = Wire.read(); //read byte 2
  }

  dat_rec = word(dataReceived[0], dataReceived[1]);
  //return dat_rec;
  return dataReceived[0]; //we use only one half of PCF8575, so only first byte is enough
}


byte SX1509_readB(byte devAdd, byte regAdd)
{
  byte readValue;
  unsigned int timeout = 1000;

  Wire.beginTransmission(devAdd);
  Wire.write(regAdd);
  Wire.endTransmission();
  Wire.requestFrom(devAdd, (byte) 1);

  while ((Wire.available() < 1) && (timeout != 0))
    timeout--;
    
  if (timeout == 0)
    return 0x55;

  readValue = Wire.read();

  return readValue;
}




void SX1509_writeB(byte devAdd, byte regAdd, byte writeVal)
{
  Wire.beginTransmission(devAdd);
  Wire.write(regAdd);
  Wire.write(writeVal);
  Wire.endTransmission();
}


//IO interrupt routine
void PCF_INT_ISR() {
  pcf_int_trigger = true;
}

SX1509 library

Credits

Lucky_G
0 projects • 3 followers

Comments