#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include <math.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
// Keypad setup
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
{'1', '2', '3', '/'},
{'4', '5', '6', '*'},
{'7', '8', '9', '-'},
{'C', '0', '=', '+'}
};
byte rowPins[ROWS] = {9, 8, 7, 6};
byte colPins[COLS] = {5, 4, 3, 2};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
// Additional functions keypad
const byte ROWS2 = 4;
const byte COLS2 = 4;
char keys2[ROWS2][COLS2] = {
{'^', '(', ')', '%'}, // exponent, (, ), %
{'s', 'c', 't', 'l'}, // sin, cos, tan, log
{'S', 'C', 'o', 'n'}, // sec, csc, cot, ln
{'!', '.', '=', 'e'} // factorial, ., equals, e
};
byte rowPins2[ROWS2] = {13, 12, 11, 10};
byte colPins2[COLS2] = {A3, A2, A1, A0};
Keypad keypad2 = Keypad(makeKeymap(keys2), rowPins2, colPins2, ROWS2, COLS2);
String input = "";
float result = 0;
bool calculated = false;
bool outputDisplayed = false;
void setup() {
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Calculator:");
delay(2000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Input: ");
}
void loop() {
char key = keypad.getKey();
char key2 = keypad2.getKey();
// Handle main keypad input
if (key) {
handlePrimaryKey(key);
}
// Handle additional functions keypad input
if (key2) {
handleSecondaryKey(key2);
}
// Clear the input if needed
if (outputDisplayed && (key == 'C' || key2 == 'C')) {
clearInput();
}
}
void handlePrimaryKey(char key) {
if (key == '=') {
if (input.length() > 0 && !calculated) {
result = evaluateExpression(input);
lcd.clear();
lcd.setCursor(0, 1);
lcd.print("Result: ");
lcd.print(result, 2);
calculated = true;
outputDisplayed = true;
}
} else if (key == 'C') {
clearInput();
} else if (isdigit(key) || key == '.' || (key == '-' && input.length() == 0)) {
input += key;
lcd.setCursor(7 + input.length() - 1, 0); // Update cursor position
lcd.print(key);
} else if (isOperator(key) && input.length() > 0 && !calculated) {
input += key;
lcd.setCursor(7 + input.length() - 1, 0); // Update cursor position
lcd.print(key);
} else if (key == '(' || key == ')') {
input += key;
lcd.setCursor(7 + input.length() - 1, 0); // Update cursor position
lcd.print(key);
}
}
void handleSecondaryKey(char key2) {
if (key2 == 's') { // sin
input += "sin(";
lcd.setCursor(7 + input.length() - 4, 0);
lcd.print("sin(");
} else if (key2 == 'c') { // cos
input += "cos(";
lcd.setCursor(7 + input.length() - 4, 0);
lcd.print("cos(");
} else if (key2 == 't') { // tan
input += "tan(";
lcd.setCursor(7 + input.length() - 4, 0);
lcd.print("tan(");
} else if (key2 == 'l') { // log (base 10)
input += "log(";
lcd.setCursor(7 + input.length() - 4, 0);
lcd.print("log(");
} else if (key2 == 'n') { // ln (natural logarithm)
input += "ln(";
lcd.setCursor(7 + input.length() - 4, 0);
lcd.print("ln(");
} else if (key2 == 'S') { // sec
input += "sec(";
lcd.setCursor(7 + input.length() - 4, 0);
lcd.print("sec(");
} else if (key2 == 'C') { // csc
input += "csc(";
lcd.setCursor(7 + input.length() - 4, 0);
lcd.print("csc(");
} else if (key2 == 'o') { // cot
input += "cot(";
lcd.setCursor(7 + input.length() - 4, 0);
lcd.print("cot(");
} else if (key2 == '^') { // exponent
input += "^";
lcd.setCursor(7 + input.length() - 1, 0);
lcd.print("^");
} else if (key2 == '%') { // percentage
input += "/100"; // Convert percentage to decimal
lcd.setCursor(7 + input.length() - 4, 0);
lcd.print("/100");
} else if (key2 == '!') { // factorial
if (input.length() > 0) {
int number = atoi(input.c_str());
input = String(factorial(number)); // Calculate factorial
lcd.setCursor(0, 1);
lcd.print("Fact: ");
lcd.print(input);
outputDisplayed = true;
return; // Exit to avoid further processing
}
} else if (key2 == 'e') { // e constant
input += String(M_E);
lcd.setCursor(7 + input.length() - 1, 0);
lcd.print("e");
}
}
// Updated evaluateExpression to handle log and ln
float evaluateExpression(String expression) {
int len = expression.length();
char tokens[len + 1];
expression.toCharArray(tokens, len + 1);
// Stack for operands and operators
float operandsStack[50];
char operatorsStack[50];
int operandIndex = 0;
int operatorIndex = 0;
for (int i = 0; i < len; i++) {
char token = tokens[i];
if (isdigit(token) || token == '.') {
float number = atof(tokens + i);
operandsStack[operandIndex++] = number;
while (i < len && (isdigit(tokens[i]) || tokens[i] == '.')) {
i++;
}
i--;
} else if (isOperator(token)) {
while (operatorIndex > 0 && hasPrecedence(operatorsStack[operatorIndex - 1], token)) {
float operand2 = operandsStack[--operandIndex];
float operand1 = operandsStack[--operandIndex];
char op = operatorsStack[--operatorIndex];
operandsStack[operandIndex++] = applyOperator(op, operand1, operand2);
}
operatorsStack[operatorIndex++] = token;
} else if (token == '(') {
operatorsStack[operatorIndex++] = token;
} else if (token == ')') {
while (operatorIndex > 0 && operatorsStack[operatorIndex - 1] != '(') {
float operand2 = operandsStack[--operandIndex];
float operand1 = operandsStack[--operandIndex];
char op = operatorsStack[--operatorIndex];
operandsStack[operandIndex++] = applyOperator(op, operand1, operand2);
}
operatorIndex--; // Pop '('
} else if (expression.startsWith("log(", i)) {
i += 3; // Skip 'log('
float value = evaluateExpression(expression.substring(i)); // Recursively evaluate the expression
operandsStack[operandIndex++] = log10(value); // Log base 10
while (i < len && tokens[i] != ')') i++; // Find closing parenthesis
} else if (expression.startsWith("ln(", i)) {
i += 2; // Skip 'ln('
float value = evaluateExpression(expression.substring(i)); // Recursively evaluate the expression
operandsStack[operandIndex++] = log(value); // Natural logarithm
while (i < len && tokens[i] != ')') i++; // Find closing parenthesis
} else if (expression.startsWith("sin(", i)) {
i += 4; // Skip 'sin('
float value = evaluateExpression(expression.substring(i)); // Recursively evaluate the expression
operandsStack[operandIndex++] = sin(value); // Sine
while (i < len && tokens[i] != ')') i++; // Find closing parenthesis
} else if (expression.startsWith("cos(", i)) {
i += 4; // Skip 'cos('
float value = evaluateExpression(expression.substring(i)); // Recursively evaluate the expression
operandsStack[operandIndex++] = cos(value); // Cosine
while (i < len && tokens[i] != ')') i++; // Find closing parenthesis
} else if (expression.startsWith("tan(", i)) {
i += 4; // Skip 'tan('
float value = evaluateExpression(expression.substring(i)); // Recursively evaluate the expression
operandsStack[operandIndex++] = tan(value); // Tangent
while (i < len && tokens[i] != ')') i++; // Find closing parenthesis
}
}
while (operatorIndex > 0) {
float operand2 = operandsStack[--operandIndex];
float operand1 = operandsStack[--operandIndex];
char op = operatorsStack[--operatorIndex];
operandsStack[operandIndex++] = applyOperator(op, operand1, operand2);
}
return operandsStack[0];
}
bool isOperator(char c) {
return c == '+' || c == '-' || c == '*' || c == '/' || c == '^';
}
bool hasPrecedence(char op1, char op2) {
if (op2 == '(' || op2 == ')') return false;
if (op1 == '^') return false; // Highest precedence
if ((op1 == '*' || op1 == '/') && (op2 == '+' || op2 == '-')) return false;
return true;
}
float applyOperator(char op, float a, float b) {
switch (op) {
case '+': return a + b;
case '-': return a - b;
case '*': return a * b;
case '/': return (b != 0) ? a / b : NAN; // Prevent division by zero
case '^': return pow(a, b);
default: return 0;
}
}
void clearInput() {
input = "";
result = 0;
calculated = false;
outputDisplayed = false;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Input: ");
}
long factorial(int n) {
if (n < 0) return -1; // Error for negative numbers
return (n == 0 || n == 1) ? 1 : n * factorial(n - 1);
}