Pinball ARDUINO Conversion (another one)
A KISS solution maximising OTS components minimising wiring, designing and making one off PCB, all parts available from multiple suppliers.
Devices & Components
Arduino Mega 2560 Rev3
Arduino Uno Rev3
WS2812 strip leds
fanless pc
PSU's
PC and LED Tv
Arduino screw shield
Pinball playfield
mosfet shield
Project description
Code
Main MEGA processor
arduino
Arduino Pinball machine
1#include <FastLED.h> 2// GOTTLIEB EM Pinball with a ARDUINO MEGA 3// replacing the EM Stuff and LEDS replacing bulbs 4// Written by B J Mclaren 5// based on experience of building an ARDUINO based Bally Bingo 6// This is currenty for FLYING CARPET but will be able to 7// play DUOTRON in future (Next release). 8// Special thanks to all involved in ARDUINO Pinballs. 9// Most of the code is original except some Bumper stuff 10// This solution used distributed processing with a MEGA 11// as the Master controller 12// UNO's as Auxillary Controllers for Chimes etc 13// an extra UNO when more than 12 solenoids are required (DUOTRON) 14// Processing 3(see processing.org)for Backglass (+ Sound if no Chime Unit) 15// A PC, (a Fanless PC is powerfull enough) to run the 16// software to drive a 40" LCD TV Backglass. 17// 18// There are 6 channels on each MOSFET Board. 19// PWM Pins used by the driver are 3,5,6,9,10,11 20// Board 1 ( MASTER ) mounted on MEGA is for 3 POP Bumper 21// and Ball delivery + 2 Spares 22// a single MOSFET Driver is used for the 100 points LED 23// There are 6 channels on MOSFET Board 2 24// Board 2 ( SLAVE 1 )mounted on UNO for chimes, Knocker and flippers 25// Board 3 ( SLAVE 2 )future expansion eg DUOTRON 26// Board 1 utilises a 12 Volt PSU 27// Board 2 utilises a 15 Volt PSU 28// A total of 18 solenoid Drivers can be provided 29// Comms to Slave 1 and Slave 2 via RS232 30// later versions may use I2C (so reserve A4 and A5) 31// 32// Switch and Targets ARDUINO Pins 33#define Fswitch 36 34#define Lswitch 37 35#define Yswitch 38 36#define Iswitch 39 37#define Nswitch 40 38#define Gswitch 41 39// 40#define Cswitch 42 41#define Aswitch 43 42#define Rswitch 44 43#define Pswitch 45 44#define Eswitch 46 45#define Tswitch 47 46// Misc Switches and Buttons 47#define Redbutton 27 48#define Yellbutton 28 49#define Tilt 34 50#define Slingshot 35 //ALL score slingshots are in parallel 51// 52#define B1_Bumper_Switch 29 53#define B1_MOSFET_Driver 5 54// 55#define B2_Bumper_Switch 31 56#define B2_MOSFET_Driver 3 57// 58#define B3_Bumper_Switch 30 59#define B3_MOSFET_Driver 6 60// 61#define Deliver_Ball_MOSFET_Driver 9 62// 63#define BlueLed_MOSFET_Driver 4 // Lit when 100 points 64#define Spare1_MOSFET_Driver 10 65#define Spare2_MOSFET_Driver 11 66// 67// Array for LEDs for playfield 68#define NUM_LEDS 70 //Space for up to 70 LEDS 69#define DATA_PIN A0 70// 71#define Ball_Lights 41 // Offset for Balls played LEDS 72#define On_Time 40 // Solenoids ON Time in ms 73// 74CRGB leds[NUM_LEDS]; 75// This section defined the index into the LED arrays 76// LED's for "FLYING CARPET" in centre of playfield 77int FCLamps [13] = 78{ 79 21, 22, 24, 25, 27, 28, 34, 33, 32, 31, 30, 29, 0 80}; 81// switch LED's on Playfield 82int FCswitchLamps [13] = 83{ 84 17, 8, 57, 5, 35, 50, 54, 6, 13, 7, 49, 36, 0 85}; 86// Target LED's on Playfield 87int FCTargetLamps [13] = 88{ 89 59, 20, 9, 51, 11, 60, 12, 52, 14, 19, 61, 10, 0 90}; 91// Index for special targets 92#define SR1 16 //Special R Target 1 93#define SY1 23 //Special Y Target 1 94#define SR2 26 //Special R Target 2 95#define SY2 56 //Special Y Target 2 96// 97// 12 slots to indicate "FLYING CARPET" Targets/Rollovers hit 98int FC[13]; // slots 0 and 13 not used 99int Balls = 0; 100int RandNumber = 0; // Lucky Matching number 101int BallsPerGame = 5; 102int GameOver = 1; 103int FCcount = 0; // count of numbers of FC lights ON 104int SpecialON = 0; // Special ON 105int BlueBumper = 0; // Blue Score 100 if set to 1 106int Phit = 0; // set if P rollover or target hit 107int Ahit = 0; // set if A rollover or target hit 108// if both hit Blue bumper score 100 109int Yspecial = 0; 110int Rspecial = 0; 111int replays = 0; 112int units = 0; // keep track of units for Lucky Number 113int switch_timer = 0; // determine if multi reports of a target hit 114int debounce = 50; // switch debounce in mills 115// Variables for target handling 116unsigned long System_Base_Time = 0; 117unsigned long Target_Hit_Time = 0; 118unsigned long Old_Target_Hit_Time = 0; 119unsigned long diff = 0; 120// Bumper timing stuff 121unsigned long B1_previousMillis = 0; 122unsigned long B1_currentMillis = 0; 123unsigned long B1_ON_Time = 0; 124// 125int B1_Coil_Trigger = 0; 126int B1_Coil_State_last = LOW; 127int B1_Coil_State; 128int B1_difference; 129// 130unsigned long B2_previousMillis = 0; 131unsigned long B2_currentMillis = 0; 132unsigned long B2_ON_Time = 0; 133// 134int B2_Coil_Trigger = 0; 135int B2_Coil_State_last = LOW; 136int B2_Coil_State; 137int B2_difference; 138// 139unsigned long B3_previousMillis = 0; 140unsigned long B3_currentMillis = 0; 141unsigned long B3_ON_Time = 0; 142// 143int B3_Coil_Trigger = 0; 144int B3_Coil_State_last = LOW; 145int B3_Coil_State; 146int B3_difference; 147// 148unsigned long end_time = 0; // used for timing 149unsigned long total_time = 0; 150// Max time before switching off bumpers to stop coil burnup 151int Max_On_Time = 1000; // 152void setup() 153{ 154 pinMode(Deliver_Ball_MOSFET_Driver, OUTPUT); 155 analogWrite(Deliver_Ball_MOSFET_Driver, 0); 156 // 157 pinMode(Spare1_MOSFET_Driver, OUTPUT); 158 analogWrite(Spare1_MOSFET_Driver, 0); 159 // 160 pinMode(Spare2_MOSFET_Driver, OUTPUT); 161 analogWrite(Spare2_MOSFET_Driver, 0); 162 // 163 pinMode(BlueLed_MOSFET_Driver, OUTPUT); 164 digitalWrite (BlueLed_MOSFET_Driver, 0); 165 // Pop Bumpers 166 pinMode(B1_Bumper_Switch, INPUT_PULLUP); 167 pinMode(B1_MOSFET_Driver, OUTPUT); 168 analogWrite(B1_MOSFET_Driver, 0); 169 // 170 pinMode(B2_Bumper_Switch, INPUT_PULLUP); 171 pinMode(B2_MOSFET_Driver, OUTPUT); 172 analogWrite(B2_MOSFET_Driver, 0); 173 // 174 pinMode(B3_Bumper_Switch, INPUT_PULLUP); 175 pinMode(B3_MOSFET_Driver, OUTPUT); 176 analogWrite(B3_MOSFET_Driver, 0); 177 // LEDS 178 FastLED.addLeds<WS2811, DATA_PIN, BRG>(leds, NUM_LEDS); 179 FastLED.setBrightness(100); 180 FastLED.show(); 181 // Switches and Targets 182 pinMode(Fswitch, INPUT_PULLUP); 183 pinMode(Lswitch, INPUT_PULLUP); 184 pinMode(Yswitch, INPUT_PULLUP); 185 pinMode(Iswitch, INPUT_PULLUP); 186 pinMode(Nswitch, INPUT_PULLUP); 187 pinMode(Gswitch, INPUT_PULLUP); 188 // 189 pinMode(Cswitch, INPUT_PULLUP); 190 pinMode(Aswitch, INPUT_PULLUP); 191 pinMode(Rswitch, INPUT_PULLUP); 192 pinMode(Pswitch, INPUT_PULLUP); 193 pinMode(Eswitch, INPUT_PULLUP); 194 pinMode(Tswitch, INPUT_PULLUP); 195 // 196 pinMode(Slingshot, INPUT_PULLUP); 197 pinMode(Tilt, INPUT_PULLUP); 198 // Game Start Stuff 199 pinMode(Redbutton, INPUT_PULLUP); 200 pinMode(Yellbutton, INPUT_PULLUP); 201 // 202 Serial.begin (9600); // -> Tv Monitor via Processing I3 on PC or PI 203 Serial1.begin (9600); // chime unit, ball delivery anf flippers 204} 205// 206void Lucky() 207// Are we Lucky today? 208// match number for replay 209// For Fun Only as we are a Free Play Machine 210{ 211 int u = units - (int(units / 10) * 10); 212 int r = random (0, 9); 213 if (r == u) 214 { 215 replay(); 216 } 217} 218// 219void timer () 220// Used to determine if a Target is bouncing causing 221// multiple reporting of a hit 222// this routine determines the time in milli seconds 223// since the last target hit 224// Currenty set to 200 ms - unlikely 2 targets can be 225// hit within 200ms 226{ 227 Target_Hit_Time = millis(); 228 diff = Target_Hit_Time - Old_Target_Hit_Time; 229 Old_Target_Hit_Time = Target_Hit_Time; 230 if (diff < 200 )switch_timer = 1; // adjust time to suit machine 231} 232// 233void waiton (int pin) 234{ 235 delay (debounce); // let switch settle 236 while (digitalRead(pin) == 0 ) 237 { 238 delay (debounce); 239 } 240}// end of waiton 241// 242void TopRipple(int score) 243// routine to light top 5 lights in sequence 244// if score then send add 10 command to score 245// and chime unit 246{ 247 for (int i = 0; i < 5; i = i + 1) 248 { 249 if (score == 1 ) 250 { 251 Serial.print('b'); 252 Serial1.print ('b'); 253 } 254 leds [ i ] = CRGB::Black; 255 FastLED.show(); 256 delay (50); 257 // 258 leds [ i ] = CRGB::White; 259 FastLED.show(); 260 } 261} 262// 263void replay() 264{ 265 replays++; 266 Serial.print (replays); 267 Serial1.print ('K'); // activate knocker 268} 269void reset() 270{ 271 // Light all the LEDS 272 for (int i = 0; i < 70; i = i + 1) 273 { 274 leds[i] = CRGB::White; 275 } 276 FastLED.show(); 277 // switch off LEDs that are spare underneath playfield 278 leds [58] = CRGB::Black; 279 leds [9] = CRGB::Black; 280 // 281 FastLED.show(); 282 // switch of 4 special lights 283 leds [SY1] = CRGB::Black; 284 leds [SY2] = CRGB::Black; 285 leds [SR1] = CRGB::Black; 286 leds [SR2] = CRGB::Black; 287 // now switch OFF central FLYING CARPET Lights 288 for (int i = 0; i < 13; i = i + 1) 289 { 290 int FC_Lights = FCLamps[i]; 291 leds[FC_Lights] = CRGB::Black; 292 } 293 // Switch off Ball in play and Game Over LEDS 294 for (int i = 0; i < 6; i = i + 1) 295 { 296 leds[i + Ball_Lights] = CRGB::Black; 297 } 298 FastLED.show(); 299 digitalWrite(BlueLed_MOSFET_Driver, 0); 300 BallsPerGame = 5; 301 Balls = 0; 302 units = 0; 303 FCcount = 0; 304 Phit = 0; 305 Ahit = 0; 306 Yspecial = 0; 307 Rspecial = 0; 308 GameOver = 0; 309 SpecialON = 0; // = 1 if 'Y' target and -1 if R target 310 BlueBumper = 0; // = 1 to light; set to 2 when alight 311 for (int i = 0; i < 12; i++) 312 { 313 FC[i] = 0; 314 } 315 timer(); // intialise timer 316} 317void diag() 318// Diagnostic routine to determine if switch stuck 319// and all lights are working 320{ 321 // Light all the LEDS 322 for (int i = 0; i < 70; i = i + 1) 323 { 324 leds[i] = CRGB::White; 325 } 326 FastLED.show(); 327 delay (2000); // all LEDs ON 328 // all LEDS OFF 329 for (int i = 0; i < 70; i = i + 1) 330 { 331 leds [ i ] = CRGB::Black; 332 } 333 FastLED.show(); 334 delay (1500); 335 // Check coil switch state 336 // Normal start state for Coil Switch is HIGH 337 // Error codes are 1, 10, 100 for coil faults 338 if (digitalRead(B2_Bumper_Switch) == 0) 339 { 340 Serial.print ('a'); // indicate 1 341 GameOver = 1; 342 } 343 if (digitalRead(B1_Bumper_Switch) == 0) 344 { 345 Serial.print ('b'); // indicate 10 346 GameOver = 1; 347 } 348 if (digitalRead(B3_Bumper_Switch) == 0) 349 { 350 Serial.print ('c'); // indicate 100 351 GameOver = 1; 352 } 353 // check if any switches or targets are closed 354 // inputs on pins 36 to 47 355 for (int i = 36; i >= 47; i = i - 1) 356 { 357 int Switch = digitalRead(i); 358 if (Switch == 0 ) 359 { 360 // light faulty rollover or target letter in playfield centre 361 leds[i - 15] = CRGB::White; 362 GameOver = 1; 363 } 364 } 365} 366// 367void check_for_special(int letter) 368// completing F-L-Y-I-N-G C-A-R-P-E-T sequence lights 369// 'Y' Target and switch 370// alternatively 371// 'R' Target and switch 372{ 373 FC [letter] = 1; 374 int Lmp = FCLamps[letter]; 375 leds[Lmp] = CRGB::White; 376 int Tgt = FCTargetLamps[letter]; 377 leds[Tgt] = CRGB::Black; 378 int roll = FCswitchLamps[letter]; 379 leds[roll] = CRGB::Black; 380 FastLED.show(); 381 //check if special to be switched ON 382 FCcount = 0; 383 for (int i = 0; i < 12; i++) 384 { 385 if (FC[i] == 1) 386 { 387 FCcount = FCcount + 1; 388 } 389 } 390 // check for specials in LED Array 391 // and light special if 'Flying Carpet' fully lit 392 if (FCcount == 12) 393 { 394 SpecialON = !SpecialON; 395 if (SpecialON == 0 ) 396 { 397 Rspecial = 1; 398 Yspecial = 0; 399 leds[SY1] = CRGB::White; 400 leds[SY2] = CRGB::White; 401 leds[SR1] = CRGB::Black; 402 leds[SR2] = CRGB::Black; 403 FastLED.show(); 404 } 405 if (SpecialON == 1 ) 406 { 407 Yspecial = 1; 408 Rspecial = 0; 409 leds[SR1] = CRGB::White; 410 leds[SR2] = CRGB::White; 411 leds[SY1] = CRGB::Black; 412 leds[SY2] = CRGB::Black; 413 FastLED.show(); 414 } 415 } 416} 417// 418void Check_Bumpers() 419{ 420 GameOver = 0; 421 if (( B1_Coil_Trigger == LOW) && (B1_Coil_State_last == HIGH)) 422 { 423 B1_difference = B1_currentMillis - B1_ON_Time; 424 if (B1_difference >= Max_On_Time)GameOver = 1; 425 } 426 // 427 if (( B2_Coil_Trigger == LOW) && (B2_Coil_State_last == HIGH)) 428 { 429 B2_difference = B2_currentMillis - B2_ON_Time; 430 if (B2_difference >= Max_On_Time)GameOver = 1; 431 } 432 if (( B3_Coil_Trigger == LOW) && (B3_Coil_State_last == HIGH)) 433 { 434 B3_difference = B3_currentMillis - B3_ON_Time; 435 if (B3_difference >= Max_On_Time)GameOver = 1; 436 } 437} 438// 439void B1_Bumper_Hit() 440{ 441 B1_currentMillis = System_Base_Time; //Start Time 442 B1_Coil_State = digitalRead(B1_Bumper_Switch); //Variable for Coil Switch 443 if ((B1_Coil_State == LOW) && (B1_Coil_State_last == LOW)) 444 { 445 //Coil has been triggered 446 B1_ON_Time = B1_currentMillis; 447 B1_Coil_State_last = HIGH; 448 B1_previousMillis = millis(); 449 analogWrite(B1_MOSFET_Driver, 200); //Coil Solenoid activated ! 450 B1_Coil_Trigger = 1 ; 451 } 452 else if ((B1_Coil_State == HIGH) && (B1_Coil_State_last == HIGH)) 453 { 454 //Coil released 455 B1_Coil_State_last = LOW; 456 } 457 B1_difference = B1_currentMillis - B1_previousMillis; 458 if ((B1_difference >= debounce) && (B1_Coil_Trigger == 1)) 459 { 460 B1_previousMillis = B1_currentMillis; 461 B1_Coil_Trigger = 0; 462 analogWrite(B1_MOSFET_Driver, 0); //Coil Solenoid deactivated 463 if (BlueBumper > 0 ) 464 { 465 Serial.print ('c'); 466 Serial1.print ('c'); // to Chime 100 467 } 468 else 469 { 470 Serial.print ('b'); 471 Serial1.print ('b'); // to Slave Chime 10 472 } 473 } 474} 475// 476void B2_Bumper_Hit() 477{ 478 B2_currentMillis = System_Base_Time; //Start Time 479 B2_Coil_State = digitalRead(B2_Bumper_Switch); //Variable for Coil Switch 480 if ((B2_Coil_State == LOW) && (B2_Coil_State_last == LOW)) 481 { 482 //Coil has been triggered 483 B2_ON_Time = B2_currentMillis; 484 B2_Coil_State_last = HIGH; 485 B2_previousMillis = millis(); 486 analogWrite(B2_MOSFET_Driver, 200); //Coil Solenoid activated ! 487 B2_Coil_Trigger = 1 ; 488 489 } 490 else if ((B2_Coil_State == HIGH) && (B2_Coil_State_last == HIGH)) 491 { 492 //Coil released 493 B2_Coil_State_last = LOW; 494 } 495 B2_difference = B2_currentMillis - B2_previousMillis; 496 if ((B2_difference >= debounce) && (B2_Coil_Trigger == 1)) 497 { 498 B2_previousMillis = B2_currentMillis; 499 B2_Coil_Trigger = 0; 500 analogWrite(B2_MOSFET_Driver, 0); //Coil Solenoid deactivate 501 if (BlueBumper > 0 ) 502 { 503 Serial.print ('c'); 504 Serial1.print ('c'); // to Chime 100 505 } 506 else 507 { 508 Serial.print ('b'); 509 Serial1.print ('b'); // to Slave Chime 10 510 } 511 } 512} 513// 514void B3_Bumper_Hit() 515{ 516 B3_currentMillis = System_Base_Time; //Start Time 517 B3_Coil_State = digitalRead(B3_Bumper_Switch); //Variable for Coil Switch 518 if ((B3_Coil_State == LOW) && (B3_Coil_State_last == LOW)) 519 { 520 //Coil has been triggered 521 B3_ON_Time = B3_currentMillis; 522 B3_Coil_State_last = HIGH; 523 B3_previousMillis = millis(); 524 analogWrite(B3_MOSFET_Driver, 200); //Coil Solenoid activated ! 525 B3_Coil_Trigger = 1 ; 526 } 527 else if ((B3_Coil_State == HIGH) && (B3_Coil_State_last == HIGH)) 528 { 529 //Coil released 530 B3_Coil_State_last = LOW; 531 } 532 B3_difference = B3_currentMillis - B3_previousMillis; 533 if ((B3_difference >= debounce) && (B3_Coil_Trigger == 1)) 534 { 535 B3_previousMillis = B3_currentMillis; 536 B3_Coil_Trigger = 0; 537 analogWrite(B3_MOSFET_Driver, 0); //Coil Solenoid deactivated 538 Serial.print ('c'); 539 Serial1.print ('c'); 540 } 541} 542// 543void loop() 544{ 545 System_Base_Time = millis(); 546 if (GameOver == 1) 547 // Game Over light ON all others OFF 548 // set Gameover to 2 since we only want it to 549 // set the lights once 550 { 551 for (int i = 0; i < 70; i = i + 1) 552 { 553 leds [ i ] = CRGB::Black; 554 } 555 leds [ 41 ] = CRGB::White; 556 FastLED.show(); 557 GameOver = 2; 558 Serial1.print ('D'); // switch off aux processor 559 560 } 561 // timings are as follows: 562 // NOTE Targets can bounce for up to 200 milliseconds 563 // around 'loop'; approx 2 milli second for approx 20 564 // switch / target reads 565 // Score output 2 milliseconds (longer for 50 score) 566 // Pop Bumpers approx 2 milliseconds 567 // FastLED.show takes approx 2 to 3 milli seconds 568 // Flipper not applicable since not controlled by the MEGA board 569 // only commands to switch ON or OFF at start and end of game 570 // sent to Slave 1 UNO. 571 // 572 if (digitalRead(Redbutton) == 0) 573 // used to start game if no replays left 574 // add 1 to get a free game 575 { 576 waiton (Redbutton); 577 diag(); // error codes displayed on backglass 578 if (replays == 0) 579 { 580 replay(); // give a free replay 581 Serial1.print ('K'); // to AUX 1 GameOver 582 } // activate Knocker 583 replays = replays - 1; // reduce replays by 1 584 Serial.print (replays); // update backglass 585 Serial.print ('g'); // reset backglass score to "0000" 586 Serial1.print ('D'); // to AUX 1 GameOver 587 delay(1000); // allow a reset on slave processors 588 Serial1.print ('E'); // -> AUX 1 New Game 589 reset(); 590 // Deliver 1st ball ready for new game start 591 Balls = 1; 592 leds[46] = CRGB::White; 593 // activate solonoid to kick ball into shooter lane 594 analogWrite(Deliver_Ball_MOSFET_Driver, 200); 595 // give the right amount of kick,delay here no problem 596 // since nothing else happening 597 delay (50); 598 analogWrite(Deliver_Ball_MOSFET_Driver, 0); 599 TopRipple(0); 600 } 601 // Everything OK; so Game ON 602 if (GameOver == 0) 603 { 604 B1_Bumper_Hit(); 605 B2_Bumper_Hit(); 606 B3_Bumper_Hit(); 607 Check_Bumpers(); 608 switch_timer = 0; 609 if (digitalRead(Yellbutton) == 0) 610 { 611 waiton(Yellbutton); 612 leds[47 - Balls] = CRGB::Black; 613 Balls++; 614 leds[47 - Balls] = CRGB::White; 615 // If Game Over so tell backglass 616 if (Balls > BallsPerGame) 617 { 618 Serial.print ('x'); 619 Serial1.print ('X'); // to Slave 1 GameOver 620 GameOver = 1; 621 Balls = 0; // stops multiple Game Over 622 } 623 else 624 { 625 TopRipple(0); 626 // activate solonoid to kick ball into shooter lane 627 analogWrite(Deliver_Ball_MOSFET_Driver, 200); 628 // give the right amount of kick 629 delay (50); 630 analogWrite(Deliver_Ball_MOSFET_Driver, 0); 631 } 632 } 633 // 634 if (digitalRead(Tilt) == 0) 635 { 636 //light 'TILT' Lamp 637 waiton (Tilt); // wait for TILT sensor to stabalize 638 Serial.print ('t'); // inform backglass software 639 GameOver = 1; 640 } 641 // 642 if ((Phit == 1) && (Ahit == 1)) 643 { 644 if (BlueBumper == 0)BlueBumper = 1; 645 } 646 // 647 // Sling Shots 648 if (digitalRead(Slingshot) == 0) 649 { 650 waiton (Slingshot); // wait for button release 651 Serial.print ('a'); 652 Serial1.print ('a'); //to Chime 1 653 units++; 654 } 655 // switchs and Targets 656 // These are connected in parallel so no need for seperate code 657 // NOTE LEDS Lights for FLYING CARPET are numbered from 0 to 11 658 if (digitalRead(Fswitch) == 0) 659 { 660 waiton (Fswitch); // wait for button release 661 TopRipple(1); 662 // light appropriate light 663 check_for_special(0); 664 } 665 // 666 if (digitalRead(Lswitch) == 0) 667 { 668 waiton (Lswitch); // wait for button release 669 TopRipple(1); 670 // light appropriate light 671 check_for_special(1); 672 } 673 // 674 if (digitalRead(Yswitch) == 0) 675 { 676 waiton (Yswitch); // wait for button release 677 TopRipple(1); 678 // light appropriate light 679 check_for_special(2); 680 if (Yspecial == 1 ) 681 { 682 // although Replays are awarded, they are for 683 // AMUSEMENT ONLY 684 // The display software will ingores replays above 9 685 replays++; 686 Serial.print (replays); 687 Serial1.print ('R'); 688 } 689 } 690 // 691 if (digitalRead(Iswitch) == 0) 692 { 693 waiton (Iswitch); // wait for button release 694 TopRipple(1); 695 //light appropriate light 696 check_for_special(3); 697 } 698 // 699 if (digitalRead(Nswitch) == 0) 700 { 701 waiton (Nswitch); // wait for button release 702 TopRipple(1); 703 //light appropriate light 704 check_for_special(4); 705 } 706 // 707 if (digitalRead(Gswitch) == 0) 708 { 709 waiton (Gswitch); // wait for button release 710 TopRipple(1); 711 //light appropriate light 712 check_for_special(5); 713 } 714 if (digitalRead(Cswitch) == 0) 715 { 716 waiton (Cswitch); // wait for button release 717 timer(); 718 if (switch_timer == 0) 719 { 720 Serial.print ('c'); 721 Serial1.print ('c'); 722 //light appropriate light 723 check_for_special(6); 724 } 725 } 726 // 727 if (digitalRead(Aswitch) == 0) 728 { 729 waiton (Aswitch); // wait for button release 730 timer(); 731 if (switch_timer == 0) 732 { 733 Serial.print ('c'); 734 Serial1.print ('c'); 735 Ahit = 1; 736 //light appropriate light 737 check_for_special(7); 738 } 739 } 740 // 741 if (digitalRead(Rswitch) == 0) 742 { 743 waiton (Rswitch); // wait for button release 744 timer(); 745 if (switch_timer == 0) 746 { 747 Serial.print ('c'); 748 Serial1.print ('c'); 749 //light appropriate light 750 check_for_special(8); 751 if (Rspecial == 1 ) 752 { 753 // although Replays are awarded, they are for 754 // AMUSEMENT ONLY 755 replay(); 756 } 757 } 758 } 759 // 760 if (digitalRead(Pswitch) == 0) 761 { 762 waiton (Pswitch); // wait for button release 763 timer(); 764 if (switch_timer == 0) 765 { 766 Serial.print ('c'); 767 Serial1.print ('c'); 768 //light appropriate light 769 check_for_special(9); 770 Phit = 1; 771 } 772 } 773 // 774 if (digitalRead(Eswitch) == 0) 775 { 776 waiton (Eswitch); // wait for button release 777 timer(); 778 if (switch_timer == 0) 779 { 780 Serial.print ('c'); 781 Serial1.print ('c'); 782 //light appropriate light 783 check_for_special(10); 784 } 785 } 786 // 787 if (digitalRead(Tswitch) == 0) 788 { 789 waiton (Tswitch); // wait for button release 790 timer(); 791 { 792 if (switch_timer == 0) 793 { 794 Serial.print ('c'); 795 Serial1.print ('c'); 796 } 797 //light appropriate light 798 check_for_special(11); 799 } 800 } 801 } 802} 803
UNO for Flippers, Knocker and Chimes
arduino
1// Version 2.0 13/11/20 2// GOTTLIEB Flying Carpet EM Pinball with a ARDUINO's 3// replacing the EM Stuff and LEDS replacing bulbs. 4// Written by B J Mclaren based on experience of doing 5// an ARDUINO based Bally Bingo 6// This solution uses: 7// A MEGA as the Master controller for the Playfield stuff 8// AUX1 (UNO) has 6 pwm channels for Chime Unit, Flippers 9// and Knocker 10// This is the AUX1 code for an UNO and a FREETRONICS 6 Channel 11// MOSFET Shield 12// 13// Valid Commands are 14// 'a' = 1st score chime 15// 'b' = 2nd score chime 16// 'c' = 3rd score chime 17// 'K' = Knocker 18// 'E' = Enable AUX processor 19// 'D' = Disable AUX processor (eg Game Over / Tilt) 20// 21#define Right_Flipper_Switch A0 22#define Left_Flipper_Switch A1 23// 24#define Chime1_Driver 3 25#define Chime2_Driver 5 26#define Chime3_Driver 6 27#define Knocker_Driver 9 28#define Left_Flipper_Driver 10 29#define Right_Flipper_Driver 11 30// 31#define On_Time 50 // Chime ON Time in ms 32#define LED 13 33char ch; 34int GameON; 35int LFlipperON = 0; 36int RFlipperON = 0; 37int Chime1ON = 0; 38int Chime2ON = 0; 39int Chime3ON = 0; 40int KnockerON = 0; 41int LPWM = 0; 42int RPWM = 0; 43// 44unsigned long System_Time = 0; 45unsigned long Chime1ON_Time = 0; 46unsigned long Chime2ON_Time = 0; 47unsigned long Chime3ON_Time = 0; 48unsigned long KnockerON_Time = 0; 49unsigned long LFlipperON_Time = 0; 50unsigned long RFlipperON_Time = 0; 51unsigned long diff = 0; 52// 53void setup() 54{ 55 Serial.begin (9600); 56 pinMode(LED, OUTPUT); 57 digitalWrite(LED, LOW); 58 // 59 pinMode(Chime1_Driver, OUTPUT); 60 digitalWrite(Chime1_Driver, LOW); 61 pinMode(Chime2_Driver, OUTPUT); 62 digitalWrite(Chime2_Driver, LOW); 63 pinMode(Chime3_Driver, OUTPUT); 64 digitalWrite(Chime3_Driver, LOW); 65 // 66 pinMode(Knocker_Driver, OUTPUT); 67 digitalWrite(Knocker_Driver, LOW); 68 // 69 pinMode(Right_Flipper_Switch, INPUT_PULLUP); 70 analogWrite(Right_Flipper_Driver, 0); 71 // 72 pinMode(Left_Flipper_Switch, INPUT_PULLUP); 73 analogWrite(Left_Flipper_Driver, 0); 74 // Setup Variables 75 GameON = 0; 76 LFlipperON = 0; 77 RFlipperON = 0; 78 System_Time = 0; 79 Chime1ON = 0; // Flag to indicate chime is ctive 80 Chime2ON = 0; 81 Chime3ON = 0; 82 KnockerON = 0; 83 System_Time = 0; // base time for timing operations 84 Chime1ON_Time = 0; // time chime became active 85 Chime2ON_Time = 0; 86 Chime3ON_Time = 0; 87 LFlipperON_Time = 0; 88 RFlipperON_Time = 0; 89 diff = 0; 90 // 91} 92// 93void loop() 94{ 95 System_Time = millis(); 96 // 97 if (RFlipperON == 1 ) 98 { 99 diff = System_Time - RFlipperON_Time; 100 // if flipper held for 1 seconds reduce power 101 if (diff > 1000) 102 { 103 RPWM = 190; 104 } 105 } 106 if (LFlipperON == 1 ) 107 { 108 diff = System_Time - LFlipperON_Time; 109 // if flipper held for 1 seconds reduce power 110 if (diff > 1000) 111 { 112 LPWM = 190; 113 } 114 } 115 // 116 if (KnockerON == 1 ) 117 { 118 diff = System_Time - KnockerON_Time; 119 if (diff > On_Time ) 120 { 121 KnockerON = 0; 122 digitalWrite(Knocker_Driver, LOW); 123 } 124 } 125 if (Chime1ON == 1 ) 126 { 127 diff = System_Time - Chime1ON_Time; 128 if (diff > On_Time ) 129 { 130 Chime1ON = 0; 131 digitalWrite(Chime1_Driver, LOW); 132 } 133 } 134 if (Chime2ON == 1 ) 135 { 136 diff = System_Time - Chime2ON_Time; 137 if (diff > On_Time ) 138 { 139 Chime2ON = 0; 140 digitalWrite(Chime2_Driver, LOW); 141 } 142 } 143 if (Chime3ON == 1 ) 144 { 145 diff = System_Time - Chime3ON_Time; 146 if (diff > On_Time ) 147 { 148 Chime3ON = 0; 149 digitalWrite(Chime3_Driver, LOW); 150 } 151 } 152 // 153 if (Serial.available() > 0) 154 { 155 // Read input from ARDUINO MEGA 156 ch = Serial.read(); 157 if (ch == 'E') 158 { // enable processor eg New Game 159 GameON = 1; 160 digitalWrite(LED, HIGH); 161 System_Time = 0; 162 Chime1ON = 0; 163 Chime2ON = 0; 164 Chime3ON = 0; 165 KnockerON = 0; 166 LFlipperON = 0; 167 RFlipperON = 0; 168 } 169 if (ch == 'D') 170 { // disable processor Game Over / Tilt 171 GameON = 0; 172 digitalWrite(LED, LOW); 173 analogWrite(Left_Flipper_Driver, 0); 174 analogWrite(Right_Flipper_Driver, 0); 175 } 176 // 177 if (ch == 'K') 178 { 179 // activate Knocker 180 digitalWrite(Knocker_Driver, HIGH); 181 KnockerON = 1; 182 KnockerON_Time = millis(); 183 } 184 if (ch == 'a') 185 { // activate 1st Chime 186 digitalWrite(Chime1_Driver, HIGH); 187 Chime1ON = 1; 188 Chime1ON_Time = millis(); 189 } 190 if (ch == 'b') 191 { // activate 2nd Chime 192 digitalWrite(Chime2_Driver, HIGH); 193 Chime2ON = 1; 194 Chime2ON_Time = millis(); 195 } 196 if (ch == 'c') 197 { // activate 3rd Chime 198 digitalWrite(Chime3_Driver, HIGH); 199 Chime3ON = 1; 200 Chime3ON_Time = millis(); 201 } 202 } 203 // Switch Off Flipper 204 if (digitalRead(Right_Flipper_Switch) == HIGH) 205 { //Flipper OFF 206 analogWrite(Right_Flipper_Driver, 0); 207 RFlipperON = 0; 208 RPWM = 255; 209 } 210 if (digitalRead(Left_Flipper_Switch) == HIGH) 211 { //Flipper OFF 212 analogWrite(Left_Flipper_Driver, 0); 213 LFlipperON = 0; 214 LPWM = 255; 215 } 216 if (GameON == 1) 217 { // Flipper active only when Game is on 218 if (digitalRead(Right_Flipper_Switch) == LOW) 219 { 220 analogWrite(Right_Flipper_Driver, RPWM ); 221 if ( RFlipperON == 0) 222 { 223 RFlipperON_Time = millis(); 224 } 225 RFlipperON = 1; 226 } 227 if (digitalRead(Left_Flipper_Switch) == LOW) 228 { // Left Flipper ON 229 analogWrite(Left_Flipper_Driver, LPWM ); 230 if ( LFlipperON == 0) 231 { 232 LFlipperON_Time = millis(); 233 } 234 LFlipperON = 1; 235 } 236 } 237} 238
Processing P3 for backglass PC
processing
Used to display score and backglass graphics
1import processing.serial.*; 2import ddf.minim.*; 3Minim minim; 4AudioPlayer base; 5AudioPlayer chime100; 6AudioPlayer chime10; 7AudioPlayer chime1; 8AudioPlayer reel; 9// 10Serial myPort; // The serial port: 11PImage bg; 12PImage img []; 13int y=205; 14int x0=639; 15int x1=737; 16int x2=835; 17int x3=933; 18// 19// Highest Score Variable 20int highscore; 21int highscoreones; 22int highscoretens; 23int highscorehundreds; 24int highscorethous; 25// 26int d; 27int thous; 28int hundreds; 29int tens; 30int ones; 31int oldthous; 32int oldhundreds; 33int oldtens; 34int oldones; 35int oldscore; 36int newscore; 37int add; 38int reset; 39// 40// 41void setup() 42{ 43 minim = new Minim(this); 44 base = minim.loadFile("base.wav"); 45 chime100 = minim.loadFile("chime100.wav"); 46 chime10 = minim.loadFile("chime10.wav"); 47 chime1 = minim.loadFile("chime1.wav"); 48 reel=minim.loadFile("reel.wav"); 49 // 50 myPort = new Serial(this, Serial.list()[0], 9600); 51 //size(978,1080); 52 //bg = loadImage("FC1.png"); 53 size(1080,1193); 54 bg = loadImage("FC.png"); 55 newscore = 0; 56 int nPics = 10; 57 img = new PImage [nPics]; 58 for (int i = 0; i <nPics; i++) 59 { 60 img[i] = loadImage(+i+".jpg"); 61 } 62 background(bg); 63// 64} 65// 66void display() 67{ 68 oldthous = thous; 69 oldhundreds = hundreds; 70 oldtens = tens; 71 oldones = ones; 72 oldscore = newscore; 73 if(oldscore>9999)oldscore=0; 74 thous = int(oldscore/1000); 75 hundreds = int(oldscore/100); 76 hundreds = hundreds-(int(hundreds/10)*10); 77 tens = int(oldscore/10); 78 tens = tens-(int(tens/10)*10); 79 ones = oldscore-(int(oldscore/10)*10); 80 // 81 image(img[ones], x3, y); 82 image(img[tens], x2, y); 83 image(img[hundreds], x1, y); 84 image(img[thous], x0, y); 85 delay(20); 86} 87// 88void draw() 89 { 90 if (reset==1) 91 { 92 int total=ones+(10*tens)+(100*hundreds)+(1000*thous); 93 if (total == 0) 94 { 95 reset=0; 96 ones=0; 97 tens=0; 98 hundreds=0; 99 thous=0; 100 newscore=0; 101 oldscore=0; 102 } 103// 104 if (ones != 0) 105 { 106 ones=ones+1; 107 if (ones==10)ones=0; 108 image(img[ones], x3, y); 109 reel.rewind(); 110 reel.play(); 111 delay(75); 112 } 113// 114 if (tens != 0) 115 { 116 tens=tens+1; 117 if (tens==10)tens=0; 118 image(img[tens], x2, y); 119 reel.rewind(); 120 reel.play(); 121 delay(75); 122 } 123// 124 if (hundreds != 0) 125 { 126 hundreds=hundreds+1; 127 if (hundreds==10)hundreds=0; 128 image(img[hundreds], x1, y); 129 reel.rewind(); 130 reel.play(); 131 delay(75); 132 } 133 if (thous != 0) 134 { 135 thous=thous+1; 136 if (thous==10)thous=0; 137 image(img[thous], x0, y); 138 reel.rewind(); 139 reel.play(); 140 delay(75); 141 } 142 } 143// Process any inputs 144 while (myPort.available() > 0) 145 { 146 char inByte = myPort.readChar(); 147// 148 if (inByte == 'x') 149 { 150 base.rewind(); 151 base.play(); 152 } 153 if (inByte == 'g') 154 { 155 reset = 1; 156 base.rewind(); 157 base.play(); 158 add=0; 159 } 160 if (inByte == 'a') 161 { 162 add = 1; 163 chime1.rewind(); 164 chime1.play(); 165 } 166 if (inByte == 'b') 167 { 168 add = 10; 169 chime10.rewind(); 170 chime10.play(); 171 } 172 if (inByte == 'c') 173 { 174 add = 100; 175 chime100.rewind(); 176 chime100.play(); 177 } 178 if (add>0) 179 { 180 oldscore = newscore; 181 newscore = newscore+add; 182 add=0; 183 } 184 display(); 185 } 186} 187
Main MEGA processor
arduino
Arduino Pinball machine
1#include <FastLED.h> 2// GOTTLIEB EM Pinball with a ARDUINO MEGA 3// replacing the EM Stuff and LEDS replacing bulbs 4// Written by B J Mclaren 5// based on experience of building an ARDUINO based Bally Bingo 6// This is currenty for FLYING CARPET but will be able to 7// play DUOTRON in future (Next release). 8// Special thanks to all involved in ARDUINO Pinballs. 9// Most of the code is original except some Bumper stuff 10// This solution used distributed processing with a MEGA 11// as the Master controller 12// UNO's as Auxillary Controllers for Chimes etc 13// an extra UNO when more than 12 solenoids are required (DUOTRON) 14// Processing 3(see processing.org)for Backglass (+ Sound if no Chime Unit) 15// A PC, (a Fanless PC is powerfull enough) to run the 16// software to drive a 40" LCD TV Backglass. 17// 18// There are 6 channels on each MOSFET Board. 19// PWM Pins used by the driver are 3,5,6,9,10,11 20// Board 1 ( MASTER ) mounted on MEGA is for 3 POP Bumper 21// and Ball delivery + 2 Spares 22// a single MOSFET Driver is used for the 100 points LED 23// There are 6 channels on MOSFET Board 2 24// Board 2 ( SLAVE 1 )mounted on UNO for chimes, Knocker and flippers 25// Board 3 ( SLAVE 2 )future expansion eg DUOTRON 26// Board 1 utilises a 12 Volt PSU 27// Board 2 utilises a 15 Volt PSU 28// A total of 18 solenoid Drivers can be provided 29// Comms to Slave 1 and Slave 2 via RS232 30// later versions may use I2C (so reserve A4 and A5) 31// 32// Switch and Targets ARDUINO Pins 33#define Fswitch 36 34#define Lswitch 37 35#define Yswitch 38 36#define Iswitch 39 37#define Nswitch 40 38#define Gswitch 41 39// 40#define Cswitch 42 41#define Aswitch 43 42#define Rswitch 44 43#define Pswitch 45 44#define Eswitch 46 45#define Tswitch 47 46// Misc Switches and Buttons 47#define Redbutton 27 48#define Yellbutton 28 49#define Tilt 34 50#define Slingshot 35 //ALL score slingshots are in parallel 51// 52#define B1_Bumper_Switch 29 53#define B1_MOSFET_Driver 5 54// 55#define B2_Bumper_Switch 31 56#define B2_MOSFET_Driver 3 57// 58#define B3_Bumper_Switch 30 59#define B3_MOSFET_Driver 6 60// 61#define Deliver_Ball_MOSFET_Driver 9 62// 63#define BlueLed_MOSFET_Driver 4 // Lit when 100 points 64#define Spare1_MOSFET_Driver 10 65#define Spare2_MOSFET_Driver 11 66// 67// Array for LEDs for playfield 68#define NUM_LEDS 70 //Space for up to 70 LEDS 69#define DATA_PIN A0 70// 71#define Ball_Lights 41 // Offset for Balls played LEDS 72#define On_Time 40 // Solenoids ON Time in ms 73// 74CRGB leds[NUM_LEDS]; 75// This section defined the index into the LED arrays 76// LED's for "FLYING CARPET" in centre of playfield 77int FCLamps [13] = 78{ 79 21, 22, 24, 25, 27, 28, 34, 33, 32, 31, 30, 29, 0 80}; 81// switch LED's on Playfield 82int FCswitchLamps [13] = 83{ 84 17, 8, 57, 5, 35, 50, 54, 6, 13, 7, 49, 36, 0 85}; 86// Target LED's on Playfield 87int FCTargetLamps [13] = 88{ 89 59, 20, 9, 51, 11, 60, 12, 52, 14, 19, 61, 10, 0 90}; 91// Index for special targets 92#define SR1 16 //Special R Target 1 93#define SY1 23 //Special Y Target 1 94#define SR2 26 //Special R Target 2 95#define SY2 56 //Special Y Target 2 96// 97// 12 slots to indicate "FLYING CARPET" Targets/Rollovers hit 98int FC[13]; // slots 0 and 13 not used 99int Balls = 0; 100int RandNumber = 0; // Lucky Matching number 101int BallsPerGame = 5; 102int GameOver = 1; 103int FCcount = 0; // count of numbers of FC lights ON 104int SpecialON = 0; // Special ON 105int BlueBumper = 0; // Blue Score 100 if set to 1 106int Phit = 0; // set if P rollover or target hit 107int Ahit = 0; // set if A rollover or target hit 108// if both hit Blue bumper score 100 109int Yspecial = 0; 110int Rspecial = 0; 111int replays = 0; 112int units = 0; // keep track of units for Lucky Number 113int switch_timer = 0; // determine if multi reports of a target hit 114int debounce = 50; // switch debounce in mills 115// Variables for target handling 116unsigned long System_Base_Time = 0; 117unsigned long Target_Hit_Time = 0; 118unsigned long Old_Target_Hit_Time = 0; 119unsigned long diff = 0; 120// Bumper timing stuff 121unsigned long B1_previousMillis = 0; 122unsigned long B1_currentMillis = 0; 123unsigned long B1_ON_Time = 0; 124// 125int B1_Coil_Trigger = 0; 126int B1_Coil_State_last = LOW; 127int B1_Coil_State; 128int B1_difference; 129// 130unsigned long B2_previousMillis = 0; 131unsigned long B2_currentMillis = 0; 132unsigned long B2_ON_Time = 0; 133// 134int B2_Coil_Trigger = 0; 135int B2_Coil_State_last = LOW; 136int B2_Coil_State; 137int B2_difference; 138// 139unsigned long B3_previousMillis = 0; 140unsigned long B3_currentMillis = 0; 141unsigned long B3_ON_Time = 0; 142// 143int B3_Coil_Trigger = 0; 144int B3_Coil_State_last = LOW; 145int B3_Coil_State; 146int B3_difference; 147// 148unsigned long end_time = 0; // used for timing 149unsigned long total_time = 0; 150// Max time before switching off bumpers to stop coil burnup 151int Max_On_Time = 1000; // 152void setup() 153{ 154 pinMode(Deliver_Ball_MOSFET_Driver, OUTPUT); 155 analogWrite(Deliver_Ball_MOSFET_Driver, 0); 156 // 157 pinMode(Spare1_MOSFET_Driver, OUTPUT); 158 analogWrite(Spare1_MOSFET_Driver, 0); 159 // 160 pinMode(Spare2_MOSFET_Driver, OUTPUT); 161 analogWrite(Spare2_MOSFET_Driver, 0); 162 // 163 pinMode(BlueLed_MOSFET_Driver, OUTPUT); 164 digitalWrite (BlueLed_MOSFET_Driver, 0); 165 // Pop Bumpers 166 pinMode(B1_Bumper_Switch, INPUT_PULLUP); 167 pinMode(B1_MOSFET_Driver, OUTPUT); 168 analogWrite(B1_MOSFET_Driver, 0); 169 // 170 pinMode(B2_Bumper_Switch, INPUT_PULLUP); 171 pinMode(B2_MOSFET_Driver, OUTPUT); 172 analogWrite(B2_MOSFET_Driver, 0); 173 // 174 pinMode(B3_Bumper_Switch, INPUT_PULLUP); 175 pinMode(B3_MOSFET_Driver, OUTPUT); 176 analogWrite(B3_MOSFET_Driver, 0); 177 // LEDS 178 FastLED.addLeds<WS2811, DATA_PIN, BRG>(leds, NUM_LEDS); 179 FastLED.setBrightness(100); 180 FastLED.show(); 181 // Switches and Targets 182 pinMode(Fswitch, INPUT_PULLUP); 183 pinMode(Lswitch, INPUT_PULLUP); 184 pinMode(Yswitch, INPUT_PULLUP); 185 pinMode(Iswitch, INPUT_PULLUP); 186 pinMode(Nswitch, INPUT_PULLUP); 187 pinMode(Gswitch, INPUT_PULLUP); 188 // 189 pinMode(Cswitch, INPUT_PULLUP); 190 pinMode(Aswitch, INPUT_PULLUP); 191 pinMode(Rswitch, INPUT_PULLUP); 192 pinMode(Pswitch, INPUT_PULLUP); 193 pinMode(Eswitch, INPUT_PULLUP); 194 pinMode(Tswitch, INPUT_PULLUP); 195 // 196 pinMode(Slingshot, INPUT_PULLUP); 197 pinMode(Tilt, INPUT_PULLUP); 198 // Game Start Stuff 199 pinMode(Redbutton, INPUT_PULLUP); 200 pinMode(Yellbutton, INPUT_PULLUP); 201 // 202 Serial.begin (9600); // -> Tv Monitor via Processing I3 on PC or PI 203 Serial1.begin (9600); // chime unit, ball delivery anf flippers 204} 205// 206void Lucky() 207// Are we Lucky today? 208// match number for replay 209// For Fun Only as we are a Free Play Machine 210{ 211 int u = units - (int(units / 10) * 10); 212 int r = random (0, 9); 213 if (r == u) 214 { 215 replay(); 216 } 217} 218// 219void timer () 220// Used to determine if a Target is bouncing causing 221// multiple reporting of a hit 222// this routine determines the time in milli seconds 223// since the last target hit 224// Currenty set to 200 ms - unlikely 2 targets can be 225// hit within 200ms 226{ 227 Target_Hit_Time = millis(); 228 diff = Target_Hit_Time - Old_Target_Hit_Time; 229 Old_Target_Hit_Time = Target_Hit_Time; 230 if (diff < 200 )switch_timer = 1; // adjust time to suit machine 231} 232// 233void waiton (int pin) 234{ 235 delay (debounce); // let switch settle 236 while (digitalRead(pin) == 0 ) 237 { 238 delay (debounce); 239 } 240}// end of waiton 241// 242void TopRipple(int score) 243// routine to light top 5 lights in sequence 244// if score then send add 10 command to score 245// and chime unit 246{ 247 for (int i = 0; i < 5; i = i + 1) 248 { 249 if (score == 1 ) 250 { 251 Serial.print('b'); 252 Serial1.print ('b'); 253 } 254 leds [ i ] = CRGB::Black; 255 FastLED.show(); 256 delay (50); 257 // 258 leds [ i ] = CRGB::White; 259 FastLED.show(); 260 } 261} 262// 263void replay() 264{ 265 replays++; 266 Serial.print (replays); 267 Serial1.print ('K'); // activate knocker 268} 269void reset() 270{ 271 // Light all the LEDS 272 for (int i = 0; i < 70; i = i + 1) 273 { 274 leds[i] = CRGB::White; 275 } 276 FastLED.show(); 277 // switch off LEDs that are spare underneath playfield 278 leds [58] = CRGB::Black; 279 leds [9] = CRGB::Black; 280 // 281 FastLED.show(); 282 // switch of 4 special lights 283 leds [SY1] = CRGB::Black; 284 leds [SY2] = CRGB::Black; 285 leds [SR1] = CRGB::Black; 286 leds [SR2] = CRGB::Black; 287 // now switch OFF central FLYING CARPET Lights 288 for (int i = 0; i < 13; i = i + 1) 289 { 290 int FC_Lights = FCLamps[i]; 291 leds[FC_Lights] = CRGB::Black; 292 } 293 // Switch off Ball in play and Game Over LEDS 294 for (int i = 0; i < 6; i = i + 1) 295 { 296 leds[i + Ball_Lights] = CRGB::Black; 297 } 298 FastLED.show(); 299 digitalWrite(BlueLed_MOSFET_Driver, 0); 300 BallsPerGame = 5; 301 Balls = 0; 302 units = 0; 303 FCcount = 0; 304 Phit = 0; 305 Ahit = 0; 306 Yspecial = 0; 307 Rspecial = 0; 308 GameOver = 0; 309 SpecialON = 0; // = 1 if 'Y' target and -1 if R target 310 BlueBumper = 0; // = 1 to light; set to 2 when alight 311 for (int i = 0; i < 12; i++) 312 { 313 FC[i] = 0; 314 } 315 timer(); // intialise timer 316} 317void diag() 318// Diagnostic routine to determine if switch stuck 319// and all lights are working 320{ 321 // Light all the LEDS 322 for (int i = 0; i < 70; i = i + 1) 323 { 324 leds[i] = CRGB::White; 325 } 326 FastLED.show(); 327 delay (2000); // all LEDs ON 328 // all LEDS OFF 329 for (int i = 0; i < 70; i = i + 1) 330 { 331 leds [ i ] = CRGB::Black; 332 } 333 FastLED.show(); 334 delay (1500); 335 // Check coil switch state 336 // Normal start state for Coil Switch is HIGH 337 // Error codes are 1, 10, 100 for coil faults 338 if (digitalRead(B2_Bumper_Switch) == 0) 339 { 340 Serial.print ('a'); // indicate 1 341 GameOver = 1; 342 } 343 if (digitalRead(B1_Bumper_Switch) == 0) 344 { 345 Serial.print ('b'); // indicate 10 346 GameOver = 1; 347 } 348 if (digitalRead(B3_Bumper_Switch) == 0) 349 { 350 Serial.print ('c'); // indicate 100 351 GameOver = 1; 352 } 353 // check if any switches or targets are closed 354 // inputs on pins 36 to 47 355 for (int i = 36; i >= 47; i = i - 1) 356 { 357 int Switch = digitalRead(i); 358 if (Switch == 0 ) 359 { 360 // light faulty rollover or target letter in playfield centre 361 leds[i - 15] = CRGB::White; 362 GameOver = 1; 363 } 364 } 365} 366// 367void check_for_special(int letter) 368// completing F-L-Y-I-N-G C-A-R-P-E-T sequence lights 369// 'Y' Target and switch 370// alternatively 371// 'R' Target and switch 372{ 373 FC [letter] = 1; 374 int Lmp = FCLamps[letter]; 375 leds[Lmp] = CRGB::White; 376 int Tgt = FCTargetLamps[letter]; 377 leds[Tgt] = CRGB::Black; 378 int roll = FCswitchLamps[letter]; 379 leds[roll] = CRGB::Black; 380 FastLED.show(); 381 //check if special to be switched ON 382 FCcount = 0; 383 for (int i = 0; i < 12; i++) 384 { 385 if (FC[i] == 1) 386 { 387 FCcount = FCcount + 1; 388 } 389 } 390 // check for specials in LED Array 391 // and light special if 'Flying Carpet' fully lit 392 if (FCcount == 12) 393 { 394 SpecialON = !SpecialON; 395 if (SpecialON == 0 ) 396 { 397 Rspecial = 1; 398 Yspecial = 0; 399 leds[SY1] = CRGB::White; 400 leds[SY2] = CRGB::White; 401 leds[SR1] = CRGB::Black; 402 leds[SR2] = CRGB::Black; 403 FastLED.show(); 404 } 405 if (SpecialON == 1 ) 406 { 407 Yspecial = 1; 408 Rspecial = 0; 409 leds[SR1] = CRGB::White; 410 leds[SR2] = CRGB::White; 411 leds[SY1] = CRGB::Black; 412 leds[SY2] = CRGB::Black; 413 FastLED.show(); 414 } 415 } 416} 417// 418void Check_Bumpers() 419{ 420 GameOver = 0; 421 if (( B1_Coil_Trigger == LOW) && (B1_Coil_State_last == HIGH)) 422 { 423 B1_difference = B1_currentMillis - B1_ON_Time; 424 if (B1_difference >= Max_On_Time)GameOver = 1; 425 } 426 // 427 if (( B2_Coil_Trigger == LOW) && (B2_Coil_State_last == HIGH)) 428 { 429 B2_difference = B2_currentMillis - B2_ON_Time; 430 if (B2_difference >= Max_On_Time)GameOver = 1; 431 } 432 if (( B3_Coil_Trigger == LOW) && (B3_Coil_State_last == HIGH)) 433 { 434 B3_difference = B3_currentMillis - B3_ON_Time; 435 if (B3_difference >= Max_On_Time)GameOver = 1; 436 } 437} 438// 439void B1_Bumper_Hit() 440{ 441 B1_currentMillis = System_Base_Time; //Start Time 442 B1_Coil_State = digitalRead(B1_Bumper_Switch); //Variable for Coil Switch 443 if ((B1_Coil_State == LOW) && (B1_Coil_State_last == LOW)) 444 { 445 //Coil has been triggered 446 B1_ON_Time = B1_currentMillis; 447 B1_Coil_State_last = HIGH; 448 B1_previousMillis = millis(); 449 analogWrite(B1_MOSFET_Driver, 200); //Coil Solenoid activated ! 450 B1_Coil_Trigger = 1 ; 451 } 452 else if ((B1_Coil_State == HIGH) && (B1_Coil_State_last == HIGH)) 453 { 454 //Coil released 455 B1_Coil_State_last = LOW; 456 } 457 B1_difference = B1_currentMillis - B1_previousMillis; 458 if ((B1_difference >= debounce) && (B1_Coil_Trigger == 1)) 459 { 460 B1_previousMillis = B1_currentMillis; 461 B1_Coil_Trigger = 0; 462 analogWrite(B1_MOSFET_Driver, 0); //Coil Solenoid deactivated 463 if (BlueBumper > 0 ) 464 { 465 Serial.print ('c'); 466 Serial1.print ('c'); // to Chime 100 467 } 468 else 469 { 470 Serial.print ('b'); 471 Serial1.print ('b'); // to Slave Chime 10 472 } 473 } 474} 475// 476void B2_Bumper_Hit() 477{ 478 B2_currentMillis = System_Base_Time; //Start Time 479 B2_Coil_State = digitalRead(B2_Bumper_Switch); //Variable for Coil Switch 480 if ((B2_Coil_State == LOW) && (B2_Coil_State_last == LOW)) 481 { 482 //Coil has been triggered 483 B2_ON_Time = B2_currentMillis; 484 B2_Coil_State_last = HIGH; 485 B2_previousMillis = millis(); 486 analogWrite(B2_MOSFET_Driver, 200); //Coil Solenoid activated ! 487 B2_Coil_Trigger = 1 ; 488 489 } 490 else if ((B2_Coil_State == HIGH) && (B2_Coil_State_last == HIGH)) 491 { 492 //Coil released 493 B2_Coil_State_last = LOW; 494 } 495 B2_difference = B2_currentMillis - B2_previousMillis; 496 if ((B2_difference >= debounce) && (B2_Coil_Trigger == 1)) 497 { 498 B2_previousMillis = B2_currentMillis; 499 B2_Coil_Trigger = 0; 500 analogWrite(B2_MOSFET_Driver, 0); //Coil Solenoid deactivate 501 if (BlueBumper > 0 ) 502 { 503 Serial.print ('c'); 504 Serial1.print ('c'); // to Chime 100 505 } 506 else 507 { 508 Serial.print ('b'); 509 Serial1.print ('b'); // to Slave Chime 10 510 } 511 } 512} 513// 514void B3_Bumper_Hit() 515{ 516 B3_currentMillis = System_Base_Time; //Start Time 517 B3_Coil_State = digitalRead(B3_Bumper_Switch); //Variable for Coil Switch 518 if ((B3_Coil_State == LOW) && (B3_Coil_State_last == LOW)) 519 { 520 //Coil has been triggered 521 B3_ON_Time = B3_currentMillis; 522 B3_Coil_State_last = HIGH; 523 B3_previousMillis = millis(); 524 analogWrite(B3_MOSFET_Driver, 200); //Coil Solenoid activated ! 525 B3_Coil_Trigger = 1 ; 526 } 527 else if ((B3_Coil_State == HIGH) && (B3_Coil_State_last == HIGH)) 528 { 529 //Coil released 530 B3_Coil_State_last = LOW; 531 } 532 B3_difference = B3_currentMillis - B3_previousMillis; 533 if ((B3_difference >= debounce) && (B3_Coil_Trigger == 1)) 534 { 535 B3_previousMillis = B3_currentMillis; 536 B3_Coil_Trigger = 0; 537 analogWrite(B3_MOSFET_Driver, 0); //Coil Solenoid deactivated 538 Serial.print ('c'); 539 Serial1.print ('c'); 540 } 541} 542// 543void loop() 544{ 545 System_Base_Time = millis(); 546 if (GameOver == 1) 547 // Game Over light ON all others OFF 548 // set Gameover to 2 since we only want it to 549 // set the lights once 550 { 551 for (int i = 0; i < 70; i = i + 1) 552 { 553 leds [ i ] = CRGB::Black; 554 } 555 leds [ 41 ] = CRGB::White; 556 FastLED.show(); 557 GameOver = 2; 558 Serial1.print ('D'); // switch off aux processor 559 560 } 561 // timings are as follows: 562 // NOTE Targets can bounce for up to 200 milliseconds 563 // around 'loop'; approx 2 milli second for approx 20 564 // switch / target reads 565 // Score output 2 milliseconds (longer for 50 score) 566 // Pop Bumpers approx 2 milliseconds 567 // FastLED.show takes approx 2 to 3 milli seconds 568 // Flipper not applicable since not controlled by the MEGA board 569 // only commands to switch ON or OFF at start and end of game 570 // sent to Slave 1 UNO. 571 // 572 if (digitalRead(Redbutton) == 0) 573 // used to start game if no replays left 574 // add 1 to get a free game 575 { 576 waiton (Redbutton); 577 diag(); // error codes displayed on backglass 578 if (replays == 0) 579 { 580 replay(); // give a free replay 581 Serial1.print ('K'); // to AUX 1 GameOver 582 } // activate Knocker 583 replays = replays - 1; // reduce replays by 1 584 Serial.print (replays); // update backglass 585 Serial.print ('g'); // reset backglass score to "0000" 586 Serial1.print ('D'); // to AUX 1 GameOver 587 delay(1000); // allow a reset on slave processors 588 Serial1.print ('E'); // -> AUX 1 New Game 589 reset(); 590 // Deliver 1st ball ready for new game start 591 Balls = 1; 592 leds[46] = CRGB::White; 593 // activate solonoid to kick ball into shooter lane 594 analogWrite(Deliver_Ball_MOSFET_Driver, 200); 595 // give the right amount of kick,delay here no problem 596 // since nothing else happening 597 delay (50); 598 analogWrite(Deliver_Ball_MOSFET_Driver, 0); 599 TopRipple(0); 600 } 601 // Everything OK; so Game ON 602 if (GameOver == 0) 603 { 604 B1_Bumper_Hit(); 605 B2_Bumper_Hit(); 606 B3_Bumper_Hit(); 607 Check_Bumpers(); 608 switch_timer = 0; 609 if (digitalRead(Yellbutton) == 0) 610 { 611 waiton(Yellbutton); 612 leds[47 - Balls] = CRGB::Black; 613 Balls++; 614 leds[47 - Balls] = CRGB::White; 615 // If Game Over so tell backglass 616 if (Balls > BallsPerGame) 617 { 618 Serial.print ('x'); 619 Serial1.print ('X'); // to Slave 1 GameOver 620 GameOver = 1; 621 Balls = 0; // stops multiple Game Over 622 } 623 else 624 { 625 TopRipple(0); 626 // activate solonoid to kick ball into shooter lane 627 analogWrite(Deliver_Ball_MOSFET_Driver, 200); 628 // give the right amount of kick 629 delay (50); 630 analogWrite(Deliver_Ball_MOSFET_Driver, 0); 631 } 632 } 633 // 634 if (digitalRead(Tilt) == 0) 635 { 636 //light 'TILT' Lamp 637 waiton (Tilt); // wait for TILT sensor to stabalize 638 Serial.print ('t'); // inform backglass software 639 GameOver = 1; 640 } 641 // 642 if ((Phit == 1) && (Ahit == 1)) 643 { 644 if (BlueBumper == 0)BlueBumper = 1; 645 } 646 // 647 // Sling Shots 648 if (digitalRead(Slingshot) == 0) 649 { 650 waiton (Slingshot); // wait for button release 651 Serial.print ('a'); 652 Serial1.print ('a'); //to Chime 1 653 units++; 654 } 655 // switchs and Targets 656 // These are connected in parallel so no need for seperate code 657 // NOTE LEDS Lights for FLYING CARPET are numbered from 0 to 11 658 if (digitalRead(Fswitch) == 0) 659 { 660 waiton (Fswitch); // wait for button release 661 TopRipple(1); 662 // light appropriate light 663 check_for_special(0); 664 } 665 // 666 if (digitalRead(Lswitch) == 0) 667 { 668 waiton (Lswitch); // wait for button release 669 TopRipple(1); 670 // light appropriate light 671 check_for_special(1); 672 } 673 // 674 if (digitalRead(Yswitch) == 0) 675 { 676 waiton (Yswitch); // wait for button release 677 TopRipple(1); 678 // light appropriate light 679 check_for_special(2); 680 if (Yspecial == 1 ) 681 { 682 // although Replays are awarded, they are for 683 // AMUSEMENT ONLY 684 // The display software will ingores replays above 9 685 replays++; 686 Serial.print (replays); 687 Serial1.print ('R'); 688 } 689 } 690 // 691 if (digitalRead(Iswitch) == 0) 692 { 693 waiton (Iswitch); // wait for button release 694 TopRipple(1); 695 //light appropriate light 696 check_for_special(3); 697 } 698 // 699 if (digitalRead(Nswitch) == 0) 700 { 701 waiton (Nswitch); // wait for button release 702 TopRipple(1); 703 //light appropriate light 704 check_for_special(4); 705 } 706 // 707 if (digitalRead(Gswitch) == 0) 708 { 709 waiton (Gswitch); // wait for button release 710 TopRipple(1); 711 //light appropriate light 712 check_for_special(5); 713 } 714 if (digitalRead(Cswitch) == 0) 715 { 716 waiton (Cswitch); // wait for button release 717 timer(); 718 if (switch_timer == 0) 719 { 720 Serial.print ('c'); 721 Serial1.print ('c'); 722 //light appropriate light 723 check_for_special(6); 724 } 725 } 726 // 727 if (digitalRead(Aswitch) == 0) 728 { 729 waiton (Aswitch); // wait for button release 730 timer(); 731 if (switch_timer == 0) 732 { 733 Serial.print ('c'); 734 Serial1.print ('c'); 735 Ahit = 1; 736 //light appropriate light 737 check_for_special(7); 738 } 739 } 740 // 741 if (digitalRead(Rswitch) == 0) 742 { 743 waiton (Rswitch); // wait for button release 744 timer(); 745 if (switch_timer == 0) 746 { 747 Serial.print ('c'); 748 Serial1.print ('c'); 749 //light appropriate light 750 check_for_special(8); 751 if (Rspecial == 1 ) 752 { 753 // although Replays are awarded, they are for 754 // AMUSEMENT ONLY 755 replay(); 756 } 757 } 758 } 759 // 760 if (digitalRead(Pswitch) == 0) 761 { 762 waiton (Pswitch); // wait for button release 763 timer(); 764 if (switch_timer == 0) 765 { 766 Serial.print ('c'); 767 Serial1.print ('c'); 768 //light appropriate light 769 check_for_special(9); 770 Phit = 1; 771 } 772 } 773 // 774 if (digitalRead(Eswitch) == 0) 775 { 776 waiton (Eswitch); // wait for button release 777 timer(); 778 if (switch_timer == 0) 779 { 780 Serial.print ('c'); 781 Serial1.print ('c'); 782 //light appropriate light 783 check_for_special(10); 784 } 785 } 786 // 787 if (digitalRead(Tswitch) == 0) 788 { 789 waiton (Tswitch); // wait for button release 790 timer(); 791 { 792 if (switch_timer == 0) 793 { 794 Serial.print ('c'); 795 Serial1.print ('c'); 796 } 797 //light appropriate light 798 check_for_special(11); 799 } 800 } 801 } 802} 803
Processing P3 for backglass PC
processing
Used to display score and backglass graphics
1import processing.serial.*; 2import ddf.minim.*; 3Minim minim; 4AudioPlayer 5 base; 6AudioPlayer chime100; 7AudioPlayer chime10; 8AudioPlayer chime1; 9AudioPlayer 10 reel; 11// 12Serial myPort; // The serial port: 13PImage bg; 14PImage img []; 15int 16 y=205; 17int x0=639; 18int x1=737; 19int x2=835; 20int x3=933; 21// 22// Highest 23 Score Variable 24int highscore; 25int highscoreones; 26int highscoretens; 27int 28 highscorehundreds; 29int highscorethous; 30// 31int d; 32int thous; 33int hundreds; 34int 35 tens; 36int ones; 37int oldthous; 38int oldhundreds; 39int oldtens; 40int 41 oldones; 42int oldscore; 43int newscore; 44int add; 45int reset; 46// 47// 48void 49 setup() 50{ 51 minim = new Minim(this); 52 base = minim.loadFile("base.wav"); 53 54 chime100 = minim.loadFile("chime100.wav"); 55 chime10 = minim.loadFile("chime10.wav"); 56 57 chime1 = minim.loadFile("chime1.wav"); 58 reel=minim.loadFile("reel.wav"); 59 60 // 61 myPort = new Serial(this, Serial.list()[0], 9600); 62 //size(978,1080); 63 64 //bg = loadImage("FC1.png"); 65 size(1080,1193); 66 bg = loadImage("FC.png"); 67 68 newscore = 0; 69 int nPics = 10; 70 img = new PImage [nPics]; 71 for (int 72 i = 0; i <nPics; i++) 73 { 74 img[i] = loadImage(+i+".jpg"); 75 } 76 77 background(bg); 78// 79} 80// 81void display() 82{ 83 oldthous = thous; 84 85 oldhundreds = hundreds; 86 oldtens = tens; 87 oldones = ones; 88 oldscore 89 = newscore; 90 if(oldscore>9999)oldscore=0; 91 thous = int(oldscore/1000); 92 93 hundreds = int(oldscore/100); 94 hundreds = hundreds-(int(hundreds/10)*10); 95 96 tens = int(oldscore/10); 97 tens = tens-(int(tens/10)*10); 98 ones = oldscore-(int(oldscore/10)*10); 99 100 // 101 image(img[ones], x3, y); 102 image(img[tens], x2, y); 103 image(img[hundreds], 104 x1, y); 105 image(img[thous], x0, y); 106 delay(20); 107} 108// 109void draw() 110 111 { 112 if (reset==1) 113 { 114 int total=ones+(10*tens)+(100*hundreds)+(1000*thous); 115 116 if (total == 0) 117 { 118 reset=0; 119 ones=0; 120 tens=0; 121 122 hundreds=0; 123 thous=0; 124 newscore=0; 125 oldscore=0; 126 127 } 128// 129 if (ones != 0) 130 { 131 ones=ones+1; 132 133 if (ones==10)ones=0; 134 image(img[ones], x3, y); 135 reel.rewind(); 136 137 reel.play(); 138 delay(75); 139 } 140// 141 if (tens 142 != 0) 143 { 144 tens=tens+1; 145 if (tens==10)tens=0; 146 image(img[tens], 147 x2, y); 148 reel.rewind(); 149 reel.play(); 150 delay(75); 151 152 } 153// 154 if (hundreds != 0) 155 { 156 hundreds=hundreds+1; 157 158 if (hundreds==10)hundreds=0; 159 image(img[hundreds], x1, y); 160 161 reel.rewind(); 162 reel.play(); 163 delay(75); 164 } 165 166 if (thous != 0) 167 { 168 thous=thous+1; 169 if (thous==10)thous=0; 170 171 image(img[thous], x0, y); 172 reel.rewind(); 173 reel.play(); 174 175 delay(75); 176 } 177 } 178// Process any inputs 179 while (myPort.available() 180 > 0) 181 { 182 char inByte = myPort.readChar(); 183// 184 if (inByte 185 == 'x') 186 { 187 base.rewind(); 188 base.play(); 189 } 190 if 191 (inByte == 'g') 192 { 193 reset = 1; 194 base.rewind(); 195 base.play(); 196 197 add=0; 198 } 199 if (inByte == 'a') 200 { 201 add = 1; 202 chime1.rewind(); 203 204 chime1.play(); 205 } 206 if (inByte == 'b') 207 { 208 add = 10; 209 chime10.rewind(); 210 211 chime10.play(); 212 } 213 if (inByte == 'c') 214 { 215 add = 100; 216 217 chime100.rewind(); 218 chime100.play(); 219 } 220 if (add>0) 221 { 222 223 oldscore = newscore; 224 newscore = newscore+add; 225 add=0; 226 } 227 228 display(); 229 } 230} 231
UNO for Flippers, Knocker and Chimes
arduino
1// Version 2.0 13/11/20 2// GOTTLIEB Flying Carpet EM Pinball with a 3 ARDUINO's 4// replacing the EM Stuff and LEDS replacing bulbs. 5// Written by 6 B J Mclaren based on experience of doing 7// an ARDUINO based Bally Bingo 8// 9 This solution uses: 10// A MEGA as the Master controller for the Playfield stuff 11// 12 AUX1 (UNO) has 6 pwm channels for Chime Unit, Flippers 13// and Knocker 14// This 15 is the AUX1 code for an UNO and a FREETRONICS 6 Channel 16// MOSFET Shield 17// 18// 19 Valid Commands are 20// 'a' = 1st score chime 21// 'b' = 2nd score chime 22// 23 'c' = 3rd score chime 24// 'K' = Knocker 25// 'E' = Enable AUX processor 26// 27 'D' = Disable AUX processor (eg Game Over / Tilt) 28// 29#define Right_Flipper_Switch 30 A0 31#define Left_Flipper_Switch A1 32// 33#define Chime1_Driver 3 34#define 35 Chime2_Driver 5 36#define Chime3_Driver 6 37#define Knocker_Driver 9 38#define 39 Left_Flipper_Driver 10 40#define Right_Flipper_Driver 11 41// 42#define On_Time 43 50 // Chime ON Time in ms 44#define LED 13 45char ch; 46int GameON; 47int 48 LFlipperON = 0; 49int RFlipperON = 0; 50int Chime1ON = 0; 51int Chime2ON = 0; 52int 53 Chime3ON = 0; 54int KnockerON = 0; 55int LPWM = 0; 56int RPWM = 0; 57// 58unsigned 59 long System_Time = 0; 60unsigned long Chime1ON_Time = 0; 61unsigned long Chime2ON_Time 62 = 0; 63unsigned long Chime3ON_Time = 0; 64unsigned long KnockerON_Time = 0; 65unsigned 66 long LFlipperON_Time = 0; 67unsigned long RFlipperON_Time = 0; 68unsigned long 69 diff = 0; 70// 71void setup() 72{ 73 Serial.begin (9600); 74 pinMode(LED, 75 OUTPUT); 76 digitalWrite(LED, LOW); 77 // 78 pinMode(Chime1_Driver, OUTPUT); 79 80 digitalWrite(Chime1_Driver, LOW); 81 pinMode(Chime2_Driver, OUTPUT); 82 digitalWrite(Chime2_Driver, 83 LOW); 84 pinMode(Chime3_Driver, OUTPUT); 85 digitalWrite(Chime3_Driver, LOW); 86 87 // 88 pinMode(Knocker_Driver, OUTPUT); 89 digitalWrite(Knocker_Driver, LOW); 90 91 // 92 pinMode(Right_Flipper_Switch, INPUT_PULLUP); 93 analogWrite(Right_Flipper_Driver, 94 0); 95 // 96 pinMode(Left_Flipper_Switch, INPUT_PULLUP); 97 analogWrite(Left_Flipper_Driver, 98 0); 99 // Setup Variables 100 GameON = 0; 101 LFlipperON = 0; 102 RFlipperON 103 = 0; 104 System_Time = 0; 105 Chime1ON = 0; // Flag to indicate 106 chime is ctive 107 Chime2ON = 0; 108 Chime3ON = 0; 109 KnockerON = 0; 110 System_Time 111 = 0; // base time for timing operations 112 Chime1ON_Time = 0; // 113 time chime became active 114 Chime2ON_Time = 0; 115 Chime3ON_Time = 0; 116 LFlipperON_Time 117 = 0; 118 RFlipperON_Time = 0; 119 diff = 0; 120 // 121} 122// 123void loop() 124{ 125 126 System_Time = millis(); 127 // 128 if (RFlipperON == 1 ) 129 { 130 diff 131 = System_Time - RFlipperON_Time; 132 // if flipper held for 1 seconds reduce 133 power 134 if (diff > 1000) 135 { 136 RPWM = 190; 137 } 138 } 139 140 if (LFlipperON == 1 ) 141 { 142 diff = System_Time - LFlipperON_Time; 143 144 // if flipper held for 1 seconds reduce power 145 if (diff > 1000) 146 { 147 148 LPWM = 190; 149 } 150 } 151 // 152 if (KnockerON == 1 ) 153 { 154 diff 155 = System_Time - KnockerON_Time; 156 if (diff > On_Time ) 157 { 158 KnockerON 159 = 0; 160 digitalWrite(Knocker_Driver, LOW); 161 } 162 } 163 if (Chime1ON 164 == 1 ) 165 { 166 diff = System_Time - Chime1ON_Time; 167 if (diff > On_Time 168 ) 169 { 170 Chime1ON = 0; 171 digitalWrite(Chime1_Driver, LOW); 172 173 } 174 } 175 if (Chime2ON == 1 ) 176 { 177 diff = System_Time - Chime2ON_Time; 178 179 if (diff > On_Time ) 180 { 181 Chime2ON = 0; 182 digitalWrite(Chime2_Driver, 183 LOW); 184 } 185 } 186 if (Chime3ON == 1 ) 187 { 188 diff = System_Time 189 - Chime3ON_Time; 190 if (diff > On_Time ) 191 { 192 Chime3ON = 0; 193 194 digitalWrite(Chime3_Driver, LOW); 195 } 196 } 197 // 198 if (Serial.available() 199 > 0) 200 { 201 // Read input from ARDUINO MEGA 202 ch = Serial.read(); 203 204 if (ch == 'E') 205 { // enable processor eg New Game 206 GameON = 1; 207 208 digitalWrite(LED, HIGH); 209 System_Time = 0; 210 Chime1ON = 0; 211 212 Chime2ON = 0; 213 Chime3ON = 0; 214 KnockerON = 0; 215 LFlipperON 216 = 0; 217 RFlipperON = 0; 218 } 219 if (ch == 'D') 220 { // disable 221 processor Game Over / Tilt 222 GameON = 0; 223 digitalWrite(LED, LOW); 224 225 analogWrite(Left_Flipper_Driver, 0); 226 analogWrite(Right_Flipper_Driver, 227 0); 228 } 229 // 230 if (ch == 'K') 231 { 232 // activate Knocker 233 234 digitalWrite(Knocker_Driver, HIGH); 235 KnockerON = 1; 236 KnockerON_Time 237 = millis(); 238 } 239 if (ch == 'a') 240 { // activate 1st Chime 241 digitalWrite(Chime1_Driver, 242 HIGH); 243 Chime1ON = 1; 244 Chime1ON_Time = millis(); 245 } 246 if 247 (ch == 'b') 248 { // activate 2nd Chime 249 digitalWrite(Chime2_Driver, 250 HIGH); 251 Chime2ON = 1; 252 Chime2ON_Time = millis(); 253 } 254 if 255 (ch == 'c') 256 { // activate 3rd Chime 257 digitalWrite(Chime3_Driver, 258 HIGH); 259 Chime3ON = 1; 260 Chime3ON_Time = millis(); 261 } 262 } 263 264 // Switch Off Flipper 265 if (digitalRead(Right_Flipper_Switch) == HIGH) 266 267 { //Flipper OFF 268 analogWrite(Right_Flipper_Driver, 0); 269 RFlipperON 270 = 0; 271 RPWM = 255; 272 } 273 if (digitalRead(Left_Flipper_Switch) == HIGH) 274 275 { //Flipper OFF 276 analogWrite(Left_Flipper_Driver, 0); 277 LFlipperON 278 = 0; 279 LPWM = 255; 280 } 281 if (GameON == 1) 282 { // Flipper active only 283 when Game is on 284 if (digitalRead(Right_Flipper_Switch) == LOW) 285 { 286 287 analogWrite(Right_Flipper_Driver, RPWM ); 288 if ( RFlipperON == 0) 289 290 { 291 RFlipperON_Time = millis(); 292 } 293 RFlipperON = 294 1; 295 } 296 if (digitalRead(Left_Flipper_Switch) == LOW) 297 { // Left 298 Flipper ON 299 analogWrite(Left_Flipper_Driver, LPWM ); 300 if ( LFlipperON 301 == 0) 302 { 303 LFlipperON_Time = millis(); 304 } 305 LFlipperON 306 = 1; 307 } 308 } 309} 310
Main MEGA processor
arduino
Arduino Pinball machine
1#include <FastLED.h> 2// GOTTLIEB EM Pinball with a ARDUINO MEGA 3// 4 replacing the EM Stuff and LEDS replacing bulbs 5// Written by B J Mclaren 6// 7 based on experience of building an ARDUINO based Bally Bingo 8// This is currenty 9 for FLYING CARPET but will be able to 10// play DUOTRON in future (Next release). 11// 12 Special thanks to all involved in ARDUINO Pinballs. 13// Most of the code is original 14 except some Bumper stuff 15// This solution used distributed processing with a 16 MEGA 17// as the Master controller 18// UNO's as Auxillary Controllers for Chimes 19 etc 20// an extra UNO when more than 12 solenoids are required (DUOTRON) 21// 22 Processing 3(see processing.org)for Backglass (+ Sound if no Chime Unit) 23// A 24 PC, (a Fanless PC is powerfull enough) to run the 25// software to drive a 40" 26 LCD TV Backglass. 27// 28// There are 6 channels on each MOSFET Board. 29// PWM 30 Pins used by the driver are 3,5,6,9,10,11 31// Board 1 ( MASTER ) mounted on MEGA 32 is for 3 POP Bumper 33// and Ball delivery + 2 Spares 34// a single MOSFET Driver 35 is used for the 100 points LED 36// There are 6 channels on MOSFET Board 2 37// 38 Board 2 ( SLAVE 1 )mounted on UNO for chimes, Knocker and flippers 39// Board 3 40 ( SLAVE 2 )future expansion eg DUOTRON 41// Board 1 utilises a 12 Volt PSU 42// 43 Board 2 utilises a 15 Volt PSU 44// A total of 18 solenoid Drivers can be provided 45// 46 Comms to Slave 1 and Slave 2 via RS232 47// later versions may use I2C (so reserve 48 A4 and A5) 49// 50// Switch and Targets ARDUINO Pins 51#define Fswitch 36 52#define 53 Lswitch 37 54#define Yswitch 38 55#define Iswitch 39 56#define Nswitch 40 57#define 58 Gswitch 41 59// 60#define Cswitch 42 61#define Aswitch 43 62#define Rswitch 63 44 64#define Pswitch 45 65#define Eswitch 46 66#define Tswitch 47 67// Misc 68 Switches and Buttons 69#define Redbutton 27 70#define Yellbutton 28 71#define 72 Tilt 34 73#define Slingshot 35 //ALL score slingshots are in parallel 74// 75#define 76 B1_Bumper_Switch 29 77#define B1_MOSFET_Driver 5 78// 79#define B2_Bumper_Switch 80 31 81#define B2_MOSFET_Driver 3 82// 83#define B3_Bumper_Switch 30 84#define 85 B3_MOSFET_Driver 6 86// 87#define Deliver_Ball_MOSFET_Driver 9 88// 89#define 90 BlueLed_MOSFET_Driver 4 // Lit when 100 points 91#define Spare1_MOSFET_Driver 92 10 93#define Spare2_MOSFET_Driver 11 94// 95// Array for LEDs for playfield 96#define 97 NUM_LEDS 70 //Space for up to 70 LEDS 98#define DATA_PIN A0 99// 100#define 101 Ball_Lights 41 // Offset for Balls played LEDS 102#define On_Time 40 103 // Solenoids ON Time in ms 104// 105CRGB leds[NUM_LEDS]; 106// This 107 section defined the index into the LED arrays 108// LED's for "FLYING CARPET" 109 in centre of playfield 110int FCLamps [13] = 111{ 112 21, 22, 24, 25, 27, 28, 34, 113 33, 32, 31, 30, 29, 0 114}; 115// switch LED's on Playfield 116int FCswitchLamps 117 [13] = 118{ 119 17, 8, 57, 5, 35, 50, 54, 6, 13, 7, 49, 36, 0 120}; 121// Target 122 LED's on Playfield 123int FCTargetLamps [13] = 124{ 125 59, 20, 9, 51, 11, 60, 126 12, 52, 14, 19, 61, 10, 0 127}; 128// Index for special targets 129#define SR1 16 130 //Special R Target 1 131#define SY1 23 //Special 132 Y Target 1 133#define SR2 26 //Special R Target 2 134#define 135 SY2 56 //Special Y Target 2 136// 137// 12 slots to indicate 138 "FLYING CARPET" Targets/Rollovers hit 139int FC[13]; // slots 140 0 and 13 not used 141int Balls = 0; 142int RandNumber = 0; // Lucky 143 Matching number 144int BallsPerGame = 5; 145int GameOver = 1; 146int FCcount = 0; 147 // count of numbers of FC lights ON 148int SpecialON = 0; // 149 Special ON 150int BlueBumper = 0; // Blue Score 100 if set to 1 151int 152 Phit = 0; // set if P rollover or target hit 153int Ahit = 0; 154 // set if A rollover or target hit 155// if both hit Blue bumper 156 score 100 157int Yspecial = 0; 158int Rspecial = 0; 159int replays = 0; 160int units 161 = 0; // keep track of units for Lucky Number 162int switch_timer 163 = 0; // determine if multi reports of a target hit 164int debounce = 50; 165 // switch debounce in mills 166// Variables for target handling 167unsigned 168 long System_Base_Time = 0; 169unsigned long Target_Hit_Time = 0; 170unsigned long 171 Old_Target_Hit_Time = 0; 172unsigned long diff = 0; 173// Bumper timing stuff 174unsigned 175 long B1_previousMillis = 0; 176unsigned long B1_currentMillis = 0; 177unsigned long 178 B1_ON_Time = 0; 179// 180int B1_Coil_Trigger = 0; 181int B1_Coil_State_last = LOW; 182int 183 B1_Coil_State; 184int B1_difference; 185// 186unsigned long B2_previousMillis = 187 0; 188unsigned long B2_currentMillis = 0; 189unsigned long B2_ON_Time = 0; 190// 191int 192 B2_Coil_Trigger = 0; 193int B2_Coil_State_last = LOW; 194int B2_Coil_State; 195int 196 B2_difference; 197// 198unsigned long B3_previousMillis = 0; 199unsigned long B3_currentMillis 200 = 0; 201unsigned long B3_ON_Time = 0; 202// 203int B3_Coil_Trigger = 0; 204int B3_Coil_State_last 205 = LOW; 206int B3_Coil_State; 207int B3_difference; 208// 209unsigned long end_time 210 = 0; // used for timing 211unsigned long total_time = 0; 212// Max time 213 before switching off bumpers to stop coil burnup 214int Max_On_Time = 1000; // 215void 216 setup() 217{ 218 pinMode(Deliver_Ball_MOSFET_Driver, OUTPUT); 219 analogWrite(Deliver_Ball_MOSFET_Driver, 220 0); 221 // 222 pinMode(Spare1_MOSFET_Driver, OUTPUT); 223 analogWrite(Spare1_MOSFET_Driver, 224 0); 225 // 226 pinMode(Spare2_MOSFET_Driver, OUTPUT); 227 analogWrite(Spare2_MOSFET_Driver, 228 0); 229 // 230 pinMode(BlueLed_MOSFET_Driver, OUTPUT); 231 digitalWrite (BlueLed_MOSFET_Driver, 232 0); 233 // Pop Bumpers 234 pinMode(B1_Bumper_Switch, INPUT_PULLUP); 235 pinMode(B1_MOSFET_Driver, 236 OUTPUT); 237 analogWrite(B1_MOSFET_Driver, 0); 238 // 239 pinMode(B2_Bumper_Switch, 240 INPUT_PULLUP); 241 pinMode(B2_MOSFET_Driver, OUTPUT); 242 analogWrite(B2_MOSFET_Driver, 243 0); 244 // 245 pinMode(B3_Bumper_Switch, INPUT_PULLUP); 246 pinMode(B3_MOSFET_Driver, 247 OUTPUT); 248 analogWrite(B3_MOSFET_Driver, 0); 249 // LEDS 250 FastLED.addLeds<WS2811, 251 DATA_PIN, BRG>(leds, NUM_LEDS); 252 FastLED.setBrightness(100); 253 FastLED.show(); 254 255 // Switches and Targets 256 pinMode(Fswitch, INPUT_PULLUP); 257 pinMode(Lswitch, 258 INPUT_PULLUP); 259 pinMode(Yswitch, INPUT_PULLUP); 260 pinMode(Iswitch, INPUT_PULLUP); 261 262 pinMode(Nswitch, INPUT_PULLUP); 263 pinMode(Gswitch, INPUT_PULLUP); 264 // 265 266 pinMode(Cswitch, INPUT_PULLUP); 267 pinMode(Aswitch, INPUT_PULLUP); 268 pinMode(Rswitch, 269 INPUT_PULLUP); 270 pinMode(Pswitch, INPUT_PULLUP); 271 pinMode(Eswitch, INPUT_PULLUP); 272 273 pinMode(Tswitch, INPUT_PULLUP); 274 // 275 pinMode(Slingshot, INPUT_PULLUP); 276 277 pinMode(Tilt, INPUT_PULLUP); 278 // Game Start Stuff 279 pinMode(Redbutton, 280 INPUT_PULLUP); 281 pinMode(Yellbutton, INPUT_PULLUP); 282 // 283 Serial.begin 284 (9600); // -> Tv Monitor via Processing I3 on PC or PI 285 Serial1.begin 286 (9600); // chime unit, ball delivery anf flippers 287} 288// 289void Lucky() 290// 291 Are we Lucky today? 292// match number for replay 293// For Fun Only as we are a 294 Free Play Machine 295{ 296 int u = units - (int(units / 10) * 10); 297 int r = 298 random (0, 9); 299 if (r == u) 300 { 301 replay(); 302 } 303} 304// 305void 306 timer () 307// Used to determine if a Target is bouncing causing 308// multiple 309 reporting of a hit 310// this routine determines the time in milli seconds 311// 312 since the last target hit 313// Currenty set to 200 ms - unlikely 2 targets can 314 be 315// hit within 200ms 316{ 317 Target_Hit_Time = millis(); 318 diff = Target_Hit_Time 319 - Old_Target_Hit_Time; 320 Old_Target_Hit_Time = Target_Hit_Time; 321 if (diff 322 < 200 )switch_timer = 1; // adjust time to suit machine 323} 324// 325void waiton 326 (int pin) 327{ 328 delay (debounce); // let switch settle 329 while 330 (digitalRead(pin) == 0 ) 331 { 332 delay (debounce); 333 } 334}// end of waiton 335// 336void 337 TopRipple(int score) 338// routine to light top 5 lights in sequence 339// if score 340 then send add 10 command to score 341// and chime unit 342{ 343 for (int i = 0; 344 i < 5; i = i + 1) 345 { 346 if (score == 1 ) 347 { 348 Serial.print('b'); 349 350 Serial1.print ('b'); 351 } 352 leds [ i ] = CRGB::Black; 353 FastLED.show(); 354 355 delay (50); 356 // 357 leds [ i ] = CRGB::White; 358 FastLED.show(); 359 360 } 361} 362// 363void replay() 364{ 365 replays++; 366 Serial.print (replays); 367 368 Serial1.print ('K'); // activate knocker 369} 370void reset() 371{ 372 373 // Light all the LEDS 374 for (int i = 0; i < 70; i = i + 1) 375 { 376 leds[i] 377 = CRGB::White; 378 } 379 FastLED.show(); 380 // switch off LEDs that are spare 381 underneath playfield 382 leds [58] = CRGB::Black; 383 leds [9] = CRGB::Black; 384 385 // 386 FastLED.show(); 387 // switch of 4 special lights 388 leds [SY1] = CRGB::Black; 389 390 leds [SY2] = CRGB::Black; 391 leds [SR1] = CRGB::Black; 392 leds [SR2] = CRGB::Black; 393 394 // now switch OFF central FLYING CARPET Lights 395 for (int i = 0; i < 13; i 396 = i + 1) 397 { 398 int FC_Lights = FCLamps[i]; 399 leds[FC_Lights] = CRGB::Black; 400 401 } 402 // Switch off Ball in play and Game Over LEDS 403 for (int i = 0; i < 404 6; i = i + 1) 405 { 406 leds[i + Ball_Lights] = CRGB::Black; 407 } 408 FastLED.show(); 409 410 digitalWrite(BlueLed_MOSFET_Driver, 0); 411 BallsPerGame = 5; 412 Balls = 0; 413 414 units = 0; 415 FCcount = 0; 416 Phit = 0; 417 Ahit = 0; 418 Yspecial = 0; 419 420 Rspecial = 0; 421 GameOver = 0; 422 SpecialON = 0; // = 1 if 'Y' 423 target and -1 if R target 424 BlueBumper = 0; // = 1 to light; set 425 to 2 when alight 426 for (int i = 0; i < 12; i++) 427 { 428 FC[i] = 0; 429 430 } 431 timer(); // intialise timer 432} 433void diag() 434// 435 Diagnostic routine to determine if switch stuck 436// and all lights are working 437{ 438 439 // Light all the LEDS 440 for (int i = 0; i < 70; i = i + 1) 441 { 442 leds[i] 443 = CRGB::White; 444 } 445 FastLED.show(); 446 delay (2000); // 447 all LEDs ON 448 // all LEDS OFF 449 for (int i = 0; i < 70; i = i + 1) 450 { 451 452 leds [ i ] = CRGB::Black; 453 } 454 FastLED.show(); 455 delay (1500); 456 457 // Check coil switch state 458 // Normal start state for Coil Switch is HIGH 459 460 // Error codes are 1, 10, 100 for coil faults 461 if (digitalRead(B2_Bumper_Switch) 462 == 0) 463 { 464 Serial.print ('a'); // indicate 1 465 GameOver 466 = 1; 467 } 468 if (digitalRead(B1_Bumper_Switch) == 0) 469 { 470 Serial.print 471 ('b'); // indicate 10 472 GameOver = 1; 473 } 474 if (digitalRead(B3_Bumper_Switch) 475 == 0) 476 { 477 Serial.print ('c'); // indicate 100 478 GameOver 479 = 1; 480 } 481 // check if any switches or targets are closed 482 // inputs on 483 pins 36 to 47 484 for (int i = 36; i >= 47; i = i - 1) 485 { 486 int Switch 487 = digitalRead(i); 488 if (Switch == 0 ) 489 { 490 // light faulty rollover 491 or target letter in playfield centre 492 leds[i - 15] = CRGB::White; 493 GameOver 494 = 1; 495 } 496 } 497} 498// 499void check_for_special(int letter) 500// completing 501 F-L-Y-I-N-G C-A-R-P-E-T sequence lights 502// 'Y' Target and switch 503// alternatively 504// 505 'R' Target and switch 506{ 507 FC [letter] = 1; 508 int Lmp = FCLamps[letter]; 509 510 leds[Lmp] = CRGB::White; 511 int Tgt = FCTargetLamps[letter]; 512 leds[Tgt] 513 = CRGB::Black; 514 int roll = FCswitchLamps[letter]; 515 leds[roll] = CRGB::Black; 516 517 FastLED.show(); 518 //check if special to be switched ON 519 FCcount = 0; 520 521 for (int i = 0; i < 12; i++) 522 { 523 if (FC[i] == 1) 524 { 525 FCcount 526 = FCcount + 1; 527 } 528 } 529 // check for specials in LED Array 530 // and 531 light special if 'Flying Carpet' fully lit 532 if (FCcount == 12) 533 { 534 SpecialON 535 = !SpecialON; 536 if (SpecialON == 0 ) 537 { 538 Rspecial = 1; 539 Yspecial 540 = 0; 541 leds[SY1] = CRGB::White; 542 leds[SY2] = CRGB::White; 543 leds[SR1] 544 = CRGB::Black; 545 leds[SR2] = CRGB::Black; 546 FastLED.show(); 547 } 548 549 if (SpecialON == 1 ) 550 { 551 Yspecial = 1; 552 Rspecial = 0; 553 554 leds[SR1] = CRGB::White; 555 leds[SR2] = CRGB::White; 556 leds[SY1] 557 = CRGB::Black; 558 leds[SY2] = CRGB::Black; 559 FastLED.show(); 560 } 561 562 } 563} 564// 565void Check_Bumpers() 566{ 567 GameOver = 0; 568 if (( B1_Coil_Trigger 569 == LOW) && (B1_Coil_State_last == HIGH)) 570 { 571 B1_difference = B1_currentMillis 572 - B1_ON_Time; 573 if (B1_difference >= Max_On_Time)GameOver = 1; 574 } 575 // 576 577 if (( B2_Coil_Trigger == LOW) && (B2_Coil_State_last == HIGH)) 578 { 579 B2_difference 580 = B2_currentMillis - B2_ON_Time; 581 if (B2_difference >= Max_On_Time)GameOver 582 = 1; 583 } 584 if (( B3_Coil_Trigger == LOW) && (B3_Coil_State_last == HIGH)) 585 586 { 587 B3_difference = B3_currentMillis - B3_ON_Time; 588 if (B3_difference 589 >= Max_On_Time)GameOver = 1; 590 } 591} 592// 593void B1_Bumper_Hit() 594{ 595 596 B1_currentMillis = System_Base_Time; //Start Time 597 B1_Coil_State = digitalRead(B1_Bumper_Switch); 598 //Variable for Coil Switch 599 if ((B1_Coil_State == LOW) && (B1_Coil_State_last 600 == LOW)) 601 { 602 //Coil has been triggered 603 B1_ON_Time = B1_currentMillis; 604 605 B1_Coil_State_last = HIGH; 606 B1_previousMillis = millis(); 607 analogWrite(B1_MOSFET_Driver, 608 200); //Coil Solenoid activated ! 609 B1_Coil_Trigger = 1 ; 610 } 611 else 612 if ((B1_Coil_State == HIGH) && (B1_Coil_State_last == HIGH)) 613 { 614 //Coil 615 released 616 B1_Coil_State_last = LOW; 617 } 618 B1_difference = B1_currentMillis 619 - B1_previousMillis; 620 if ((B1_difference >= debounce) && (B1_Coil_Trigger == 621 1)) 622 { 623 B1_previousMillis = B1_currentMillis; 624 B1_Coil_Trigger = 625 0; 626 analogWrite(B1_MOSFET_Driver, 0); //Coil Solenoid deactivated 627 if 628 (BlueBumper > 0 ) 629 { 630 Serial.print ('c'); 631 Serial1.print ('c'); 632 // to Chime 100 633 } 634 else 635 { 636 Serial.print ('b'); 637 638 Serial1.print ('b'); // to Slave Chime 10 639 } 640 } 641} 642// 643void 644 B2_Bumper_Hit() 645{ 646 B2_currentMillis = System_Base_Time; //Start Time 647 648 B2_Coil_State = digitalRead(B2_Bumper_Switch); //Variable for Coil Switch 649 650 if ((B2_Coil_State == LOW) && (B2_Coil_State_last == LOW)) 651 { 652 //Coil 653 has been triggered 654 B2_ON_Time = B2_currentMillis; 655 B2_Coil_State_last 656 = HIGH; 657 B2_previousMillis = millis(); 658 analogWrite(B2_MOSFET_Driver, 659 200); //Coil Solenoid activated ! 660 B2_Coil_Trigger = 1 ; 661 662 } 663 664 else if ((B2_Coil_State == HIGH) && (B2_Coil_State_last == HIGH)) 665 { 666 667 //Coil released 668 B2_Coil_State_last = LOW; 669 } 670 B2_difference = 671 B2_currentMillis - B2_previousMillis; 672 if ((B2_difference >= debounce) && (B2_Coil_Trigger 673 == 1)) 674 { 675 B2_previousMillis = B2_currentMillis; 676 B2_Coil_Trigger 677 = 0; 678 analogWrite(B2_MOSFET_Driver, 0); //Coil Solenoid deactivate 679 if 680 (BlueBumper > 0 ) 681 { 682 Serial.print ('c'); 683 Serial1.print ('c'); 684 // to Chime 100 685 } 686 else 687 { 688 Serial.print ('b'); 689 690 Serial1.print ('b'); // to Slave Chime 10 691 } 692 } 693} 694// 695void 696 B3_Bumper_Hit() 697{ 698 B3_currentMillis = System_Base_Time; //Start Time 699 700 B3_Coil_State = digitalRead(B3_Bumper_Switch); //Variable for Coil Switch 701 702 if ((B3_Coil_State == LOW) && (B3_Coil_State_last == LOW)) 703 { 704 //Coil 705 has been triggered 706 B3_ON_Time = B3_currentMillis; 707 B3_Coil_State_last 708 = HIGH; 709 B3_previousMillis = millis(); 710 analogWrite(B3_MOSFET_Driver, 711 200); //Coil Solenoid activated ! 712 B3_Coil_Trigger = 1 ; 713 } 714 else 715 if ((B3_Coil_State == HIGH) && (B3_Coil_State_last == HIGH)) 716 { 717 //Coil 718 released 719 B3_Coil_State_last = LOW; 720 } 721 B3_difference = B3_currentMillis 722 - B3_previousMillis; 723 if ((B3_difference >= debounce) && (B3_Coil_Trigger == 724 1)) 725 { 726 B3_previousMillis = B3_currentMillis; 727 B3_Coil_Trigger = 728 0; 729 analogWrite(B3_MOSFET_Driver, 0); //Coil Solenoid deactivated 730 Serial.print 731 ('c'); 732 Serial1.print ('c'); 733 } 734} 735// 736void loop() 737{ 738 System_Base_Time 739 = millis(); 740 if (GameOver == 1) 741 // Game Over light ON all others OFF 742 743 // set Gameover to 2 since we only want it to 744 // set the lights once 745 746 { 747 for (int i = 0; i < 70; i = i + 1) 748 { 749 leds [ i ] = CRGB::Black; 750 751 } 752 leds [ 41 ] = CRGB::White; 753 FastLED.show(); 754 GameOver = 755 2; 756 Serial1.print ('D'); // switch off aux processor 757 758 } 759 760 // timings are as follows: 761 // NOTE Targets can bounce for up to 200 milliseconds 762 763 // around 'loop'; approx 2 milli second for approx 20 764 // switch / target 765 reads 766 // Score output 2 milliseconds (longer for 50 score) 767 // Pop Bumpers 768 approx 2 milliseconds 769 // FastLED.show takes approx 2 to 3 milli seconds 770 771 // Flipper not applicable since not controlled by the MEGA board 772 // only 773 commands to switch ON or OFF at start and end of game 774 // sent to Slave 1 UNO. 775 776 // 777 if (digitalRead(Redbutton) == 0) 778 // used to start game if no replays 779 left 780 // add 1 to get a free game 781 { 782 waiton (Redbutton); 783 diag(); 784 // error codes displayed on backglass 785 if (replays == 786 0) 787 { 788 replay(); // give a free replay 789 Serial1.print 790 ('K'); // to AUX 1 GameOver 791 } // activate 792 Knocker 793 replays = replays - 1; // reduce replays by 1 794 Serial.print 795 (replays); // update backglass 796 Serial.print ('g'); // reset backglass 797 score to "0000" 798 Serial1.print ('D'); // to AUX 1 GameOver 799 delay(1000); 800 // allow a reset on slave processors 801 Serial1.print ('E'); 802 // -> AUX 1 New Game 803 reset(); 804 // Deliver 1st ball ready for 805 new game start 806 Balls = 1; 807 leds[46] = CRGB::White; 808 // activate 809 solonoid to kick ball into shooter lane 810 analogWrite(Deliver_Ball_MOSFET_Driver, 811 200); 812 // give the right amount of kick,delay here no problem 813 // since 814 nothing else happening 815 delay (50); 816 analogWrite(Deliver_Ball_MOSFET_Driver, 817 0); 818 TopRipple(0); 819 } 820 // Everything OK; so Game ON 821 if (GameOver 822 == 0) 823 { 824 B1_Bumper_Hit(); 825 B2_Bumper_Hit(); 826 B3_Bumper_Hit(); 827 828 Check_Bumpers(); 829 switch_timer = 0; 830 if (digitalRead(Yellbutton) 831 == 0) 832 { 833 waiton(Yellbutton); 834 leds[47 - Balls] = CRGB::Black; 835 836 Balls++; 837 leds[47 - Balls] = CRGB::White; 838 // If Game Over 839 so tell backglass 840 if (Balls > BallsPerGame) 841 { 842 Serial.print 843 ('x'); 844 Serial1.print ('X'); // to Slave 1 GameOver 845 GameOver 846 = 1; 847 Balls = 0; // stops multiple Game Over 848 } 849 850 else 851 { 852 TopRipple(0); 853 // activate solonoid to 854 kick ball into shooter lane 855 analogWrite(Deliver_Ball_MOSFET_Driver, 200); 856 857 // give the right amount of kick 858 delay (50); 859 analogWrite(Deliver_Ball_MOSFET_Driver, 860 0); 861 } 862 } 863 // 864 if (digitalRead(Tilt) == 0) 865 { 866 867 //light 'TILT' Lamp 868 waiton (Tilt); // wait for TILT sensor 869 to stabalize 870 Serial.print ('t'); // inform backglass software 871 872 GameOver = 1; 873 } 874 // 875 if ((Phit == 1) && (Ahit == 1)) 876 877 { 878 if (BlueBumper == 0)BlueBumper = 1; 879 } 880 // 881 // 882 Sling Shots 883 if (digitalRead(Slingshot) == 0) 884 { 885 waiton (Slingshot); 886 // wait for button release 887 Serial.print ('a'); 888 Serial1.print 889 ('a'); //to Chime 1 890 units++; 891 } 892 // switchs and Targets 893 894 // These are connected in parallel so no need for seperate code 895 // NOTE 896 LEDS Lights for FLYING CARPET are numbered from 0 to 11 897 if (digitalRead(Fswitch) 898 == 0) 899 { 900 waiton (Fswitch); // wait for button release 901 902 TopRipple(1); 903 // light appropriate light 904 check_for_special(0); 905 906 } 907 // 908 if (digitalRead(Lswitch) == 0) 909 { 910 waiton (Lswitch); 911 // wait for button release 912 TopRipple(1); 913 // light appropriate 914 light 915 check_for_special(1); 916 } 917 // 918 if (digitalRead(Yswitch) 919 == 0) 920 { 921 waiton (Yswitch); // wait for button release 922 923 TopRipple(1); 924 // light appropriate light 925 check_for_special(2); 926 927 if (Yspecial == 1 ) 928 { 929 // although Replays are awarded, 930 they are for 931 // AMUSEMENT ONLY 932 // The display 933 software will ingores replays above 9 934 replays++; 935 Serial.print 936 (replays); 937 Serial1.print ('R'); 938 } 939 } 940 // 941 if 942 (digitalRead(Iswitch) == 0) 943 { 944 waiton (Iswitch); // wait 945 for button release 946 TopRipple(1); 947 //light appropriate light 948 949 check_for_special(3); 950 } 951 // 952 if (digitalRead(Nswitch) == 953 0) 954 { 955 waiton (Nswitch); // wait for button release 956 TopRipple(1); 957 958 //light appropriate light 959 check_for_special(4); 960 } 961 // 962 963 if (digitalRead(Gswitch) == 0) 964 { 965 waiton (Gswitch); // 966 wait for button release 967 TopRipple(1); 968 //light appropriate light 969 970 check_for_special(5); 971 } 972 if (digitalRead(Cswitch) == 0) 973 { 974 975 waiton (Cswitch); // wait for button release 976 timer(); 977 978 if (switch_timer == 0) 979 { 980 Serial.print ('c'); 981 Serial1.print 982 ('c'); 983 //light appropriate light 984 check_for_special(6); 985 986 } 987 } 988 // 989 if (digitalRead(Aswitch) == 0) 990 { 991 waiton 992 (Aswitch); // wait for button release 993 timer(); 994 if (switch_timer 995 == 0) 996 { 997 Serial.print ('c'); 998 Serial1.print ('c'); 999 1000 Ahit = 1; 1001 //light appropriate light 1002 check_for_special(7); 1003 1004 } 1005 } 1006 // 1007 if (digitalRead(Rswitch) == 0) 1008 { 1009 waiton 1010 (Rswitch); // wait for button release 1011 timer(); 1012 if (switch_timer 1013 == 0) 1014 { 1015 Serial.print ('c'); 1016 Serial1.print ('c'); 1017 1018 //light appropriate light 1019 check_for_special(8); 1020 if 1021 (Rspecial == 1 ) 1022 { 1023 // although Replays are awarded, they 1024 are for 1025 // AMUSEMENT ONLY 1026 replay(); 1027 } 1028 1029 } 1030 } 1031 // 1032 if (digitalRead(Pswitch) == 0) 1033 { 1034 waiton 1035 (Pswitch); // wait for button release 1036 timer(); 1037 if (switch_timer 1038 == 0) 1039 { 1040 Serial.print ('c'); 1041 Serial1.print ('c'); 1042 1043 //light appropriate light 1044 check_for_special(9); 1045 Phit 1046 = 1; 1047 } 1048 } 1049 // 1050 if (digitalRead(Eswitch) == 0) 1051 { 1052 1053 waiton (Eswitch); // wait for button release 1054 timer(); 1055 1056 if (switch_timer == 0) 1057 { 1058 Serial.print ('c'); 1059 Serial1.print 1060 ('c'); 1061 //light appropriate light 1062 check_for_special(10); 1063 1064 } 1065 } 1066 // 1067 if (digitalRead(Tswitch) == 0) 1068 { 1069 waiton 1070 (Tswitch); // wait for button release 1071 timer(); 1072 { 1073 if 1074 (switch_timer == 0) 1075 { 1076 Serial.print ('c'); 1077 Serial1.print 1078 ('c'); 1079 } 1080 //light appropriate light 1081 check_for_special(11); 1082 1083 } 1084 } 1085 } 1086} 1087
Downloadable files
UNO Schematic
Flippers, Chimes and knocker drivers
UNO Schematic

UNO Schematic
Flippers, Chimes and knocker drivers
UNO Schematic

Comments
Only logged in users can leave comments