/**
STM32 Calculator for Nucleo-C031C6
Adapted from Arduino Calculator by Uri Shaked.
Copyright (C) 2020, Uri Shaked.
Released under the MIT License.
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
/* Display (I2C-based 16x2 LCD) */
#define I2C_ADDR 0x27
LiquidCrystal_I2C lcd(I2C_ADDR, 16, 2);
/* Keypad setup */
const byte KEYPAD_ROWS = 4;
const byte KEYPAD_COLS = 4;
byte rowPins[KEYPAD_ROWS] = {D9, D10, D11, D12}; // Adjust based on Wokwi
byte colPins[KEYPAD_COLS] = {D13, D14, D15, D16}; // Adjust based on Wokwi
char keys[KEYPAD_ROWS][KEYPAD_COLS] = {
{'1', '2', '3', '+'},
{'4', '5', '6', '-'},
{'7', '8', '9', '*'},
{'.', '0', '=', '/'}
};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, KEYPAD_ROWS, KEYPAD_COLS);
/* LED Pins */
#define RED_LED D5 // Red LED for errors
#define YELLOW_LED D6 // Yellow LED for operation input
#define GREEN_LED D7 // Green LED for result
/* Variables */
String memory = "";
String current = "";
char operation = 0;
bool decimalPoint = false;
void setLEDs(bool red, bool yellow, bool green) {
digitalWrite(RED_LED, red ? HIGH : LOW);
digitalWrite(YELLOW_LED, yellow ? HIGH : LOW);
digitalWrite(GREEN_LED, green ? HIGH : LOW);
}
void pulseRed() {
setLEDs(true, false, false);
delay(100);
setLEDs(false, false, false);
}
void showSplashScreen() {
lcd.setCursor(0, 0);
lcd.print("STM32 Calculator");
lcd.setCursor(3, 1);
String message = "Ready!";
for (byte i = 0; i < message.length(); i++) {
lcd.print(message[i]);
delay(50);
}
delay(500);
}
void updateCursor() {
if (millis() / 250 % 2 == 0) {
lcd.cursor();
} else {
lcd.noCursor();
}
}
double calculate(char operation, double left, double right) {
switch (operation) {
case '+': return left + right;
case '-': return left - right;
case '*': return left * right;
case '/':
if (right == 0) {
pulseRed();
return 0; // Handle division by zero
}
return left / right;
}
return 0;
}
void processInput(char key) {
// Handle negative numbers at the start
if (key == '-' && current == "") {
current = "-";
lcd.print("-");
return;
}
switch (key) {
case '+':
case '-':
case '*':
case '/':
if (!operation) {
memory = current;
current = "";
}
operation = key;
lcd.setCursor(0, 1);
lcd.print(key);
lcd.setCursor(current.length() + 1, 1);
setLEDs(false, true, false); // Yellow LED for operation
return;
case '=':
if (memory == "" || current == "") {
pulseRed();
return;
}
double leftNum = memory.toDouble();
double rightNum = current.toDouble();
double result = calculate(operation, leftNum, rightNum);
memory = String(result);
current = "";
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(memory);
lcd.setCursor(0, 1);
lcd.print(operation);
setLEDs(false, false, true); // Green LED for result
return;
}
// Prevent multiple decimal points
if (key == '.' && current.indexOf('.') >= 0) {
pulseRed();
return;
}
// Handle leading zero
if (key != '.' && current == "0") {
current = String(key);
} else if (key) {
current += String(key);
}
lcd.print(key);
}
void setup() {
// Initialize Serial
Serial.begin(115200);
// Initialize LCD
lcd.init();
lcd.backlight();
lcd.clear();
lcd.cursor();
// Initialize LED pins
pinMode(RED_LED, OUTPUT);
pinMode(YELLOW_LED, OUTPUT);
pinMode(GREEN_LED, OUTPUT);
setLEDs(false, false, false);
// Show splash screen
showSplashScreen();
lcd.clear();
lcd.cursor();
lcd.setCursor(1, 0);
}
void loop() {
updateCursor();
char key = keypad.getKey();
if (key) {
processInput(key);
}
}