Mbed based laser tag system using IR LEDs and receivers
Dependencies: mbed fwdcrc16library PinDetect TextLCD
This project was the result of an embedded systems design course held in 2013.
main.cpp@5:6e6ab7e5074e, 2019-08-15 (annotated)
- Committer:
- Mike951
- Date:
- Thu Aug 15 18:48:47 2019 +0000
- Revision:
- 5:6e6ab7e5074e
- Parent:
- 4:7294c20b1025
Finished and tested IR Laser Tag project
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Mike951 | 5:6e6ab7e5074e | 1 | ////////////////////////////////////////// |
Mike951 | 5:6e6ab7e5074e | 2 | //Embedded Systems Design Final Project // |
Mike951 | 5:6e6ab7e5074e | 3 | //Robert Michael Swan // |
Mike951 | 5:6e6ab7e5074e | 4 | //March 21, 2013 // |
Mike951 | 5:6e6ab7e5074e | 5 | // // |
Mike951 | 5:6e6ab7e5074e | 6 | //Compiled Code Size: 17.7KB // |
Mike951 | 5:6e6ab7e5074e | 7 | ////////////////////////////////////////// |
Mike951 | 5:6e6ab7e5074e | 8 | //Libraries Used |
Mike951 | 0:69e5ee3b618d | 9 | #include "mbed.h" |
Mike951 | 0:69e5ee3b618d | 10 | #include "TextLCD.h" |
Mike951 | 0:69e5ee3b618d | 11 | #include "PinDetect.h" |
Mike951 | 0:69e5ee3b618d | 12 | #include "crc16.h" |
Mike951 | 5:6e6ab7e5074e | 13 | //Peripherals |
Mike951 | 1:24f46931d010 | 14 | PinDetect sw2(P0_11); //switch2 debounced input |
Mike951 | 1:24f46931d010 | 15 | PinDetect sw3(P0_10); //switch3 debounced input |
Mike951 | 0:69e5ee3b618d | 16 | TextLCD lcd(P1_15, P1_16, P1_19, P1_20, P1_21, P1_22); // rs, e, d4-d7 led pins:4,6,11-14 |
Mike951 | 0:69e5ee3b618d | 17 | DigitalOut LB(P1_31); //lcd backlight |
Mike951 | 0:69e5ee3b618d | 18 | DigitalOut LP(P1_29); //lcd power |
Mike951 | 0:69e5ee3b618d | 19 | DigitalOut led1(P0_22); //on-board led ds1 |
Mike951 | 0:69e5ee3b618d | 20 | DigitalOut led2(P0_23); //on-board led ds2 |
Mike951 | 2:15134f79b400 | 21 | Serial IR(P1_27,P1_26); //IR transmitter and receiver output and input control P1_27 controls IR diode, P1_26 controls IR reciever |
Mike951 | 0:69e5ee3b618d | 22 | PwmOut Square_Gen(P1_25); //square wave generator for IR led |
Mike951 | 5:6e6ab7e5074e | 23 | //Timers |
Mike951 | 1:24f46931d010 | 24 | Timeout stats; //used for displaying text for limited periods of time |
Mike951 | 2:15134f79b400 | 25 | Timeout shot_time; //used to ensure shots take place in a brief period of time |
Mike951 | 2:15134f79b400 | 26 | Timeout flash; //used to flash leds and backlight when shooting or tagging |
Mike951 | 2:15134f79b400 | 27 | Timer timer; //used as seconds for reset timer |
Mike951 | 1:24f46931d010 | 28 | Ticker clock_tick; //used with timer for minutes of reset timer |
Mike951 | 5:6e6ab7e5074e | 29 | //Required global variables |
Mike951 | 1:24f46931d010 | 30 | unsigned mins = 0; //global variable for minutes in game, since ticker interrupt cannot attach functions that have parameters |
Mike951 | 1:24f46931d010 | 31 | bool btn2 = false; //global variable for sw2, since the PinDetect interrupt cannot attach functions that have parameters |
Mike951 | 1:24f46931d010 | 32 | bool btn3 = false; //global variable for sw3, since the PinDetect interrupt cannot attach functions that have parameters |
Mike951 | 2:15134f79b400 | 33 | bool done = false; //global variable for timeout, since TimeOut interrupt cannot attach functions that have parameters |
Mike951 | 2:15134f79b400 | 34 | bool taggable = false; //global variable for whether serial received input will be used or not |
Mike951 | 4:7294c20b1025 | 35 | volatile bool tagged = false; //global variable for whether tag is complete |
Mike951 | 2:15134f79b400 | 36 | char id_rx[15]; //global variable for received ID. Required to use serial interrupt correctly |
Mike951 | 2:15134f79b400 | 37 | unsigned id_pos = 0; //global variable for recieved ID array location. Also required for serial interrupt. |
Mike951 | 0:69e5ee3b618d | 38 | |
Mike951 | 5:6e6ab7e5074e | 39 | //Functions |
Mike951 | 4:7294c20b1025 | 40 | /*Minute Interrupt |
Mike951 | 4:7294c20b1025 | 41 | Intended to be called every minute to increment the minute counter. |
Mike951 | 4:7294c20b1025 | 42 | Also resets the seconds timer as it reaches 60 seconds (assuming it is called at timer.start();) |
Mike951 | 4:7294c20b1025 | 43 | */ |
Mike951 | 1:24f46931d010 | 44 | void minutes() |
Mike951 | 1:24f46931d010 | 45 | { |
Mike951 | 1:24f46931d010 | 46 | mins ++; |
Mike951 | 1:24f46931d010 | 47 | timer.reset(); |
Mike951 | 1:24f46931d010 | 48 | } |
Mike951 | 1:24f46931d010 | 49 | |
Mike951 | 2:15134f79b400 | 50 | /* Flashing interrupt |
Mike951 | 2:15134f79b400 | 51 | Intended to be used with a timeout object to flash lights when shot or shooting |
Mike951 | 2:15134f79b400 | 52 | */ |
Mike951 | 2:15134f79b400 | 53 | void flasher() |
Mike951 | 2:15134f79b400 | 54 | { |
Mike951 | 2:15134f79b400 | 55 | LB = 0; |
Mike951 | 2:15134f79b400 | 56 | led1 = !led1; |
Mike951 | 2:15134f79b400 | 57 | led2 = !led2; |
Mike951 | 2:15134f79b400 | 58 | } |
Mike951 | 2:15134f79b400 | 59 | |
Mike951 | 4:7294c20b1025 | 60 | /*Shot Check/Reset Interrupt |
Mike951 | 4:7294c20b1025 | 61 | Intended to be called after a short period of time to start array over from the start |
Mike951 | 4:7294c20b1025 | 62 | Should keep data from being received over an excessive amount of time and thus is one |
Mike951 | 4:7294c20b1025 | 63 | method of ensuring player is actually tagged |
Mike951 | 4:7294c20b1025 | 64 | */ |
Mike951 | 4:7294c20b1025 | 65 | void shot_check() |
Mike951 | 4:7294c20b1025 | 66 | { |
Mike951 | 4:7294c20b1025 | 67 | id_pos = 0; //resets current id |
Mike951 | 4:7294c20b1025 | 68 | } |
Mike951 | 4:7294c20b1025 | 69 | |
Mike951 | 4:7294c20b1025 | 70 | /*Serial Callback interrupt |
Mike951 | 4:7294c20b1025 | 71 | Receives IR information using IR receiver |
Mike951 | 4:7294c20b1025 | 72 | If taggable = false, received data is thrown away. |
Mike951 | 4:7294c20b1025 | 73 | Otherwise, up to 15 characters are collected in a time period of 0.5 seconds |
Mike951 | 4:7294c20b1025 | 74 | If less than 15 characters received in 0.5 seconds, function array returns to first bit |
Mike951 | 4:7294c20b1025 | 75 | */ |
Mike951 | 0:69e5ee3b618d | 76 | void callback() |
Mike951 | 0:69e5ee3b618d | 77 | { |
Mike951 | 2:15134f79b400 | 78 | // Note: you need to actually read from the serial buffer to clear the RX interrupt |
Mike951 | 2:15134f79b400 | 79 | if (!taggable) |
Mike951 | 2:15134f79b400 | 80 | { |
Mike951 | 2:15134f79b400 | 81 | IR.getc(); //ensures no extra buffering left over when player is not taggable |
Mike951 | 2:15134f79b400 | 82 | return; |
Mike951 | 2:15134f79b400 | 83 | } |
Mike951 | 2:15134f79b400 | 84 | |
Mike951 | 2:15134f79b400 | 85 | id_rx[id_pos] = IR.getc(); //place received character into array |
Mike951 | 4:7294c20b1025 | 86 | /*if (id_pos == 0) //starts a timer for the time in which receiver must receive a full id |
Mike951 | 0:69e5ee3b618d | 87 | { |
Mike951 | 2:15134f79b400 | 88 | shot_time.attach(&shot_check, 0.5); |
Mike951 | 4:7294c20b1025 | 89 | }*/ |
Mike951 | 4:7294c20b1025 | 90 | if(id_pos >= 14) |
Mike951 | 0:69e5ee3b618d | 91 | { |
Mike951 | 2:15134f79b400 | 92 | id_pos = 0; //ensures no array overflows |
Mike951 | 2:15134f79b400 | 93 | shot_time.detach(); //ensures no further action upon array until next time tagged |
Mike951 | 5:6e6ab7e5074e | 94 | tagged = true; //changes tagged flag such that the main code will trigger after an ID is fully received |
Mike951 | 4:7294c20b1025 | 95 | return; |
Mike951 | 0:69e5ee3b618d | 96 | } |
Mike951 | 2:15134f79b400 | 97 | id_pos ++; //increment to next array position for id |
Mike951 | 2:15134f79b400 | 98 | return; |
Mike951 | 0:69e5ee3b618d | 99 | } |
Mike951 | 0:69e5ee3b618d | 100 | |
Mike951 | 4:7294c20b1025 | 101 | /*Button 2 Interrupt |
Mike951 | 4:7294c20b1025 | 102 | Sets button variable to true for use in code when button is pressed |
Mike951 | 4:7294c20b1025 | 103 | */ |
Mike951 | 1:24f46931d010 | 104 | void btn2Pressed() |
Mike951 | 0:69e5ee3b618d | 105 | { |
Mike951 | 0:69e5ee3b618d | 106 | led1 = !led1; |
Mike951 | 1:24f46931d010 | 107 | btn2 = true; |
Mike951 | 0:69e5ee3b618d | 108 | } |
Mike951 | 0:69e5ee3b618d | 109 | |
Mike951 | 4:7294c20b1025 | 110 | /*Button 3 Interrupt |
Mike951 | 4:7294c20b1025 | 111 | Sets button variable to true for use in code when button is pressed |
Mike951 | 4:7294c20b1025 | 112 | */ |
Mike951 | 1:24f46931d010 | 113 | void btn3Pressed() |
Mike951 | 0:69e5ee3b618d | 114 | { |
Mike951 | 0:69e5ee3b618d | 115 | led2 = !led2; |
Mike951 | 1:24f46931d010 | 116 | btn3 = true; |
Mike951 | 0:69e5ee3b618d | 117 | |
Mike951 | 0:69e5ee3b618d | 118 | } |
Mike951 | 0:69e5ee3b618d | 119 | |
Mike951 | 5:6e6ab7e5074e | 120 | /*Statistics Display Timeout |
Mike951 | 5:6e6ab7e5074e | 121 | Sets display "done" flag to true |
Mike951 | 5:6e6ab7e5074e | 122 | Intended to be used with timeout interrupt and statistics function to jump out of function |
Mike951 | 5:6e6ab7e5074e | 123 | if it has been 5 seconds. |
Mike951 | 5:6e6ab7e5074e | 124 | */ |
Mike951 | 1:24f46931d010 | 125 | void finish_disp () |
Mike951 | 0:69e5ee3b618d | 126 | { |
Mike951 | 0:69e5ee3b618d | 127 | done = true; |
Mike951 | 0:69e5ee3b618d | 128 | return; |
Mike951 | 0:69e5ee3b618d | 129 | } |
Mike951 | 0:69e5ee3b618d | 130 | |
Mike951 | 1:24f46931d010 | 131 | /*Error Routine. |
Mike951 | 1:24f46931d010 | 132 | Displays "ERROR" on LCD screen and flashes leds |
Mike951 | 5:6e6ab7e5074e | 133 | for an indefinite period of time. |
Mike951 | 1:24f46931d010 | 134 | */ |
Mike951 | 1:24f46931d010 | 135 | void error_custom () |
Mike951 | 1:24f46931d010 | 136 | { |
Mike951 | 1:24f46931d010 | 137 | lcd.cls(); |
Mike951 | 1:24f46931d010 | 138 | lcd.printf("ERROR"); |
Mike951 | 1:24f46931d010 | 139 | led1 = 0; |
Mike951 | 1:24f46931d010 | 140 | led2 = 1; |
Mike951 | 1:24f46931d010 | 141 | while(1) |
Mike951 | 1:24f46931d010 | 142 | { |
Mike951 | 1:24f46931d010 | 143 | led1 = !led1; |
Mike951 | 1:24f46931d010 | 144 | led2 = !led2; |
Mike951 | 1:24f46931d010 | 145 | wait(0.5); |
Mike951 | 1:24f46931d010 | 146 | } |
Mike951 | 1:24f46931d010 | 147 | } |
Mike951 | 1:24f46931d010 | 148 | /*Alphanumeric selector |
Mike951 | 1:24f46931d010 | 149 | Used with char_sel function in order to select a number 0-9 or letters A-Z through user input. |
Mike951 | 1:24f46931d010 | 150 | Returns a char. |
Mike951 | 1:24f46931d010 | 151 | */ |
Mike951 | 1:24f46931d010 | 152 | char alpha_num_sel (bool number) |
Mike951 | 1:24f46931d010 | 153 | { |
Mike951 | 1:24f46931d010 | 154 | char n0 = '0'; |
Mike951 | 1:24f46931d010 | 155 | char n_tmp = '0'; |
Mike951 | 1:24f46931d010 | 156 | unsigned incr = 0; //used to increment characters between 0-9 or A-Z |
Mike951 | 1:24f46931d010 | 157 | unsigned mod; |
Mike951 | 1:24f46931d010 | 158 | if (number) |
Mike951 | 1:24f46931d010 | 159 | { |
Mike951 | 1:24f46931d010 | 160 | lcd.cls(); |
Mike951 | 1:24f46931d010 | 161 | lcd.printf("Pick\nNumber:%c",n_tmp); |
Mike951 | 1:24f46931d010 | 162 | n0 = '0'; |
Mike951 | 1:24f46931d010 | 163 | n_tmp = n0; |
Mike951 | 2:15134f79b400 | 164 | mod = 11; //modulus for character range |
Mike951 | 1:24f46931d010 | 165 | } |
Mike951 | 1:24f46931d010 | 166 | else |
Mike951 | 1:24f46931d010 | 167 | { |
Mike951 | 1:24f46931d010 | 168 | lcd.cls(); |
Mike951 | 1:24f46931d010 | 169 | n0 = 'A'; |
Mike951 | 1:24f46931d010 | 170 | n_tmp = n0; |
Mike951 | 1:24f46931d010 | 171 | lcd.printf("Pick\nLetter:%c",n_tmp); |
Mike951 | 1:24f46931d010 | 172 | mod = 26; |
Mike951 | 1:24f46931d010 | 173 | } |
Mike951 | 1:24f46931d010 | 174 | while(1) |
Mike951 | 1:24f46931d010 | 175 | { |
Mike951 | 1:24f46931d010 | 176 | while(!btn2 && !btn3) //waits until button input received |
Mike951 | 1:24f46931d010 | 177 | { |
Mike951 | 1:24f46931d010 | 178 | wait(0.05); |
Mike951 | 1:24f46931d010 | 179 | } |
Mike951 | 1:24f46931d010 | 180 | if(btn3) |
Mike951 | 1:24f46931d010 | 181 | { |
Mike951 | 1:24f46931d010 | 182 | btn3 = false; |
Mike951 | 1:24f46931d010 | 183 | btn2 = false; //if both butons pressed, it just selects the current character |
Mike951 | 1:24f46931d010 | 184 | return (n_tmp); |
Mike951 | 1:24f46931d010 | 185 | } |
Mike951 | 1:24f46931d010 | 186 | else if(btn2) |
Mike951 | 1:24f46931d010 | 187 | { |
Mike951 | 1:24f46931d010 | 188 | btn2 = false; |
Mike951 | 1:24f46931d010 | 189 | incr ++; |
Mike951 | 2:15134f79b400 | 190 | incr = incr % mod; //ensures that numbers stay within the 0-9/A-Z range |
Mike951 | 2:15134f79b400 | 191 | n_tmp = n0 + incr; //increment current character selected |
Mike951 | 2:15134f79b400 | 192 | if (incr == 10 && number) //feature addition to allow for space entry |
Mike951 | 2:15134f79b400 | 193 | { |
Mike951 | 2:15134f79b400 | 194 | n_tmp = ' '; |
Mike951 | 2:15134f79b400 | 195 | } |
Mike951 | 1:24f46931d010 | 196 | lcd.cls(); |
Mike951 | 1:24f46931d010 | 197 | if(number) |
Mike951 | 1:24f46931d010 | 198 | { |
Mike951 | 1:24f46931d010 | 199 | lcd.printf("Pick\nNumber:%c",n_tmp); //displays current number |
Mike951 | 1:24f46931d010 | 200 | } |
Mike951 | 1:24f46931d010 | 201 | else |
Mike951 | 1:24f46931d010 | 202 | { |
Mike951 | 1:24f46931d010 | 203 | lcd.printf("Pick\nLetter:%c",n_tmp); //displays current letter |
Mike951 | 1:24f46931d010 | 204 | } |
Mike951 | 1:24f46931d010 | 205 | } |
Mike951 | 1:24f46931d010 | 206 | else |
Mike951 | 1:24f46931d010 | 207 | { |
Mike951 | 1:24f46931d010 | 208 | error_custom(); |
Mike951 | 1:24f46931d010 | 209 | } |
Mike951 | 1:24f46931d010 | 210 | |
Mike951 | 1:24f46931d010 | 211 | } |
Mike951 | 1:24f46931d010 | 212 | } |
Mike951 | 5:6e6ab7e5074e | 213 | |
Mike951 | 1:24f46931d010 | 214 | /*Character Selection |
Mike951 | 1:24f46931d010 | 215 | Used with setup() function in order to pick a character A-Z and number 0-9 |
Mike951 | 1:24f46931d010 | 216 | for use as part of user id and/or team. Passed a 0 if selecting team letter (A-Z), |
Mike951 | 1:24f46931d010 | 217 | otherwise will select player id letter |
Mike951 | 1:24f46931d010 | 218 | */ |
Mike951 | 1:24f46931d010 | 219 | char char_sel (bool player) |
Mike951 | 1:24f46931d010 | 220 | { |
Mike951 | 1:24f46931d010 | 221 | if (player) |
Mike951 | 1:24f46931d010 | 222 | { |
Mike951 | 1:24f46931d010 | 223 | lcd.cls(); |
Mike951 | 1:24f46931d010 | 224 | lcd.printf("A-Z? or\n0-9?"); |
Mike951 | 1:24f46931d010 | 225 | while(!btn2 && !btn3) //waits until button input received |
Mike951 | 1:24f46931d010 | 226 | { |
Mike951 | 1:24f46931d010 | 227 | wait(0.05); |
Mike951 | 1:24f46931d010 | 228 | } |
Mike951 | 1:24f46931d010 | 229 | if(btn2) //if select button pressed, goes through numerical selection |
Mike951 | 1:24f46931d010 | 230 | { |
Mike951 | 1:24f46931d010 | 231 | btn2 = false; |
Mike951 | 1:24f46931d010 | 232 | btn3 = false; //if both buttons pressed at the same time, it just does numerical selection |
Mike951 | 1:24f46931d010 | 233 | |
Mike951 | 1:24f46931d010 | 234 | return(alpha_num_sel(1)); |
Mike951 | 1:24f46931d010 | 235 | } |
Mike951 | 1:24f46931d010 | 236 | else if(btn3) |
Mike951 | 1:24f46931d010 | 237 | { |
Mike951 | 1:24f46931d010 | 238 | btn3 = false; //pressing the option button in this case is the same as selecting a team |
Mike951 | 1:24f46931d010 | 239 | } |
Mike951 | 1:24f46931d010 | 240 | else |
Mike951 | 1:24f46931d010 | 241 | { |
Mike951 | 1:24f46931d010 | 242 | error_custom(); //if you somehow make it here without pressing buttons, it will throw an error |
Mike951 | 1:24f46931d010 | 243 | } |
Mike951 | 1:24f46931d010 | 244 | } |
Mike951 | 1:24f46931d010 | 245 | return(alpha_num_sel(0)); //returns capital alpha character for id or team by calling selection function |
Mike951 | 1:24f46931d010 | 246 | } |
Mike951 | 1:24f46931d010 | 247 | |
Mike951 | 1:24f46931d010 | 248 | |
Mike951 | 1:24f46931d010 | 249 | /*Setup Routine. |
Mike951 | 1:24f46931d010 | 250 | Sets the user id for use in-game. |
Mike951 | 1:24f46931d010 | 251 | Function must be passed an array of characters of size 15 |
Mike951 | 1:24f46931d010 | 252 | in order to work correctly. |
Mike951 | 1:24f46931d010 | 253 | */ |
Mike951 | 1:24f46931d010 | 254 | void setup (char* ID_array) |
Mike951 | 1:24f46931d010 | 255 | { |
Mike951 | 1:24f46931d010 | 256 | unsigned size = 1; |
Mike951 | 1:24f46931d010 | 257 | |
Mike951 | 1:24f46931d010 | 258 | lcd.cls(); |
Mike951 | 1:24f46931d010 | 259 | lcd.printf("ID Size?\n%u",size); |
Mike951 | 4:7294c20b1025 | 260 | |
Mike951 | 1:24f46931d010 | 261 | while(1) |
Mike951 | 1:24f46931d010 | 262 | { |
Mike951 | 1:24f46931d010 | 263 | while(!btn2 && !btn3) //waits until button input received |
Mike951 | 1:24f46931d010 | 264 | { |
Mike951 | 1:24f46931d010 | 265 | wait(0.05); //ensures buttons cannot be pressed extremely fast |
Mike951 | 1:24f46931d010 | 266 | } |
Mike951 | 1:24f46931d010 | 267 | if(btn2 && btn3) //routine to set size of player id in bytes |
Mike951 | 1:24f46931d010 | 268 | { |
Mike951 | 1:24f46931d010 | 269 | btn2 = false; //handling for simultaneous button pressing |
Mike951 | 1:24f46931d010 | 270 | btn3 = false; |
Mike951 | 1:24f46931d010 | 271 | size++; |
Mike951 | 1:24f46931d010 | 272 | if (size > 12) |
Mike951 | 1:24f46931d010 | 273 | { |
Mike951 | 1:24f46931d010 | 274 | size = 1; //ensures size cannot be greater than 12 or less than 1 |
Mike951 | 1:24f46931d010 | 275 | } |
Mike951 | 1:24f46931d010 | 276 | break; //sets size to whatever current size is +1 and moves on |
Mike951 | 1:24f46931d010 | 277 | } |
Mike951 | 1:24f46931d010 | 278 | else if(btn2) //increases size or loops back to 1, displays current size |
Mike951 | 1:24f46931d010 | 279 | { |
Mike951 | 1:24f46931d010 | 280 | btn2 = false; |
Mike951 | 1:24f46931d010 | 281 | size++; |
Mike951 | 1:24f46931d010 | 282 | if (size > 12) |
Mike951 | 1:24f46931d010 | 283 | { |
Mike951 | 1:24f46931d010 | 284 | size = 1; //ensures size cannot be greater than 12 or less than 1 |
Mike951 | 1:24f46931d010 | 285 | } |
Mike951 | 1:24f46931d010 | 286 | lcd.cls(); |
Mike951 | 1:24f46931d010 | 287 | lcd.printf("ID Size?\n%u",size); //displays current size |
Mike951 | 1:24f46931d010 | 288 | } |
Mike951 | 1:24f46931d010 | 289 | else if(btn3) |
Mike951 | 1:24f46931d010 | 290 | { |
Mike951 | 1:24f46931d010 | 291 | btn3 = false; //selects current size |
Mike951 | 1:24f46931d010 | 292 | break; |
Mike951 | 1:24f46931d010 | 293 | } |
Mike951 | 1:24f46931d010 | 294 | else |
Mike951 | 1:24f46931d010 | 295 | { |
Mike951 | 1:24f46931d010 | 296 | error_custom(); //error called if unexpected output |
Mike951 | 1:24f46931d010 | 297 | } |
Mike951 | 1:24f46931d010 | 298 | } |
Mike951 | 1:24f46931d010 | 299 | |
Mike951 | 1:24f46931d010 | 300 | for (unsigned j = 0; j < size; j ++) //sets player id |
Mike951 | 1:24f46931d010 | 301 | { |
Mike951 | 1:24f46931d010 | 302 | ID_array[j] = char_sel(1); |
Mike951 | 1:24f46931d010 | 303 | } |
Mike951 | 1:24f46931d010 | 304 | for (unsigned j = size; j < 12; j ++) |
Mike951 | 1:24f46931d010 | 305 | { |
Mike951 | 1:24f46931d010 | 306 | ID_array[j] = ' '; //fill unused characters with spaces |
Mike951 | 1:24f46931d010 | 307 | } |
Mike951 | 4:7294c20b1025 | 308 | |
Mike951 | 1:24f46931d010 | 309 | lcd.cls(); |
Mike951 | 1:24f46931d010 | 310 | lcd.printf("On team?\n Y or N"); |
Mike951 | 4:7294c20b1025 | 311 | |
Mike951 | 1:24f46931d010 | 312 | while(!btn2 && !btn3) //waits until button input received |
Mike951 | 1:24f46931d010 | 313 | { |
Mike951 | 1:24f46931d010 | 314 | wait(0.05); //ensures buttons cannot be pressed extremely fast |
Mike951 | 1:24f46931d010 | 315 | } |
Mike951 | 1:24f46931d010 | 316 | if(btn3) |
Mike951 | 1:24f46931d010 | 317 | { |
Mike951 | 1:24f46931d010 | 318 | btn3 = false; |
Mike951 | 1:24f46931d010 | 319 | btn2 = false; //you're on a team if you press both buttons |
Mike951 | 1:24f46931d010 | 320 | ID_array[12] = char_sel(0); //sets team letter |
Mike951 | 1:24f46931d010 | 321 | } |
Mike951 | 1:24f46931d010 | 322 | else if (btn2) |
Mike951 | 1:24f46931d010 | 323 | { |
Mike951 | 1:24f46931d010 | 324 | btn2 = false; |
Mike951 | 1:24f46931d010 | 325 | ID_array[12] = '0'; //sets team to 'zero', indicating no team |
Mike951 | 1:24f46931d010 | 326 | } |
Mike951 | 1:24f46931d010 | 327 | else |
Mike951 | 1:24f46931d010 | 328 | { |
Mike951 | 1:24f46931d010 | 329 | error_custom(); //throws an error if you somehow get here) |
Mike951 | 1:24f46931d010 | 330 | } |
Mike951 | 4:7294c20b1025 | 331 | |
Mike951 | 1:24f46931d010 | 332 | lcd.cls(); |
Mike951 | 1:24f46931d010 | 333 | lcd.printf("Your ID\n is:"); |
Mike951 | 4:7294c20b1025 | 334 | wait(1); |
Mike951 | 1:24f46931d010 | 335 | lcd.cls(); |
Mike951 | 1:24f46931d010 | 336 | for(unsigned j = 0; j <= 12; j++) //prints out player id and team |
Mike951 | 1:24f46931d010 | 337 | { |
Mike951 | 1:24f46931d010 | 338 | lcd.printf("%c",ID_array[j]); |
Mike951 | 1:24f46931d010 | 339 | if (j == 7) |
Mike951 | 1:24f46931d010 | 340 | { |
Mike951 | 4:7294c20b1025 | 341 | lcd.printf("\n"); //puts in a new line after eight characters |
Mike951 | 1:24f46931d010 | 342 | } |
Mike951 | 1:24f46931d010 | 343 | } |
Mike951 | 1:24f46931d010 | 344 | crc16_attach(ID_array,13); //attaches crc bits to last two bits of 15 character array |
Mike951 | 3:752f5f63f783 | 345 | wait(3); |
Mike951 | 1:24f46931d010 | 346 | return; |
Mike951 | 1:24f46931d010 | 347 | } |
Mike951 | 1:24f46931d010 | 348 | |
Mike951 | 2:15134f79b400 | 349 | /*ID Checking Routine |
Mike951 | 2:15134f79b400 | 350 | Checks received IDs to see if it is a valid shot |
Mike951 | 2:15134f79b400 | 351 | player_array is the 15 character id array of the player that constains a 16-bit crc in the last two bytes |
Mike951 | 2:15134f79b400 | 352 | Returns a boolean true if shot is valid, otherwise false |
Mike951 | 2:15134f79b400 | 353 | */ |
Mike951 | 2:15134f79b400 | 354 | bool check_id(char* player_array) |
Mike951 | 2:15134f79b400 | 355 | { |
Mike951 | 4:7294c20b1025 | 356 | if (id_rx[12] == player_array[12] && id_rx[12] >= 'A') |
Mike951 | 2:15134f79b400 | 357 | { |
Mike951 | 2:15134f79b400 | 358 | return false; //if ids are on the same team or are the same person, they cannot be hit by each other/themselves |
Mike951 | 2:15134f79b400 | 359 | } |
Mike951 | 4:7294c20b1025 | 360 | else if(id_rx[13] == player_array[13] && id_rx[14] == player_array[14]) |
Mike951 | 4:7294c20b1025 | 361 | { |
Mike951 | 4:7294c20b1025 | 362 | return false; |
Mike951 | 4:7294c20b1025 | 363 | } |
Mike951 | 2:15134f79b400 | 364 | return (crc16_match(id_rx, 13)); //compares the crc tag in received id to a calculated one. Returns false if different. |
Mike951 | 2:15134f79b400 | 365 | } |
Mike951 | 2:15134f79b400 | 366 | |
Mike951 | 4:7294c20b1025 | 367 | /*Respawn Display |
Mike951 | 4:7294c20b1025 | 368 | Displays appropriate information for who player was hit by while they are "respawning" |
Mike951 | 4:7294c20b1025 | 369 | Returns nothing |
Mike951 | 4:7294c20b1025 | 370 | */ |
Mike951 | 2:15134f79b400 | 371 | void respawn() |
Mike951 | 2:15134f79b400 | 372 | { |
Mike951 | 2:15134f79b400 | 373 | lcd.cls(); |
Mike951 | 2:15134f79b400 | 374 | lcd.printf("Hit by:"); |
Mike951 | 4:7294c20b1025 | 375 | wait(1); |
Mike951 | 2:15134f79b400 | 376 | lcd.cls(); |
Mike951 | 2:15134f79b400 | 377 | for(unsigned j = 0; j <= 12; j++) //prints out id and team of person who tagged player |
Mike951 | 2:15134f79b400 | 378 | { |
Mike951 | 2:15134f79b400 | 379 | lcd.printf("%c",id_rx[j]); |
Mike951 | 2:15134f79b400 | 380 | if (j == 7) |
Mike951 | 2:15134f79b400 | 381 | { |
Mike951 | 4:7294c20b1025 | 382 | lcd.printf("\n"); //puts in a new line after eight characters |
Mike951 | 2:15134f79b400 | 383 | } |
Mike951 | 2:15134f79b400 | 384 | } |
Mike951 | 4:7294c20b1025 | 385 | wait(4); |
Mike951 | 2:15134f79b400 | 386 | } |
Mike951 | 4:7294c20b1025 | 387 | /*Firing function |
Mike951 | 4:7294c20b1025 | 388 | Sends ID information through IR |
Mike951 | 4:7294c20b1025 | 389 | Parameters: player_id |
Mike951 | 4:7294c20b1025 | 390 | player_id = 15 character array that contains player id and crc hash |
Mike951 | 4:7294c20b1025 | 391 | returns nothing |
Mike951 | 4:7294c20b1025 | 392 | */ |
Mike951 | 2:15134f79b400 | 393 | void fire(char* player_id) |
Mike951 | 2:15134f79b400 | 394 | { |
Mike951 | 4:7294c20b1025 | 395 | for (unsigned i = 0; i < 15; i ++) |
Mike951 | 3:752f5f63f783 | 396 | { |
Mike951 | 4:7294c20b1025 | 397 | IR.putc(player_id[i]); |
Mike951 | 3:752f5f63f783 | 398 | } |
Mike951 | 3:752f5f63f783 | 399 | } |
Mike951 | 3:752f5f63f783 | 400 | |
Mike951 | 3:752f5f63f783 | 401 | /*Statistics Display Function |
Mike951 | 3:752f5f63f783 | 402 | Displays game statistics without interrupting gameplay significantly |
Mike951 | 3:752f5f63f783 | 403 | Requires LCD to be on. |
Mike951 | 3:752f5f63f783 | 404 | Function will end if fire button is pressed or 5 seconds have passed |
Mike951 | 3:752f5f63f783 | 405 | without the statistics button (btn2) being pressed again. |
Mike951 | 3:752f5f63f783 | 406 | Maximum amount of time possible in this function is 15 seconds, |
Mike951 | 3:752f5f63f783 | 407 | 5 seconds for each of the 3 statistics displays |
Mike951 | 3:752f5f63f783 | 408 | Parameters: tag_count = number of times player has been tagged |
Mike951 | 3:752f5f63f783 | 409 | shots = number of times player has shot |
Mike951 | 3:752f5f63f783 | 410 | mode = level of statistics looking at: tag count(0), shots(1), or time since reset(2) |
Mike951 | 3:752f5f63f783 | 411 | Returns nothing |
Mike951 | 3:752f5f63f783 | 412 | */ |
Mike951 | 3:752f5f63f783 | 413 | void statistics(const unsigned &tag_count, const unsigned &shots, short mode) |
Mike951 | 3:752f5f63f783 | 414 | { |
Mike951 | 3:752f5f63f783 | 415 | done = false; //Used to timeout on statistics display |
Mike951 | 3:752f5f63f783 | 416 | lcd.cls(); |
Mike951 | 3:752f5f63f783 | 417 | if(mode == 0) |
Mike951 | 3:752f5f63f783 | 418 | { |
Mike951 | 3:752f5f63f783 | 419 | lcd.printf("Tagged:\n%u",tag_count); |
Mike951 | 3:752f5f63f783 | 420 | } |
Mike951 | 3:752f5f63f783 | 421 | else if(mode == 1) |
Mike951 | 3:752f5f63f783 | 422 | { |
Mike951 | 3:752f5f63f783 | 423 | lcd.printf("# Shots:\n%u",shots); //shot count |
Mike951 | 3:752f5f63f783 | 424 | } |
Mike951 | 3:752f5f63f783 | 425 | else if(mode == 2) |
Mike951 | 3:752f5f63f783 | 426 | { |
Mike951 | 3:752f5f63f783 | 427 | unsigned secs = 0; //used to readout numer of seconds on timer |
Mike951 | 3:752f5f63f783 | 428 | secs = timer.read(); |
Mike951 | 3:752f5f63f783 | 429 | lcd.printf("Mins:%u\nSecs:%u", mins,secs); |
Mike951 | 3:752f5f63f783 | 430 | } |
Mike951 | 3:752f5f63f783 | 431 | else |
Mike951 | 3:752f5f63f783 | 432 | { |
Mike951 | 3:752f5f63f783 | 433 | led1 = 1; |
Mike951 | 3:752f5f63f783 | 434 | led2 = 1; |
Mike951 | 3:752f5f63f783 | 435 | return; //if no valid mode, the function will end. Used to end recursion |
Mike951 | 3:752f5f63f783 | 436 | } |
Mike951 | 3:752f5f63f783 | 437 | stats.attach(&finish_disp, 5); |
Mike951 | 3:752f5f63f783 | 438 | while(!done) |
Mike951 | 3:752f5f63f783 | 439 | { |
Mike951 | 4:7294c20b1025 | 440 | if(btn3 == true || tagged) |
Mike951 | 3:752f5f63f783 | 441 | { |
Mike951 | 3:752f5f63f783 | 442 | stats.detach(); //exit if something interrupts stats |
Mike951 | 3:752f5f63f783 | 443 | lcd.cls(); |
Mike951 | 3:752f5f63f783 | 444 | return; |
Mike951 | 3:752f5f63f783 | 445 | } |
Mike951 | 3:752f5f63f783 | 446 | else if(btn2 == true) |
Mike951 | 3:752f5f63f783 | 447 | { |
Mike951 | 3:752f5f63f783 | 448 | btn2 = false; |
Mike951 | 3:752f5f63f783 | 449 | stats.detach(); //keeps statistics display from timing out for another 5 seconds |
Mike951 | 3:752f5f63f783 | 450 | mode ++; |
Mike951 | 3:752f5f63f783 | 451 | statistics(tag_count,shots,mode); //recursive function call of statistics |
Mike951 | 3:752f5f63f783 | 452 | return; //jumps out of function whenever other forms return |
Mike951 | 3:752f5f63f783 | 453 | } |
Mike951 | 3:752f5f63f783 | 454 | wait(0.05); //function will get stuck without short wait |
Mike951 | 3:752f5f63f783 | 455 | } |
Mike951 | 3:752f5f63f783 | 456 | return; |
Mike951 | 3:752f5f63f783 | 457 | } |
Mike951 | 2:15134f79b400 | 458 | |
Mike951 | 0:69e5ee3b618d | 459 | int main() |
Mike951 | 0:69e5ee3b618d | 460 | { |
Mike951 | 0:69e5ee3b618d | 461 | Square_Gen.period_us(26); //produces a 38kHz square wave to ensure proper IR communication... |
Mike951 | 0:69e5ee3b618d | 462 | Square_Gen.pulsewidth_us(13); //...this signal is sent to one of the IR diode terminals through a transistor |
Mike951 | 4:7294c20b1025 | 463 | IR.baud(1200); //sets baud rate of serial output and input |
Mike951 | 4:7294c20b1025 | 464 | IR.attach(&callback); //attaches interrupt for serial buffer |
Mike951 | 0:69e5ee3b618d | 465 | LB = 1; //turn on lcd backlight |
Mike951 | 0:69e5ee3b618d | 466 | LP = 1; //turn on lcd power |
Mike951 | 0:69e5ee3b618d | 467 | sw2.mode(PullUp); //set buttons to a default high voltage for logic low |
Mike951 | 0:69e5ee3b618d | 468 | sw3.mode(PullUp); |
Mike951 | 0:69e5ee3b618d | 469 | sw2.setSampleFrequency(); //set buttons to default sample frequency for debouncing |
Mike951 | 0:69e5ee3b618d | 470 | sw3.setSampleFrequency(); |
Mike951 | 0:69e5ee3b618d | 471 | sw2.setAssertValue(0); //set buttons to be logic high when voltage is low. |
Mike951 | 0:69e5ee3b618d | 472 | sw3.setAssertValue(0); |
Mike951 | 1:24f46931d010 | 473 | sw2.attach_asserted( &btn2Pressed ); //attach button interrupts |
Mike951 | 1:24f46931d010 | 474 | sw3.attach_asserted( &btn3Pressed ); |
Mike951 | 1:24f46931d010 | 475 | clock_tick.attach(&minutes, 60); //ticker interrupts every 60 seconds to add 1 minute and reset timer |
Mike951 | 1:24f46931d010 | 476 | timer.reset(); //ensure timer starts at 0 |
Mike951 | 1:24f46931d010 | 477 | timer.start(); //start reset timer |
Mike951 | 0:69e5ee3b618d | 478 | |
Mike951 | 0:69e5ee3b618d | 479 | led1 = 1; |
Mike951 | 1:24f46931d010 | 480 | char id[15]; //id array, capable of storing user ids up to 12 bytes with 1 byte for team and 2 bytes for CRC. |
Mike951 | 2:15134f79b400 | 481 | unsigned tag_count = 0; //number of times player has been tagged in a game |
Mike951 | 2:15134f79b400 | 482 | unsigned shots = 0; //number of shots fired in a game. |
Mike951 | 1:24f46931d010 | 483 | lcd.cls(); //ensure lcd starts with clear screen |
Mike951 | 1:24f46931d010 | 484 | lcd.printf("Choose \nYour ID."); |
Mike951 | 1:24f46931d010 | 485 | while(btn2 == false && btn3 == false) |
Mike951 | 1:24f46931d010 | 486 | { |
Mike951 | 2:15134f79b400 | 487 | wait(0.2); //wait to start setup until either button is pressed |
Mike951 | 1:24f46931d010 | 488 | } |
Mike951 | 1:24f46931d010 | 489 | btn2 = false; //reset button values |
Mike951 | 1:24f46931d010 | 490 | btn3 = false; |
Mike951 | 1:24f46931d010 | 491 | setup(id); //setup player id and team, passing function the id array |
Mike951 | 2:15134f79b400 | 492 | taggable = true; |
Mike951 | 4:7294c20b1025 | 493 | LB = 0; //turn off lcd screen, backlight, and leds to save power during game |
Mike951 | 3:752f5f63f783 | 494 | LP = 0; |
Mike951 | 4:7294c20b1025 | 495 | led1 = 0; |
Mike951 | 4:7294c20b1025 | 496 | led2 = 0; |
Mike951 | 0:69e5ee3b618d | 497 | while(1) |
Mike951 | 3:752f5f63f783 | 498 | { |
Mike951 | 4:7294c20b1025 | 499 | if(tagged) |
Mike951 | 0:69e5ee3b618d | 500 | { |
Mike951 | 3:752f5f63f783 | 501 | flash.attach(&flasher,0.5); |
Mike951 | 4:7294c20b1025 | 502 | tagged = false; |
Mike951 | 4:7294c20b1025 | 503 | //LB = 1; //turn on backlight and leds for flash |
Mike951 | 3:752f5f63f783 | 504 | led1 = 1; |
Mike951 | 3:752f5f63f783 | 505 | led2 = 1; |
Mike951 | 3:752f5f63f783 | 506 | if (check_id(id)) |
Mike951 | 2:15134f79b400 | 507 | { |
Mike951 | 4:7294c20b1025 | 508 | taggable = false; //don't allow new tags if respawning |
Mike951 | 3:752f5f63f783 | 509 | flash.detach(); //if tag is valid, no need to flash |
Mike951 | 3:752f5f63f783 | 510 | tag_count ++; |
Mike951 | 3:752f5f63f783 | 511 | LP = 1; //turn LCD power and backlight on |
Mike951 | 2:15134f79b400 | 512 | LB = 1; |
Mike951 | 3:752f5f63f783 | 513 | respawn(); //prints appropriate respawn info |
Mike951 | 4:7294c20b1025 | 514 | taggable = true; |
Mike951 | 4:7294c20b1025 | 515 | led2 = 0; |
Mike951 | 2:15134f79b400 | 516 | } |
Mike951 | 4:7294c20b1025 | 517 | LB = 0; //turn LCD backlight and power back off |
Mike951 | 4:7294c20b1025 | 518 | LP = 0; |
Mike951 | 4:7294c20b1025 | 519 | led1 = 0; |
Mike951 | 0:69e5ee3b618d | 520 | } |
Mike951 | 3:752f5f63f783 | 521 | if(btn3) //fires IR led if btn3 is pressed |
Mike951 | 3:752f5f63f783 | 522 | { |
Mike951 | 3:752f5f63f783 | 523 | btn3 = false; |
Mike951 | 3:752f5f63f783 | 524 | flash.detach(); //lights will not flash if you fire really fast |
Mike951 | 3:752f5f63f783 | 525 | shots ++; //increment number of times ir has been shot by player |
Mike951 | 3:752f5f63f783 | 526 | LB = 1; |
Mike951 | 3:752f5f63f783 | 527 | led1 = 1; |
Mike951 | 3:752f5f63f783 | 528 | led2 = 1; |
Mike951 | 3:752f5f63f783 | 529 | flash.attach(flasher,0.5); //flashes backlight and leds when firing |
Mike951 | 3:752f5f63f783 | 530 | fire(id); //fires player id using IR diode |
Mike951 | 3:752f5f63f783 | 531 | } |
Mike951 | 4:7294c20b1025 | 532 | if (btn2) //displays statistics if btn2 is pressed |
Mike951 | 3:752f5f63f783 | 533 | { |
Mike951 | 4:7294c20b1025 | 534 | flash.detach(); |
Mike951 | 3:752f5f63f783 | 535 | btn2 = false; |
Mike951 | 3:752f5f63f783 | 536 | LP = 1; //turn on display |
Mike951 | 3:752f5f63f783 | 537 | LB = 1; |
Mike951 | 3:752f5f63f783 | 538 | statistics(tag_count,shots,0); |
Mike951 | 3:752f5f63f783 | 539 | LP = 0; |
Mike951 | 3:752f5f63f783 | 540 | LB = 0; |
Mike951 | 3:752f5f63f783 | 541 | } |
Mike951 | 3:752f5f63f783 | 542 | wait(0.01); |
Mike951 | 3:752f5f63f783 | 543 | } |
Mike951 | 5:6e6ab7e5074e | 544 | } |