#include <Keypad.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
boolean State = false;
const byte ROWS = 4;
const byte COLS = 4;
const byte MAX_IDX = 14;
const byte MIN_IDX = 1;
unsigned long time = 0;
int current_index = 0;
String Buffer = "";
boolean blink = true;
boolean equal = false;
//keypad define
char hexaKeys[ROWS][COLS] = {
{'1', '2', '3', '+'},
{'4', '5', '6', '-'},
{'7', '8', '9', 'x'},
{'C', '0', '.', '='}
};
//LCD define
byte customChar[8] = {
0b11111,
0b11111,
0b11111,
0b11111,
0b11111,
0b11111,
0b11111,
0b11111
};
byte customChar1[8] = {
0b00011,
0b00111,
0b01111,
0b11111,
0b11111,
0b01111,
0b00111,
0b00011
};
byte rowPins[ROWS] = {31, 33, 35, 37};
byte colPins[COLS] = {39, 41, 43, 45};
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);
void Cursor(int Index) {
// blink cursor
if (State == true) {
if (equal == false) {
if ((unsigned long)(millis() - time) > 500) {
time = millis();
if (blink == true) {
blink = false;
if (Index > 15) {
lcd.setCursor(15, 0);
lcd.write(byte(0));
}
else {
lcd.setCursor(Index, 0);
lcd.write(byte(0));
}
}
else {
blink = true;
if (Index > 15) {
lcd.setCursor(15, 0);
lcd.print(" ");
}
else {
lcd.setCursor(Index, 0);
lcd.print(" ");
}
}
}
else;
if (Index > 15) {
lcd.setCursor(0, 0);
lcd.write(byte(1));
}
}
}
else {}
}
int calculate(String s) {
// calculator algorithm using stack
int len = s.length();
if (len == 0) return 0;
float stack[100] = {0, 0, 0, 0, 0};
int curr = 0;
float currentNumber = 0;
char operation = '+';
int dot = 0; // decimal detect
for (int i = 0; i < len; i++) {
char currentChar = s[i];
if (currentChar == '.'){
dot = 1; // finding "." to make decimal in form of 0.X, 0.00X
}
else {
if (isDigit(currentChar)) {
// "." found, curren number = current number + X/10^x .
// "." not found, current number = curent number*10 + X
if (!dot) currentNumber = (currentNumber * 10);
currentNumber += (currentChar - '0') / pow(10,dot);
}
if (!isDigit(currentChar) || i == len - 1) {
//
if (operation == '-') {
// stack.push(-currentNumber); extraction
stack[curr] = -currentNumber;
curr++;
} else if (operation == '+') {
// stack.push(currentNumber); addition
stack[curr] = currentNumber;
curr++;
} else if (operation == 'x') {
// stackTop = stack.pop();multiplication
curr--;
float stackTop = stack[curr];
// stack.push(stackTop * currentNumber);
stack[curr] = stackTop * currentNumber;
curr++;
}
operation = currentChar;
currentNumber = 0;
}
dot = 0;
}
}
float result = 0;
while (curr-- != 0) {
result += stack[curr];
}
if (result - int(result) == 0) {
lcd.setCursor(16 - String(int(result)).length(), 1);
lcd.print(int(result));
}
else {
lcd.setCursor(16 - String(result).length(), 1);
lcd.print(result);
}
}
void setup() {
Serial.begin(9600);
lcd.init();
lcd.createChar(0, customChar);
lcd.createChar(1, customChar1);
time = millis();
}
void reset(){
lcd.clear();
current_index = 0;
Buffer = "";
equal = false;
}
void turnOff(){
reset();
State = false;
lcd.noBacklight();
}
void turnOn(){
reset();
State = true;
lcd.backlight();
}
void loop() {
Cursor(current_index);
char customKey = customKeypad.getKey();
if (customKey) {
if (customKey == 'C') { // C=on off button
if (State == false) turnOn();
else turnOff();
}
else if ((customKey == '=') && State) { // =: do the math with related operator
// if turn on & key =
equal = true;
calculate(Buffer);
}
else if (State && equal) reset(); // reset lcd after "=" and to next calculation
else if (State) { // else number/operator
Buffer = Buffer + String(customKey); // Update number/operator to String
lcd.setCursor(min(current_index,MAX_IDX), 0); // Move cursor to last position
lcd.print(Buffer.substring(current_index, Buffer.length() + 1)); //display input from start to end
current_index++; // Move cursor to the next position
}
}
}