#include long timeout; int bp1 = 11; int bp2 = 12; int advance_button = 0; int select_button = 0; int pressed = LOW; int notpressed = HIGH; int selectcheck; int alarmhours; int alarmminutes; int relay; String gpstext ; String hourstext; String minutestext; int i; int hours; int hours_24; int minutes; int day; int month; int year; int commas; byte nextbyte; byte readbyte; long current; long target; int ond; int offd; int tens = 3; int hundreds = 4; int thousands = 5; int credit = 6; int ballreturn = 7; int power = 8; int coinup = 9; int ledpin = 13; long currentscore; long targetscore; int setbutton; int advancebutton; int displayedhours; int offhours; int offminutes; int off_time; int on_time; int current_time; void advance (long sofar,long target){ // Advances the score from the current display to the required dispay. // To make things more like a real pinball the program will randomly change around the both interval and the points scored // For fun I added the occasional burst of 500 or 5000 as you might hear during an actual game. int x; while (sofar < target ){ x = random (1,4); switch (x) { case 1: if (sofar + 1000 <= target){ if (sofar + 5000 <= target && random(1,10)==5){ delay (300); for (i=0; i <5; i++){ pulse (thousands); delay(100);} delay (300); sofar = sofar+5000; } else{ sofar = sofar + 1000; pulse(thousands); } } break; case 2: if (sofar + 100 <= target){ if (sofar + 500 <= target && random(1,13)==5){ delay (300); for (i=0; i <5; i++){ pulse (hundreds); delay(100);} delay (300); sofar = sofar+500; } else{ sofar = sofar + 100; pulse(hundreds); } } break; case 3: sofar = sofar + 10; pulse(tens); break; } delay(random(75,200)); } return; } void pulse (int relay){ // advances a score or emulates a button being pressed digitalWrite(relay, LOW); delay(50); digitalWrite(relay, HIGH); return; } void updatefromgps (){ // Reads from the GPS until it finds a valid string, one that starts with $GPRMC and ends with an A after a comma Serial.flush(); int test = 1; gpstext = ""; do{ do { if (Serial.available () > 0) { readbyte= Serial.read(); gpstext=String(gpstext +char(readbyte)); } } while (int(readbyte) != 13 );//reads until CR if (gpstext.startsWith("$GPRMC",1) and gpstext.charAt(gpstext.lastIndexOf(",")+1) == 'A'){ parsegpstext(); test = 0 ; } else { gpstext = ""; } } while (test!=0); Serial.print("text from gps reads "); Serial.println (gpstext); return; } void parsegpstext (){ // Takes the GPS sting and converts GMT to Eastern standard time. If your reading this and need a different time zone look for the comment below // It should work with Daylight savings time and leap years. Would have been a lot easier to just let the clock be wrong for a couple of hours // once of twice a year I tell you! int dateof1stsunday; int dateof2ndsunday; int weekdayof1st; commas =gpstext.indexOf(',',6); hours = int(gpstext.charAt(commas +1))-48; hours = hours *10 + int(gpstext.charAt(commas +2))-48; minutes = int(gpstext.charAt(commas +3))-48; minutes = minutes*10 + int(gpstext.charAt(commas +4))-48; for (i=0; i <8 ; i++){ commas =gpstext.indexOf(',',commas +1); } day = int(gpstext.charAt(commas +1))-48; day = day *10 + int(gpstext.charAt(commas +2))-48; month = int(gpstext.charAt(commas +3))-48; month = month *10 + int(gpstext.charAt(commas +4))-48; year = int(gpstext.charAt(commas+5))-48; year = year *10 + int(gpstext.charAt(commas +6))+1952; if (day == 1 && month == 1 and hours < 5) year = year -1; // Change the GMT offset in the line below here hours = hours -4; if (month <= 3 or month >= 11){ weekdayof1st = dayofweek (year, month, 1); if (weekdayof1st = 0){ weekdayof1st = 7; } dateof1stsunday = 8 - weekdayof1st; dateof2ndsunday = 15 - weekdayof1st; if ( (month == 11 && day > dateof1stsunday) or (month == 11 && day == dateof1stsunday && hours >2) or (month ==12) or (month == 3 && day < dateof1stsunday) or (month == 3 && day == dateof1stsunday && hours <2) or (month < 3) ) { hours = hours -1; } } if (hours <= 0 ){ hours = hours +24; if (hours != 24){ day = day - 1; if (day == 0) { if (month==3){ if ((year % 4)==0) day = 29; else day = 28; } else if (month == 5 || month == 7 || month == 10 || month == 12) day = 30; else day = 31; month = month -1; if (month == 0) month = 12; } } } hours_24 = hours; if (hours_24==24) hours_24 = 0; if (hours > 12 ){ hours = hours - 12; } current_time = hours_24*60 + minutes; return; } void resetgame (){ // Here we reset the game and add up the players. The delays here might need to be tweeked depending on the machine your installing this into flash(4); digitalWrite(power, LOW); delay (2000); digitalWrite(power, HIGH); delay (2000); flash (10); for (i=0; i<4; i++){ pulse (coinup); delay (3000); } pulse (credit); delay (7000); digitalWrite(ballreturn, LOW); delay(1000); digitalWrite(ballreturn, HIGH); delay(2000); pulse (credit); delay(3000); pulse (credit) ; delay(3000); pulse (credit); delay(3000); currentscore = 0; return; } void set_clock (){ // The time needs to be player one so it will advance the minutes and hours correctly // but the other displays can be moved around or eliminated (if you have a two player game perhaps) targetscore = minutes * 10 + hours * 1000-1000; advance ( currentscore , targetscore ); digitalWrite(ballreturn, LOW); delay(2000); digitalWrite(ballreturn, HIGH); delay(4000); advance (0 , year*10-1000); delay (2000); digitalWrite(ballreturn, LOW); delay(2000); digitalWrite(ballreturn, HIGH); delay(4000); if (alarmhours == 0) advance (0,(alarmminutes*10 +24000)-1000); else advance (0,(alarmminutes*10 +alarmhours*1000)-1000); digitalWrite(ballreturn, LOW); delay(2000); digitalWrite(ballreturn, HIGH); delay(4000); advance (0, month*1000+day*10-1000); digitalWrite(ballreturn, LOW); delay(2000); digitalWrite(ballreturn, HIGH); delay(4000); currentscore = minutes * 10 + hours * 1000; displayedhours = hours; return; } int dayofweek(int y, int m, int d) { // Found this on Wikipedia // Sakamoto's Algorithm // My comments are longer than the calculations! static int t[] = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 }; y -= m < 3; return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7; } void flash (int flashcount){ // Handy to have different numers of flashes so you can see what is going on for (i=0 ; i< flashcount; i++){ digitalWrite (ledpin,HIGH); delay(100); digitalWrite(ledpin,LOW); delay(100); } return; } void set_alarm(){ // My method of dealing with keybounce - I ignore it! If a button got pressed I assume it was meant to be pressed // then add a slight delay and wait for the button to be released. // This runs once and only at startup. You have 20 seconds or so to start changing the alarm time // otherwise - just restart the Arduino timeout= millis() + 20000; while (millis ()= 24) alarmhours = alarmhours - 24; } else if (select_button == 2){ advance_button++; alarmminutes = advance_button-alarmhours; pulse (tens); delay(200); timeout = timeout +1000; if (alarmminutes == 60){ advance (0,400); alarmminutes = alarmminutes - 60; alarmhours ++; if (alarmhours >= 24) alarmhours = alarmhours - 24; } } } } } flash(7); set_shutoff(); if (alarmhours != int(EEPROM.read(0))) EEPROM.write(0,alarmhours); if (alarmminutes != int(EEPROM.read(1))) EEPROM.write(1,alarmminutes); if (offhours != int(EEPROM.read(2))) EEPROM.write(2,offhours); if (offminutes != int(EEPROM.read(3))) EEPROM.write(3,offminutes); flash (10); digitalWrite (power,LOW); return; } void set_shutoff(){ // Much the same as above (set_alarm) timeout= millis() + 20000; advance_button = 0; while (millis ()= 24) offhours = offhours - 24; } else if (select_button == 5){ advance_button++; offminutes = advance_button-offhours; pulse (tens); delay(200); timeout = timeout +1000; if (offminutes == 60){ advance (0,400); offminutes = offminutes - 60; offhours ++; if (offhours >= 24) offhours = offhours - 24; } } } } } flash(8); return; } void set_defaults(){ // Separated out from setup - just to make setup look cleaner pinMode ( tens, OUTPUT); digitalWrite( tens , HIGH ); pinMode ( hundreds, OUTPUT); digitalWrite( hundreds , HIGH ); pinMode ( thousands, OUTPUT); digitalWrite( thousands , HIGH ); pinMode ( credit, OUTPUT); digitalWrite( credit , HIGH ); pinMode ( coinup, OUTPUT); digitalWrite( coinup , HIGH ); pinMode ( ballreturn, OUTPUT); digitalWrite( ballreturn , HIGH ); pinMode ( power, OUTPUT); digitalWrite( power , LOW ); pinMode ( ledpin, OUTPUT); pinMode ( setbutton, INPUT ); pinMode ( advancebutton, INPUT); pinMode(bp1, INPUT); pinMode (bp2, INPUT); pinMode(relay, OUTPUT); digitalWrite(bp1, HIGH); digitalWrite(bp2, HIGH); alarmhours = int(EEPROM.read(0)); alarmminutes = int(EEPROM.read(1)); offhours = int(EEPROM.read(2)); offminutes = int(EEPROM.read(3)); return; } void setup (){ set_defaults(); Serial.begin (4800); flash(10); set_alarm(); on_time = alarmhours*60+alarmminutes; if (on_time >= 1440) on_time = 0; off_time = offhours *60+offminutes; if (off_time >=1440) off_time = 0; if (on_time == off_time) on_time++; } void loop () { // If it is time for sleep, power off the machine. If it is time to be awake - power it up and set the tim // and if it is already running - get that time display correct. // Also resets the game at midnight (to set the day correct) and when going from 12:59 to 01:00 updatefromgps (); if ( (on_time < off_time) && ((current_time < on_time) || (current_time > off_time)) || ((on_time > off_time) && (current_time > off_time) && (current_time < on_time)) ) digitalWrite(power,LOW); else{ if ((digitalRead(power) ==LOW) || (hours != displayedhours && hours_24 % 12 == 0)){ resetgame(); set_clock(); } else { targetscore = minutes * 10 + hours * 1000; if (currentscore < targetscore ){ advance (currentscore , targetscore); currentscore = targetscore; } else if (currentscore > targetscore) { resetgame(); set_clock(); digitalWrite(power,HIGH); flash(15); } } } }