// Shing Yan (sy228@cornell.edu)

// Raymond Siow (rs234@cornell.edu)

// Cornell University, Ithaca, NY 14853, USA

// ECE 476

// Final Project - Traffic control

// Section: Mondays 4:30pm-7:30pm

// Last Updated: April 27th, 2003, 6:16 AM.

#include <Mega32.h>

#include <stdio.h>

#include <stdlib.h>

#include <math.h>

#include <delay.h>

// other constants

#define maxkeys               16

#define NOBUTTON              99

// traffic light FSM states

#define B_GOES_A_WALK         1

#define A_DONT_WALK           2

#define B_YELLOW              3

#define B_RED                 4

#define A_GREEN               5

#define B_WALK                6

#define A_GOES_B_WALK         7

#define B_DONT_WALK           8

#define A_YELLOW              9

#define A_RED                 10

#define B_GREEN               11

#define A_WALK                12

// sensor states

#define NO_CAR                31

#define IS_CAR                32

// traffic condition constants

#define LO                    13

#define MI                    14

#define HI                    16

// traffic sensor condition

// time constants used

#define TEN_MS                10

#define HUNDRED_MS            100

#define HALF_SEC              500

#define FIVE_MIN              300000

#define L_CYCLE_LO            60*2

#define L_CYCLE_NM            90*2  //Normal

#define L_CYCLE_HI            120*2

#define LT_A_FLASH            15*2

#define LT_B_FLASH            15*2

// timer variables

int half_sec;

int traf_t;

int peds_t;

// traffic light related variables

int lightState;

int lgt_t_a;

int lgt_t_b;

int lgt_t_a_dw;

int lgt_t_b_dw;

// traffic condition

int traf_cond_a;

int traf_cond_b;

// sensors related variables

int sensorState_a1;

int sensorState_a2;

int car_q_time_a1;

int car_q_time_a2;

int sensorState_b1;

int sensorState_b2;

int car_q_time_b1;

int car_q_time_b2;

int car_q_time_a;

int car_cnt_a;

int time_base_a;

int car_q_time_b;

int car_cnt_b;

int time_base_b;

// some other constants

int hi = L_CYCLE_HI >> 1;

int mi = L_CYCLE_NM >> 1;

int lo = L_CYCLE_LO >> 1;

void light_fsm(void);

void traffic_fsm(void);

void pedestrian_fsm(void);

void initalize(void);

void main(void);

// timer0 overflow ISR

interrupt [TIM0_OVF] void timer0_overflow(void) {

// reload to force 1 mSec overflow

// Decrement the three times if they are not already zero

if (half_sec > 0) half_sec--;

if (traf_t > 0) --traf_t;

if (peds_t > 0) --peds_t;

}

// When magnetic field -> 1

// No field -> 0

// light_fsm is a function that implements the state machine used

// to control switching of the traffic lights

void light_fsm(void) {

half_sec = HALF_SEC;

/***********************************

PORT A - DIRECTION A

.0 - RED

.1 - YELLOW

.2 - GREEN

.3 - WALK

.4 - DON'T WALK

PORT B - DIRECTION B

.0 - RED

.1 - YELLOW

.2 - GREEN

.3 - WALK

.4 - DON'T WALK

***********************************/

switch (lightState) {

case B_GOES_A_WALK:

// decrement b's counter

if (lgt_t_b > 0) --lgt_t_b;

// if counter reaches don't walk... switch to a's don't walk state

if (lgt_t_b < lgt_t_b_dw) lightState = A_DONT_WALK;

// set a's timer

break;

case A_DONT_WALK:

// set walk off on a

PORTA.3 = 1;

// toggle don't walk light while decrementing b's counter

PORTA.4 = ~PORTA.4;

// if reaches 5 sec before the end of don't walk state... go to next state

if (lgt_t_b > 0) --lgt_t_b;

if ((lgt_t_b >> 1) < 5) lightState = B_YELLOW;

break;

case B_YELLOW:

// set traffic light to yellow on b

PORTB.2 = 1;

PORTB.1 = 0;

// 2 sec before going to state

if (lgt_t_b > 0) --lgt_t_b;

if ((lgt_t_b >> 1) < 3) lightState = B_RED;

// set don't walk light on a if not already

PORTA.4 = 0;

break;

case B_RED:

// set traffic light to red on b

PORTB.1 = 1;

PORTB.0 = 0;

// 1 sec before going to next state

if (lgt_t_b > 0) --lgt_t_b;

if ((lgt_t_b >> 1) < 2) lightState = A_GREEN;

break;

case A_GREEN:

// set traffic light to green on a

PORTA.0 = 1;

PORTA.2 = 0;

// 1 sec before going to next state

if (lgt_t_b > 0) --lgt_t_b;

if ((lgt_t_b >> 1) < 1) lightState = B_WALK;

break;

case B_WALK:

// set don't walk off and set walk on on b

PORTB.4 = 1;

PORTB.3 = 0;

// 1 sec befire going to next state

if (lgt_t_b > 0) --lgt_t_b;

lightState = A_GOES_B_WALK;

break;

case A_GOES_B_WALK:

// decrement a's counter

if (lgt_t_a > 0) --lgt_t_a;

// if counter reaches don't walk... switch to b's don't walk state

if (lgt_t_a < lgt_t_a_dw) lightState = B_DONT_WALK;

// set a's timer

break;

case B_DONT_WALK:

// set walk off on b

PORTB.3 = 1;

// toggle don't walk light while decrementing a's counter

PORTB.4 = ~PORTB.4;

// if reaches 5 sec before the end of don't walk state... go to next state

if (lgt_t_a > 0) --lgt_t_a;

if ((lgt_t_a >> 1) < 5) lightState = A_YELLOW;

break;

case A_YELLOW:

// set traffic light to yellow on a

PORTA.2 = 1;

PORTA.1 = 0;

// 2 sec before going to state

if (lgt_t_a > 0) --lgt_t_a;

if ((lgt_t_a >> 1) < 3) lightState = A_RED;

// set don't walk light on b if not already

PORTB.4 = 0;

break;

case A_RED:

// set traffic light to red on a

PORTA.1 = 1;

PORTA.0 = 0;

// 1 sec before going to next state

if (lgt_t_a > 0) --lgt_t_a;

if ((lgt_t_a >> 1) < 2) lightState = B_GREEN;

break;

case B_GREEN:

// set traffic light to green on b

PORTB.0 = 1;

PORTB.2 = 0;

// 1 sec before going to next state

if (lgt_t_a > 0) --lgt_t_a;

if ((lgt_t_a >> 1) < 1) lightState = A_WALK;

break;

case A_WALK:

// set don't walk off and set walk on on a

PORTA.4 = 1;

PORTA.3 = 0;

// 1 sec befire going to next state

if (lgt_t_a > 0) --lgt_t_a;

lightState = B_GOES_A_WALK;

break;

}

}

// of the traffic lights if necessary.

void traffic_fsm(void) {

/***********************************

PORT A - DIRECTION A

.6 - SENSOR IN A1

.7 - SENSOR IN A2

PORT B - DIRECTION B

.6 - SENSOR IN B1

.7 - SENSOR IN B2

***********************************/

//update the traffic condition every 10ms

traf_t = TEN_MS;

// state machine for traffic light a1

switch (sensorState_a1) {

case NO_CAR:

PORTC.3 = 1;

car_q_time_a1 = 0;

if (PINA.6 == 0){

sensorState_a1 = IS_CAR;

}

break;

case IS_CAR:

if (PINA.6 == 1) {

sensorState_a1 = NO_CAR;

car_cnt_a++;

} else {

// increment waiting time

car_q_time_a1++;

}

break;

}

// if waiting time at the sensor > 1 sec, we assume that it's stopped

// this is when the wait time is incremented

if (car_q_time_a1 > 100) {

car_q_time_a1-=100;

car_q_time_a+=2;

PORTC.3 = ~PORTC.3;

}

// state machine for traffic light a2

switch (sensorState_a2) {

case NO_CAR:

PORTC.3 = 1;

car_q_time_a2 = 0;

if (PINA.7 == 0) {

sensorState_a2 = IS_CAR;

}

break;

case IS_CAR:

if (PINA.7 == 1){

sensorState_a2 = NO_CAR;

car_cnt_a++;

} else {

// increment waiting time

car_q_time_a2++;

}

break;

}

// if waiting time at the sensor > 1 sec, we assume that it's stopped

// this is when the wait time is incremented

if (car_q_time_a2 > 100) {

car_q_time_a2-=100;

car_q_time_a+=2;

PORTC.3 = ~PORTC.3;

}

// state machine for traffic light b1

switch (sensorState_b1) {

case NO_CAR:

PORTC.7 = 1;

car_q_time_b1 = 0;

if (PINB.6 == 0){

sensorState_b1 = IS_CAR;

}

break;

case IS_CAR:

if (PINB.6 == 1) {

sensorState_b1 = NO_CAR;

car_cnt_b++;

} else {

// increment waiting time

car_q_time_b1++;

}

break;

}

// if waiting time at the sensor > 1 sec, we assume that it's stopped

// this is when the wait time is incremented

if (car_q_time_b1 > 100) {

car_q_time_b1-=100;

car_q_time_b+=2;

PORTC.7 = ~PORTC.7;

}

// state machine for traffic light a2

switch (sensorState_b2) {

case NO_CAR:

PORTC.7 = 1;

car_q_time_b2 = 0;

if (PINB.7 == 0){

sensorState_b2 = IS_CAR;

}

break;

case IS_CAR:

if (PINB.7 == 1){

sensorState_b2 = NO_CAR;

car_cnt_b++;

} else {

// increment waiting time

car_q_time_b2++;

}

break;

}

// if waiting time at the sensor > 1 sec, we assume that it's stopped

// this is when the wait time is incremented

if (car_q_time_b2 > 100) {

car_q_time_b2-=100;

car_q_time_b+=2;

PORTC.7 = ~PORTC.7;

}

}

int wait_a, rate_a, traf_a;

int wait_b, rate_b, traf_b;

int time_base;

time_base = time_base_a + time_base_b;

// set wait time for a1 and a2

if (car_q_time_a > (time_base_b*3/4)) {

wait_a = HI;

} else if (car_q_time_a < (time_base_b/4)) {

wait_a = LO;

} else {

wait_a = MI;

}

// set rate for a1 and a2

if (((float)time_base_a)/car_cnt_a < 4) {

rate_a = HI;

} else if (((float)time_base_a*2)/car_cnt_a > 10) {

rate_a = LO;

} else {

rate_a = MI;

}

traf_a = wait_a + rate_a;

// determine the traffic in road a

if (traf_a < MI*2) {

traf_cond_a = LO;

PORTC.0 = 0;

PORTC.1 = 1;

PORTC.2 = 1;

} else if (traf_a < HI*2) {

traf_cond_a = MI;

PORTC.0 = 1;

PORTC.1 = 0;

PORTC.2 = 1;

} else {

traf_cond_a = HI;

PORTC.0 = 1;

PORTC.1 = 1;

PORTC.2 = 0;

}

// set wait time for b1 and b2

if (car_q_time_b > (time_base_a*3/4)) {

wait_b = HI;

} else if (car_q_time_b < (time_base_a/4)) {

wait_b = LO;

} else {

wait_b = MI;

}

// set rate for b1 and b2

if (((float)time_base_b)/car_cnt_b < 2) {

rate_b = HI;

} else if (((float)time_base_b)/car_cnt_b > 6) {

rate_b = LO;

} else {

rate_b = MI;

}

traf_b = wait_b + rate_b;

// determine the traffic in road b

if (traf_b < MI*2) {

traf_cond_b = LO;

PORTC.4 = 0;

PORTC.5 = 1;

PORTC.6 = 1;

} else if (traf_b < HI*2) {

traf_cond_b = MI;

PORTC.4 = 1;

PORTC.5 = 0;

PORTC.6 = 1;

} else {

traf_cond_b = HI;

PORTC.4 = 1;

PORTC.5 = 1;

PORTC.6 = 0;

}

// reset variables for road a

car_q_time_a = 0;

car_cnt_a = 0;

// reset variables for road b

car_q_time_b = 0;

car_cnt_b = 0;

// now adjust the traffic light's changing time

switch (traf_cond_a + traf_cond_b) {

case (HI+HI):

// traffic is HI on both sides

break;

case (HI+MI):

// traffic is HI on one side, MI on the other

lgt_t_a_reload = (traf_cond_a == MI)? hi - 20 : hi + 20;

lgt_t_b_reload = (traf_cond_b == MI)? hi - 20 : hi + 20;

break;

case (HI+LO):

// traffic is HI on one side, LO on the other

lgt_t_a_reload = (traf_cond_a == MI)? mi - 20 : mi + 20;

lgt_t_b_reload = (traf_cond_b == MI)? mi - 20 : mi + 20;

break;

case (MI+MI):

// traffic is MI on both sides

break;

case (MI+LO):

// traffic is MI on one side, LO on the other

lgt_t_a_reload = (traf_cond_a == LO)? lo - 20 : lo + 20;

lgt_t_b_reload = (traf_cond_b == LO)? lo - 20 : lo + 20;

break;

case (LO+LO):

// traffic is MI on both sides

break;

}

}

// of the traffic lights if necessary.

void pedestrian_fsm(void) {

/***********************************

PORT A - DIRECTION A

.5 - REQUEST BUTTON IN A

PORT B - DIRECTION B

.5 - REQUEST BUTTON IN B

***********************************/

peds_t = HUNDRED_MS;

// check current light state and if the pedestrian button is pressed

if ((lightState == A_GOES_B_WALK) && (PINA.5 == 0)) {

// if traffic is low on the other road

if (traf_cond_b < HI) {

// if traffic on this road is not high

if (traf_cond_a == LO) {

peds_t = HALF_SEC*lgt_t_a_dw;

time_base_a -= (lgt_t_a - lgt_t_a_dw);

lgt_t_a = lgt_t_a_dw;

} else if (traf_cond_a == MI) {

peds_t = HALF_SEC*10;

if (lgt_t_a - 20 > lgt_t_a_dw) {

time_base_a -= 20;

lgt_t_a = lgt_t_a - 20;

} else {

time_base_a -= (lgt_t_a - lgt_t_a_dw);

lgt_t_a = lgt_t_a_dw;

}

}

// otherwise deny request

}

// else denied

} else if ((lightState == B_GOES_A_WALK) && (PINB.5 == 0)) {

// if traffic is low on the other road

if (traf_cond_a < HI) {

// if traffic on this road is not high

if (traf_cond_b == LO) {

peds_t = HALF_SEC*lgt_t_a_dw;

time_base_b -= (lgt_t_b - lgt_t_b_dw);

lgt_t_b = lgt_t_b_dw;

} else if (traf_cond_b == MI) {

peds_t = HALF_SEC*10;

if (lgt_t_b - 20 > lgt_t_b_dw) {

time_base_b -= 20;

lgt_t_b = lgt_t_b - 20;

} else {

time_base_b -= (lgt_t_b - lgt_t_b_dw);

lgt_t_b = lgt_t_b_dw;

}

}

// otherwise deny request

}

// else denied

}

}

//================================

// initialize STK500 board

void initalize(void) {

// init timer 0 to 1/uSec

// turn on timer 0 overflow ISR

TIMSK = 1;

// prescalar to 64 (1 -> 1, 2 -> 8, 3 -> 64, 4 -> 256, 5 -> 1024

TCCR0 = 3;

// initialize variables for traffic light FSM

half_sec = HALF_SEC;

lgt_t_a = 0;

lgt_t_a_dw = LT_A_FLASH;

lgt_t_b_dw = LT_B_FLASH;

peds_t = HUNDRED_MS;

traf_t = TEN_MS;

car_cnt_a = 0;

car_q_time_a = 0;

sensorState_a1 = NO_CAR;

sensorState_a2 = NO_CAR;

sensorState_b1 = NO_CAR;

sensorState_b2 = NO_CAR;

// Init port A to show keyboard result (0-4) and accept inputs (5-7)

DDRA.0 = 1; DDRA.1 = 1;

DDRA.2 = 1; DDRA.3 = 1;

DDRA.4 = 1; DDRA.5 = 0;

DDRA.6 = 0; DDRA.7 = 0;

PORTA.0 = 0;      PORTA.1 = 1;

PORTA.2 = 1;      PORTA.3 = 0;

PORTA.4 = 1;

// Init port B to show keyboard result (0-4) and accept inputs (5-7)

DDRB.0 = 1; DDRB.1 = 1;

DDRB.2 = 1; DDRB.3 = 1;

DDRB.4 = 1; DDRB.5 = 0;

DDRB.6 = 0; DDRB.7 = 0;

PORTB.0 = 1;      PORTB.1 = 1;

PORTB.2 = 0;      PORTB.3 = 1;

PORTB.4 = 0;

// output indicator from sensor

DDRC = 0xff;

PORTC = 0xff;

PORTC.1 = 0;

PORTC.5 = 0;

// input from pedestrian

DDRD = 0x00;

lightState = B_GOES_A_WALK;

traf_cond_a = MI;

traf_cond_b = MI;

//enable sleep mode

MCUCR = 0b01000000;

#asm ("sei");

}

//================================

// set up the ports and timers

void main(void) {

initalize();

while(1) {

if (half_sec == 0) light_fsm();

if (traf_t == 0) traffic_fsm();

if (peds_t == 0) pedestrian_fsm();

}  // while

}  // main