Skip to content

Instantly share code, notes, and snippets.

@adrianbn
Created July 21, 2020 15:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adrianbn/6d833e594e70348e931d937e5f573342 to your computer and use it in GitHub Desktop.
Save adrianbn/6d833e594e70348e931d937e5f573342 to your computer and use it in GitHub Desktop.
Menu
#include <LiquidCrystal.h>
#include <Keypad_I2C.h>
#define I2C_PFC8574_ADDR 0x20
#define I2C_DS1307_ADDR 0x68
// PIN DEFINITIONS
const int LED_PIN = 16;
const int LCD_BKL_PIN = 6;
const int PUMP_PIN = 5;
// LCD
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(8, 9, 13, 12, 11, 10);
const int LCD_BKL_PWM = 170; // (255 * 3.3)/5 = 168.3 But measured 170 is 3.1V
const int LCD_ROWS = 2;
const int LCD_COLS = 16;
const int NUM_MENUS = 4;
int current_menu = 0;
int frame = 0;
int cursor_pos = 0;
String menu_items[] = {"Schedule 1", "Schedule 2", "Start Pump", "Stop Pump"};
// Keypad
const byte ROWS = 4; // four rows
const byte COLS = 4; // four columns
//define the two-dimensional array on the buttons of the keypads
char hexa_keys[ROWS][COLS] = {{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
byte rowPins[ROWS] = {7, 6, 5, 4}; //connect to the column pinouts of the keypad
byte colPins[COLS] = {3, 2, 1, 0}; //connect to the row pinouts of the keypad
Keypad_I2C key_pad(makeKeymap(hexa_keys), rowPins, colPins, ROWS, COLS, I2C_PFC8574_ADDR);
const char UP = 'C';
const char DOWN = 'D';
const char CONFIRM = '*';
const char BACK = '#';
// As opposed to Python, % of negative numbers is, welp, negative.
int mod(int x, int y) {
return x<0 ? ((x + 1) % y) + y - 1 : x % y;
}
void displayMenu() {
for (int i=0; i < LCD_ROWS; i++) {
lcd.setCursor(1,i);
lcd.print(menu_items[(i + frame) % NUM_MENUS]);
}
}
void displayCursor() {
printCursor((cursor_pos + frame) % LCD_ROWS);
}
void printCursor(int row) {
for (int i=0; i < LCD_ROWS; i++) {
if (i != row) {
lcd.setCursor(0, i);
lcd.print(" ");
}
}
lcd.setCursor(0, row);
lcd.print(">");
}
void updateTimeMenu(int start_pos, int sched) {
int idx = 0;
lcd.setCursor(start_pos, 0);
lcd.blink();
char key_press = NULL;
while ((idx < DATE_LENGTH) && !(key_press == BACK || key_press == CONFIRM)) {
key_press = key_pad.getKey();
if (key_press < '9' && key_press > '0') {
if ((idx == 0 && key_press > '2') ||
(idx == 1 && key_press > '3' && schedules[sched].date[idx - 1] == '2') ||
(idx == 2 && key_press > '5')) {
continue;
}
schedules[sched].date[idx] = key_press;
lcd.print(key_press);
if (idx == 1)
lcd.print(":");
idx++;
}
}
lcd.noBlink();
}
void updateDurationMenu(int start_pos, int sch) {
char duration[2];
String d = String(schedules[sch].duration);
int idx = 0;
char key_press = NULL;
lcd.setCursor(start_pos, 1);
lcd.blink();
while ((idx < DURATION_LENGTH) && !(key_press == BACK || key_press == CONFIRM)) {
key_press = key_pad.getKey();
if (key_press <= '9' && key_press >= '0') {
duration[idx] = key_press;
lcd.print(key_press);
idx++;
}
}
if (idx == 1) { // only first digit entered
duration[1] = d.charAt(d.length() - 1);
}
schedules[sch].duration = String(duration).toInt();
lcd.noBlink();
}
void updateScheduleMenu(int sch) {
int cur = 0;
printCursor(cur);
lcd.setCursor(1,0);
lcd.print("Time: ");
printTime(schedules[sch].date);
lcd.setCursor(1,1);
lcd.print("Duration: ");
printDuration(schedules[sch].duration);
lcd.print("min");
char key_press = NULL;
while (key_press != BACK) {
key_press = key_pad.getKey();
switch(key_press) {
case CONFIRM:
if (cur == 0) {
updateTimeMenu(7, sch);
} else{
updateDurationMenu(11, sch);
}
break;
case DOWN:
cur = (cur + 1) % LCD_ROWS;
printCursor(cur);
break;
}
}
}
void startPumpMenu() {
lcd.setCursor(0,0);
lcd.print(" Pump is now on");
digitalWrite(LED_PIN, HIGH);
analogWrite(PUMP_PIN, 255);
// Wait for a key press
char key_press = NULL;
while (!(key_press = key_pad.getKey())) {
if (key_press == BACK) break;
}
}
void stopPumpMenu() {
lcd.setCursor(0,0);
lcd.print(" Pump is now off");
digitalWrite(LED_PIN, LOW);
analogWrite(PUMP_PIN, 0);
// Wait for a key press
char key_press = NULL;
while (!(BACK == key_pad.getKey()));
}
void goIntoMenu() {
lcd.clear();
switch(cursor_pos) {
case 0:
case 1:
updateScheduleMenu(cursor_pos);
break;
case 2:
startPumpMenu();
break;
case 3:
stopPumpMenu();
break;
}
lcd.clear();
}
char mainMenu() {
char key_press = key_pad.getKey();
if (key_press) {
lcd.clear();
lcdOn();
}
switch(key_press) {
case BACK:
break;
case CONFIRM:
goIntoMenu();
break;
case DOWN:
cursor_pos = mod((cursor_pos + 1), NUM_MENUS);
if ((cursor_pos + frame) % 2 == 0)
frame = mod((frame + 1), NUM_MENUS);
break;
case UP:
cursor_pos = mod((cursor_pos - 1), NUM_MENUS);
if ((cursor_pos + frame) % 2 != 0)
frame = mod((frame - 1), NUM_MENUS);
break;
default:
if (key_press != NO_KEY) {
Serial.print("Pressed: ");
Serial.println(key_press);
}
}
return key_press;
}
void setup() {
// Serial for debugging
Serial.begin(9600);
// Configure in/out pins
pinMode(LED_PIN, OUTPUT);
pinMode(LCD_BKL_PIN, OUTPUT); // The LCD Backlight control
// Init the I2C bus
Wire.begin();
// Init the Keypad library
key_pad.begin();
// End of Keypad init
// We have a 16x2 (column/row) LCD
lcd.begin(LCD_COLS, LCD_ROWS);
lcdOff();
lcd.clear();
}
void loop() {
displayMenu();
displayCursor();
mainMenu();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment