MIT-Curricular/ES/Project/code.c
2025-10-29 14:22:21 +05:30

437 lines
11 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <LPC17xx.h>
#include <stdbool.h>
/* ===================================================
* SMART CALCULATOR - LPC1768 (Final v2)
* Supports BIN, BASE4, OCT, DEC, and HEX
* with 4x4 keypad, LCD, and 7-seg status display.
*
* Features:
* - Base-aware arithmetic and I/O
* - HEX: double MODE button press within 2s = operator mode
* - Hardware 1ms timing via SysTick
* ===================================================
*/
/* 7-Segment patterns for 0F */
const unsigned char seven_seg[16] = {
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07,
0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71
};
/* ===== Pin & Mode Definitions ===== */
#define COL_BASE 15
#define ROW_BASE 19
#define COL_MASK (0x0F << COL_BASE)
#define ROW_MASK (0x0F << ROW_BASE)
#define SEG_SHIFT 4
#define DIGIT_EN (1 << 23)
#define LCD_DATA_SHIFT 23
#define LCD_DATA_MASK (0x0F << LCD_DATA_SHIFT)
#define LCD_RS (1 << 27)
#define LCD_EN (1 << 28)
#define MODE_BUTTON (1 << 12)
/* Supported Bases */
#define MODE_BIN 2
#define MODE_BASE4 4
#define MODE_OCT 8
#define MODE_DEC 10
#define MODE_HEX 16
/* Operators */
#define OP_NONE 0
#define OP_ADD 1
#define OP_SUB 2
#define OP_MUL 3
#define OP_CLR 4
#define OP_RES 5
/* ===== Global Variables ===== */
unsigned int current_base;
unsigned int input_num;
unsigned int stored_num;
unsigned int result;
unsigned int operation;
unsigned char result_displayed;
unsigned int key, last_key, stable;
unsigned int button_state, last_button_state, button_stable;
unsigned char hex_operator_mode;
unsigned long last_mode_press_time;
/* Millisecond counter via SysTick */
volatile unsigned long sys_millis = 0;
/* ===== Function Declarations ===== */
void delay(volatile unsigned int d);
void lcd_delay(unsigned long r);
void lcd_write_nibble(unsigned char nibble, unsigned char is_data);
void lcd_cmd(unsigned char cmd);
void lcd_data(unsigned char data);
void lcd_init(void);
void lcd_print_str(const char *str);
void lcd_print_num(unsigned int num, unsigned int base);
void display_mode(void);
void display_input(void);
void display_result(void);
unsigned int scan_keypad(void);
unsigned int scan_mode_button(void);
unsigned int is_valid_digit(unsigned int key);
void change_mode(void);
void handle_mode_button(void);
void operate(unsigned int op);
void perform_operation(void);
unsigned char is_operator_active(unsigned int key);
unsigned int base_arith(unsigned int a, unsigned int b,
unsigned int op, unsigned int base);
unsigned long millis(void);
/* ===== Utility ===== */
void delay(volatile unsigned int d) {
while (d--) __NOP();
}
void lcd_delay(unsigned long r) {
volatile unsigned long i;
for (i = 0; i < r; i++)
;
}
/* ===== SysTick Millisecond Tracker ===== */
void SysTick_Handler(void) {
sys_millis++;
}
unsigned long millis(void) {
return sys_millis;
}
/* ===== LCD Control ===== */
void lcd_write_nibble(unsigned char nibble, unsigned char is_data) {
unsigned long temp;
temp = (nibble & 0x0F) << LCD_DATA_SHIFT;
LPC_GPIO0->FIOPIN = (LPC_GPIO0->FIOPIN & ~LCD_DATA_MASK) | temp;
if (is_data)
LPC_GPIO0->FIOSET = LCD_RS;
else
LPC_GPIO0->FIOCLR = LCD_RS;
LPC_GPIO0->FIOSET = LCD_EN;
lcd_delay(100);
LPC_GPIO0->FIOCLR = LCD_EN;
lcd_delay(250000);
}
void lcd_cmd(unsigned char cmd) {
lcd_write_nibble(cmd >> 4, 0);
lcd_write_nibble(cmd, 0);
}
void lcd_data(unsigned char data) {
lcd_write_nibble(data >> 4, 1);
lcd_write_nibble(data, 1);
}
void lcd_init(void) {
lcd_delay(5000000);
lcd_write_nibble(0x03, 0);
lcd_delay(500000);
lcd_write_nibble(0x03, 0);
lcd_delay(500000);
lcd_write_nibble(0x03, 0);
lcd_delay(500000);
lcd_write_nibble(0x02, 0);
lcd_delay(500000);
lcd_cmd(0x28);
lcd_cmd(0x0C);
lcd_cmd(0x01);
lcd_delay(500000);
lcd_cmd(0x06);
}
void lcd_print_str(const char *str) {
while (*str)
lcd_data(*str++);
}
void lcd_print_num(unsigned int num, unsigned int base) {
char buffer[17];
int i = 0;
if (num == 0) {
lcd_data('0');
return;
}
while (num > 0 && i < 16) {
unsigned int d = num % base;
buffer[i++] = (d < 10) ? ('0' + d) : ('A' + d - 10);
num /= base;
}
while (i > 0)
lcd_data(buffer[--i]);
}
/* ===== Display Helpers ===== */
void display_mode(void) {
lcd_cmd(0x80);
lcd_print_str("Mode: ");
if (current_base == MODE_BIN)
lcd_print_str("BIN ");
else if (current_base == MODE_BASE4)
lcd_print_str("BASE4 ");
else if (current_base == MODE_OCT)
lcd_print_str("OCT ");
else if (current_base == MODE_DEC)
lcd_print_str("DEC ");
else {
lcd_print_str("HEX");
if (hex_operator_mode)
lcd_print_str("[OPS]");
else
lcd_print_str(" ");
}
}
void display_input(void) {
lcd_cmd(0xC0);
lcd_print_str("Input: ");
lcd_print_num(input_num, current_base);
lcd_print_str(" ");
}
void display_result(void) {
lcd_cmd(0xC0);
lcd_print_str("Result: ");
lcd_print_num(result, current_base);
lcd_print_str(" ");
}
/* ===== Keypad and Button ===== */
unsigned int scan_keypad(void) {
unsigned int col, row, row_bits;
for (col = 0; col < 4; col++) {
LPC_GPIO0->FIOSET = COL_MASK;
delay(50);
LPC_GPIO0->FIOCLR = (1 << (COL_BASE + col));
delay(200);
row_bits = (LPC_GPIO0->FIOPIN & ROW_MASK) >> ROW_BASE;
if (row_bits != 0x0F) {
for (row = 0; row < 4; row++) {
if (!(row_bits & (1 << row))) {
LPC_GPIO0->FIOSET = COL_MASK;
return col * 4 + row;
}
}
}
}
LPC_GPIO0->FIOSET = COL_MASK;
return 0xFF;
}
unsigned int scan_mode_button(void) {
return ((LPC_GPIO2->FIOPIN & MODE_BUTTON) == 0) ? 1 : 0;
}
/* ===== Mode and Button ===== */
void change_mode(void) {
if (current_base == MODE_DEC)
current_base = MODE_BIN;
else if (current_base == MODE_BIN)
current_base = MODE_BASE4;
else if (current_base == MODE_BASE4)
current_base = MODE_OCT;
else if (current_base == MODE_OCT)
current_base = MODE_HEX;
else
current_base = MODE_DEC;
display_mode();
input_num = stored_num = result = 0;
operation = OP_NONE;
result_displayed = 0;
display_input();
}
void handle_mode_button(void) {
unsigned long now = millis();
if (button_stable == 3 && button_state == 1) {
if (current_base == MODE_HEX) {
if ((now - last_mode_press_time) < 2000) {
hex_operator_mode = !hex_operator_mode;
display_mode();
last_mode_press_time = 0;
} else {
last_mode_press_time = now;
}
} else {
change_mode();
}
}
}
/* ===== Validation ===== */
unsigned int is_valid_digit(unsigned int key) {
if (key >= 16)
return 0;
if (current_base == MODE_BIN && key >= 2)
return 0;
if (current_base == MODE_BASE4 && key >= 4)
return 0;
if (current_base == MODE_OCT && key >= 8)
return 0;
if (current_base == MODE_DEC && key >= 10)
return 0;
return 1;
}
/* ===== Arithmetic ===== */
unsigned int base_arith(unsigned int a, unsigned int b,
unsigned int op, unsigned int base) {
unsigned int r;
switch (op) {
case OP_ADD:
r = a + b;
break;
case OP_SUB:
r = (a >= b) ? (a - b) : 0;
break;
case OP_MUL:
r = a * b;
break;
default:
r = a;
break;
}
return r;
}
/* ===== Operation/Arithmetic Handling ===== */
void operate(unsigned int op) {
stored_num = input_num;
input_num = 0;
operation = op;
result_displayed = 0;
}
void perform_operation(void) {
result = base_arith(stored_num, input_num, operation, current_base);
display_result();
input_num = result;
operation = OP_NONE;
result_displayed = 1;
}
/* ===== Key Classifier ===== */
unsigned char is_operator_active(unsigned int key) {
if (key >= 11 && key <= 15) {
if (current_base == MODE_HEX)
return hex_operator_mode;
else
return 1;
}
return 0;
}
/* ===== MAIN ===== */
int main(void) {
current_base = MODE_DEC;
input_num = stored_num = result = 0;
operation = OP_NONE;
result_displayed = 0;
key = last_key = 0xFF;
stable = 0;
button_stable = 0;
button_state = last_button_state = 0;
hex_operator_mode = 0;
last_mode_press_time = 0;
/* ===== SystemClock & SysTick Setup ===== */
SystemCoreClockUpdate();
SysTick_Config(SystemCoreClock / 1000); // 1ms tick
/* ===== Peripheral Init ===== */
LPC_PINCON->PINSEL0 = 0;
LPC_PINCON->PINSEL1 = 0;
LPC_PINCON->PINSEL3 = 0;
LPC_PINCON->PINSEL4 = 0;
LPC_GPIO0->FIODIR |= COL_MASK;
LPC_GPIO0->FIODIR &= ~ROW_MASK;
LPC_GPIO0->FIOSET = COL_MASK;
LPC_GPIO2->FIODIR &= ~MODE_BUTTON;
LPC_GPIO0->FIODIR |= (0xFF << SEG_SHIFT);
LPC_GPIO1->FIODIR |= DIGIT_EN;
LPC_GPIO0->FIODIR |= LCD_DATA_MASK | LCD_RS | LCD_EN;
lcd_init();
display_mode();
display_input();
/* ===== Main Loop ===== */
while (1) {
key = scan_keypad();
button_state = scan_mode_button();
// Debounce keypad
if (key == last_key)
stable = (stable < 5) ? stable + 1 : stable;
else {
last_key = key;
stable = 0;
}
// Debounce button
if (button_state == last_button_state)
button_stable = (button_stable < 5) ? button_stable + 1 : button_stable;
else {
last_button_state = button_state;
button_stable = 0;
}
handle_mode_button();
if (stable == 3 && key != 0xFF) {
if (is_operator_active(key)) {
switch (key) {
case 11: operate(OP_ADD); display_input(); break;
case 12: input_num = stored_num = result = 0;
operation = OP_NONE; display_input(); break;
case 13: operate(OP_SUB); display_input(); break;
case 14: operate(OP_MUL); display_input(); break;
case 15: perform_operation(); break;
}
} else if (is_valid_digit(key)) {
result_displayed = 0;
input_num = input_num * current_base + key;
display_input();
}
stable = 5;
}
// Simple 7-seg base display
LPC_GPIO0->FIOCLR = (0xFF << SEG_SHIFT);
unsigned int segval = 0x3F; // default '0'
if (current_base == MODE_BIN) segval = seven_seg[2];
else if (current_base == MODE_BASE4) segval = seven_seg[4];
else if (current_base == MODE_OCT) segval = seven_seg[8];
else if (current_base == MODE_DEC) segval = seven_seg[0];
else if (current_base == MODE_HEX) segval = seven_seg[0xA]; // 'A' for HEX
LPC_GPIO0->FIOSET = (segval << SEG_SHIFT);
LPC_GPIO1->FIOSET = DIGIT_EN;
delay(3000);
}
}