// Include the libraries:
#include <Keypad.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
const byte ROWS = 4; // define number of rows
const byte COLS = 4; // define number of columns
byte rowPins[] = {9, 8, 7, 6}; // connect first four pins to 9, 8, 7, 6
byte colPins[] = {5, 4, 3, 2}; // connect last four pins to 5, 4, 3, 2
// define the key labels
char hexaKeys[ROWS][COLS] = {
{'1','2','3','a'},
{'4','5','6','b'},
{'7','8','9','c'},
{'*','0','#','d'}
};
LiquidCrystal_I2C lcd(0x27, 20, 4);
Keypad kp = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);
void setup() {
lcd.init(); // initialize the LCD
lcd.backlight(); // turn on the backlight
Serial.begin(9600); // Start serial monitor
delay(100);
lcd.home(); // set cursor at top left
lcdLineXY(1, 1, "Cybalent's Calc :)", true); // print starting text
lcdLineXY(3, 2, "Code by kos256", false); // you gotta include me too :P
delay(2000); // wait 2 seconds
lcdLineXY(1, 0, "Tap * key for help", true); delay(1000);
lcd.clear();
}
bool containsChar(char* items, char target, int itemLen) {
bool result = false;
for (int i = 0; i < itemLen; i++) {
if (items[i] == target) {
result = true;
break;
}
}
return result;
}
String backspace(String str) {
String result = str;
if(str.length() > 0) {
result.remove(result.length() - 1);
}
return result;
}
void lcdLine(String text, int line, bool clr) {
if(clr) lcd.clear();
lcd.setCursor(0, line-1);
lcd.print(text);
}
void lcdLineXY(int x, int y, String text, bool clr) {
if(clr) lcd.clear();
lcd.setCursor(x, y);
lcd.print(text);
}
String expression = "";
bool exitMenu = false;
bool redrawHelpMenu = false;
void loop() {
while(1) {
lcd.blink();
lcdLine(expression, 1, true);
char key;
while(1) {
key = kp.getKey(); // get the pressed key on the keypad
if(key) break;
}
lcd.noBlink();
if(containsChar("1234567890", key, 10)) {
expression += String(key);
}
if(containsChar("abcd", key, 4)) {
if(key=='a') {
expression += "+";
}
if(key=='b') {
expression += "-";
}
if(key=='c') {
expression += "*";
}
if(key=='d') {
expression += "/";
}
}
if(containsChar("*#", key, 2)) { // If * or # is pressed then run this statement
if(key == '#') { // If # is pressed, evaluate the expression and calculate.
char esbuf[2]; String cResult;
bool SYNTAX_signsTogether, SYNTAX_noNumbers, SYNTAX_empty, SYNTAX_strayOperator;
// temporary expression buffers (sebuf = expression syntax buffer)
// calc result
/* Error codes (cuz ain't no way im putting the whole reason up on screen)
01 - Empty expression.
02 - Repeated operator. {e.g. 4++7*96/+2}
03 - Only operator(s), no numbers. {e.g. The whole expression is literally just "+".}
04 - Stray operator. {e.g. "*37-4" or "13+7-" or both.}
*/
// Check for syntax errors:
lcdLine("Calculating...", 3, false);
cResult = "<no calc method>";
SYNTAX_empty = expression.length() == 0; // expression is empty
//if(containsChar("+-/*", expression[0], 4)) SYNTAX_strayOperator = true; // if there's a operator at the start of the expression
if(!SYNTAX_empty) {
for (int i = 0; i < expression.length()-1; i++) {
esbuf[0] = expression[i];
esbuf[1] = expression[i+1];
bool SYNTAX_signsTogether = containsChar("+-*/", esbuf[0], 4) && containsChar("+-*/", esbuf[1], 4);
if(SYNTAX_signsTogether) {
cResult = "Syntax error! 02"; // repeated operator
break;
}
Serial.println(String(i) + " " + String(esbuf[0]) + String(esbuf[1]));
delay(10);
}
SYNTAX_strayOperator =
containsChar("+-*/", esbuf[1], 4) || // if there's a operator at the start of the expression or
containsChar("+-*/", expression[0], 4); // if there's a operator at the end of the expression
SYNTAX_noNumbers = true; // only operators, no numbers
for (int i = 0; i < expression.length(); i++) {
if(containsChar("1234567890", expression[i], 10)) {
SYNTAX_noNumbers = false;
break;
}
}
}
// todo edit mode
if (SYNTAX_strayOperator) cResult = "Syntax error! 04";
if (SYNTAX_empty) cResult = "Syntax error! 01";
if (SYNTAX_noNumbers) cResult = "Syntax error! 03";
// Do the actual calculation:
lcdLine(" ", 3, false);
lcdLine("= " + String(cResult), 3, false);
lcd.noBlink();
while(1) {
key = kp.getKey();
if(key) break;
}
if(key == '#') {
expression = "";
}
}
if(key == '*') { // If * is pressed, do the help stuff...
while(1) {
lcdLineXY(6, 0, "* Help *", true); // Display title
lcdLineXY(1, 1, "Controls", false); // Display first option (Controls)
lcdLineXY(1, 2, "More options...", false); // Display second option (More...)
lcdLineXY(1, 3, "Back", false); // Display third option (Exit help menu)
lcdLineXY(10, 3, "A - Select", false);
exitMenu = false;
redrawHelpMenu = false;
int menui = 0; // Menu index stores what option is currently selected.
lcdLine(">", menui+2, false);
while(1) {
while(1) {
key = kp.getKey();
if(key) {
break;
}
}
if(key == 'a') { // If A (select) is pressed, select the current option.
if (menui == 2) { // If back is selected, exit the menu loop.
exitMenu = true;
break;
}
if (menui == 1) { // If more is selected, show a new menu.
menui = 0;
lcdLineXY(1, 0, "Backspace", true);
lcdLineXY(1, 1, "Clear [AC]", false);
lcdLineXY(1, 2, "Symbols", false);
lcdLineXY(1, 3, "Edit mode", false);
lcdLine(">", menui+1, false);
/* to do:
Add a symbol submenu.
Include:
- Brackets
- Sqrt
- Cbrt
- Exponent
*/
while(1) {
while(1) {
key = kp.getKey();
if(key) {
break;
}
}
if(key=='8') { // If 8 (down) is pressed, increase menu index.
lcdLine(" ", menui+1, false);
if(menui != 3) menui++;
}
if(key=='2') { // If 2 (up) is pressed, decrease menu index.
lcdLine(" ", menui+1, false);
if(menui != 0) menui--;
}
if(key=='a') { // Current option selected.
if(menui == 0) { // If selected Backspace then delete last char of expression and exit menu loop.
exitMenu = true;
expression = backspace(expression);
break;
}
if(menui == 1) { // If selected Clear then clear whole expression and exit menu loop.
exitMenu = true;
expression = "";
break;
}
}
lcdLine(">", menui+1, false);
}
}
if(exitMenu) break;
if (menui == 0) { // If Controls is selected, show the controls sequence.
while(1) {
// limit. "xxxxxxxxxxxxxxxxxxxx"
lcdLineXY(6, 0, "Welcome!", true);
lcdLineXY(0, 1, "If you're a new user", false);
lcdLineXY(0, 2, "this guide is yours.", false);
lcdLineXY(0, 3, "Press any button...", false);
while(1) {key=kp.getKey(); if(key){break;}}
lcdLineXY(0, 0, "If you want to exit", true);
lcdLineXY(0, 1, "this guide anytime,", false);
lcdLineXY(0, 2, "simply press B.", false);
lcdLineXY(0, 3, "Otherwise press any!", false);
while(1) {key=kp.getKey(); if(key){break;}}
if(key == 'b') break;
lcdLineXY(0, 0, "First things first..", true);
lcdLineXY(0, 1, "How do you type?", false);
lcdLineXY(0, 2, "Just press numbers,", false);
lcdLineXY(0, 3, "watch them appear!", false);
while(1) {key=kp.getKey(); if(key){break;}}
if(key == 'b') break;
lcdLineXY(0, 0, "During calc mode:", true);
lcdLineXY(0, 1, "A: Add B: Minus", false);
lcdLineXY(0, 2, "C: Times D: Divide", false);
lcdLineXY(0, 3, "#: Calculate", false);
while(1) {key=kp.getKey(); if(key){break;}}
if(key == 'b') break;
lcdLineXY(0, 0, "If you press any", true);
lcdLineXY(0, 1, "button after calcul-", false);
lcdLineXY(0, 2, "ating the expression", false);
//lcdLineXY(0, 3, "", false);
while(1) {key=kp.getKey(); if(key){break;}}
if(key == 'b') break;
lcdLineXY(0, 0, "You can edit the", true);
lcdLineXY(0, 1, "expression. But if", false);
lcdLineXY(0, 2, "you press # again,", false);
lcdLineXY(0, 3, "it'll clear it all.", false);
while(1) {key=kp.getKey(); if(key){break;}}
if(key == 'b') break;
lcdLineXY(0, 0, "During menus:", true);
lcdLineXY(0, 1, "2: Up 8: Down", false);
lcdLineXY(0, 2, "4: Left 6: Right", false);
lcdLineXY(0, 3, "A: Select B: Back", false);
while(1) {key=kp.getKey(); if(key){break;}}
if(key == 'b') break;
lcdLineXY(0, 0, "Having trouble with", true);
lcdLineXY(0, 1, "Up Down Left Right?", false);
lcdLineXY(0, 2, "Think of it like a", false);
lcdLineXY(0, 3, "WASD keypad!", false);
while(1) {key=kp.getKey(); if(key){break;}}
if(key == 'b') break;
lcdLineXY(0, 0, "Edit mode allows you", true);
lcdLineXY(0, 1, "to edit your current", false);
lcdLineXY(0, 2, "expression in case", false);
lcdLineXY(0, 3, "you made a mistake.", false);
while(1) {key=kp.getKey(); if(key){break;}}
if(key == 'b') break;
// limit. "xxxxxxxxxxxxxxxxxxxx"
lcdLineXY(0, 0, "A & B to move cursor", true);
lcdLineXY(0, 1, "C to backspace", false);
lcdLineXY(0, 2, "D to clear all", false);
lcdLineXY(0, 3, "# to quit edit mode.", false);
while(1) {key=kp.getKey(); if(key){break;}}
if(key == 'b') break;
lcdLineXY(0, 0, "You can always press", true);
lcdLineXY(0, 1, "the * key at almost", false);
lcdLineXY(0, 2, "any time to view", false);
lcdLineXY(0, 3, "corresponding guides", false);
while(1) {key=kp.getKey(); if(key){break;}}
if(key == 'b') break;
//lcdLineXY(0, 0, "", true);
lcdLineXY(1, 1, "Calc mode keypad", true);
lcdLineXY(0, 2, "Press any button....", false);
//lcdLineXY(0, 3, "corresponding guides", false);
while(1) {key=kp.getKey(); if(key){break;}}
if(key == 'b') break;
lcdLineXY(3, 0, "1|2|3|+", true);
lcdLineXY(3, 1, "4|5|6|-", true);
lcdLineXY(3, 2, "7|8|9|*", false);
lcdLineXY(3, 3, "H|0|=|/", false);
while(1) {key=kp.getKey(); if(key){break;}}
if(key == 'b') break;
//lcdLineXY(0, 0, "", true);
lcdLineXY(5, 1, "Menu keypad", true);
lcdLineXY(0, 2, "Press any button....", false);
//lcdLineXY(0, 3, "corresponding guides", false);
while(1) {key=kp.getKey(); if(key){break;}}
if(key == 'b') break;
lcdLineXY(3, 0, " |U| |OK", true);
lcdLineXY(3, 1, "L| |R|BACK", true);
lcdLineXY(3, 2, " |D| | ", false);
lcdLineXY(3, 3, " | | | ", false);
// lcd custom char function
while(1) {key=kp.getKey(); if(key){break;}}
if(key == 'b') break;
//lcdLineXY(0, 0, "", true);
lcdLineXY(2, 1, "Edit mode keypad", true);
lcdLineXY(0, 2, "Press any button....", false);
//lcdLineXY(0, 3, "corresponding guides", false);
while(1) {key=kp.getKey(); if(key){break;}}
if(key == 'b') break;
lcdLineXY(3, 0, " |U| | ", true);
lcdLineXY(3, 1, "L| |R| ", true);
lcdLineXY(3, 2, " |D| | ", false);
lcdLineXY(2, 3, "OK| | | ", false);
while(1) {key=kp.getKey(); if(key){break;}}
if(key == 'b') break;
//lcdLineXY(0, 0, "", true);
lcdLineXY(0, 1, "That's basically it!", true);
lcdLineXY(5, 2, "have fun :)", false);
//lcdLineXY(0, 3, "", false);
while(1) {key=kp.getKey(); if(key){break;}}
if(key == 'b') break;
// limit. "xxxxxxxxxxxxxxxxxxxx"
break;
}
redrawHelpMenu = true;
}
}
if(key == '8') { // If 8 (down) is pressed, increase menu index.
lcdLine(" ", menui+2, false);
if(menui != 2) menui++;
}
if(key == '2') { // If 2 (up) is pressed, decrease menu index.
lcdLine(" ", menui+2, false);
if(menui != 0) menui--;
}
lcdLine(">", menui+2, false);
if(exitMenu || redrawHelpMenu) break;
}
if(exitMenu) break;
}
}
}
}
}