Advertisement
Guest User

Untitled

a guest
Jun 3rd, 2013
52
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 12.08 KB | None | 0 0
  1. // include the Arduino LCD and math libraries
  2. #include <LiquidCrystal.h>
  3.  
  4. // States
  5. #define S_idle 1
  6. #define S_ready 2
  7. #define S_coin 3
  8. #define S_set_timer 4
  9. #define S_pause 5
  10. #define S_override 6
  11. #define S_limit 7
  12. #define S_countdown 8
  13. #define S_timeup 9
  14.  
  15. // Default startup state
  16. int state = S_idle;
  17.  
  18. // LCD PINs
  19. LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
  20.  
  21. // Display backlight pins
  22. const int LCDr = 3;
  23. const int LCDg = 5;
  24. const int LCDb = 6;
  25.  
  26. // Other PINs
  27. const int CoinSW = 2;
  28. const int VideoSW = 4;
  29. const int StartSW = A0;
  30. const int PauseSW = A1;
  31. const int CoinLED = A2;
  32. const int OverrideSW = A3;
  33. const int VideoDetect  = A4;
  34. const int Speaker = A5;
  35.  
  36. // Button debounce vars
  37. int buttonState;
  38. int lastButtonState = HIGH;
  39. long lastDebounceTime = 0;
  40. long debounceDelay = 50;
  41.  
  42. // Coin counting and time vars
  43. unsigned long AllowedPlaytime;
  44. unsigned long CurrentMillis;
  45. int CoinCount = 0;
  46. int CoinTimeValue = 30; // Amount of time (in minutes) that the coin is worth.
  47. int DepositStringIndex = 0;
  48. int TimeStringIndex = 0;
  49.  
  50. // Video on/off switching vars
  51. int VideoSwitchState = LOW;
  52. long VideoSwitchBuffer = 2000; // Add some seconds to AllowedPlaytime after video ON switching event to compensate for TV sync time.
  53. unsigned long SwitchPreviousMillis = 0;
  54. long VideoSwitchInterval = 500;
  55.  
  56. // Warning beep vars
  57. unsigned long LastWarningTime = 0;
  58. long WarningBeepInterval1 = 60000; // 60 seconds
  59. long WarningBeepInterval2 = 1000; // 1 seconds
  60.  
  61. bool ClearLCD = false;
  62. bool PauseRun = false;
  63.  
  64. // Strings for the deposit display
  65. char* DepositStrings[]= {
  66. "     ", // Placeholder does not display.
  67. "$0.25", // 30 min
  68. "$0.50", // 1 hour
  69. "$0.75", // 1.5 hours
  70. "$1.00", // 2 hours
  71. "$1.25", // 2.5 hours
  72. "$1.50", // 3 hours
  73. "$1.75", // 3.5 hours
  74. "$2.00", // 4 hours
  75. "$2.25", // 4.5 hours
  76. "$2.50", // 5 hours
  77. "$2.75", // 5.5 hours
  78. "$3.00", // 6 hours
  79. "$3.25", // 6.5 hours
  80. "$3.75", // 7 hours
  81. "$4.00", // 7.5 hours
  82. "$4.25", // Placeholder does not display.
  83. };
  84.  
  85. char* TimeStrings[]= {
  86. "     ", // Placeholder does not display.
  87. "30m  ",
  88. "1h   ",
  89. "1.5h ",
  90. "2h   ",
  91. "2.5h ",
  92. "3h   ",
  93. "3.5h ",
  94. "4h   ",
  95. "4.5h ",
  96. "5h   ",
  97. "5.5h ",
  98. "6h   ",
  99. "6.5h ",
  100. "7h   ",
  101. "7.5h ",
  102. "8h   ", // Placeholder does not display.
  103. };
  104.  
  105. // Characters for display on the LCD.
  106. byte armsUp[8] = {
  107.   0b00100,
  108.   0b01010,
  109.   0b00100,
  110.   0b10101,
  111.   0b01110,
  112.   0b00100,
  113.   0b00100,
  114.   0b01010
  115. };
  116.  
  117. byte armsDown[8] = {
  118.   0b00100,
  119.   0b01010,
  120.   0b00100,
  121.   0b00100,
  122.   0b01110,
  123.   0b10101,
  124.   0b00100,
  125.   0b01010
  126. };
  127.  
  128. byte smiley[8] = {
  129.   0b00000,
  130.   0b00000,
  131.   0b01010,
  132.   0b00000,
  133.   0b00000,
  134.   0b10001,
  135.   0b01110,
  136.   0b00000
  137. };
  138.  
  139. byte frownie[8] = {
  140.   0b00000,
  141.   0b00000,
  142.   0b01010,
  143.   0b00000,
  144.   0b00000,
  145.   0b00000,
  146.   0b01110,
  147.   0b10001
  148. };
  149.  
  150. void setup() {
  151. // Initilize the LCD
  152. lcd.begin(16, 2);
  153.  
  154. // Set PINs as inputs or outputs.
  155. pinMode(LCDr, OUTPUT);
  156. pinMode(LCDg, OUTPUT);
  157. pinMode(LCDb, OUTPUT);
  158. pinMode(VideoSW, OUTPUT);
  159. pinMode(Speaker, OUTPUT);
  160. pinMode(CoinSW, INPUT);
  161. pinMode(StartSW, INPUT);
  162. pinMode(PauseSW, INPUT);
  163. pinMode(CoinLED, OUTPUT);
  164. pinMode(OverrideSW, INPUT);
  165. pinMode(VideoDetect,INPUT);
  166.  
  167. // Enable internal resistors on button PINs so we don't have to use external resistors.
  168. digitalWrite(CoinSW, HIGH);
  169. digitalWrite(StartSW, HIGH);
  170. digitalWrite(PauseSW, HIGH);
  171. digitalWrite(OverrideSW, HIGH);
  172. digitalWrite(VideoDetect, HIGH);
  173.  
  174. // Initilize special LCD charaters.
  175. lcd.createChar(1, armsUp);
  176. lcd.createChar(2, armsDown);
  177. lcd.createChar(3, smiley);
  178. lcd.createChar(4, frownie);
  179.  
  180. // For testing comment out in production.
  181. Serial.begin(9600);
  182. }
  183.  
  184. void loop() {
  185.     switch(state) {
  186.      
  187.       case S_idle:
  188.         F_idle();
  189.       break;
  190.    
  191.       case S_ready:
  192.         F_ready();
  193.       break;
  194.      
  195.       case S_override:
  196.         F_override();
  197.       break;
  198.      
  199.       case S_coin:
  200.         F_coin();
  201.       break;
  202.      
  203.       case S_limit:
  204.         F_limit();
  205.       break;
  206.      
  207.       case S_set_timer:
  208.         F_set_timer();
  209.       break;  
  210.    
  211.       case S_countdown:
  212.         F_countdown();
  213.       break;
  214.    
  215.       case S_timeup:
  216.         F_timeup();
  217.       break;
  218.      
  219.       case S_pause:
  220.         F_pause();
  221.       break;  
  222.    }
  223. }
  224.  
  225. // Functions //
  226. void F_idle() {
  227.   LCDBacklight(255, 0, 0); // Red
  228.   lcd.setCursor(2, 0);
  229.   lcd.write(2);
  230.   lcd.print(" NOT READY ");
  231.   lcd.write(2);
  232.   lcd.setCursor(3, 1);
  233.   lcd.print("Press START");
  234.  
  235.   DepositStringIndex = 0; // Reset
  236.   TimeStringIndex = 0; // Reset
  237.   CoinCount =0; // Reset
  238.  
  239.   // If it's on, turn the video off.
  240.   while (digitalRead(VideoDetect) == LOW) {
  241.     F_video_off();
  242.   }
  243.  
  244.   if (digitalRead(StartSW) == LOW) { // Button logic is invertid since we're using the internal resistors. When button is pressed the PIN goes LOW, when not pressed it's HIGH.
  245.     lcd.clear();
  246.     state = S_ready;
  247.   }
  248.  
  249.   if (digitalRead(OverrideSW) == LOW){
  250.     lcd.clear();
  251.     state = S_override;
  252.   }
  253. }
  254.  
  255. void F_ready() {
  256.   LCDBacklight(0, 255, 0);
  257.   lcd.setCursor(4, 0);
  258.   lcd.write(1);
  259.   lcd.print(" READY ");
  260.   lcd.write(1);
  261.   lcd.setCursor(2, 1);
  262.   lcd.print("Insert Coins");
  263.  
  264.   digitalWrite(CoinLED, HIGH);
  265.  
  266.   if (digitalRead(CoinSW) == LOW) {
  267.     lcd.clear();
  268.     state = S_coin;
  269.   }
  270. }
  271.  
  272. void F_override() {
  273.   if (ClearLCD == true) {
  274.     ClearLCD = false;
  275.     lcd.clear();
  276.   }
  277.  
  278.   // Turn the video on.
  279.   while (digitalRead(VideoDetect) == HIGH) {
  280.     F_video_on();
  281.   }
  282.  
  283.   LCDBacklight(255,255,0); // Yellow
  284.   lcd.setCursor(3, 0);
  285.   lcd.print("Override On");
  286.   lcd.setCursor(2, 1);
  287.   lcd.write(3);
  288.   lcd.print(" Lucky You ");
  289.   lcd.write(3);
  290.  
  291.   if (digitalRead(OverrideSW) == HIGH){
  292.     lcd.clear();
  293.     state = S_idle;
  294.   }    
  295. }
  296.  
  297. void F_coin() {
  298.   LCDBacklight(255, 153, 0); // Orange
  299.   lcd.setCursor(0, 0);
  300.   lcd.print("Deposited:");
  301.   lcd.print(DepositStrings[DepositStringIndex]);
  302.   lcd.setCursor(0, 1);
  303.   lcd.print("Playtime:");
  304.   lcd.print(TimeStrings[TimeStringIndex]);
  305.  
  306. // We need to debounce the coin counting switch. Otherwise we'd count several coins when only one was deposited.
  307.   int reading = digitalRead(CoinSW) == LOW;
  308.  
  309.   if (reading != lastButtonState) {
  310.     lastDebounceTime = millis();
  311.   }
  312.  
  313.   if ((millis() - lastDebounceTime) > debounceDelay) {
  314.     if (reading != buttonState) {
  315.       buttonState = reading;
  316.       if (buttonState == LOW) { // Logic is invertid since we're using the internal resistors. When button is pressed the PIN goes LOW, when not pressed it's HIGH.
  317.         CoinCount = CoinCount + CoinTimeValue; // Count the coin deposit.
  318.         DepositStringIndex++;
  319.         TimeStringIndex++;
  320.       }
  321.     }
  322.   }
  323.   lastButtonState = reading;
  324. // Done debouncing and depositing.
  325.  
  326.   if (DepositStringIndex == 15) {
  327.    CoinCount = CoinCount + CoinTimeValue; // System does not grab the last coin deposited when it hits the limit so we count it here.
  328.    lcd.clear();
  329.    digitalWrite(CoinLED, LOW);
  330.    state = S_limit;
  331.   }
  332.  
  333.   if (digitalRead(StartSW) == LOW) { // Logic is inverted since we're using the internal resistors. When button is pressed the PIN goes LOW, when not pressed it's HIGH.
  334.     lcd.clear();
  335.     digitalWrite(CoinLED, LOW);
  336.     state = S_set_timer;
  337.   }
  338. }
  339.  
  340. void F_limit() {
  341.   LCDBacklight(255, 0, 0); // Red
  342.   lcd.setCursor(2, 0);
  343.   lcd.print("8 Hour Limit");
  344.   lcd.setCursor(3, 1);
  345.   lcd.print("Press START");
  346.  
  347.   if (digitalRead(StartSW) == LOW) { // Logic is inverted since we're using the internal resistors. When button is pressed the PIN goes LOW, when not pressed it's HIGH.
  348.     lcd.clear();
  349.     state = S_set_timer;
  350.   }
  351. }
  352.  
  353. void F_set_timer() {
  354.   AllowedPlaytime = CoinCount * 60000; // Multiply the CoinCount by 60000 (milliseconds) to get teh AllowedPlaytime.
  355.  
  356.   // Turn the video on.
  357.   while (digitalRead(VideoDetect) == HIGH) {  
  358.     F_video_on();
  359.   }
  360.  
  361.   AllowedPlaytime = AllowedPlaytime + VideoSwitchBuffer; // Add some time (VideoSwitchBuffer) to make up for the time it took the TV to sync back up and display video.
  362.  
  363.   state = S_countdown;
  364. }
  365.  
  366. void F_countdown() {
  367.   if (ClearLCD == true) {
  368.     lcd.clear();
  369.     ClearLCD = false;
  370.   }
  371.  
  372.   LCDBacklight(0, 0, 255); // Blue
  373.   lcd.setCursor(2, 0);
  374.   lcd.print("Time Started:");
  375.  
  376.   // If second has passed then we subtract that from the AllowedPlaytime
  377.   if (millis() - CurrentMillis > 1000) {
  378.     AllowedPlaytime = AllowedPlaytime - 1000;
  379.     CurrentMillis = millis();
  380.     F_timeDisplay();
  381.    
  382.   // If there is less than 5 minutes of playtime left start sounding an audible alarm at the interval defined.  
  383.   if (AllowedPlaytime <= 300000) { // 5 min
  384.     if (millis() - LastWarningTime > WarningBeepInterval1) {
  385.       F_warning1();
  386.     }
  387.  
  388.   // Or if there is less than 10 seconds of playtime left start sounding an audible alarm at the interval defined.
  389.   else if (AllowedPlaytime <= 10000) { // 10 seconds
  390.     if (millis() - LastWarningTime > WarningBeepInterval2) {
  391.       F_warning2();
  392.     }
  393.   }
  394. }
  395.   }
  396.  
  397.   if (digitalRead(PauseSW) == LOW) { // Logic is inverted since we're using the internal resistors. When button is pressed the PIN goes LOW, when not pressed it's HIGH.
  398.     lcd.clear();
  399.     state = S_pause;
  400.   }
  401.  
  402.   if (AllowedPlaytime == 0) {
  403.     lcd.clear();
  404.     state = S_timeup;
  405.   }
  406. }
  407.  
  408. void F_pause() {
  409.   LCDBacklight(255, 0, 255); // Pink
  410.   lcd.setCursor(2, 0);
  411.   lcd.print("Time Paused:");
  412.  
  413.   F_timeDisplay();
  414.  
  415.   // Turn the video off to prevent abuse of the pause.
  416.   while (digitalRead(VideoDetect) == LOW) {
  417.     F_video_off();
  418.   }
  419.    
  420.   if (digitalRead(StartSW) == LOW) { // Logic is inverted since we're using the internal resistors. When button is pressed the PIN goes LOW, when not pressed it's HIGH.
  421.     lcd.clear();
  422.     // Turn the video back on since we unpaused.
  423.     while (digitalRead(VideoDetect) == HIGH) {
  424.       F_video_on();
  425.     }
  426.    
  427.     AllowedPlaytime = AllowedPlaytime + VideoSwitchBuffer; // Add some time (VideoSwitchBuffer) to make up for the time it took to turn the video on.
  428.     state = S_countdown;
  429.   }
  430. }
  431.  
  432. void F_timeup() {
  433.   LCDBacklight(255, 255, 0); // Yellow
  434.   lcd.setCursor(2, 0);
  435.   lcd.write(4);
  436.   lcd.print(" Times Up ");
  437.   lcd.write(4);
  438.  
  439.   tone(Speaker, 2000, 1000);
  440.  
  441.   while (digitalRead(VideoDetect) == LOW) {
  442.     F_video_off();
  443.   }
  444.  
  445.   delay(5000);
  446.  
  447.   state = S_idle;
  448. }
  449.  
  450. void F_timeDisplay() {
  451.   lcd.setCursor(4, 1);
  452.  
  453.   int seconds = AllowedPlaytime / 1000;
  454.   int minutes = seconds / 60;
  455.   int hours = minutes / 60;
  456.  
  457.   seconds = seconds % 60;
  458.   minutes = minutes % 60;
  459.    
  460.   if (hours < 10) {
  461.     lcd.print("0");
  462.     lcd.print(hours);
  463.     lcd.print(":");
  464.      
  465.   if (minutes < 10)
  466.     lcd.print("0");
  467.     lcd.print(minutes);
  468.     lcd.print(":");
  469.        
  470.   if (seconds < 10)      
  471.     lcd.print("0");    
  472.     lcd.print(seconds);
  473.   }
  474. }
  475.  
  476. void F_video_on() {
  477.   LCDBacklight(255,255,0); // Yellow
  478.   lcd.setCursor(5, 0);
  479.   lcd.print("Standby");
  480.   lcd.setCursor(0, 1);
  481.   lcd.print("Turning Video On");
  482.  
  483.   unsigned long CurrentMillis = millis();
  484.    
  485.     if(CurrentMillis - SwitchPreviousMillis > VideoSwitchInterval) {
  486.       SwitchPreviousMillis = CurrentMillis;  
  487.         if (VideoSwitchState == LOW)
  488.           VideoSwitchState = HIGH;
  489.         else
  490.           VideoSwitchState = LOW;
  491.     digitalWrite(VideoSW, VideoSwitchState);
  492.     }
  493.   ClearLCD = true;  
  494. }
  495.  
  496. void F_video_off() {
  497.   unsigned long CurrentMillis = millis();
  498.    
  499.     if(CurrentMillis - SwitchPreviousMillis > VideoSwitchInterval) {
  500.       SwitchPreviousMillis = CurrentMillis;  
  501.         if (VideoSwitchState == LOW)
  502.           VideoSwitchState = HIGH;
  503.         else
  504.           VideoSwitchState = LOW;    
  505.     digitalWrite(VideoSW, VideoSwitchState);
  506.     }
  507. }
  508.  
  509. void F_warning1() {
  510.   tone(Speaker, 500, 1000);
  511.   LastWarningTime = millis();
  512. }
  513.  
  514. void F_warning2() {
  515.   tone(Speaker, 1000, 200);
  516.   LastWarningTime = millis();
  517. }
  518.  
  519. void LCDBacklight(uint8_t r, uint8_t g, uint8_t b) {
  520.   // common anode so invert!
  521.   r = map(r, 0, 255, 255, 0);
  522.   g = map(g, 0, 255, 255, 0);
  523.   b = map(b, 0, 255, 255, 0);
  524.   analogWrite(LCDr, r);
  525.   analogWrite(LCDg, g);
  526.   analogWrite(LCDb, b);
  527. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement