AvBrand Exploring Technology
AvBrand Exploring Technology
All Projects Car PC Thermostat Power Monitor Toilet Dog Dish PopCARD Cheapo Power Dance Floor 

PopCARD: Pop Machine Cash Card - Source Code

This code is copyright © 2011 Avatar-X. If you use it, please let me know.
// POPCARD INTERFACE // CREATED BY AvBrand.com, April 2011 #include <SPI.h> #include <Ethernet.h> #include <LiquidCrystal.h> #include "pitches.h" // the media access control (ethernet hardware) address for the shield: byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; byte ip[] = { 192, 168, 1, 10 }; //the IP address for the shield: byte server[] = { 192, 168, 1, 11 }; // The server to connect to. char data[50]; // Data buffer for TCP comms byte dataPos = 0; // Position in data buffer. char myName[20]; // Current user's name float myCredit = 0; // Current credit char serRead[20]; // Serial input buffer byte serPos = 0; // Position in input buffer. byte CURR_MODE = 0; // Current operation mode. long modeStart = 0; // When did we enter this mode? byte buyPrompt = 0; // Have we shown the "push to buy" prompt yet? long lastPing = 0; // When did we receive the last ping? #define PIN_RFID_RX 0 #define PIN_RFID_RESET 2 #define PIN_LCD_RS 3 #define PIN_LCD_ENABLE 4 #define PIN_LCD_D4 5 #define PIN_LCD_D5 6 #define PIN_LCD_D6 7 #define PIN_LCD_D7 8 #define PIN_VEND_RELAY 9 // pulse twice to add $1 to machine #define PIN_BILL_ENABLE A0 // when HIGH, the vending machine can accept money. #define PIN_BUTTON A1 // press to add money #define PIN_BUZZER A2 // the piezo buzzer #define PIN_RESET_NET A3 // network module reset // LCD and TCP clients LiquidCrystal lcd(PIN_LCD_RS, PIN_LCD_ENABLE, PIN_LCD_D4, PIN_LCD_D5, PIN_LCD_D6, PIN_LCD_D7); Client client(server, 6643); #define MODE_STARTUP 0 // Initial mode #define MODE_CONNECT 1 // Connecting #define MODE_UNAVAIL 2 // Unavailable / Not connected #define MODE_IDLE 3 // Idle, Not doing anything #define MODE_WAIT_NAME 4 // Tag was scanned, waiting for the name of the person #define MODE_WAIT_CREDIT 5 // Name received, now waiting for the credit amount to show up. #define MODE_READY 6 // Ready for the user to insert money with the button #define MODE_ERROR 7 // Something went wrong. #define MODE_WAIT_BUY 8 // Waiting for BUY confirmation. #define MODE_NO_MONEY 9 // No money #define MODE_NO_MONEY2 10 // No Money message #2 #define MODE_NO_MORE 11 // Can't put any money in right now, due to INHIBIT #define MODE_UNKNOWN 12 // Unknown card was scanned void setup() { buzz(NOTE_C4, 8); // Startup sound delay(500); // Start up the ethernet interface. pinMode(PIN_RESET_NET, OUTPUT); digitalWrite(PIN_RESET_NET, LOW); // Startup sound again buzz(NOTE_D4, 8); // Set up the ethernet and serial. Ethernet.begin(mac, ip); Serial.begin(9600); // Give the ethernet time to start up. delay(500); // Startup sound position 3 buzz(NOTE_E4, 8); // Set up the LCD module lcd.begin(16, 2); lcd.print("Startup"); buzz(NOTE_G4, 8); // Set up my pins. pinMode(PIN_VEND_RELAY, OUTPUT); pinMode(PIN_RFID_RESET, OUTPUT); pinMode(PIN_BILL_ENABLE, INPUT); pinMode(PIN_BUTTON, INPUT); pinMode(PIN_BUZZER, OUTPUT); // Play the "One Up" sound to start soundOneUp(); // Turn on the RFID module digitalWrite(PIN_RFID_RESET, HIGH); // Set the initial mode and make the connection. setMode(MODE_STARTUP); connectToServer(); } void loop () { // Main program loop. long mil = millis(); // Did the timer loop around? Prevent errors or hangs by the timer looping back to 0 if (lastPing > mil) lastPing = mil; if (modeStart > mil) modeStart = mil; // Is my TCP connection still alive? if ((!client.connected() && lastPing == 0) || mil - lastPing > 15000) { // Reconnect. connectToServer(); } // If we are connected, then the rest of the logic can run. switch (CURR_MODE) { case MODE_IDLE: checkRFID(); // See if a tag has been scanned. break; case MODE_READY: // Only allow us to be in this mode for 8 seconds if (mil - modeStart > 8000) { setMode(MODE_IDLE); // Jump out of this mode and go back to being ready to scan cards } if (mil - modeStart > 4000 && buyPrompt == 0) // Display buy prompt after 4 seconds { buyPrompt = 1; // 1234567890123456 lcd.clear(); lcd.print("Push Button"); lcd.setCursor(0,1); lcd.print("to spend $1.00"); break; } // Check the button. if (digitalRead(PIN_BUTTON) == HIGH) { // Are we allowed to add money? if (digitalRead(PIN_BILL_ENABLE) == HIGH) { setMode(MODE_WAIT_BUY); sendCommand('B', ""); } else { // We've already reached the max amount, or maybe the pop machine isn't ready for us. setMode(MODE_NO_MORE); } } break; case MODE_WAIT_NAME: // Timeout for these modes case MODE_WAIT_CREDIT: case MODE_WAIT_BUY: if (mil - modeStart > 8000) setMode(MODE_ERROR); // Jump out of this mode and go back to being ready to scan cards break; case MODE_ERROR: case MODE_NO_MONEY2: case MODE_UNKNOWN: if (mil - modeStart > 2000) setMode(MODE_IDLE); // Jump out of this mode and go back to being ready to scan cards break; case MODE_NO_MORE: if (mil - modeStart > 2000) setMode(MODE_READY); // Go back to the credit display. break; case MODE_NO_MONEY: if (mil - modeStart > 2000) setMode(MODE_NO_MONEY2); // Show the 2nd 'No Money' message break; } if (client.connected()) { // See if the client has sent us any data. checkNetData(); } } void setMode(byte b) // Change to this mode. { CURR_MODE = b; modeStart = millis(); // When did we enter this mode? lcd.clear(); switch(b) { case MODE_STARTUP: // 1234567890123456 lcd.print("Starting Up..."); break; case MODE_CONNECT: lcd.print("Connecting..."); break; case MODE_UNAVAIL: lcd.print("Cards Not Avail."); lcd.setCursor(0,1); lcd.print("Use Coins Below"); // Turn off the RFID module. digitalWrite(PIN_RFID_RESET, LOW); break; case MODE_IDLE: // 1234567890123456 lcd.print(" Scan your "); lcd.setCursor(0,1); lcd.print(" PopCARD now! "); // Turn on the RFID module. digitalWrite(PIN_RFID_RESET, HIGH); break; case MODE_WAIT_NAME: lcd.print("Please wait..."); break; case MODE_WAIT_CREDIT: lcd.setCursor(0,1); lcd.print("Please wait..."); break; case MODE_READY: buyPrompt = 0; lcd.print(myName); showMoney(); break; case MODE_ERROR: lcd.print("An error occured."); break; case MODE_WAIT_BUY: lcd.print("Adding Credit, "); lcd.setCursor(0,1); lcd.print("Please Wait!"); break; case MODE_NO_MONEY: // 1234567890123456 lcd.print("Not Enough Funds"); showMoney(); break; case MODE_NO_MORE: // 1234567890123456 lcd.print("Max Amount"); lcd.setCursor(0,1); lcd.print("Reached."); break; case MODE_NO_MONEY2: // 1234567890123456 lcd.print("See Alex"); lcd.setCursor(0,1); lcd.print("to buy credit."); break; case MODE_UNKNOWN: // 1234567890123456 lcd.print("Invalid or"); lcd.setCursor(0,1); lcd.print("Unknown Card"); break; } } void showMoney() { lcd.setCursor(0,1); // 1234567890123456 // Credit: $XX.XX lcd.print("Credit: $"); lcd.print(myCredit, DEC); lcd.setCursor(myCredit < 10 ? 13 : 14, 1); lcd.print(" "); } void connectToServer() { lastPing = millis(); setMode(MODE_CONNECT); // Reset the network module before all connections. buzz(NOTE_C4, 8); digitalWrite(PIN_RESET_NET, LOW); delay(100); digitalWrite(PIN_RESET_NET, HIGH); delay(500); Ethernet.begin(mac, ip); delay(1000); client.stop(); // Close the connection if (client.connect()) { setMode(MODE_IDLE); } else { setMode(MODE_UNAVAIL); } } void checkNetData() { // See if there is data available on the network interface. if (client.available() > 0) { byte d = client.read(); switch (d) { case 0x02: // Start of transmission dataPos = 0; break; case 0x03: // End of transmission data[dataPos] = 0; // Blank out the end. readCommand(); break; default: // Data byte. Put it in the buffer. data[dataPos] = d; dataPos++; } } } void readCommand() // Parse an input command from the network interface. { // First byte should be the command. char dd[20]; // Copy the data. for (byte i = 1; i <= dataPos && i < 21; i++) dd[i-1] = data[i]; switch (data[0]) { case 'P': // Ping lastPing = millis(); break; case 'N': // Name has arrived. Copy into MyName if (CURR_MODE == MODE_WAIT_NAME) { for (byte i = 1; i <= dataPos && i < 21; i++) myName[i-1] = data[i]; setMode(MODE_WAIT_CREDIT); } break; case 'C': // Credit amount has arrived if (CURR_MODE == MODE_WAIT_CREDIT) { myCredit = atof(dd); setMode(MODE_READY); } break; case 'Y': // Yes, you may buy. if (CURR_MODE == MODE_WAIT_BUY) { myCredit = atof(dd); // Store the new credit amount soundOneUp(); // Play the credit noise addCredit(); // Add $1 to the vending machine. delay(700); // Provide enough time for the pop machine to register the credit. setMode(MODE_READY); } break; case 'X': // Not enough money. if (CURR_MODE == MODE_WAIT_BUY) { // Play a sad sound. buzz(NOTE_G5, 8); buzz(NOTE_G4, 8); buzz(NOTE_G3, 8); // Show the no money message. setMode(MODE_NO_MONEY); } break; case 'R': // Unknown card. setMode(MODE_UNKNOWN); break; } } void sendCommand(byte cmd, char cData[]) // Send a command to the host. { // Send a command back to the server. client.write(0x02); client.write(cmd); client.print(cData); client.write(0x03); } void checkRFID() { // Check the serial port for data from the RFID module. if (Serial.available() > 0) { byte d = Serial.read(); switch (d) { case 0x02: // Start of transmission serPos = 0; break; case 0x03: // End of transmission readTag(); break; default: // Add to buffer. serRead[serPos] = d; serPos++; } } } void readTag() // Parse the data from a card. { serRead[10] = 0; Serial.print("Card Read:"); Serial.println(serRead); setMode(MODE_WAIT_NAME); // Make a beep buzz(NOTE_B4, 8); buzz(NOTE_E5, 4); // Ask the server who this is. sendCommand('S', serRead); // Turn off the RFID module. digitalWrite(PIN_RFID_RESET, LOW); } void addCredit() { // Pulsing the 'VEND NO' and 'VEND COM' lines on the vendor // twice tells it that $1 has been inserted. digitalWrite(PIN_VEND_RELAY, HIGH); delay(150); digitalWrite(PIN_VEND_RELAY, LOW); delay(400); digitalWrite(PIN_VEND_RELAY, HIGH); delay(150); digitalWrite(PIN_VEND_RELAY, LOW); } void buzz(long note, long dTime) { // Play a tone. tone(PIN_BUZZER, note, 1000 / dTime); delay(1000/dTime); noTone(PIN_BUZZER); } void soundOneUp() { // Make the one-up sound. tone(PIN_BUZZER, NOTE_E5, 125); delay(125); tone(PIN_BUZZER, NOTE_G5, 125); delay(125); tone(PIN_BUZZER, NOTE_E6, 125); delay(125); tone(PIN_BUZZER, NOTE_C6, 125); delay(125); tone(PIN_BUZZER, NOTE_D6, 125); delay(125); tone(PIN_BUZZER, NOTE_G6, 125); delay(125); noTone(PIN_BUZZER); }
copyright © 2024 AvBrand.com - sitemap