// 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 #include #include #include #include // other constants #define T0reload 256-250 #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 #define READY_TO_ADJ 17 #define RECENTLY_ADJ 18 // 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; int lgt_t_a_reload; int lgt_t_b_reload; // 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 adjust_traf(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 TCNT0 = T0reload; // 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; adjust_traf(); break; } } // This task checks the road condition every 10ms and adjust the variables // 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; } } void adjust_traf(void) { 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 time_base_a = lgt_t_a_reload; car_q_time_a = 0; car_cnt_a = 0; // reset variables for road b time_base_b = lgt_t_b_reload; 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 lgt_t_a_reload = hi; lgt_t_b_reload = hi; 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 lgt_t_a_reload = mi; lgt_t_b_reload = mi; 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 lgt_t_a_reload = lo; lgt_t_b_reload = lo; break; } lgt_t_a = lgt_t_a_reload; lgt_t_b = lgt_t_b_reload; } // This task polls the pedestrian input and adjust the variables // 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 TCNT0 = T0reload; // 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_reload = L_CYCLE_NM >> 1; lgt_t_a = 0; lgt_t_b_reload = L_CYCLE_NM >> 1; lgt_t_b = lgt_t_b_reload; 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; time_base_b = lgt_t_b_reload; time_base_a = lgt_t_a_reload; // 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