//Import libraries. #include #include #include #include // This is the RealTimeModule address. #define DS1307 0x68 //Initialize LCD. LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // Initialize values for timekeeping. byte second = 0; byte minute = 0; byte hour = 0; byte weekday = 0; byte monthday = 0; byte month = 0; byte year = 0; //Initialize values for alarms. byte minsB1 = 0, hourB1 = 0, lastB1mins = 0, lastB1hour = 0; byte minsB2 = 0, hourB2 = 0, lastB2mins = 0, lastB2hour = 0; byte minsB3 = 0, hourB3 = 0, lastB3mins = 0, lastB3hour = 0; bool b1 = true, b2 = true, b3 = true; //Define photoresistor values. int bottle1 = 0; int bottle2 = 0; int bottle3 = 0; int lastBottle = 0; int bottleReset = 0; int curr = 0; // Define keypad values. #define btnRIGHT 0 #define btnUP 1 #define btnDOWN 2 #define btnLEFT 3 #define btnSELECT 4 #define btnNONE 5 int lcd_key = 0; int adc_key_in = 0; //Define memory locations for the EEPROM. #define ONE_PERIOD 0 #define ONE_PILLS 1 #define TWO_PERIOD 2 #define TWO_PILLS 3 #define THREE_PERIOD 4 #define THREE_PILLS 5 // Read keypad buttons. int read_LCD_buttons(){ adc_key_in = analogRead(0); //Debounce time. delay(100); //Correction for value drifting. int k = (analogRead(0) - adc_key_in); if(5 < abs(k)) { return btnNONE;} if (adc_key_in > 1000) return btnNONE; if (adc_key_in < 50) return btnRIGHT; if (adc_key_in < 250) return btnUP; if (adc_key_in < 450) return btnDOWN; if (adc_key_in < 650) return btnLEFT; if (adc_key_in < 850) return btnSELECT; return btnNONE; } //Menu variables. MenuBackend menu = MenuBackend(menuUsed,menuChanged); //initialize menuitems MenuItem setupMode = MenuItem("setupMode"); MenuItem setupHours = MenuItem("setupHours"); MenuItem setupMinutes = MenuItem("setupMinutes"); MenuItem setupBottles = MenuItem("setupBottles"); MenuItem B1interval = MenuItem("B1interval"); MenuItem B1pills = MenuItem("B1pills"); MenuItem B2interval = MenuItem("B2interval"); MenuItem B2pills = MenuItem("B2pills"); MenuItem B3interval = MenuItem("B3interval"); MenuItem B3pills = MenuItem("B3pills"); void setup(){ //Wire handles communication with RTM. Wire.begin(); //Serial is used for debugging purposes. Serial.begin(9600); //LCD is main output. lcd.begin(16, 2); //Set pins for LEDs. pinMode(11,OUTPUT); pinMode(12,OUTPUT); pinMode(13,OUTPUT); //Control backlight. pinMode(10, OUTPUT); analogWrite(10, 100); //Setup menu. menu.getRoot().add(setupMode); setupMode.add(setupBottles).addRight(setupHours).addRight(setupMinutes); setupBottles.add(B1interval).addRight(B1pills).addRight(B2interval).addRight(B2pills).addRight(B3interval).addRight(B3pills); menu.toRoot(); //Test EEPROM memory. EEPROM.write(ONE_PERIOD, (char)1); EEPROM.write(ONE_PILLS, (char)1); EEPROM.write(TWO_PERIOD, (char)1); EEPROM.write(TWO_PILLS, (char)2); EEPROM.write(THREE_PERIOD, (char)1); EEPROM.write(THREE_PILLS, (char)3); } void loop(){ //Check alarms for each bottle. checkAlarms(); //Manage GUI. if(menu.getCurrent().getName()==menu.getRoot()){ readTime(); mainMenuAction(); }else if(menu.getCurrent().getName() == "setupHours" || menu.getCurrent().getName() == "setupMinutes"){ printTime(); }else if(menu.getCurrent().getName() == "B1interval"){ printNumber(EEPROM.read(ONE_PERIOD)); }else if(menu.getCurrent().getName() == "B1pills"){ printNumber(EEPROM.read(ONE_PILLS)); }else if(menu.getCurrent().getName() == "B2interval"){ printNumber(EEPROM.read(TWO_PERIOD)); }else if(menu.getCurrent().getName() == "B2pills"){ printNumber(EEPROM.read(TWO_PILLS)); }else if(menu.getCurrent().getName() == "B3interval"){ printNumber(EEPROM.read(THREE_PERIOD)); }else if(menu.getCurrent().getName() == "B3pills"){ printNumber(EEPROM.read(THREE_PILLS)); }else{ lcd.setCursor(0,0); lcd.print(" "); } //Respond to user input (through pushbuttons) lcd_key = read_LCD_buttons(); navigateMenus(); } void navigateMenus(){ MenuItem currentMenu=menu.getCurrent(); switch (lcd_key) { case btnRIGHT: { menu.moveRight(); break; } case btnLEFT: { menu.moveLeft(); break; } case btnUP: { if(currentMenu.getName() == "setupHours"){ hour++; if(hour>23){hour=0;} setTime(); }else if(currentMenu.getName() == "setupMinutes"){ minute++; if(minute>59){minute=0;} setTime(); }else if(currentMenu.getName() == "B1pills"){ char newVal = EEPROM.read(ONE_PILLS); newVal = newVal + 1; if(newVal > 10){ newVal = 0;} EEPROM.write(ONE_PILLS, (char)newVal); }else if(currentMenu.getName() == "B1interval"){ char newVal = EEPROM.read(ONE_PERIOD); newVal = newVal + 1; if(newVal > 24){ newVal = 0;} EEPROM.write(ONE_PERIOD, (char)newVal); }else if(currentMenu.getName() == "B2pills"){ char newVal = EEPROM.read(TWO_PILLS); newVal = newVal + 1; if(newVal > 10){ newVal = 0;} EEPROM.write(TWO_PILLS, (char)newVal); }else if(currentMenu.getName() == "B2interval"){ char newVal = EEPROM.read(TWO_PERIOD); newVal = newVal + 1; if(newVal > 24){ newVal = 0;} EEPROM.write(TWO_PERIOD, (char)newVal); }else if(currentMenu.getName() == "B3pills"){ char newVal = EEPROM.read(THREE_PILLS); newVal = newVal + 1; if(newVal > 10){ newVal = 0;} EEPROM.write(THREE_PILLS, (char)newVal); }else if(currentMenu.getName() == "B3interval"){ char newVal = EEPROM.read(THREE_PERIOD); newVal = newVal + 1; if(newVal > 24){ newVal = 0;} EEPROM.write(THREE_PERIOD, (char)newVal); }else if(currentMenu.getName() == menu.getRoot()){ if(bottleReset == 1){ hourB1 = lastB1hour; minsB1 = lastB1mins; Serial.print("Last: "); Serial.print(lastB1hour); Serial.print(":"); Serial.println(lastB1mins); Serial.print("Now: "); Serial.print(hourB1); Serial.print(":"); Serial.println(minsB1); } } break; } case btnDOWN: { if(currentMenu.getName() == "setupHours"){ hour--; if(hour<0){hour=23;} setTime(); }else if(currentMenu.getName() == "setupMinutes"){ minute--; if(minute<0){minute=59;} setTime(); }else if(currentMenu.getName() == "B1pills"){ char newVal = EEPROM.read(ONE_PILLS); newVal = newVal - 1; if(newVal < 0){ newVal = 10;} EEPROM.write(ONE_PILLS, (char)newVal); }else if(currentMenu.getName() == "B1interval"){ char newVal = EEPROM.read(ONE_PERIOD); newVal = newVal - 1; if(newVal < 0){ newVal = 24;} EEPROM.write(ONE_PERIOD, (char)newVal); }else if(currentMenu.getName() == "B2pills"){ char newVal = EEPROM.read(TWO_PILLS); newVal = newVal - 1; if(newVal < 0){ newVal = 10;} EEPROM.write(TWO_PILLS, (char)newVal); }else if(currentMenu.getName() == "B2interval"){ char newVal = EEPROM.read(TWO_PERIOD); newVal = newVal - 1; if(newVal < 0){ newVal = 24;} EEPROM.write(TWO_PERIOD, (char)newVal); }else if(currentMenu.getName() == "B3pills"){ char newVal = EEPROM.read(THREE_PILLS); newVal = newVal - 1; if(newVal < 0){ newVal = 10;} EEPROM.write(THREE_PILLS, (char)newVal); }else if(currentMenu.getName() == "B3interval"){ char newVal = EEPROM.read(THREE_PERIOD); newVal = newVal - 1; if(newVal < 0){ newVal = 24;} EEPROM.write(THREE_PERIOD, (char)newVal); } break; } case btnSELECT: { if(currentMenu.moveDown()){ menu.moveDown(); }else{ menu.use(); } break; } case btnNONE: { break; } } } //Functions handling alarms. void setAlarm(int bottle, char interval){ if(bottle == 1){ lastB1hour = hourB1; lastB1mins = minsB1; hourB1 = minute + interval; if(hourB1>59){hourB1=hourB1-60;} minsB1 = second; //Debugging. Serial.print("Now: "); Serial.print(hourB1); Serial.print(":"); Serial.println(minsB1); }else if(bottle == 2){ lastB2hour = hourB2; lastB2mins = minsB2; hourB2 = minute + interval; if(hourB2>59){hourB2=hourB2-60;} minsB2 = second; Serial.print("Now: "); Serial.print(hourB2); Serial.print(":"); Serial.println(minsB2); }else if(bottle == 3){ lastB3hour = hourB3; lastB3mins = minsB3; hourB3 = minute + interval; if(hourB3>59){hourB3=hourB3-60;} minsB3 = second; Serial.print("Now: "); Serial.print(hourB3); Serial.print(":"); Serial.println(minsB3); } } void checkAlarms(){ if(!b1){ if(minute == hourB1 && second >= minsB1){ b1 = true; } } if(!b2){ if(minute == hourB2 && second >= minsB2){ b2 = true; } } if(!b3){ if(minute == hourB3 && second >= minsB3){ b3 = true; } } digitalWrite(11, b1); digitalWrite(12, b2); digitalWrite(13, b3); } //Helper functions for clock. byte decToBcd(byte val) {return ((val/10*16) + (val%10));} byte bcdToDec(byte val) {return ((val/16*10) + (val%16));} // Set the time in the RTM. void setTime() { // The following codes transmits the data to the RTC Wire.beginTransmission(DS1307); Wire.write(byte(0)); Wire.write(decToBcd(second)); Wire.write(decToBcd(minute)); Wire.write(decToBcd(hour)); Wire.write(decToBcd(weekday)); Wire.write(decToBcd(monthday)); Wire.write(decToBcd(month)); Wire.write(decToBcd(year)); Wire.write(byte(0)); Wire.endTransmission(); // Ends transmission of data } //Read time from RTM. void readTime() { Wire.beginTransmission(DS1307); Wire.write(byte(0)); Wire.endTransmission(); Wire.requestFrom(DS1307, 7); second = bcdToDec(Wire.read()); minute = bcdToDec(Wire.read()); hour = bcdToDec(Wire.read()); weekday = bcdToDec(Wire.read()); monthday = bcdToDec(Wire.read()); month = bcdToDec(Wire.read()); year = bcdToDec(Wire.read()); } //Print time. void printTime(){ lcd.setCursor(0,0); lcd.print(" "); if (hour < 10){lcd.print("0");} lcd.print(hour, DEC); lcd.print(":"); if (minute < 10){lcd.print("0");} lcd.print(minute, DEC); lcd.print(":"); if (second < 10){lcd.print("0");} lcd.print(second, DEC); lcd.print(" "); } //Print a number. void printNumber(int number){ lcd.setCursor(0,0); lcd.print(" "); if(number/10 == 0){ lcd.print("0"); }else{ lcd.print(" "); } lcd.print(number); lcd.print(" "); } //Menu callback functions. //Navigation controls. void menuChanged(MenuChangeEvent changed){ MenuItem newMenuItem=changed.to; //get the destination menu lcd.setCursor(0,1); //set the start position for lcd printing to the second row if(newMenuItem.getName()==menu.getRoot()){ lcd.print(" "); }else if (newMenuItem.getName()=="setupMode"){ lcd.print("ENTER SETUP MODE"); }else if (newMenuItem.getName()=="setupHours"){ lcd.print("Set hour. "); }else if (newMenuItem.getName()=="setupMinutes"){ lcd.print("Set minute. "); }else if (newMenuItem.getName()=="setupBottles"){ lcd.print("Setup bottles. "); }else if (newMenuItem.getName()=="B1interval"){ lcd.print("B1 interval. "); }else if (newMenuItem.getName()=="B1pills"){ lcd.print("B1 pill number. "); }else if (newMenuItem.getName()=="B2interval"){ lcd.print("B2 interval. "); }else if (newMenuItem.getName()=="B2pills"){ lcd.print("B2 pill number. "); }else if (newMenuItem.getName()=="B3interval"){ lcd.print("B3 interval. "); }else if (newMenuItem.getName()=="B3pills"){ lcd.print("B3 pill number. "); } } //Usage controls. void menuUsed(MenuUseEvent used){ menu.toRoot(); //back to Main } //Root menu action. void mainMenuAction(){ //Read values of photoresistors. bottle1 = analogRead(1); bottle2 = analogRead(2); bottle3 = analogRead(3); //Find out which bottle(s) are out of the box, print instructions. if(bottle1 < 800){ b1 = false; char nextIn = EEPROM.read(ONE_PERIOD); curr = 1; printInstructions(EEPROM.read(ONE_PILLS), nextIn); setAlarm(1,nextIn); } else if(bottle2 < 800){ b2 = false; curr = 2; char nextIn = EEPROM.read(TWO_PERIOD); printInstructions(EEPROM.read(TWO_PILLS), nextIn); setAlarm(2,nextIn); }else if(bottle3 < 800){ curr = 3; b3 = false; char nextIn = EEPROM.read(THREE_PERIOD); printInstructions(EEPROM.read(THREE_PILLS), nextIn); setAlarm(3,nextIn); }else{ if(lastBottle != 0){ lcd.clear(); lastBottle = 0; } printTime(); } } //Print instructions for each bottle. void printInstructions(int pills, int period){ //Don't clear if bottle hasn't changed. if(lastBottle != curr){ lcd.clear(); } lastBottle = curr; bottleReset = curr; lcd.setCursor(0,0); lcd.print("Take "); lcd.print(pills); lcd.print(" pill(s)"); lcd.setCursor(0,1); lcd.print("every "); lcd.print(period); lcd.print(" hours."); return; }