Components and supplies
1
Arduino Micro
1
piezo speaker
2
16x2 LCD display with I²C interface
1
Copper Stripboard
1
Plastic container
2
AZDelivery IR module i2c
Tools and machines
1
Soldering kit
Apps and platforms
1
Arduino IDE 2.0 (beta)
Project description
Code
LapCounter
cpp
Some comments are in italian.
1/*Version 20230817 2 assegnazione dei PIN su A-Micro 3 Arduino ----7--9 4 pista ---tr1-tr2 5 Configurazione Display LCD 16x2 6 */ 7 8// include la libreria: 9#include<Wire.h> 10#include <LiquidCrystal_I2C.h> 11LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display 12LiquidCrystal_I2C lcd2(0x26,16,2); // set the LCD address to 0x26 for a 16 chars and 2 line display 13#define TONE_USE_INT 14#define TONE_PITCH 440 15#include <TonePitch.h> 16// -------mappatura dei pin e stato contatti 17int audio=6; 18const byte trk1 = 7; //IR attached to this pin //pin per l'interruttore sensore dei lap sulla corsia 1 19const byte trk2 = 9; //IR attached to this pin //pin per l'interruttore sensore dei lap sulla corsia 2 20int trk1State = 0; //this variable tracks the state of IR, 21int trk2State = 0; //this variable tracks the state of IR, 22bool checkIR1 = true; //variable used to verify if an obstacle remain under IR1 23bool checkIR2 = true; //variable used to verify if an obstacle remain under IR1 24bool firstCKPT = false; //variable used in the two lane loop to be sure that the player doesn't miss a ring 25bool secondCKPT= false; //variable used in the two lane loop to be sure that the player doesn't miss a ring 26//----variabili per menu----- 27//----Menu percorso 28int tipoPercorso=0; 29int scegliPercorso=1; 30int c1a=0; int c2a=6; int c3a=12; //cursor position in the display in the track menu 31//----Menu gara---- 32int tipoGara=0; 33int scegliGara=1; 34int c1b=0; int c2b=11; //cursor position in the display in the race menu 35//---Gara a Giri--- 36int totLap = 5; //default value for LAP race 37int trk1Lap = 0; 38int trk2Lap = 0; 39int lap0tr1 = 0; 40int lap0tr2 = 0; 41int menuGiri=1; 42int c1c=0; int c2c=4; int c3c=11; //cursor position in the display in the lap menu 43//---Gara a Tempo--- 44long timeRace = 1; //default value for timerace in minutes 45long timeRaceMillis; //timerace in millis 46long timeStart; //time when the race start 47long timeNow; 48long timeRemain; // =timeEnd-timeStart-timeNow-timeStart 49long timeEnd;//time the race will end timeStart + timeRace 50long timePassed; 51int menuTempo=1; 52//---altre variabili--- 53int winnerState =0; 54unsigned long lastDebounceTime1 = 0; // the last time the output pin was toggled 55unsigned long lastDebounceTime2 = 0; // the last time the output pin was toggled 56unsigned long trk1mill = 0; // millis for trk1 57unsigned long trk2mill = 0; // millis for trk2 58unsigned long debounceDelay = 2500; // the debounce time in millis; increase if the output flickers //tempo dell'anti-rimbalzo - da regolare 59long mm1,ss1,dec1; //minutes seconds and dec for Player 1 60long mm2,ss2,dec2; //minutes seconds and dec for Player 2 61long mm,ss,dec; //variabili per gli orologi 62String minut1,secondi1,deci1; 63String minut2,secondi2,deci2; 64String tpminut; 65String tpsecondi; 66String tpdeci; 67unsigned long trk1LapTime,trk1BestLapTime,trk1EndLapTime,trk1StartLapTime; 68unsigned long trk2LapTime,trk2BestLapTime,trk2EndLapTime,trk2StartLapTime; 69String testoP1; 70String testoP2; 71 72//----------------------SETUP---------------------------- 73void setup() { 74 pinMode(trk1,INPUT); 75 pinMode(trk2,INPUT); 76 lcd.init();lcd2.init(); //initialize the lcd 77 lcd.backlight(); lcd2.backlight();//turn on the LCD backlight 78 lcd.clear();lcd2.clear(); //clear the LCD screens and positions the cursor in the upper-left corner 79 lcd2.home();lcd2.print("LANE 1 MOVE");lcd2.setCursor(0,1);lcd2.print("LANE 2 SELECT");startSound(); //use the IR to manage the cursor 80 //-----routine per scegliere il tracciato------ 81 scegliTracciato(); //go to the routine to chose the track 82 scegliCorsa(); //go to the routine to chose time or lap race 83 84 //from here the START procedure 85 86 lcd.clear();lcd2.clear(); //pulisco lo schermo 87 lcd.home();lcd.print("PRENDI POSIZIONE");//be ready ! 88 lcd2.home();lcd2.print("PRENDI POSIZIONE");//be ready ! 89 delay(10000); 90 lcd.home();lcd.print(" SEMAFORO "); 91 lcd2.home();lcd2.print(" SEMAFORO "); 92 delay(3000); 93 //Richiama la routine semaforo 94 semaforo(); 95 lcd.setCursor(0,0);lcd.print("P1L: --:--"); 96 lcd.setCursor(0,1);lcd.print(" best:--:--:--"); 97 98 lcd2.setCursor(0,0);lcd2.print("P2L: --:--"); 99 lcd2.setCursor(0,1);lcd2.print(" best:--:--:--"); 100 checkIR1 = false; 101 checkIR2 = false; 102 timeStart=millis();//last row of setup 103 trk1StartLapTime=timeStart; 104 trk2StartLapTime=timeStart; 105} 106//-------------------------END SETUP----------------------------------- 107//-------------------------INIZIO LOOP----------------------------------- 108void loop() { 109 // Campiona lo stato dei pulsanti - premuti o non premuti? 110 trk1State = digitalRead(trk1); 111 trk2State = digitalRead(trk2); 112 113 switch (scegliPercorso) { // Sposta il cursore 114 case 1: 115 if (tipoGara == 1) { 116 garaAGiri(); // Gara a giri per 2 giocatori su 2 corsie 117 } 118 if (tipoGara == 2) { 119 garaATempo(); // Gara a tempo per 2 giocatori su 2 corsie 120 } 121 break; 122 case 2: 123 if (tipoGara == 1) { 124 garaAGiri(); // Gara a giri per 1 giocatore in un percorso ad anello 125 } 126 if (tipoGara == 2) { 127 garaATempo(); // Gara a tempo per 1 giocatore in un percorso ad anello 128 } 129 break; 130 case 3: 131 if (tipoGara == 1) { 132 loopDoppioGiri(); // Percorso incrociato a giri per 1 giocatore 133 } 134 if (tipoGara == 2) { 135 loopDoppioTempo(); // Percorso incrociato a tempo per 1 giocatore 136 } 137 break; 138 } 139} 140 141//--------------------END LOOP----------- 142void scegliTracciato() { 143 lcd.setCursor(0, 0); 144 lcd2.setCursor(0, 0); // Posiziona il cursore 145 lcd.home(); 146 lcd.print("scegli tracciato"); // Scegli il tracciato 147 lcd.setCursor(0, 1); 148 lcd.print("2trk rly1 rly2"); // 0,1---6,1--12,1 posizione del cursore 149 lcd.setCursor(0, 1); 150 lcd.blink(); 151 152 while (tipoPercorso == 0) { // Ciclo per la scelta del tipoPercorso spostando il cursore 153 delay(500); 154 155 if (digitalRead(7) == 1) { 156 tone(audio, NOTE_G4, 50); 157 scegliPercorso = (scegliPercorso % 3) + 1; // Gestione del conteggio e della rotazione 158 159 switch (scegliPercorso) { // Sposta il cursore quando il sensore IR è oscurato 160 case 1: 161 lcd.setCursor(c1a, 1); // Due giocatori 162 break; 163 case 2: 164 lcd.setCursor(c2a, 1); // Giocatore singolo con percorso ad anello 165 break; 166 case 3: 167 lcd.setCursor(c3a, 1); // Giocatore singolo con corsia incrociata 168 break; 169 } 170 } 171 172 if (digitalRead(9) == 1) { // Imposta il percorso ed esce dal ciclo while 173 tipoPercorso = scegliPercorso; 174 tone(audio, NOTE_G5, 50); 175 lcd.noBlink(); 176 177 if (tipoPercorso == 1) { 178 lcd.clear(); 179 lcd.setCursor(0, 0); 180 lcd.print("2 corsie classic"); // Due giocatori 181 } 182 if (tipoPercorso == 2) { 183 lcd.clear(); 184 lcd.setCursor(0, 0); 185 lcd.print("1 corsia rally"); // Giocatore singolo con percorso ad anello 186 } 187 if (tipoPercorso == 3) { 188 lcd.clear(); 189 lcd.setCursor(0, 0); 190 lcd.print("2 corsie rally"); // Giocatore singolo con corsia incrociata 191 } 192 delay(4000); 193 } 194 } 195 lcd.noBlink(); 196} 197 198void scegliCorsa() { 199 // ----- Routine per scegliere il tipo di gara ------ 200 lcd.home(); 201 lcd.print("scegli tipo gara"); // Scegli il tipo di gara 202 lcd.setCursor(0, 1); 203 lcd.print("GIRI TEMPO"); // 0,1--- 11,1 posizione del cursore in base alla scelta 204 lcd.setCursor(0, 1); 205 206 while (tipoGara == 0) { 207 lcd.blink(); // Mostra il cursore 208 delay(500); 209 210 if (digitalRead(7) == 1) { 211 tone(audio, NOTE_G4, 50); 212 scegliGara = (scegliGara % 3) + 1; // Gestione del conteggio e della rotazione 213 214 switch (scegliGara) { 215 case 1: 216 lcd.setCursor(c1b, 1); 217 break; 218 case 2: 219 lcd.setCursor(c2b, 1); 220 break; 221 } 222 } 223 224 if (digitalRead(9) == 1) { 225 tipoGara = scegliGara; 226 tone(audio, NOTE_G5, 50); 227 228 if (tipoGara == 1) { 229 lcd.clear(); 230 lcd.home(); 231 lcd.print("Gara a giri"); // Gara a giri 232 } 233 if (tipoGara == 2) { 234 lcd.clear(); 235 lcd.setCursor(0, 0); 236 lcd.print("Gara a tempo"); // Gara a tempo 237 } 238 lcd.noBlink(); 239 delay(500); 240 } 241 242 switch (tipoGara) { 243 case 1: // Gara a giri - imposta il numero di giri 244 configuraGiri(); 245 break; 246 case 2: // Gara a tempo - imposta i minuti 247 totLap = 0; 248 configuraTempo(); 249 break; 250 } 251 } 252 253 lcd.noBlink(); 254} 255 256void configuraGiri() { // Ottimizzato 257 lcd.clear(); 258 lcd.home(); 259 lcd.print("Up Down Enter"); // 0,1---4,1--11,1 posizione del cursore in base alla scelta 260 lcd.blink(); 261 262 int k = 0; 263 int colonna = 0; 264 265 while (k == 0) { 266 delay(500); 267 268 if (digitalRead(trk1) == 1) { 269 tone(audio, NOTE_G4, 50); 270 menuGiri = (menuGiri % 3) + 1; // Gestione del conteggio e della rotazione 271 272 switch (menuGiri) { // Sposta il cursore 273 case 1: 274 colonna = c1c; 275 break; 276 case 2: 277 colonna = c2c; 278 break; 279 case 3: 280 colonna = c3c; 281 break; 282 } 283 284 lcd.setCursor(colonna, 0); // Imposta il cursore sulla colonna corretta 285 } 286 287 if (digitalRead(trk2) == 1) { 288 tone(audio, NOTE_G5, 50); 289 290 switch (menuGiri) { // Sposta il cursore 291 case 1: 292 totLap++; 293 break; 294 case 2: 295 totLap--; 296 if (totLap < 1) { 297 totLap = 1; 298 } 299 break; 300 case 3: 301 k = 1; 302 lcd.noBlink(); 303 break; 304 } 305 } 306 lcd.setCursor(0, 1); 307 lcd.print("giri: "); 308 lcd.print(totLap); 309 lcd.print(" "); 310 lcd.setCursor(colonna, 0); 311 } 312 trk1Lap = totLap; 313 trk2Lap = totLap; 314 lcd.clear(); 315 lcd2.clear(); 316 lcd.home(); 317 lcd.print("----------------"); 318 lcd2.home(); 319 lcd2.print("----------------"); 320 lcd.setCursor(0, 1); 321 lcd.print("GARA DA "); 322 lcd.print(totLap); 323 lcd.print(" GIRI"); 324 lcd2.setCursor(0, 1); 325 lcd2.print("GARA DA "); 326 lcd2.print(totLap); 327 lcd2.print(" GIRI"); 328 lcd.noBlink(); 329 delay(5000); 330} 331 332void configuraTempo() { 333 lcd.clear(); 334 lcd.home(); 335 lcd.print("Up Down Enter"); // 0,1---4,1--11,1 posizione del cursore in base alla scelta 336 lcd.blink(); 337 338 int k = 0; 339 int colonna = 0; 340 341 while (k == 0) { 342 delay(500); 343 344 if (digitalRead(trk1) == 1) { 345 tone(audio, NOTE_G4, 50); 346 menuTempo = (menuTempo % 3) + 1; // Gestisce la rotazione 347 348 switch (menuTempo) { // Sposta il cursore 349 case 1: 350 lcd.setCursor(c1c, 0); 351 colonna = c1c; 352 break; 353 case 2: 354 lcd.setCursor(c2c, 0); 355 colonna = c2c; 356 break; 357 case 3: 358 lcd.setCursor(c3c, 0); 359 colonna = c3c; 360 break; 361 } 362 } 363 if (digitalRead(trk2) == 1) { 364 tone(audio, NOTE_G5, 50); 365 366 switch (menuTempo) { // Sposta il cursore 367 case 1: 368 timeRace++; 369 break; 370 case 2: 371 timeRace--; 372 if (timeRace < 1) { 373 timeRace = 1; 374 } 375 break; 376 case 3: 377 k = 1; 378 lcd.noBlink(); 379 break; 380 } 381 } 382 lcd.setCursor(0, 1); 383 lcd.print("minuti: "); 384 lcd.print(timeRace); 385 lcd.print(" "); 386 lcd.setCursor(colonna, 0); 387 } 388 389 timeRaceMillis = timeRace * 60000; 390 trk1Lap = 0; 391 trk2Lap = 0; 392 lcd.clear(); 393 lcd2.clear(); 394 lcd.home(); 395 lcd.print("----------------"); 396 lcd2.home(); 397 lcd2.print("----------------"); 398 lcd.setCursor(0, 1); 399 lcd.print("GARA DA "); 400 lcd.print(timeRace); 401 lcd.print(" Min"); 402 lcd2.setCursor(0, 1); 403 lcd2.print("GARA DA "); 404 lcd2.print(timeRace); 405 lcd2.print(" Min"); 406 lcd.noBlink(); 407 delay(5000); 408} 409 410//---------- SEMFORO-------- 411void semaforo() { //ottimizzato 412 lcd.clear();lcd2.clear(); 413 for (int col = 1; col <15; col = col + 3) { 414 lcd.setCursor(col, 1);lcd2.setCursor(col, 1); 415 lcd.print("0");lcd2.print("0");tone(audio,NOTE_F4,50); 416 delay(1200); 417 } 418 lcd.clear();lcd2.clear();tone(audio,NOTE_C5,250); 419} 420 421//-------Clock for LAP race----------- 422long orologioRace(){ 423 mm=timePassed/60000; 424 ss=(timePassed-mm*60000)/1000; 425 dec=(timePassed-mm*60000-ss*1000)/10; 426 lcd.setCursor(11, 0); 427 lcd.print(mm >= 10 ? mm : "0" + String(mm)); 428 lcd.print(":"); 429 lcd.print(ss >= 10 ? ss : "0" + String(ss)); 430 if(tipoPercorso==1) { //shows the contdown for the second player 431 lcd2.setCursor(11, 0); 432 lcd2.print(mm >= 10 ? mm : "0" + String(mm)); 433 lcd2.print(":"); 434 lcd2.print(ss >= 10 ? ss : "0" + String(ss)); 435 } 436} 437//-----CLOCK for TIME RACE- COUNTDOWN----- 438long orologio() { 439 mm = timeRemain / 60000; 440 ss = (timeRemain - mm * 60000) / 1000; 441 lcd.setCursor(11, 0); 442 lcd.print(mm >= 10 ? mm : "0" + String(mm)); 443 lcd.print(":"); 444 lcd.print(ss >= 10 ? ss : "0" + String(ss)); 445 if(tipoPercorso==1) { //shows the contdown for the second player 446 lcd2.setCursor(11, 0); 447 lcd2.print(mm >= 10 ? mm : "0" + String(mm)); 448 lcd2.print(":"); 449 lcd2.print(ss >= 10 ? ss : "0" + String(ss)); 450 } 451} 452 453//------format the BEST TIME---------- 454void formattaBest(){ //ottimizzato 455 mm1 = trk1BestLapTime / 60000; 456 ss1 = (trk1BestLapTime - mm1 * 60000) / 1000; 457 dec1 = (trk1BestLapTime - mm1 * 60000 - ss1 * 1000) / 10; 458 minut1 = (mm1 < 10) ? "0" + String(mm1) : String(mm1); 459 secondi1 = (ss1 < 10) ? "0" + String(ss1) : String(ss1); 460 deci1 = (dec1 < 10) ? "0" + String(dec1) : String(dec1); 461 462 if (tipoPercorso==1 || tipoPercorso==3){ 463 mm2 = trk2BestLapTime / 60000; 464 ss2 = (trk2BestLapTime - mm2 * 60000) / 1000; 465 dec2 = (trk2BestLapTime - mm2 * 60000 - ss2 * 1000) / 10; 466 minut2 = (mm2 < 10) ? "0" + String(mm2) : String(mm2); 467 secondi2 = (ss2 < 10) ? "0" + String(ss2) : String(ss2); 468 deci2 = (dec2 < 10) ? "0" + String(dec2) : String(dec2); 469 } 470} 471void formattaLast(){ //ottimizzato 472 mm1 = trk1LapTime / 60000; 473 ss1 = (trk1LapTime - mm1 * 60000) / 1000; 474 dec1 = (trk1LapTime - mm1 * 60000 - ss1 * 1000) / 10; 475 476 minut1 = (mm1 < 10) ? "0" + String(mm1) : String(mm1); 477 secondi1 = (ss1 < 10) ? "0" + String(ss1) : String(ss1); 478 deci1 = (dec1 < 10) ? "0" + String(dec1) : String(dec1); 479} 480//---gestione dei suoni---------- OTTIMIZZATO 481void playSound(int pin, int note, int duration) { 482 tone(pin, note, duration); 483 delay(duration + 50); // Add a small delay to avoid overlapping of tones 484 noTone(pin); 485} 486 487void startSound() { 488 int duration = 80; 489 playSound(audio, NOTE_C5, duration); 490 playSound(audio, NOTE_D5, duration); 491 playSound(audio, NOTE_F5, duration); 492 playSound(audio, NOTE_A5, duration); 493 playSound(audio, NOTE_GS5, duration); 494 playSound(audio, NOTE_A5, duration); 495 playSound(audio, NOTE_F5, duration * 2); 496} 497 498void endSound() { 499 int duration = 80; 500 playSound(audio, NOTE_C5, duration); 501 playSound(audio, NOTE_E5, duration); 502 playSound(audio, NOTE_G5, duration); 503 playSound(audio, NOTE_C6, duration); 504 playSound(audio, NOTE_G5, duration); 505 playSound(audio, NOTE_C6, duration * 2); 506} 507 508void byeSound() { 509 int duration = 100; 510 playSound(audio, NOTE_C5, duration); 511 playSound(audio, NOTE_B4, duration); 512 playSound(audio, NOTE_AS4, duration); 513 playSound(audio, NOTE_A4, duration); 514 playSound(audio, NOTE_GS4, duration * 5); 515} 516 517//--------Play again menu--------- 518void ricomincia() { //ottimizzato 519 int a = 0; 520 int r = 0; 521 int m = 0; 522 523 while (a == 0) { //resta nel ciclo finchè a resta 0 524 if (digitalRead(7) == 1 && digitalRead(9) == 1) { //rileva l'oscuramento di entrambi i sensori per entrare nel menu 525 tone(audio, NOTE_G5, 50); 526 lcd.clear(); 527 lcd.setCursor(0, 0); 528 lcd.print(" Ricominciare?"); // Play again? 529 lcd.setCursor(0, 1); 530 lcd.print("1=SI 2=menu 3=NO"); 531 delay(1000); 532 533 while (r == 0) { //resta nel ciclo finchè r resta 0 534 delay(500); 535 if (digitalRead(7) == 1 && digitalRead(9) == 0) { // scelta 1 "SI" per rigiocare 536 a = 1; 537 r = 1; 538 tone(audio, NOTE_G5, 50); 539 } 540 if (digitalRead(7) == 0 && digitalRead(9) == 1) { // scelta 2 "menu" per rigiocare 541 a = 1; 542 r = 1; 543 m = 1; 544 tone(audio, NOTE_G5, 50); 545 } 546 if (digitalRead(7) == 1 && digitalRead(9) == 1) { //scelta "NO" per uscire 547 lcd.clear();lcd2.clear(); 548 lcd.setCursor(0, 0); 549 lcd.print(" ARRIVEDERCI"); 550 byeSound(); 551 exit(0); 552 } 553 } 554 } 555 } 556 if (a==1 && m==0){ 557 winnerState =0; 558 trk1Lap = totLap; 559 trk2Lap = totLap; 560 lap0tr1 = 0; 561 lap0tr2 = 0; 562 trk1State = 0; 563 trk2State = 0; 564 trk1BestLapTime=0; 565 trk2BestLapTime=0; 566 checkIR1=false; 567 checkIR2=false; 568 firstCKPT=false; 569 secondCKPT=false; 570 setup(); 571 } 572 if (a==1 && m==1){ 573 574 checkIR1 = true; //variable used to verify if an obstacle remain under IR1 575 checkIR2 = true; //variable used to verify if an obstacle remain under IR1 576 firstCKPT = false; //variable used in the two lane loop to be sure that the player doesn't miss a ring 577 secondCKPT= false; //variable used in the two lane loop to be sure that the player doesn't miss a ring 578 //----variabili per menu----- 579 //----Menu percorso 580 tipoPercorso=0; 581 scegliPercorso=1; 582 c1a=0; c2a=6; c3a=12; //cursor position in the display in the track menu 583 //----Menu gara---- 584 tipoGara=0; 585 scegliGara=1; 586 c1b=0; c2b=11; //cursor position in the display in the race menu 587 //---Gara a Giri--- 588 totLap = 5; //default value for LAP race 589 trk1Lap = 0; 590 trk2Lap = 0; 591 lap0tr1 = 0; 592 lap0tr2 = 0; 593 menuGiri=1; 594 c1c=0; c2c=4; c3c=11; //cursor position in the display in the lap menu 595 //---Gara a Tempo--- 596 timeRace = 1; //default value for timerace in minutes 597 timeRaceMillis; //timerace in millis 598 timeStart; //time when the race start 599 timeNow; 600 timeRemain; // =timeEnd-timeStart-timeNow-timeStart 601 timeEnd;//time the race will end timeStart + timeRace 602 timePassed; 603 menuTempo=1; 604 //---altre variabili--- 605 winnerState =0; 606 lastDebounceTime1 = 0; // the last time the output pin was toggled 607 lastDebounceTime2 = 0; // the last time the output pin was toggled 608 trk1mill = 0; // millis for trk1 609 trk2mill = 0; // millis for trk2 610 debounceDelay = 2500; // the debounce time in millis; increase if the output flickers //tempo dell'anti-rimbalzo - da regolare 611 mm1,ss1,dec1; //minutes seconds and dec for Player 1 612 mm2,ss2,dec2; //minutes seconds and dec for Player 2 613 mm,ss,dec; //variabili per gli orologi 614 minut1,secondi1,deci1; 615 minut2,secondi2,deci2; 616 tpminut; 617 tpsecondi; 618 tpdeci; 619 trk1LapTime,trk1BestLapTime,trk1EndLapTime,trk1StartLapTime; 620 trk2LapTime,trk2BestLapTime,trk2EndLapTime,trk2StartLapTime; 621 testoP1; 622 testoP2; 623 setup(); 624 } 625} 626 627//----from here the routines for each kind of races --- MOTORI DELLE GARE---- 628 629/*gara per due giocatori a giri (tipoPercorso=1) oppure per singolo giocatore con rally loop (tipoPercorso2). 630 *in questo caso la parte di rilvamento giri del secondo giocatore viene esclusa con una IF sul tipo di percorso 631 */ 632void garaAGiri() { //----funzionante 633 634 // Calcola il tempo trascorso nella gara 635 timeNow = millis(); 636 timePassed = timeNow - timeStart; 637 orologioRace(); 638 639 // Gestione sensore IR per il giocatore 1 640 if (trk1State == 1 && checkIR1==false) { 641 trk1mill = millis(); 642 tone(audio, NOTE_C5, 50); 643 checkIR1 = true; 644 if ((trk1mill - lastDebounceTime1) > debounceDelay) { 645 if (lap0tr1 == 1) { 646 lastDebounceTime1 = millis(); 647 trk1EndLapTime = trk1mill; 648 trk1LapTime = trk1EndLapTime - trk1StartLapTime; 649 trk1Lap = trk1Lap - 1; 650 lcd.setCursor(4,0); 651 lcd.print(trk1Lap); //scrive i giri 652 653 if (trk1LapTime <= trk1BestLapTime || trk1BestLapTime==0 ) { // if (trk1BestLapTime == 0 || trk1LapTime <= trk1BestLapTime) { 654 trk1BestLapTime = trk1LapTime; 655 formattaBest(); 656 testoP1 = minut1 + ":" + secondi1 + ":" + deci1; 657 lcd.setCursor(8, 1);lcd.print(testoP1); 658 } 659 trk1StartLapTime = lastDebounceTime1; 660 } 661 if (lap0tr1 == 0){ // Primo giro 662 lap0tr1 = 1; 663 trk1Lap = totLap; 664 lastDebounceTime1 = millis(); 665 trk1StartLapTime = timeStart; 666 lcd.setCursor(4,0); 667 lcd.print(trk1Lap); //scrive i giri 668 } 669 } 670 } 671 672 // Gestione sensore IR per il giocatore 2 673 if (tipoPercorso==1) { 674 if (trk2State == 1 && checkIR2==false) { 675 trk2mill = millis(); 676 tone(audio, NOTE_E5, 50); 677 checkIR2 = true; 678 679 if ((trk2mill - lastDebounceTime2) > debounceDelay) { 680 // Controllo primo giro 681 if (lap0tr2 == 1) { 682 trk2Lap = trk2Lap - 1; 683 lastDebounceTime2 = millis(); 684 trk2EndLapTime = trk2mill; 685 trk2LapTime = trk2EndLapTime - trk2StartLapTime; 686 lcd2.setCursor(4,0); 687 lcd2.print(trk2Lap); //scrive i giri 688 trk2StartLapTime = lastDebounceTime2; 689 if (trk2LapTime <= trk2BestLapTime || trk2BestLapTime==0 ) { 690 trk2BestLapTime = trk2LapTime; 691 formattaBest(); 692 testoP2 = minut2 + ":" + secondi2 + ":" + deci2; 693 lcd2.setCursor(8, 1);lcd2.print(testoP2); 694 } 695 } 696 if (lap0tr2 == 0) { // Primo giro 697 lap0tr2 = 1; 698 trk2Lap = totLap; 699 lastDebounceTime2 = millis(); 700 trk1StartLapTime = timeStart; 701 lcd2.setCursor(4,0); 702 lcd2.print(trk1Lap); //scrive i giri 703 } 704 } 705 } 706 } 707 708 // Riporta lo stato dei sensori a false quando non rilevano nulla 709 if (trk1State == 0) { 710 checkIR1 = false; 711 } 712 if (trk2State == 0) { 713 checkIR2 = false; 714 } 715 716 // Controllo se uno dei partecipanti ha terminato la gara 717 if (trk1Lap == 0 || trk2Lap == 0) { 718 winnerState = 1000; 719 endSound(); 720 if (trk1Lap <= 0 && trk2Lap > 0) { //P1 vince 721 lcd.setCursor(7, 0); 722 lcd.print("WIN"); 723 if (tipoPercorso==1) { 724 lcd2.setCursor(7, 0); 725 lcd2.print("Lose"); 726 } 727 } 728 if (tipoPercorso==1) { 729 if (trk2Lap <= 0 && trk1Lap > 0) { //P2 vince 730 lcd2.setCursor(7, 0); 731 lcd2.print("WIN"); 732 lcd.setCursor(7, 0); 733 lcd.print("Lose"); 734 } 735 } 736 } 737 738 // Ritarda per consentire ai partecipanti di vedere i risultati prima di ricominciare 739 if (winnerState == 1000) { 740 delay(20000); 741 ricomincia(); 742 } 743} 744 745//---------------- 746/*gara per due giocatori a tempo (tipoPercorso=1) oppure per singolo giocatore con rally loop (tipoPercorso2). 747 *in questo caso la parte di rilvamento giri del secondo giocatore viene esclusa con una IF sul tipo di percorso 748 */ 749void garaATempo() { //-----------Funzionante 750 timeNow = millis(); 751 752 // Calcola i parametri relativi al tempo di gara 753 timeEnd = timeStart + timeRaceMillis; 754 timePassed = timeNow - timeStart; 755 timeRemain = timeRaceMillis - timePassed; 756 757 // Controlla se il tempo è scaduto 758 if (timeRemain >= 0) { 759 orologio(); 760 } 761 else { 762 winnerState = 1000; 763 } 764 // Gestione sensore IR per il giocatore 1 765 if (trk1State == 1 && winnerState < 1000 && checkIR1==false) { 766 trk1mill = millis(); 767 tone(audio, NOTE_C5, 50); 768 checkIR1 = true; 769 770 if ((trk1mill - lastDebounceTime1) > debounceDelay) { 771 if (lap0tr1 == 1) { 772 lastDebounceTime1 = millis(); // Imposta il tempo corrente 773 trk1EndLapTime = trk1mill; 774 trk1LapTime = trk1EndLapTime - trk1StartLapTime; 775 trk1StartLapTime = lastDebounceTime1; 776 trk1Lap = trk1Lap + 1; 777 lcd.setCursor(4, 0); 778 lcd.print(trk1Lap); 779 780 // Aggiorna il miglior tempo se è il primo giro o se il tempo attuale è migliore 781 if (trk1LapTime < trk1BestLapTime || trk1BestLapTime==0) { 782 trk1BestLapTime = trk1LapTime; 783 // Mostra il miglior tempo sul display per il giocatore 1 784 formattaBest(); 785 testoP1 = minut1 + ":" + secondi1 + ":" + deci1; 786 lcd.setCursor(8, 1); 787 lcd.print(testoP1); 788 } 789 } 790 if (lap0tr1 == 0){ // Primo giro 791 lap0tr1 = 1; 792 trk1Lap = 0; 793 lastDebounceTime1 = millis(); // Imposta il tempo corrente 794 trk1StartLapTime = timeStart; 795 lcd.setCursor(4, 0); 796 lcd.print(trk1Lap); 797 } 798 } 799 } 800 801 // Gestione sensore IR per il giocatore 2 (solo se tipoPercorso è 1) 802 if (tipoPercorso == 1 && trk2State == 1 && winnerState < 1000 && checkIR2==false) { 803 trk2mill = millis(); 804 tone(audio, NOTE_G5, 50); 805 checkIR2 = true; 806 807 if ((trk2mill - lastDebounceTime2) > debounceDelay) { 808 // Controllo primo giro 809 if (lap0tr2 == 1) { 810 lastDebounceTime2 = millis(); // Imposta il tempo corrente 811 trk2EndLapTime = trk2mill; 812 trk2LapTime = trk2EndLapTime - trk2StartLapTime; 813 trk2StartLapTime = lastDebounceTime2; 814 trk2Lap = trk2Lap + 1; 815 lcd2.setCursor(4,0); 816 lcd2.print(trk2Lap); 817 // Aggiorna il miglior tempo se è il primo giro o se il tempo attuale è migliore 818 if (trk2BestLapTime == 0 || trk2LapTime <= trk2BestLapTime) { 819 trk2BestLapTime = trk2LapTime; 820 // Mostra il miglior tempo sul display per il giocatore 2 821 formattaBest(); 822 testoP2 = " " + minut2 + ":" + secondi2 + ":" + deci2; 823 lcd2.setCursor(7, 1); 824 lcd2.print(testoP2); 825 } 826 } 827 if (lap0tr2 == 0) { // Primo giro 828 lap0tr2 = 1; 829 trk2Lap = 0; 830 lastDebounceTime2 = millis(); // Imposta il tempo corrente 831 trk2StartLapTime = timeStart; 832 lcd2.setCursor(4, 0); 833 lcd2.print(trk2Lap); 834 } 835 } 836 } 837 838 // Riporta lo stato dei sensori a falso quando non rilevano nulla 839 if (trk1State == 0) { 840 checkIR1 = false; 841 } 842 if (trk2State == 0) { 843 checkIR2 = false; 844 } 845 846 // Controllo se uno dei partecipanti ha terminato la gara 847 if (winnerState == 1000 ) { 848 if (trk1Lap > trk2Lap) { //vince P1 849 lcd.setCursor(7,0); 850 lcd.print("WINNER "); 851 } 852 if (tipoPercorso == 1 && trk1Lap < trk2Lap) { //vince P2 853 lcd2.setCursor(7,0); 854 lcd2.print("WINNER "); 855 } 856 if (tipoPercorso == 1 && trk1Lap == trk2Lap) { //in caso di parità allo scadere del tempo aspetta la prima macchina che passa sotto il traguardo 857 while (trk2State == 0 && trk1State == 0) { 858 // Wait until one car passes the finish line 859 trk1State = digitalRead(trk1); 860 trk2State = digitalRead(trk2); 861 } 862 if (trk1State == 1) { 863 lcd.setCursor(7, 0); 864 lcd.print("WINNER "); 865 } 866 if (trk2State == 1) { 867 lcd2.setCursor(7, 0); 868 lcd2.print("WINNER "); 869 } 870 } 871 endSound(); 872 delay(20000); 873 ricomincia(); 874 } 875} 876 877//---------------------------- 878void loopDoppioGiri() { //Funzionante 879 880 // Calcola il tempo trascorso nella gara 881 timeNow = millis(); 882 timePassed = timeNow - timeStart; 883 orologioRace(); 884 885// Gestione sensore IR per il giocatore 1 886 if (trk1State == 1 && checkIR1==false) { 887 trk1mill = millis(); 888 tone(audio, NOTE_C5, 50); 889 checkIR1 = true; 890 if ((trk1mill - lastDebounceTime1) > debounceDelay) { 891 if (lap0tr1 == 1 && firstCKPT==false && secondCKPT== true) { 892 lastDebounceTime1 = millis(); 893 trk1EndLapTime = trk1mill; 894 trk1LapTime = trk1EndLapTime - trk1StartLapTime; 895 trk1StartLapTime = lastDebounceTime1; 896 firstCKPT=true; 897 secondCKPT=false; 898 trk1Lap = trk1Lap - 1; 899 lcd.setCursor(4,0); 900 lcd.print(trk1Lap); //scrive i giri 901 902 if (trk1LapTime <= trk1BestLapTime || trk1BestLapTime==0 ) { // if (trk1BestLapTime == 0 || trk1LapTime <= trk1BestLapTime) { 903 trk1BestLapTime = trk1LapTime; 904 formattaBest(); 905 testoP1 = minut1 + ":" + secondi1 + ":" + deci1; 906 lcd.setCursor(8, 1);lcd.print(testoP1); 907 } 908 } 909 if (lap0tr1 == 0){ // Primo giro 910 lap0tr1 = 1; 911 trk1Lap = totLap; 912 lastDebounceTime1 = millis(); 913 trk1StartLapTime = timeStart; 914 lcd.setCursor(4,0); 915 lcd.print(trk1Lap); //scrive i giri 916 firstCKPT=true; 917 secondCKPT=false; 918 } 919 } 920 } 921 922 // Gestione sensore IR per il giocatore 2 923 if (trk2State == 1 && checkIR2==false) { 924 trk2mill = millis(); 925 tone(audio, NOTE_E5, 50); 926 checkIR2 = true; 927 928 if ((trk2mill - lastDebounceTime2) > debounceDelay) { 929 // Controllo primo giro 930 if (lap0tr1 == 1 && firstCKPT==true && secondCKPT== false) { 931 lastDebounceTime2 = millis(); 932 trk2EndLapTime = trk2mill; 933 trk2LapTime = trk2EndLapTime - trk1StartLapTime; 934 //trk2StartLapTime = trk1StartLapTime; 935 firstCKPT=false; 936 secondCKPT=true; 937 if (trk2LapTime <= trk2BestLapTime || trk2BestLapTime==0 ) { 938 trk2BestLapTime = trk2LapTime; 939 formattaBest(); 940 testoP2 = "inter:"+minut2 + ":" + secondi2 + ":" + deci2; 941 lcd2.setCursor(1, 1);lcd2.print(testoP2); 942 } 943 } 944 } 945 } 946 947 // Riporta lo stato dei sensori a false quando non rilevano nulla 948 if (trk1State == 0) { 949 checkIR1 = false; 950 } 951 if (trk2State == 0) { 952 checkIR2 = false; 953 } 954 955 // Controllo se uno dei partecipanti ha terminato la gara 956 if (trk1Lap == 0) { 957 958 // Visualizza il vincitore del giocatore 1 959 lcd.setCursor(7,0); 960 lcd.print("WIN"); 961 winnerState = 1000; 962 endSound(); 963 // Ritarda per consentire ai partecipanti di vedere i risultati prima di ricominciare 964 if (winnerState == 1000) { 965 delay(10000); 966 ricomincia(); 967 } 968 } 969} 970//--------------engine for Time Race for one player with cross between two lane 971void loopDoppioTempo() { 972 timeNow=millis(); 973 //----parametri del tempo di gara 974 timeEnd=timeStart+timeRaceMillis; 975 timePassed=timeNow-timeStart; 976 timeRemain=timeRaceMillis-timePassed; 977 //controllo se il tempo è scaduto 978 if (timeRemain>=0) { 979 orologio(); 980 } 981 else { 982 winnerState = 1000; 983 }//fine controllo tempo scaduto 984 //---debounce e conteggio giri 985 if (trk1State == 1 && winnerState <1000 && checkIR1 == false){ 986 trk1mill = millis();tone(audio,NOTE_C5,50);checkIR1 = true; 987 //filter out any noise by setting a time buffer 988 if ((trk1mill - lastDebounceTime1) > debounceDelay ){ //check debaunce car has passed IR2 before 989 if (lap0tr1 == 1 && firstCKPT==false && secondCKPT==true) { 990 trk1Lap = trk1Lap+1; 991 lastDebounceTime1 = millis(); //set the current time 992 trk1EndLapTime = trk1mill; 993 trk1LapTime=trk1EndLapTime-trk1StartLapTime; 994 trk1StartLapTime= lastDebounceTime1; 995 firstCKPT=true;secondCKPT=false; 996 lcd.setCursor(4,0); 997 lcd.print(trk1Lap); //scrive i giri 998 if (trk1LapTime <trk1BestLapTime|| trk1BestLapTime==0) { 999 trk1BestLapTime=trk1LapTime; 1000 formattaBest(); 1001 testoP1=String (minut1 + ":" + secondi1 + ":" + deci1); 1002 lcd.setCursor(8,1);lcd.print(testoP1); 1003 } 1004 } 1005 if (lap0tr1 == 0) { // first LAP non rileva il primo giro 1006 lap0tr1=1; //car under IR1 1007 trk1Lap = 0; 1008 lastDebounceTime1 = millis(); //set the current time 1009 trk1StartLapTime= timeStart; 1010 firstCKPT=true;secondCKPT=false; //regular situation 1011 } 1012 } 1013 } //close if(time buffer) 1014 if (trk2State == 1 && winnerState <1000 && checkIR2 == false) { 1015 trk2mill = millis();tone(audio,NOTE_G5,50);checkIR2 = true; 1016 //filter out any noise by setting a time buffer 1017 if ((trk2mill - lastDebounceTime2) > debounceDelay ) { 1018 if (lap0tr1 == 1&& firstCKPT==true && secondCKPT==false) { 1019 lastDebounceTime2 = millis(); //set the current time 1020 trk2EndLapTime = trk2mill; 1021 trk2LapTime=trk2EndLapTime-trk1StartLapTime; 1022 firstCKPT=false;secondCKPT=true; 1023 trk2StartLapTime= lastDebounceTime1; 1024 if (trk2LapTime <= trk2BestLapTime||trk2BestLapTime==0) { 1025 trk2BestLapTime=trk2LapTime; 1026 formattaBest(); 1027 testoP2=String ("Part: " + minut2 + ":" + secondi2 + ":" + deci2); 1028 lcd2.setCursor(3,1);lcd2.print(testoP2); 1029 } 1030 } 1031 } 1032 }//close if(time buffer) 1033 if (trk1State == 0) {checkIR1=false;} 1034 if (trk2State == 0) {checkIR2=false;} 1035 if (winnerState == 1000) { 1036 lcd.setCursor(7,0); 1037 lcd.print("FINISH "); 1038 endSound(); 1039 delay(20000);ricomincia(); 1040 } 1041} 1042 1043 1044 1045/* True Fase table 1046LAP FH SH 1047Sta F F 10480 T F 1049H0 F T 10501 T F 1051H1 F T 10522 T F 1053 1054 1055*/
Comments
Only logged in users can leave comments