Components and supplies
Arduino Micro
piezo speaker
16x2 LCD display with I²C interface
Copper Stripboard
Plastic container
AZDelivery IR module i2c
Tools and machines
Soldering kit
Apps and platforms
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
sierra070
7 months ago
I'm sorry to answer you only now, I don't visit the site often. I saw that you completed your project, I hope that my program could have been of help to you. If I can help you again, contact me.
pompebled
10 months ago
This is exactly what I was looking for! Question: If I omit the two extra 'tracks', will one LCD be sufficient?
pompebled
10 months ago
I uploaded the sketch and now run into the issue that my Italian is non existant; I don't understand how to proceed... Could you upload an English version?