#include <avr/io.h>
#include <util/delay.h>
#include <string.h>
#include <stdlib.h>
// Function prototypes
void LCD_Init();
void LCD_Command(uint8_t cmd);
void LCD_Char(uint8_t data);
void LCD_String(const char *str);
void LCD_Clear();
void LCD_SetCursor(uint8_t row, uint8_t col);
uint8_t Keypad_Scan();
void delay_ms(uint16_t ms);
// Main function
int main() {
uint8_t key;
char num1[10] = {0};
char num2[10] = {0};
char operator = 0;
uint8_t index = 0;
int result = 0;
// Configure LCD and initialize
LCD_Init();
LCD_Clear();
LCD_String("Calculator Ready");
// Infinite loop
while (1) {
key = Keypad_Scan(); // Scan keypad
if (key) { // If a key was pressed
if (key >= '0' && key <= '9') { // Number keys
if (operator == 0) {
// Input number 1
if (index < sizeof(num1) - 1) {
num1[index++] = key;
LCD_SetCursor(1, 0);
LCD_String(num1);
}
} else {
// Input number 2
if (index < sizeof(num2) - 1) {
num2[index++] = key;
LCD_SetCursor(1, 0);
LCD_String(num2);
}
}
} else if (key == '+' || key == '-' || key == '*' || key == '/') {
operator = key;
index = 0; // Reset index to accept the second number
LCD_SetCursor(0, 0);
LCD_Char(key);
} else if (key == '=') {
// Perform the calculation
int val1 = atoi(num1);
int val2 = atoi(num2);
switch (operator) {
case '+':
result = val1 + val2;
break;
case '-':
result = val1 - val2;
break;
case '*':
result = val1 * val2;
break;
case '/':
if (val2 != 0) result = val1 / val2;
else result = 0; // Handle divide by zero
break;
default:
result = 0;
}
// Display result
char resultStr[17];
snprintf(resultStr, 17, "Result: %d", result);
LCD_Clear();
LCD_String(resultStr);
_delay_ms(1000);
LCD_Clear();
LCD_String("Calculator Ready");
operator = 0;
index = 0;
memset(num1, 0, sizeof(num1));
memset(num2, 0, sizeof(num2));
}
}
}
}
/* LCD Functions */
void LCD_Init() {
// Set RS, EN, and data lines as outputs
DDRB |= (1 << PB4) | (1 << PB5);
DDRD |= 0xF0; // PD4 to PD7 as outputs
_delay_ms(20);
// Initialize LCD
LCD_Command(0x33);
_delay_ms(5);
LCD_Command(0x32);
_delay_ms(5);
LCD_Command(0x28); // 4-bit mode, 2 lines, 5x8 font
_delay_ms(5);
LCD_Command(0x0C); // Display ON, Cursor OFF
_delay_ms(5);
LCD_Command(0x06); // Entry mode
_delay_ms(5);
LCD_Clear();
}
void LCD_Command(uint8_t cmd) {
PORTD = (cmd & 0xF0); // Send high nibble
PORTB |= (1 << PB4); // RS = 0
PORTB |= (1 << PB5); // Enable
_delay_ms(1);
PORTB &= ~(1 << PB5);
_delay_ms(1);
}
void LCD_Char(uint8_t data) {
PORTD = (data & 0xF0); // Send high nibble
PORTB |= (1 << PB4); // RS = 1
PORTB |= (1 << PB5);
_delay_ms(1);
PORTB &= ~(1 << PB5);
_delay_ms(1);
}
void LCD_String(const char *str) {
while (*str) {
LCD_Char(*str++);
}
}
void LCD_Clear() {
LCD_Command(0x01);
_delay_ms(2);
}
void LCD_SetCursor(uint8_t row, uint8_t col) {
if (row == 0) {
LCD_Command(0x80 + col);
} else if (row == 1) {
LCD_Command(0xC0 + col);
}
}
uint8_t Keypad_Scan() {
// Set columns as outputs
DDRB |= 0x0F;
PORTB = 0x00;
// Scan rows
for (uint8_t i = 0; i < 4; i++) {
PORTB = (1 << i);
_delay_ms(10);
for (uint8_t j = 0; j < 4; j++) {
if (PIND & (1 << j)) {
return '0' + j + i * 4;
}
}
}
return 0;
}