#include <90s8515.h> #include #include #include #asm .equ __lcd_port=0x1b // set LCD to PORTA #endasm #include // LCD driver routines // Set if you want the game board to start #define START // Set if you want to use the prototype board //#define BOARD // states for game play state machine #define sendCoord 1 #define receiveCoord 2 #define start 3 #define sendCheck 4 #define enterCoord 5 #define release 6 #define debounce 7 #define stillPressed 8 #define debounceRelease 9 #define detectTerm 10 #define stillPressedTerm 11 #define receiveResult 12 #define checkCoord 13 #define sendResult 14 #define pause 15 #define waitOpponentReady 16 #define displayWait 17 #define dbStart 18 #define waitAttack 19 // states for getting boats #define promptBoat 1 #define waitBoat 2 #define getBoat 3 #define debounceBoat 4 #define stillPressedBoat 5 #define t1 30 // timer1: enter state machine every 30ms #define BUFFER_LENGTH 2 // UART receive buffer length #define MAX_KEYS 8 // number of valid keys on keypad #define MAX_LENGTH 2 //number of coordintes #define enter 8 // enter key '#' #define NUM_BOATS 2 // number of boats #define MAX_BOAT_LENGTH 4 // maximum boat length #define BOARD_SIZE 4 // max board size is 4x4 // Structure to hold the coordinates struct coordinate { unsigned har coord; unsigned char hit; }; // Structure to hold the boats struct boat { struct coordinate position[MAX_BOAT_LENGTH]; // Array of all the coordinates for the boat unsigned char length; // length of the boat unsigned char status; }; struct boat boatMap[NUM_BOATS]; // map to store boat positions unsigned char state; // state machine variable unsigned char time1, reload; // timer 1 variables unsigned char butnum, maybe, keyCount, keyStr; //keypad scan variables unsigned char temp; unsigned char result; // result of attack unsigned char numBoatsLeft; // number of boats left to be sunk unsigned int t; // counter unsigned char mapReady; unsigned char startGame; // UART variables unsigned char r_index; unsigned char r_buffer[BUFFER_LENGTH]; unsigned char r_ready; unsigned char r_char; // Game state machine void _displayWait(void); // void _waitOpponentReady(void); // wait for opponent to finish entering boats void _start(void); // start the turn by pushing '9' void _dbStart(void); // debounce start // Attack states void _enterCoord(void); // enter coordinates for attack void _sendCoord(void); // send coordinates to other mcu void _sendCheck(void); // check transmission complete void _pause(void); // wait for results from other mcu void _receiveResult(void); // receive result from other mcu // Defense states void _receiveCoord(void); // recieve atatck coordinates void _checkCoord(void); // check coordinates against map void _sendResult(void); // send result to other mcu void _waitAttack(void); // pause before switching to attack // Read map state machine void readMapControl(void); // control for map reading state machine void _promptBoat(void); // prompt user for boat input void _waitBoat(void); // wait for user input void _getBoat(void); // calls boardScan to read boat void _debounceBoat(void); void _stillPressedBoat(void); // Keypad states void _release(void); void _debounce(void); void _detectTerm(void); void _stillPressed(void); void _stillPressedTerm(void); void _debounceRelease(void); void control(void); // state machine control void initialize(void); // initialization void keypadScan(); // keypad scan routine char convertToA(char); // convert to ascii void boardScan(void); // board scan routine void insertBoat(char, char *, char); // insert boat into map void initMap(void); // debug function for creating a map char findBoat(char, char); // find a boat in the map //key pad scan table //{1, 2, 3, 4, 5, 6, 7, 9} flash unsigned char keytbl[MAX_KEYS]={0xf6, 0xee, 0xbe, 0xf5, 0xed, 0xbd, 0xf3, 0xbb}; // Values used for boardScan flash unsigned char DDRDtbl[7] = {0, 4, 8, 16, 32, 64, 128}; flash unsigned char masktbl[7] = {2, 4, 8, 16, 32, 64, 128}; //2^(i) //********************************************************** //timer 0 overflow ISR interrupt [TIM0_OVF] void timer0_overflow(void) { //reload to force 1 mSec overflow TCNT0=reload; //Decrement the three times if they are not already zero if (time1>0) --time1; } //********************************************************** //interrupt when we have something to get from UDR interrupt [UART_RXC] void uart_rec(void) { r_char = UDR; // get a char if(r_char == 0xbe) { startGame = 1; return; } // build the input string if ((r_char != 0x00) && (r_index < BUFFER_LENGTH)) r_buffer[r_index++]=r_char; else { r_buffer[r_index]=0x00; // zero terminate r_ready=1; // signal cmd processor UCR.7=0; // disable recieve } } //********************************************************** // Main task scheduler loop void main(void) { initialize(); //initMap(); while(1) { if (time1==0) { if(mapReady == 0) readMapControl(); else control(); } } } //********************************************************* // State machine control void control(void) { time1 = t1; switch(state) { case displayWait: _displayWait(); break; case waitOpponentReady: _waitOpponentReady(); break; case start: _start(); break; case dbStart: _dbStart(); break; case enterCoord: _enterCoord(); break; case sendCoord: _sendCoord(); break; case sendCheck: _sendCheck(); break; case pause: _pause(); break; case receiveResult: _receiveResult(); break; case receiveCoord: _receiveCoord(); break; case checkCoord: _checkCoord(); break; case sendResult: _sendResult(); break; case waitAttack: _waitAttack(); break; case release: _release(); break; case debounce: _debounce(); break; case detectTerm: _detectTerm(); break; case stillPressedTerm: _stillPressedTerm(); break; case stillPressed: _stillPressed(); break; case debounceRelease: _debounceRelease(); break; default: state = start; _start(); break; } } void _displayWait(void) { lcd_clear(); lcd_putsf("Waiting!"); UCR.7 = 1; state = waitOpponentReady; } void _waitOpponentReady(void) { if(startGame == 1) { //let the games begin! lcd_clear(); #ifdef START state = start; lcd_putsf("Go Go Go!"); UCR.7 = 0; #else state = receiveCoord; lcd_putsf("Look out!"); UCR.7 = 1; #endif } } void _start(void) { if (butnum == enter) state = dbStart; else keypadScan(); } void _dbStart(void) { if(butnum != enter) state = enterCoord; else keypadScan(); } void _enterCoord(void) { //prompt user to enter xy coordinates lcd_clear(); lcd_gotoxy(0,0); lcd_putsf("xy="); keypadScan(); keyCount = 0; state = release; } void _release(void) { if (butnum==0) keypadScan(); else { maybe = butnum; keypadScan(); state = debounce; } } void _debounce(void) { if (butnum==maybe) { state = detectTerm; } else { keypadScan(); state = release; } } void _detectTerm(void) { if (butnum == enter) { if (keyCount == MAX_LENGTH) state = stillPressedTerm; else { state = release; keypadScan(); } } else { if (keyCount < MAX_LENGTH) { if (keyCount == 0) keyStr = butnum; else keyStr = (keyStr << 4) | butnum; // display coordinate on LCD lcd_gotoxy(keyCount+3, 0); lcd_putchar(convertToA(butnum)); keyCount++; } keypadScan(); state = stillPressed; } } void _stillPressedTerm(void) { if (butnum == enter) { keypadScan(); } else { keyCount=0; state = sendCoord; } } void _stillPressed(void) { if (butnum == maybe) { keypadScan(); } else { keypadScan(); state = debounceRelease; } } void _debounceRelease(void) { if (butnum == maybe) { keypadScan(); state = stillPressed; } else { keypadScan(); state = release; } } void _sendCoord(void) { //Send x,y, and term putchar(keyStr); putchar('\0'); state = sendCheck; } void _sendCheck(void) { if (USR.6 == 1) { state = pause; UCR.7 = 1; lcd_clear(); temp = 0; t = 10; } } void _pause(void) { if (t==0) { lcd_gotoxy(temp++,0); lcd_putsf("."); t = 10; } else t--; if (temp == 7) state = receiveResult; } void _receiveResult(void) { if(r_ready==1) { lcd_clear(); lcd_gotoxy(0,0); if(r_buffer[0] != 0xff) { temp = r_buffer[0] & 0x07; switch (temp) { case 1: lcd_putsf("*hit*"); break; case 3: lcd_putsf("*sunk*"); break; case 7: lcd_putsf("You win!"); break; } } else lcd_putsf("miss :p"); r_ready = 0; r_index = 0; UCR.7 = 1; state = receiveCoord; } } void _receiveCoord(void) { if(r_ready==1) { lcd_clear(); lcd_putsf("bomb@ "); // display on LCD temp = r_buffer[0] >> 4; lcd_gotoxy(5,0); lcd_putchar(convertToA(temp)); temp = r_buffer[0] & 0x0f; lcd_gotoxy(6,0); lcd_putchar(convertToA(temp)); state = checkCoord; r_ready = 0; r_index = 0; } } void _checkCoord(void) { char index; index = findBoat(r_buffer[0], 1); // look for boat // is boat found? if(index != -1) { result = 0x01; boatMap[index].status--; // boat sunk if(boatMap[index].status == 0) { result = 0x03; numBoatsLeft--; // all boats sunk if(numBoatsLeft == 0) result = 0x07; } } else result = 0xff; state = sendResult; } void _sendResult(void) { putchar(result); putchar('\0'); t = 75; state = waitAttack; } void _waitAttack(void) { if (t==0) { //display result lcd_clear(); lcd_gotoxy(0,0); if(result != 0xff) { temp = result & 0x07; switch (temp) { case 1: lcd_putsf("ouch :o"); break; case 3: lcd_putsf("bye boat"); break; case 7: lcd_putsf("You lost!"); break; } } else lcd_putsf("phew :)"); state = start; keypadScan(); } else t--; } void initialize(void) { UCR = 0x10 + 0x08 ; //enable serial transmit and receive UBRR = 25 ; //set baud rate to 9600 UCR.7 = 1; //set up timer 0 //62.5 x (64x.25) microSec = 1.0 mSec, so prescale 64, and count 62 times. reload=256-62; TCNT0=reload; TCCR0=3; TIMSK=2; //task1 timer time1 = t1; lcd_init(16); lcd_clear(); r_ready = 0; // buffer not ready r_index = 0; // initialize buffer index // Read map first numBoatsLeft = 0; /*initMap(); mapReady = 1; startGame = 1; state = waitOpponentReady; */ state = promptBoat; mapReady = 0; startGame = 0; //crank up the ISRs #asm sei #endasm } //********************************************************** // scan keypad void keypadScan(void) { char key; //current key //get upper nibble DDRB = 0x27; PORTB = 0xd8; delay_us(5); key = PINB; //get lower nibble DDRB = 0xd8; PORTB = 0x27; delay_us(5); key = key | PINB; //find matching keycode in keytbl if (key != 0xff) { for (butnum=0; butnum> 4; col = foundBoat[i] & 0x0f; lcd_gotoxy((i)*3,0); lcd_putchar(convertToA(row)); lcd_gotoxy((i)*3+1,0); lcd_putchar(convertToA(col)); } } else { lcd_gotoxy(2, 0); lcd_putchar('$'); */ for(i=0; i> 4; col = boatCoord[i] & 0x0f; lcd_gotoxy((i)*3,0); lcd_putchar(convertToA(row)); lcd_gotoxy((i)*3+1,0); lcd_putchar(convertToA(col)); } } void readMapControl(void) { time1 = t1; switch(state) { case promptBoat: _promptBoat(); break; case waitBoat: _waitBoat(); break; case getBoat: _getBoat(); break; case debounceBoat: _debounceBoat(); break; case stillPressedBoat: _stillPressedBoat(); break; default: state = promptBoat; } } void _promptBoat(void) { if(numBoatsLeft != NUM_BOATS) { lcd_clear(); lcd_gotoxy(0,0); lcd_putsf("Boat"); lcd_gotoxy(5, 0); lcd_putchar(convertToA(numBoatsLeft)); state = waitBoat; keypadScan(); } else { // map is now ready... // let the other board know you're ready!!! putchar(0xbe); mapReady = 1; state = displayWait; //putchar('\0'); } } void _waitBoat(void) { if (butnum==0) keypadScan(); else if (butnum==enter) { keypadScan(); state = debounceBoat; } } void _debounceBoat(void) { if (butnum==enter) { state = getBoat; } else { state = debounceBoat; keypadScan(); } } void _getBoat(void) { state = stillPressedBoat; boardScan(); keypadScan(); } void _stillPressedBoat(void) { if (butnum != enter) state = promptBoat; keypadScan(); } /*** * Used for debugging purposes... creates a default map with boats already in place */ void initMap(void) { unsigned char blah[4]; /* blah[0] = 0x77; blah[1] = 0x76; blah[2] = 0x75; bl