// Curtis Henkel // Mark Campbell // ECE 476 Final Project // May 6, 2005 #include #include #include #include #define ScrollButtonPressed PushState[1]==Pushed #define NextPlayer 1 #define Reset 4 #define GameUp 1 #define GameDown 2 #define Start 3 //declare variables unsigned char hi[2], lo[2], board[2][26], cycle = 1; // led display encodings long menu_long, score_long[2][2], hit_long, debug_long, winner_long ; // state variable states enum {Not_Hit, Just_Hit, Hit}; enum {GameMenu, CurrentPlayerScore, ScrollScores, ShowDartHit, WinnerDisplay}; enum {Pushed, MaybePushed, NotPushed, MaybeNotPushed}; enum {Three01, Cricket, Golf}; int LED_State, PushState[3], GameStyle; int count, debounce_time, debug_time, read_time, blink_count, i, j, rand_int, rand_count; int score[2], cricket_score[2]; char LastButtonPressed, game_number, max_game_number=2, player, num_players, sheet, num_sheets; char winner, dart_hit, dart_value, dart_ring, scroll_player, scroll_sheet, darts_left=3; char ResetButtonPressed; char mux_select, next_mux, hack_timer; int time1, time2, phase; char blink, blink_phase; char pidx, pads_hit[5], pcount; char debug_level; int rail[32]; int last_read[32]; char PadState[32], hit_count[32]; // changes *x to have digit(0-9) in place(1-3) void led_digit(long *x, char place, char digit) { switch (place){ case 3: *x &= 0xc3ffe3ff; switch (digit){ case 0: *x |= 0x2c001c00; break; case 1: *x |= 0x00001800; break; case 2: *x |= 0x38001400; break; case 3: *x |= 0x18001c00; break; case 4: *x |= 0x14001800; break; case 5: *x |= 0x1c000c00; break; case 6: *x |= 0x3c000c00; break; case 7: *x |= 0x00001c00; break; case 8: *x |= 0x3c001c00; break; case 9: *x |= 0x1c001c00; break; }; break; case 2: *x &= 0xfc7ffc3f; switch (digit){ case 0: *x |= 0x038002c0; break; case 1: *x |= 0x01800000; break; case 2: *x |= 0x030001c0; break; case 3: *x |= 0x03800180; break; case 4: *x |= 0x01800300; break; case 5: *x |= 0x02800380; break; case 6: *x |= 0x028003c0; break; case 7: *x |= 0x03800000; break; case 8: *x |= 0x038003c0; break; case 9: *x |= 0x03800380; break; }; break; case 1: *x &= 0xff87ffc7; switch (digit){ case 0: *x |= 0x00580038; break; case 1: *x |= 0x00000030; break; case 2: *x |= 0x00700028; break; case 3: *x |= 0x00300038; break; case 4: *x |= 0x00280030; break; case 5: *x |= 0x00380018; break; case 6: *x |= 0x00780018; break; case 7: *x |= 0x00000038; break; case 8: *x |= 0x00780038; break; case 9: *x |= 0x00380038; break; }; break; }; } // changes *x to show updated cricket score void led_cricket_update(long *x){ *x &= 0xc0000000; if (board[player][20]==0) *x |= 0x04001400; else if (board[player][20]==1) *x |= 0x04000400; else if (board[player][20]==2) *x |= 0x04000000; if (board[player][19]==0) *x |= 0x03000200; else if (board[player][19]==1) *x |= 0x02000200; else if (board[player][19]==2) *x |= 0x00000200; if (board[player][18]==0) *x |= 0x00080028; else if (board[player][18]==1) *x |= 0x00080008; else if (board[player][18]==2) *x |= 0x00080000; if (board[player][17]==0) *x |= 0x28000800; else if (board[player][17]==1) *x |= 0x28000000; else if (board[player][17]==2) *x |= 0x20000000; if (board[player][16]==0) *x |= 0x008000c0; else if (board[player][16]==1) *x |= 0x000000c0; else if (board[player][16]==2) *x |= 0x00000040; if (board[player][15]==0) *x |= 0x00500010; else if (board[player][15]==1) *x |= 0x00500000; else if (board[player][15]==2) *x |= 0x00400000; if (board[player][25]==0) *x |= 0x10200100; else if (board[player][25]==1) *x |= 0x00200100; else if (board[player][25]==2) *x |= 0x00200000; } // changes *x to display num void led_number(long *x, int num){ char place = 1; *x &= 0xc000c000; if (num==0) led_digit(x,1,0); while (num > 0){ led_digit(x, place, num%10); num /= 10; place++; } } // changes the player leds in *x void led_player(long *x, char num){ switch (num){ case 3: *x = (*x & 0x3fffffff); break; // both off case 0: *x = (*x & 0x3fffffff) | 0x80000000; break; case 1: *x = (*x & 0x3fffffff) | 0x40000000; break; case 2: *x = (*x & 0x3fffffff) | 0xc0000000; break; // both on case 4: *x ^= 0xc0000000; break; //invert }; } // sets the LED output variables to x void led_set(long x){ lo[1] = (char) (x & 0x000000ff); x >>= 8; hi[1] = (char) (x & 0x000000ff); x >>= 8; lo[0] = (char) (x & 0x000000ff); x >>= 8; hi[0] = (char) (x & 0x000000ff); } // updates the hit_long to show last dart hit void led_hit_update(){ hit_long = 0; led_player(&hit_long, player); led_number(&hit_long, dart_value); if (dart_ring==2) hit_long |= 0x08000400; else if (dart_ring==3) hit_long |= 0x18000400; } // updates the menu_long to show the new game number void led_menu_update(){ led_number(&menu_long, game_number+600); menu_long &= 0xefffffff; } // updates the winner_long to show the winner void led_winner(){ led_number(&winner_long, winner); led_player(&winner_long, winner-1); winner_long |= 0x340016c0; } // displays debug_long for t milliseconds // use: led_number(&debug_long, var_name); // debug(2000); void debug(int t){ led_set(debug_long); debug_time = t; } // changes scores and score_longs according to dart hit // and the rules of the current game void score_dart(){ dart_hit = 0; if (darts_left>0){ darts_left--; switch(GameStyle){ case Three01: if (dart_value * dart_ring > score[player]){ // bust darts_left = 0; } else { score[player] -= dart_value * dart_ring; led_number(&score_long[player][0], score[player]); if (score[player]==0) winner = player + 1; } break; case Cricket: if (dart_value>=15){ if (board[player][dart_value] + dart_ring <=3) { board[player][dart_value] += dart_ring; led_cricket_update(&score_long[player][1]); } else if (board[player][dart_value] + dart_ring > 3) { score[player] += dart_value*(board[player][dart_value] + dart_ring - 3); board[player][dart_value] = 3; led_number(&score_long[player][0], score[player]); led_cricket_update(&score_long[player][1]); } else if (board[player][dart_value]==3) { score[player] += dart_value*dart_ring; led_number(&score_long[player][0], score[player]); } if ((score_long[0][1] & 0x3fffffff)==0 && score[0]>score[1]) winner = 1; if ((score_long[1][1] & 0x3fffffff)==0 && score[1]>score[0]) winner = 2; } break; }; } } // initializes variables to selected game void init_game(){ dart_hit=0; num_players = 2; player = 0; winner = 0; switch(game_number){ case 1: GameStyle = Three01; num_sheets = 1; for (i=0; i 10){ PadState[mux_select] = Just_Hit; last_read[mux_select] = level; } break; case Just_Hit: if (diff_to_rail < 10) { PadState[mux_select] = Not_Hit; } else if (absdiff < 10){ PadState[mux_select] = Hit; hit_count[mux_select]++; pads_hit[pidx++] = mux_select; last_read[mux_select] = level; dart_value = 0; /* debug mode decode(mux_select); if (dart_value !=0) { led_number(&debug_long, dart_value); // debug(3000); } */ } break; case Hit: if (diff_to_rail < 10) { PadState[mux_select] = Not_Hit; last_read[mux_select] = level; } else if (diff > 5){ PadState[mux_select] = Just_Hit; last_read[mux_select] = level; } break; }; if ((mux_select) == debug_level || (mux_select==0 && debug_level==32) ){ led_number(&debug_long, level); // led_number(&debug_long, diff_to_rail); // led_number(&debug_long, rail[mux_select]); // led_number(&debug_long, last_read[mux_select]); led_player(&debug_long, PadState[mux_select]); //debug(60000); } // if 2 pads were hit, process the info if (mux_select ==0){ if (pidx==1) pcount++; if (pidx>=2){ for (i=0; i0) dart_hit=1; led_hit_update(); } if(pcount>10) { pcount=0; pidx=0; } } } interrupt[TIM0_COMP] void tim0(void){ char temp; count++; rand_count++; if (debug_time>0) debug_time--; if (debounce_time>0) debounce_time--; if (read_time>0) read_time--; if (time1>0) time1--; if (time2>0) time2--; if (blink) { if (blink_count>0) blink_count--; if (blink_count==0) { blink_phase=~blink_phase; blink_count = 250; } } else { blink_phase = 0; } if (time2<=0){ // output LED variables to LED // time2 = 500; time2 = 8; if (++phase>1) phase = 0; cycle ^= 0x03; temp = blink_phase ? 0: hi[phase]; PORTD.7 = ((temp & 0b10000000) > 0) ? 1 : 0; PORTC.0 = ((temp & 0b01000000) > 0) ? 1 : 0; PORTC.1 = ((temp & 0b00100000) > 0) ? 1 : 0; PORTC.2 = ((temp & 0b00010000) > 0) ? 1 : 0; PORTC.3 = ((temp & 0b00001000) > 0) ? 1 : 0; PORTC.4 = ((temp & 0b00000100) > 0) ? 1 : 0; PORTC.5 = ((temp & 0b00000010) > 0) ? 1 : 0; PORTC.6 = ((temp & 0b00000001) > 0) ? 1 : 0; temp = blink_phase ? 0 : lo[phase]; PORTC.7 = ((temp & 0b10000000) > 0) ? 1 : 0; PORTA.7 = ((temp & 0b01000000) > 0) ? 1 : 0; PORTA.6 = ((temp & 0b00100000) > 0) ? 1 : 0; PORTA.5 = ((temp & 0b00010000) > 0) ? 1 : 0; PORTA.4 = ((temp & 0b00001000) > 0) ? 1 : 0; PORTA.3 = (cycle ==1) ? 0: 1; PORTA.2 = (cycle ==1) ? 1: 0; } } // updates the LED state on various events: button presses, dart hits void LED_Update(void){ switch(LED_State){ case GameMenu: led_set(menu_long); switch(LastButtonPressed){ case GameUp: game_number+=2; case GameDown: game_number--; if(game_number>max_game_number) game_number = 1; if(game_number<1) game_number = max_game_number; led_menu_update(); led_set(menu_long); LastButtonPressed=0; break; case Start: debug_level = game_number; init_game(); LED_State = CurrentPlayerScore; count = 0; led_set(score_long[player][sheet]); LastButtonPressed=0; break; default: //led_number(&debug_long, 999); //debug(1000); }; break; case CurrentPlayerScore: if(winner>0) { LED_State = WinnerDisplay; led_winner(); led_set(winner_long); count = 0; } else if (dart_hit && darts_left>0){ LED_State = ShowDartHit; score_dart(); led_hit_update(); dart_hit=0; count = 0; led_set(hit_long); } else if (ScrollButtonPressed){ LED_State = ScrollScores; scroll_player = 0; scroll_sheet = 0; count = 0; led_set(score_long[scroll_player][scroll_sheet]); } else if (LastButtonPressed == NextPlayer){ LastButtonPressed=0; darts_left = 3; player++; if (player>=num_players) player = 0; sheet=0; pidx = 0; dart_hit=0; led_set(score_long[player][sheet]); } else if (num_sheets>1 && count>1500){ sheet++; if(sheet>=num_sheets) sheet = 0; count = 0; led_set(score_long[player][sheet]); } else if (LastButtonPressed == Reset){ LastButtonPressed=0; LED_State = GameMenu; game_number=1; led_menu_update(); led_set(menu_long); } break; case ScrollScores: if (!ScrollButtonPressed) { LED_State = CurrentPlayerScore; led_set(score_long[player][sheet]); count=0; } else if (count>=500){ scroll_player++; if (scroll_player>=num_players){ scroll_player=0; scroll_sheet++; if(scroll_sheet>= num_sheets) scroll_sheet=0; } led_set(score_long[scroll_player][scroll_sheet]); count = 0; } break; case ShowDartHit: if(count>=1000){ LED_State = CurrentPlayerScore; count = 0; led_set(score_long[player][sheet]); } break; case WinnerDisplay: if (LastButtonPressed>0){ LED_State = GameMenu; LastButtonPressed=0; game_number=1; led_menu_update(); led_set(menu_long); } break; default: //led_number(&debug_long, 777); //debug(2000); }; blink = (LED_State == CurrentPlayerScore && darts_left==0)||(LED_State==WinnerDisplay); } // debounces the buttons void check_key_press(void){ char button_pressed; debounce_time = 30; for(i=0; i<3; i++){ switch(i){ case 0: button_pressed = ~PIND.4; break; case 1: button_pressed = ~PIND.5; break; case 2: button_pressed = ~PIND.6; break; }; switch(PushState[i]){ case NotPushed: if (button_pressed) { PushState[i] = MaybePushed; } break; case MaybePushed: if (button_pressed) { PushState[i] = Pushed; } else PushState[i] = NotPushed; break; case Pushed: if (!button_pressed) PushState[i] = MaybeNotPushed; break; case MaybeNotPushed: if (!button_pressed) { PushState[i] = NotPushed; LastButtonPressed = i+1; if (LED_State!=GameMenu && LastButtonPressed==Start) LastButtonPressed = Reset; rand_int = rand_count; } else PushState[i] = Pushed; break; }; } //end for } void main(void){ char temp; DDRD=0x8f; // PORT D is an output - 7 to LED, 3-0 to muxes, 6-4 to button PORTD=0x70; DDRC=0xff; // PORT C is an output - LED DDRB=0x00; // PORT B is input - buttons PORTB=0xff; DDRA=0xfc; // PORT A : A.0,1 is input to ADC , rest output to LED TIMSK=2; TCCR0 = 0x0b; OCR0 = 249; time1 = 2000; //init the A to D converter //channel zero/ left adj /INTERNAL Aref ADMUX = 0b01100000; //enable ADC and set prescaler to 1/128*16MHz=125,000 //and clear interupt enable //and start a conversion ADCSR = 0b11000111; #asm sei #endasm LED_State = GameMenu; PushState[0] = NotPushed; PushState[1] = NotPushed; PushState[2] = NotPushed; game_number = 1; led_menu_update(); led_set(menu_long); for (i=0; i<32; i++){ rail[i] = ((i<=2) || (i==29)|| (i==15)||(i==30)) ? 255:0; last_read[i] = rail[i]; } while (1){ if (read_time==0 && LED_State!=GameMenu) scan4hit(); if (debounce_time==0) check_key_press(); temp = LastButtonPressed; if (debug_time==0) LED_Update(); } }