Mbed based laser tag system using IR LEDs and receivers
Dependencies: mbed fwdcrc16library PinDetect TextLCD
main.cpp
00001 ////////////////////////////////////////// 00002 //Embedded Systems Design Final Project // 00003 //Robert Michael Swan // 00004 //March 21, 2013 // 00005 // // 00006 //Compiled Code Size: 17.7KB // 00007 ////////////////////////////////////////// 00008 //Libraries Used 00009 #include "mbed.h" 00010 #include "TextLCD.h" 00011 #include "PinDetect.h" 00012 #include "crc16.h" 00013 //Peripherals 00014 PinDetect sw2(P0_11); //switch2 debounced input 00015 PinDetect sw3(P0_10); //switch3 debounced input 00016 TextLCD lcd(P1_15, P1_16, P1_19, P1_20, P1_21, P1_22); // rs, e, d4-d7 led pins:4,6,11-14 00017 DigitalOut LB(P1_31); //lcd backlight 00018 DigitalOut LP(P1_29); //lcd power 00019 DigitalOut led1(P0_22); //on-board led ds1 00020 DigitalOut led2(P0_23); //on-board led ds2 00021 Serial IR(P1_27,P1_26); //IR transmitter and receiver output and input control P1_27 controls IR diode, P1_26 controls IR reciever 00022 PwmOut Square_Gen(P1_25); //square wave generator for IR led 00023 //Timers 00024 Timeout stats; //used for displaying text for limited periods of time 00025 Timeout shot_time; //used to ensure shots take place in a brief period of time 00026 Timeout flash; //used to flash leds and backlight when shooting or tagging 00027 Timer timer; //used as seconds for reset timer 00028 Ticker clock_tick; //used with timer for minutes of reset timer 00029 //Required global variables 00030 unsigned mins = 0; //global variable for minutes in game, since ticker interrupt cannot attach functions that have parameters 00031 bool btn2 = false; //global variable for sw2, since the PinDetect interrupt cannot attach functions that have parameters 00032 bool btn3 = false; //global variable for sw3, since the PinDetect interrupt cannot attach functions that have parameters 00033 bool done = false; //global variable for timeout, since TimeOut interrupt cannot attach functions that have parameters 00034 bool taggable = false; //global variable for whether serial received input will be used or not 00035 volatile bool tagged = false; //global variable for whether tag is complete 00036 char id_rx[15]; //global variable for received ID. Required to use serial interrupt correctly 00037 unsigned id_pos = 0; //global variable for recieved ID array location. Also required for serial interrupt. 00038 00039 //Functions 00040 /*Minute Interrupt 00041 Intended to be called every minute to increment the minute counter. 00042 Also resets the seconds timer as it reaches 60 seconds (assuming it is called at timer.start();) 00043 */ 00044 void minutes() 00045 { 00046 mins ++; 00047 timer.reset(); 00048 } 00049 00050 /* Flashing interrupt 00051 Intended to be used with a timeout object to flash lights when shot or shooting 00052 */ 00053 void flasher() 00054 { 00055 LB = 0; 00056 led1 = !led1; 00057 led2 = !led2; 00058 } 00059 00060 /*Shot Check/Reset Interrupt 00061 Intended to be called after a short period of time to start array over from the start 00062 Should keep data from being received over an excessive amount of time and thus is one 00063 method of ensuring player is actually tagged 00064 */ 00065 void shot_check() 00066 { 00067 id_pos = 0; //resets current id 00068 } 00069 00070 /*Serial Callback interrupt 00071 Receives IR information using IR receiver 00072 If taggable = false, received data is thrown away. 00073 Otherwise, up to 15 characters are collected in a time period of 0.5 seconds 00074 If less than 15 characters received in 0.5 seconds, function array returns to first bit 00075 */ 00076 void callback() 00077 { 00078 // Note: you need to actually read from the serial buffer to clear the RX interrupt 00079 if (!taggable) 00080 { 00081 IR.getc(); //ensures no extra buffering left over when player is not taggable 00082 return; 00083 } 00084 00085 id_rx[id_pos] = IR.getc(); //place received character into array 00086 /*if (id_pos == 0) //starts a timer for the time in which receiver must receive a full id 00087 { 00088 shot_time.attach(&shot_check, 0.5); 00089 }*/ 00090 if(id_pos >= 14) 00091 { 00092 id_pos = 0; //ensures no array overflows 00093 shot_time.detach(); //ensures no further action upon array until next time tagged 00094 tagged = true; //changes tagged flag such that the main code will trigger after an ID is fully received 00095 return; 00096 } 00097 id_pos ++; //increment to next array position for id 00098 return; 00099 } 00100 00101 /*Button 2 Interrupt 00102 Sets button variable to true for use in code when button is pressed 00103 */ 00104 void btn2Pressed() 00105 { 00106 led1 = !led1; 00107 btn2 = true; 00108 } 00109 00110 /*Button 3 Interrupt 00111 Sets button variable to true for use in code when button is pressed 00112 */ 00113 void btn3Pressed() 00114 { 00115 led2 = !led2; 00116 btn3 = true; 00117 00118 } 00119 00120 /*Statistics Display Timeout 00121 Sets display "done" flag to true 00122 Intended to be used with timeout interrupt and statistics function to jump out of function 00123 if it has been 5 seconds. 00124 */ 00125 void finish_disp () 00126 { 00127 done = true; 00128 return; 00129 } 00130 00131 /*Error Routine. 00132 Displays "ERROR" on LCD screen and flashes leds 00133 for an indefinite period of time. 00134 */ 00135 void error_custom () 00136 { 00137 lcd.cls(); 00138 lcd.printf("ERROR"); 00139 led1 = 0; 00140 led2 = 1; 00141 while(1) 00142 { 00143 led1 = !led1; 00144 led2 = !led2; 00145 wait(0.5); 00146 } 00147 } 00148 /*Alphanumeric selector 00149 Used with char_sel function in order to select a number 0-9 or letters A-Z through user input. 00150 Returns a char. 00151 */ 00152 char alpha_num_sel (bool number) 00153 { 00154 char n0 = '0'; 00155 char n_tmp = '0'; 00156 unsigned incr = 0; //used to increment characters between 0-9 or A-Z 00157 unsigned mod; 00158 if (number) 00159 { 00160 lcd.cls(); 00161 lcd.printf("Pick\nNumber:%c",n_tmp); 00162 n0 = '0'; 00163 n_tmp = n0; 00164 mod = 11; //modulus for character range 00165 } 00166 else 00167 { 00168 lcd.cls(); 00169 n0 = 'A'; 00170 n_tmp = n0; 00171 lcd.printf("Pick\nLetter:%c",n_tmp); 00172 mod = 26; 00173 } 00174 while(1) 00175 { 00176 while(!btn2 && !btn3) //waits until button input received 00177 { 00178 wait(0.05); 00179 } 00180 if(btn3) 00181 { 00182 btn3 = false; 00183 btn2 = false; //if both butons pressed, it just selects the current character 00184 return (n_tmp); 00185 } 00186 else if(btn2) 00187 { 00188 btn2 = false; 00189 incr ++; 00190 incr = incr % mod; //ensures that numbers stay within the 0-9/A-Z range 00191 n_tmp = n0 + incr; //increment current character selected 00192 if (incr == 10 && number) //feature addition to allow for space entry 00193 { 00194 n_tmp = ' '; 00195 } 00196 lcd.cls(); 00197 if(number) 00198 { 00199 lcd.printf("Pick\nNumber:%c",n_tmp); //displays current number 00200 } 00201 else 00202 { 00203 lcd.printf("Pick\nLetter:%c",n_tmp); //displays current letter 00204 } 00205 } 00206 else 00207 { 00208 error_custom(); 00209 } 00210 00211 } 00212 } 00213 00214 /*Character Selection 00215 Used with setup() function in order to pick a character A-Z and number 0-9 00216 for use as part of user id and/or team. Passed a 0 if selecting team letter (A-Z), 00217 otherwise will select player id letter 00218 */ 00219 char char_sel (bool player) 00220 { 00221 if (player) 00222 { 00223 lcd.cls(); 00224 lcd.printf("A-Z? or\n0-9?"); 00225 while(!btn2 && !btn3) //waits until button input received 00226 { 00227 wait(0.05); 00228 } 00229 if(btn2) //if select button pressed, goes through numerical selection 00230 { 00231 btn2 = false; 00232 btn3 = false; //if both buttons pressed at the same time, it just does numerical selection 00233 00234 return(alpha_num_sel(1)); 00235 } 00236 else if(btn3) 00237 { 00238 btn3 = false; //pressing the option button in this case is the same as selecting a team 00239 } 00240 else 00241 { 00242 error_custom(); //if you somehow make it here without pressing buttons, it will throw an error 00243 } 00244 } 00245 return(alpha_num_sel(0)); //returns capital alpha character for id or team by calling selection function 00246 } 00247 00248 00249 /*Setup Routine. 00250 Sets the user id for use in-game. 00251 Function must be passed an array of characters of size 15 00252 in order to work correctly. 00253 */ 00254 void setup (char* ID_array) 00255 { 00256 unsigned size = 1; 00257 00258 lcd.cls(); 00259 lcd.printf("ID Size?\n%u",size); 00260 00261 while(1) 00262 { 00263 while(!btn2 && !btn3) //waits until button input received 00264 { 00265 wait(0.05); //ensures buttons cannot be pressed extremely fast 00266 } 00267 if(btn2 && btn3) //routine to set size of player id in bytes 00268 { 00269 btn2 = false; //handling for simultaneous button pressing 00270 btn3 = false; 00271 size++; 00272 if (size > 12) 00273 { 00274 size = 1; //ensures size cannot be greater than 12 or less than 1 00275 } 00276 break; //sets size to whatever current size is +1 and moves on 00277 } 00278 else if(btn2) //increases size or loops back to 1, displays current size 00279 { 00280 btn2 = false; 00281 size++; 00282 if (size > 12) 00283 { 00284 size = 1; //ensures size cannot be greater than 12 or less than 1 00285 } 00286 lcd.cls(); 00287 lcd.printf("ID Size?\n%u",size); //displays current size 00288 } 00289 else if(btn3) 00290 { 00291 btn3 = false; //selects current size 00292 break; 00293 } 00294 else 00295 { 00296 error_custom(); //error called if unexpected output 00297 } 00298 } 00299 00300 for (unsigned j = 0; j < size; j ++) //sets player id 00301 { 00302 ID_array[j] = char_sel(1); 00303 } 00304 for (unsigned j = size; j < 12; j ++) 00305 { 00306 ID_array[j] = ' '; //fill unused characters with spaces 00307 } 00308 00309 lcd.cls(); 00310 lcd.printf("On team?\n Y or N"); 00311 00312 while(!btn2 && !btn3) //waits until button input received 00313 { 00314 wait(0.05); //ensures buttons cannot be pressed extremely fast 00315 } 00316 if(btn3) 00317 { 00318 btn3 = false; 00319 btn2 = false; //you're on a team if you press both buttons 00320 ID_array[12] = char_sel(0); //sets team letter 00321 } 00322 else if (btn2) 00323 { 00324 btn2 = false; 00325 ID_array[12] = '0'; //sets team to 'zero', indicating no team 00326 } 00327 else 00328 { 00329 error_custom(); //throws an error if you somehow get here) 00330 } 00331 00332 lcd.cls(); 00333 lcd.printf("Your ID\n is:"); 00334 wait(1); 00335 lcd.cls(); 00336 for(unsigned j = 0; j <= 12; j++) //prints out player id and team 00337 { 00338 lcd.printf("%c",ID_array[j]); 00339 if (j == 7) 00340 { 00341 lcd.printf("\n"); //puts in a new line after eight characters 00342 } 00343 } 00344 crc16_attach(ID_array,13); //attaches crc bits to last two bits of 15 character array 00345 wait(3); 00346 return; 00347 } 00348 00349 /*ID Checking Routine 00350 Checks received IDs to see if it is a valid shot 00351 player_array is the 15 character id array of the player that constains a 16-bit crc in the last two bytes 00352 Returns a boolean true if shot is valid, otherwise false 00353 */ 00354 bool check_id(char* player_array) 00355 { 00356 if (id_rx[12] == player_array[12] && id_rx[12] >= 'A') 00357 { 00358 return false; //if ids are on the same team or are the same person, they cannot be hit by each other/themselves 00359 } 00360 else if(id_rx[13] == player_array[13] && id_rx[14] == player_array[14]) 00361 { 00362 return false; 00363 } 00364 return (crc16_match(id_rx, 13)); //compares the crc tag in received id to a calculated one. Returns false if different. 00365 } 00366 00367 /*Respawn Display 00368 Displays appropriate information for who player was hit by while they are "respawning" 00369 Returns nothing 00370 */ 00371 void respawn() 00372 { 00373 lcd.cls(); 00374 lcd.printf("Hit by:"); 00375 wait(1); 00376 lcd.cls(); 00377 for(unsigned j = 0; j <= 12; j++) //prints out id and team of person who tagged player 00378 { 00379 lcd.printf("%c",id_rx[j]); 00380 if (j == 7) 00381 { 00382 lcd.printf("\n"); //puts in a new line after eight characters 00383 } 00384 } 00385 wait(4); 00386 } 00387 /*Firing function 00388 Sends ID information through IR 00389 Parameters: player_id 00390 player_id = 15 character array that contains player id and crc hash 00391 returns nothing 00392 */ 00393 void fire(char* player_id) 00394 { 00395 for (unsigned i = 0; i < 15; i ++) 00396 { 00397 IR.putc(player_id[i]); 00398 } 00399 } 00400 00401 /*Statistics Display Function 00402 Displays game statistics without interrupting gameplay significantly 00403 Requires LCD to be on. 00404 Function will end if fire button is pressed or 5 seconds have passed 00405 without the statistics button (btn2) being pressed again. 00406 Maximum amount of time possible in this function is 15 seconds, 00407 5 seconds for each of the 3 statistics displays 00408 Parameters: tag_count = number of times player has been tagged 00409 shots = number of times player has shot 00410 mode = level of statistics looking at: tag count(0), shots(1), or time since reset(2) 00411 Returns nothing 00412 */ 00413 void statistics(const unsigned &tag_count, const unsigned &shots, short mode) 00414 { 00415 done = false; //Used to timeout on statistics display 00416 lcd.cls(); 00417 if(mode == 0) 00418 { 00419 lcd.printf("Tagged:\n%u",tag_count); 00420 } 00421 else if(mode == 1) 00422 { 00423 lcd.printf("# Shots:\n%u",shots); //shot count 00424 } 00425 else if(mode == 2) 00426 { 00427 unsigned secs = 0; //used to readout numer of seconds on timer 00428 secs = timer.read(); 00429 lcd.printf("Mins:%u\nSecs:%u", mins,secs); 00430 } 00431 else 00432 { 00433 led1 = 1; 00434 led2 = 1; 00435 return; //if no valid mode, the function will end. Used to end recursion 00436 } 00437 stats.attach(&finish_disp, 5); 00438 while(!done) 00439 { 00440 if(btn3 == true || tagged) 00441 { 00442 stats.detach(); //exit if something interrupts stats 00443 lcd.cls(); 00444 return; 00445 } 00446 else if(btn2 == true) 00447 { 00448 btn2 = false; 00449 stats.detach(); //keeps statistics display from timing out for another 5 seconds 00450 mode ++; 00451 statistics(tag_count,shots,mode); //recursive function call of statistics 00452 return; //jumps out of function whenever other forms return 00453 } 00454 wait(0.05); //function will get stuck without short wait 00455 } 00456 return; 00457 } 00458 00459 int main() 00460 { 00461 Square_Gen.period_us(26); //produces a 38kHz square wave to ensure proper IR communication... 00462 Square_Gen.pulsewidth_us(13); //...this signal is sent to one of the IR diode terminals through a transistor 00463 IR.baud(1200); //sets baud rate of serial output and input 00464 IR.attach(&callback); //attaches interrupt for serial buffer 00465 LB = 1; //turn on lcd backlight 00466 LP = 1; //turn on lcd power 00467 sw2.mode(PullUp); //set buttons to a default high voltage for logic low 00468 sw3.mode(PullUp); 00469 sw2.setSampleFrequency(); //set buttons to default sample frequency for debouncing 00470 sw3.setSampleFrequency(); 00471 sw2.setAssertValue(0); //set buttons to be logic high when voltage is low. 00472 sw3.setAssertValue(0); 00473 sw2.attach_asserted( &btn2Pressed ); //attach button interrupts 00474 sw3.attach_asserted( &btn3Pressed ); 00475 clock_tick.attach(&minutes, 60); //ticker interrupts every 60 seconds to add 1 minute and reset timer 00476 timer.reset(); //ensure timer starts at 0 00477 timer.start(); //start reset timer 00478 00479 led1 = 1; 00480 char id[15]; //id array, capable of storing user ids up to 12 bytes with 1 byte for team and 2 bytes for CRC. 00481 unsigned tag_count = 0; //number of times player has been tagged in a game 00482 unsigned shots = 0; //number of shots fired in a game. 00483 lcd.cls(); //ensure lcd starts with clear screen 00484 lcd.printf("Choose \nYour ID."); 00485 while(btn2 == false && btn3 == false) 00486 { 00487 wait(0.2); //wait to start setup until either button is pressed 00488 } 00489 btn2 = false; //reset button values 00490 btn3 = false; 00491 setup(id); //setup player id and team, passing function the id array 00492 taggable = true; 00493 LB = 0; //turn off lcd screen, backlight, and leds to save power during game 00494 LP = 0; 00495 led1 = 0; 00496 led2 = 0; 00497 while(1) 00498 { 00499 if(tagged) 00500 { 00501 flash.attach(&flasher,0.5); 00502 tagged = false; 00503 //LB = 1; //turn on backlight and leds for flash 00504 led1 = 1; 00505 led2 = 1; 00506 if (check_id(id)) 00507 { 00508 taggable = false; //don't allow new tags if respawning 00509 flash.detach(); //if tag is valid, no need to flash 00510 tag_count ++; 00511 LP = 1; //turn LCD power and backlight on 00512 LB = 1; 00513 respawn(); //prints appropriate respawn info 00514 taggable = true; 00515 led2 = 0; 00516 } 00517 LB = 0; //turn LCD backlight and power back off 00518 LP = 0; 00519 led1 = 0; 00520 } 00521 if(btn3) //fires IR led if btn3 is pressed 00522 { 00523 btn3 = false; 00524 flash.detach(); //lights will not flash if you fire really fast 00525 shots ++; //increment number of times ir has been shot by player 00526 LB = 1; 00527 led1 = 1; 00528 led2 = 1; 00529 flash.attach(flasher,0.5); //flashes backlight and leds when firing 00530 fire(id); //fires player id using IR diode 00531 } 00532 if (btn2) //displays statistics if btn2 is pressed 00533 { 00534 flash.detach(); 00535 btn2 = false; 00536 LP = 1; //turn on display 00537 LB = 1; 00538 statistics(tag_count,shots,0); 00539 LP = 0; 00540 LB = 0; 00541 } 00542 wait(0.01); 00543 } 00544 }
Generated on Tue Aug 9 2022 09:20:03 by 1.7.2