/*
July 16, 2020
This will be use to explore the use of 4x4 keypad for
1. T9 text entry
2. A, B, C, and D will be use for the menu operations
Author: George Bantique ( TechToTinker )
*/
// #include "LiquidCrystal.h"
#include "Keypad.h"
#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
#include <Wire.h>
#define DEFAULT_DELAY 300
const int stepsPerRevolution = 2048;
const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
int x = 0; // Holds the LCD x position
int y = 0; // Holds the LCD y position
int minValue = 0; // Lower character location for T9 text entry
int maxValue = 0; // Max character location for T9 text entry
int keyPressTime = 200; // Number of loops check of the key
String msg = ""; // Holds the created message
String num = ""; // Holds the mobile number
String alpha = "!@_$%?1 ABCabc2 DEFdef3 GHIghi4 JKLjkl5 MNOnmo6 PQRSpqrs7 TUVtuv8 WXYZwxyz9 * 0# "; // Characters for T9 text entry
char hexaKeys[ROWS][COLS] = { // Character matrix for the keypad
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {7, 6, 5, 4}; // pin assignments for keypad rows
byte colPins[COLS] = {3, 2, 1, 0}; // pin assignments for keypad columns
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);
// LiquidCrystal lcd(13, 12, 11, 10, 9, 8); // pin assignments for LCD
LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 20, 4);
byte charUp[8] = { // arrow up character for LCD
B00100,
B01110,
B11111,
B00000,
B00000,
B00000,
B00000,
B00000
};
byte charDown[8] = { // arrow down character for LCD
B00000,
B00000,
B00000,
B00000,
B00000,
B11111,
B01110,
B00100
};
byte charUpDown[8] = { // arrow up and down character for LCD
B00100,
B01110,
B11111,
B00000,
B00000,
B11111,
B01110,
B00100
};
byte menuLevel = 0; // Level 0: no menu display, display anything you like
// Level 1: display main menu
// Level 2: display sub menu
// Level 3: display sub menu of sub menu
byte menu = 1; // holds the menu level
byte sub = 1; // holds the sub menu level
String account_number;
int distance_value;
RTC_DS1307 rtc;
DateTime now;
char daysOfWeek[7][12] = {
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday"
};
String month;
String date_year;
String day;
String hours;
String minutes;
String seconds;
void setup()
{
// Serial.begin(115200);
lcd.init();
lcd.backlight();
lcd.begin(20, 4); // initialized the LCD as 16 characters with 2 lines
if (! rtc.begin()) {
lcd.clear();
lcd.print("Couldn't find RTC");
Serial.println("Couldn't find RTC");
Serial.flush();
abort();
}
Serial.println("Updating time...");
lcd.clear();
lcd.print("Updating time...");
// automatically sets the RTC to the date & time on PC this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
lcd.createChar(0, charUp); // arrow up character
lcd.createChar(1, charDown); // arrow down character
lcd.createChar(2, charUpDown); // arrow up and down character
updateLevel_0(); // display the HOME screen
}
void loop() {
// Process the keys
processkey();
// updateLevel_0();
// restart();
// Do other stuffs here
}
void restart(){
int delay_time = 0;
lcd.clear();
for(int i = 9; delay_time < i ; i--){
lcd.setCursor(0,0);
lcd.print("Sys. restarting in");
lcd.setCursor(0,19);
lcd.print(i);
delay(1000);
}
lcd.clear();
lcd.setCursor(0,1);
lcd.print("Done resetting");
delay(1500);
}
void processkey() {
char key = customKeypad.getKey();
if (isAlpha(key)) { // check if key press is a letter
processKeys(key); // process it according to keys
}
}
void processKeys(char keyPressed) {
switch (menuLevel) {
case 0: // Level 0, home screen
switch ( keyPressed ) {
case 'D': // Enter
menu = 1;
menuLevel = 1; // go to main menu
updateLevel_1(); // show main menu
delay(DEFAULT_DELAY);
break;
case 'A': // Up
break;
case 'B': // Down
break;
case 'C': // Back
menuLevel = 0; // go to home screen
updateLevel_0(); // show home screen
delay(DEFAULT_DELAY);
break;
default:
break;
}
break;
case 1: // Level 1, main menu
switch ( keyPressed ) {
case 'D': // Enter
switch (menu){
case 0:
break;
case 1:
set_account();
menuLevel = 1; // go to sub menu
updateLevel_1();
delay(DEFAULT_DELAY);
break;
case 2:
Account_info();
menuLevel = 1; // go to sub menu
updateLevel_1();
delay(DEFAULT_DELAY);
break;
case 3:
refill();
// menuLevel = 1; // go to sub menu
updateLevel_1();
delay(DEFAULT_DELAY);
break;
case 4:
// set_account();
menuLevel = 1; // go to sub menu
updateLevel_1();
delay(DEFAULT_DELAY);
break;
case 5:
Account_info();
menuLevel = 1; // go to sub menu
updateLevel_1();
delay(DEFAULT_DELAY);
break;
case 6:
lcd.clear();
lcd.print("Enter Network name");
delay(1000);
enterMSG();
delay(500);
lcd.clear();
lcd.print("Enter Network pass");
delay(500);
enterNUM();
menuLevel = 1; // go to sub menu
updateLevel_1();
delay(DEFAULT_DELAY);
break;
default:
break;
}
case 'A': // Up
menu--;
updateLevel_1(); // show main menu
delay(DEFAULT_DELAY);
break;
case 'B': // Down
menu++;
updateLevel_1(); // show main menu
delay(DEFAULT_DELAY);
break;
case 'C': // Back
menuLevel = 0; // hide menu, go back to level 0
updateLevel_0(); // show home screen
delay(DEFAULT_DELAY);
break;
default:
break;
}
break;
default:
break;
}
}
void updateLevel_0() {
DateTime now = rtc.now();
date_year = (now.year());
month = now.month();
day = now.day();
hours = now.hour();
minutes = now.minute();
seconds = now.second();
if(minutes.length() == 1){
minutes = "0"+minutes;
}
String time = hours + ":"+ minutes+":"+seconds;
String date_day = day + "/" + month +"/"+date_year;
lcd.clear();
lcd.println("Auto Pill Dispenser");
lcd.setCursor(0, 1);
lcd.print("Date:");
lcd.setCursor(6, 1);
lcd.print(date_day);
lcd.setCursor(0,2);
lcd.print("Time:");
lcd.setCursor(6,2);
lcd.print(time);
lcd.setCursor(0,3);
lcd.print("Next pill");
lcd.setCursor(10, 3);
lcd.print("1600H");
}
void Account_info() { // this is for demonstration only
// you need to modify this and adapt
// to your specific application
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Patient account info");
lcd.setCursor(0, 1);
lcd.print("Acct No:8068877799");
lcd.setCursor(0, 2);
lcd.print("Type: In patient");
lcd.setCursor(0, 3);
lcd.print("Age: 30 yrs");
delay(5000);
}
void updateLevel_1 () {
switch (menu) {
case 0:
menu = 1;
break;
case 1:
lcd.clear();
lcd.print(">Patient account");
lcd.setCursor(0, 1);
lcd.print(" Measure vitals ");
lcd.setCursor(0, 2);
lcd.print(" Refill medication");
lcd.setCursor(0, 3);
lcd.print(" Emergency Dispense ");
lcd.setCursor(18, 3);
lcd.write((byte)1); // down arrow
break;
case 2:
lcd.clear();
lcd.print(" Patient account ");
lcd.setCursor(0, 1);
lcd.print(">Measure vitals");
lcd.setCursor(0, 2);
lcd.print(" Refill medication ");
lcd.setCursor(0, 3);
lcd.print(" Emergency Dispense ");
lcd.setCursor(18, 3);
lcd.write((byte)2); // up and down arrow
break;
case 3:
lcd.clear();
lcd.print(" Patient account ");
lcd.setCursor(0, 1);
lcd.print(" Measure vitals");
lcd.setCursor(0, 2);
lcd.print(">Refill medication ");
lcd.setCursor(0, 3);
lcd.print(" Emergency Dispense");
lcd.setCursor(18, 3);
lcd.write((byte)2); // up arrow
break;
case 4:
lcd.clear();
lcd.print(" Patient account ");
lcd.setCursor(0, 1);
lcd.print(" Measure vitals");
lcd.setCursor(0, 2);
lcd.print(" Refill medication ");
lcd.setCursor(0, 3);
lcd.print(">Emergency Dispense");
lcd.setCursor(18, 3);
lcd.write((byte)2); // up arrow
break;
case 5:
lcd.clear();
lcd.print(" Measure vitals");
lcd.setCursor(0, 1);
lcd.print(" Refill medication ");
lcd.setCursor(0, 2);
lcd.print(" Emergency Dispense");
lcd.setCursor(0, 3);
lcd.print(">Account info");
lcd.setCursor(18, 3);
lcd.write((byte)2); // up arrow
break;
case 6:
lcd.clear();
lcd.print(" Refill medication");
lcd.setCursor(0, 1);
lcd.print(" Emergency Dispense");
lcd.setCursor(0, 2);
lcd.print(" Account info");
lcd.setCursor(0, 3);
lcd.print(">WIFI set up");
lcd.setCursor(18, 3);
lcd.write((byte)0); // up arrow
break;
case 7:
menu = 6;
break;
}
}
void set_account() {
char account_key;
lcd.clear();
x = 0;
y = 0;
account_number = "";
do {
account_key = customKeypad.getKey();
lcd.setCursor(0,y);
lcd.print("Account number");
if (isDigit(account_key)) { // verify if the key press is a number
account_number = account_number + account_key;
distance_value = account_number.toInt();
lcd.setCursor(x,1);
lcd.print(account_key); // print it to the lcd
x++; // increment the x position
if (x > 1) // if the lcd reached the rightmost position
{ // then wrap to the next line
if(account_number.length() > 10){
account_number = "";
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Max of 10 digits");
lcd.setCursor(0,1);
delay(2000);
account_key = '#';
}
}
} else { // key press is not a number
if (account_key == 'C') { // if *, means backspace
if ( (x > 0) || (y > 0) ) { // prevent backspace when no character yet
x = x - 1; // go back to previous character position
lcd.setCursor(x,1); // set the new lcd position
lcd.print("*"); // write *, which means for editing
account_number.remove(account_number.length() - 1); // remove the last character from the string
}
}
}
} while (account_key != '#'); // exit the loop when # is pressed
// means entering number is complete
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Account set to:");
lcd.setCursor(0, 1);
lcd.print(account_number);
delay(2000);
}
void refill()
{
char compertment_number;
int compertment_angle;
lcd.clear();
do {
compertment_number = customKeypad.getKey();
Serial.print(compertment_number);
lcd.setCursor(0,0);
lcd.print("Select compertment");
lcd.setCursor(0,1);
lcd.print("1-Comp One");
lcd.setCursor(11,1);
lcd.print("2-Comp Two");
lcd.setCursor(0,2);
lcd.print("3-Comp Three");
lcd.setCursor(0,3);
lcd.print("4-Comp Four");
if(compertment_number == '1'){
lcd.clear();
lcd.print("Refill initialized");
delay(500);
lcd.setCursor(0,1);
lcd.print("Refilling medication");
lcd.setCursor(0,2);
lcd.print("Compartment one");
delay(500);
compertment_angle = 78;
float multiplyer = (stepsPerRevolution / 360);
int steps_number = multiplyer * compertment_angle;
// myStepper.step(steps_number);
// delay(1000);
// myStepper.step(-steps_number);
// delay(500);
delay(1500);
compertment_number = '#';
Serial.print(compertment_number);
}
else if(compertment_number == '2'){
lcd.clear();
lcd.print("Refill initialized");
delay(500);
lcd.setCursor(0,1);
lcd.print("Refilling medication");
lcd.setCursor(0,2);
lcd.print("Compartment two");
delay(500);
compertment_angle = 165;
float multiplyer = (stepsPerRevolution / 360);
int steps_number = multiplyer * compertment_angle;
// myStepper.step(steps_number);
// delay(1000);
// myStepper.step(-steps_number);
// delay(500);
delay(1500);
compertment_number = '#';
Serial.print(compertment_number);
}
else if(compertment_number == '3'){
lcd.clear();
lcd.print("Refill initialized");
delay(500);
lcd.setCursor(0,1);
lcd.print("Refilling medication");
lcd.setCursor(0,2);
lcd.print("Compartment three");
delay(500);
compertment_angle = 250;
float multiplyer = (stepsPerRevolution / 360);
int steps_number = multiplyer * compertment_angle;
// myStepper.step(steps_number);
// delay(1000);
// myStepper.step(-steps_number);
// delay(500);
delay(1500);
compertment_number = '#';
Serial.print(compertment_number);
}
else if(compertment_number == '4'){
lcd.clear();
lcd.print("Refill initialized");
delay(500);
lcd.setCursor(0,1);
lcd.print("Refilling medication");
lcd.setCursor(0,2);
lcd.print("Compartment four");
delay(500);
compertment_angle = 330;
float multiplyer = (stepsPerRevolution / 360);
int steps_number = multiplyer * compertment_angle;
// myStepper.step(steps_number);
// delay(1000);
// myStepper.step(-steps_number);
// delay(500);
delay(1500);
compertment_number = '#';
Serial.print(compertment_number);
}
// delay(300);
// compertment_number = '#';
} while (compertment_number != '#'); // exit the loop when # is pressed
// means entering number is complete
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Done refilling");
delay(1500);
}
void enterMSG() {
char key;
lcd.clear(); // clear the LCD display
x = 0; // init the x position to zero
y = 0; // init the y position to zero
msg = ""; // clear the msg variable
do {
key = customKeypad.getKey();
if (key == '1') { // if a key is pressed,
parseKey(0, 7, key); // compare it to the alpha string array
} else if (key == '2') {
parseKey(8, 15, key);
} else if (key == '3') {
parseKey(16, 23, key);
} else if (key == '4') {
parseKey(24, 31, key);
} else if (key == '5') {
parseKey(32, 39, key);
} else if (key == '6') {
parseKey(40, 47, key);
} else if (key == '7') {
parseKey(48, 57, key);
} else if (key == '8') {
parseKey(58, 65, key);
} else if (key == '9') {
parseKey(66, 75, key);
} else if (key == '0') {
parseKey(76, 79, key);
} else if (key == '*') {
parseKey(50, 51, key);
} else if (key == '#') {
// do nothing
}
} while (key != '#'); // exit the loop when # is pressed
lcd.setCursor(0, 0); // these are for verification only
lcd.print("Network name"); // feel free to modify it and
lcd.setCursor(0, 1); // adapt to your specific requirements
lcd.print(msg);
delay(2000);
}
void enterNUM() {
char key;
lcd.clear();
x = 0;
y = 0;
num = "";
do {
key = customKeypad.getKey();
if (isDigit(key)) { // verify if the key press is a number
num = num + key;
lcd.setCursor(x,y);
lcd.print(key); // print it to the lcd
x++; // increment the x position
if (x > 15) // if the lcd reached the rightmost position
{ // then wrap to the next line
x = 0;
y = 1;
}
} else { // key press is not a number
if (key == '*') { // if *, means backspace
if ( (x > 0) || (y > 0) ) { // prevent backspace when no character yet
x = x - 1; // go back to previous character position
lcd.setCursor(x,y); // set the new lcd position
lcd.print("*"); // write *, which means for editing
num.remove(num.length() - 1); // remove the last character from the string
}
}
}
} while (key != '#'); // exit the loop when # is pressed
// means entering number is complete
lcd.setCursor(0, 0);
lcd.print("Pasword entered");
lcd.setCursor(0, 1);
lcd.print(num);
delay(2000);
}
void parseKey(int minValue, int maxValue, char keyPress) {
int ch = minValue;
char key = keyPress;
if (keyPress == '*') { // if *, means backspace
if ( (x > 0) || (y > 0) ) { // prevent backspace when no character yet
x = x - 1; // go back to previous character position
lcd.setCursor(x,y); // set the new lcd position
lcd.print("*"); // write *, which means for editing
msg.remove(msg.length() - 1); // remove the last character from the string
}
} else {
for (int i = 0; i < keyPressTime; i++) {
if (key == keyPress) { // make sure that same key is press
lcd.setCursor(x, y); // set the lcd position
lcd.print(alpha[ch]); // print the character according to the character position
ch++; // increment character position
if (ch > maxValue) { // if the character counter reached the max value
ch = minValue; // reset to min value
i = 0; // reset the loop counter
}
}
key = customKeypad.getKey(); // get the keypress
delay(10); // delay for some time
}
x++; // increment the x position
msg += alpha[ch - 1]; // add the character to the variable msg
if (x > 15) { // if the lcd reached the rightmost position
y = 1; // then wrap to the next line
x = 0; // in first character in the left
}
}
}