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