#include <math.h>
#include <Wire.h>
#include <hd44780.h>
#include <hd44780ioClass/hd44780_I2Cexp.h>
hd44780_I2Cexp lcd;
//--------------------------------------------------DATA--------------------------------------------------
const int ROW_COUNT = 4;
const int COL_COUNT = 5;
int rowPins[ROW_COUNT] = {2, 3, 4, 5};
int colPins[COL_COUNT] = {8, 9, 10, 11, 12};
bool buttonStates[ROW_COUNT][COL_COUNT] = {false};
bool prevButtonStates[ROW_COUNT][COL_COUNT] = {false};
char buttonVals[ROW_COUNT][COL_COUNT] = {
{'7', '8', '9', 'D', 'C'},
{'4', '5', '6', '*', '/'},
{'1', '2', '3', '+', '-'},
{'0', '.', 'E', 'a', '='},
};
const int MAX_INPUT_SIZE = 100;
const int MAX_MEMORY_SIZE = 8;
const int MAX_STACK_SIZE = 100;
struct Input{
char data[MAX_INPUT_SIZE];
int len;
};
Input userInput = {};
struct Token{
char type;
union{
float val;
char op;
};
};
enum ErrorCodes{
SUCCESS,
MULTIPLE_DECIMAL_POINTS,
};
struct TokenExpression{
int tokenCount;
ErrorCodes status;
Token data[MAX_INPUT_SIZE];
};
struct Stack{
int top;
Token data[MAX_STACK_SIZE];
void POP(){
top--;
};
void PUSH(Token input){
top++;
data[top] = input;
};
Token PEEK(){
return data[top];
};
};
struct Memory{
float ans[MAX_MEMORY_SIZE];
char expr[MAX_INPUT_SIZE];
};
Memory memory = {};
struct Cursor{
int x;
int y;
};
Cursor cursor = {};
//-----------------------------------------------FUNCTIONS------------------------------------------------
bool isOperator(char input){
const int OPERATOR_COUNT = 4;
char operatorArray[OPERATOR_COUNT] = {'+', '-', '*', '/'};
for(int i = 0; i < OPERATOR_COUNT; i++){
if(input == operatorArray[i]){
return true;
}
}
return false;
}
TokenExpression tokenize(Input input){
TokenExpression output = {};
int i = 0;
while(i < input.len){
if(isDigit(input.data[i]) || input.data[i] == '.'){
float num = 0;
bool seenDecimal = false;
int digitsAD = 0;
while((isDigit(input.data[i]) || input.data[i] == '.') && i < input.len){
if(input.data[i] == '.'){
if(seenDecimal){
output.status = MULTIPLE_DECIMAL_POINTS;
return output;
};
seenDecimal = true;
i++;
continue;
};
if(isDigit(input.data[i]) && !seenDecimal){
num = num * 10 + (input.data[i] - '0');
i++;
continue;
};
if(isDigit(input.data[i]) && seenDecimal){
digitsAD++;
num = num + (input.data[i] - '0') * pow(0.1, digitsAD);
i++;
continue;
};
}
output.data[output.tokenCount].type = 'n';
output.data[output.tokenCount].val = num;
output.tokenCount++;
}
if(isOperator(input.data[i])){
output.data[output.tokenCount].type = 'o';
output.data[output.tokenCount].op = input.data[i];
i++;
output.tokenCount++;
}
}
output.status = SUCCESS;
return output;
}
int precedence(char op){
if(op == '+' || op == '-'){
return 1;
}else if(op == '*' || op == '/'){
return 2;
};
}
TokenExpression shuntingYard(TokenExpression infixExpression){
TokenExpression RPNExpression = {
.tokenCount = infixExpression.tokenCount
};
int RPNLen = 0;
Stack opStack = {
.top = -1
};
for(int i = 0; i < infixExpression.tokenCount; i++){
if(infixExpression.data[i].type == 'n'){
RPNExpression.data[RPNLen].val = infixExpression.data[i].val;
RPNLen++;
}else if(infixExpression.data[i].type == 'o'){
if(opStack.top > -1){
while(precedence(infixExpression.data[i].op) < precedence(opStack.PEEK().op)){
RPNExpression.data[RPNLen] = opStack.PEEK();
RPNLen++;
opStack.POP();
continue;
}
opStack.PUSH(infixExpression.data[i]);
};
};
}
RPNExpression.status = SUCCESS;
return RPNExpression;
}
float evaluateRPN(TokenExpression RPNExpression){
Stack numberStack = {
.top = -1
};
for(int i = 0; i < RPNExpression.tokenCount; i++){
if(RPNExpression.data[i].type == 'n'){
numberStack.PUSH(RPNExpression.data[i]);
}else if(RPNExpression.data[i].type == 'o'){
float num1 = numberStack.PEEK().val;
numberStack.POP();
float num2 = numberStack.PEEK().val;
numberStack.POP();
Token ans = {
.type = 'n'
};
if(RPNExpression.data[i].op == '+'){
ans.val = num2 + num1;
}else if(RPNExpression.data[i].op == '-'){
ans.val = num2 - num1;
}else if(RPNExpression.data[i].op == '*'){
ans.val = num2 * num1;
}else if(RPNExpression.data[i].op == '/'){
ans.val = num2 / num1;
};
numberStack.PUSH(ans);
};
}
return numberStack.data[numberStack.top].val;
}
float evaluate(Input input){
TokenExpression infixExpression = tokenize(input);
TokenExpression RPNExpression = shuntingYard(infixExpression);
float ans = evaluateRPN(RPNExpression);
return ans;
}
void clearInput(){
for(int i = 0; i < userInput.len; i++){
userInput.data[i] = '\0';
}
userInput.len = 0;
lcd.clear();
cursor.x = 0;
cursor.y = 0;
lcd.setCursor(cursor.x, cursor.y);
}
void deleteChar(){
userInput.len--;
userInput.data[userInput.len] = '\0';
cursor.x--;
lcd.setCursor(cursor.x, cursor.y);
lcd.print(' ');
lcd.setCursor(cursor.x, cursor.y);
}
void printChar(char input){
userInput.data[userInput.len] = input;
userInput.len++;
lcd.print(input);
cursor.x++;
lcd.setCursor(cursor.x, cursor.y);
}
//---------------------------------------------SETUP AND LOOP---------------------------------------------
void setup() {
for(int row = 0; row < ROW_COUNT; row++){
pinMode(rowPins[row], OUTPUT);
}
for(int col = 0; col < COL_COUNT; col++){
pinMode(colPins[col], INPUT_PULLUP);
}
lcd.begin(20, 4);
lcd.setCursor(cursor.x, cursor.y);
lcd.blink();
Serial.begin(9600);
}
void loop() {
//SCAN
for(int currentRow = 0; currentRow < ROW_COUNT; currentRow++){
for(int row = 0; row < ROW_COUNT; row++){
digitalWrite(rowPins[row], HIGH);
}
digitalWrite(rowPins[currentRow], LOW);
for(int currentCol = 0; currentCol < COL_COUNT; currentCol++){
prevButtonStates[currentRow][currentCol] = buttonStates[currentRow][currentCol];
buttonStates[currentRow][currentCol] = !digitalRead(colPins[currentCol]);
}
}
//OUTPUT
for(int currentRow = 0; currentRow < ROW_COUNT; currentRow++){
for(int currentCol = 0; currentCol < COL_COUNT; currentCol++){
if(buttonStates[currentRow][currentCol] && !prevButtonStates[currentRow][currentCol]){
char val = buttonVals[currentRow][currentCol];
if(val == '='){
float ans = evaluate(userInput);
cursor.x = 3;
cursor.y = 3;
lcd.setCursor(cursor.x, cursor.y);
lcd.print(ans);
}else if(val == 'C'){
clearInput();
}else if(val == 'D'){
deleteChar();
}else{
printChar(val);
}
}
}
}
delay(15);
}[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
[0]
[9]
[DEL]
[AC]
[*]
[/]
[+]
[-]
[=]
[.]
[E]
[ANS]