This commit is contained in:
sherlock 2025-10-29 14:22:21 +05:30
parent 6693a1a831
commit f710e88793

View file

@ -1,13 +1,15 @@
#include <LPC17xx.h> #include <LPC17xx.h>
#include <stdbool.h>
/* =================================================== /* ===================================================
* SMART CALCULATOR - LPC176x * SMART CALCULATOR - LPC1768 (Final v2)
* Supports BIN, BASE4, OCT, DEC, and HEX * Supports BIN, BASE4, OCT, DEC, and HEX
* with 4x4 keypad, LCD, and 7-seg status. * with 4x4 keypad, LCD, and 7-seg status display.
* *
* BIN/BASE4/OCT/DEC: operators BF direct * Features:
* HEX: operators BF only when MODE button held * - Base-aware arithmetic and I/O
* Arithmetic is performed modulo the current base * - HEX: double MODE button press within 2s = operator mode
* - Hardware 1ms timing via SysTick
* =================================================== * ===================================================
*/ */
@ -45,20 +47,27 @@ const unsigned char seven_seg[16] = {
#define OP_ADD 1 #define OP_ADD 1
#define OP_SUB 2 #define OP_SUB 2
#define OP_MUL 3 #define OP_MUL 3
#define OP_CLR 4
#define OP_RES 5
/* ===== Global Variables (predeclared) ===== */ /* ===== Global Variables ===== */
int input_num;
int stored_num;
int result;
unsigned int current_base; unsigned int current_base;
unsigned int input_num;
unsigned int stored_num;
unsigned int result;
unsigned int operation; unsigned int operation;
unsigned char lcd_flag;
unsigned char result_displayed; unsigned char result_displayed;
unsigned int key, last_key, stable; unsigned int key, last_key, stable;
unsigned int button_state, last_button_state, button_stable; unsigned int button_state, last_button_state, button_stable;
/* ===== Function Prototypes ===== */ 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 delay(volatile unsigned int d);
void lcd_delay(unsigned long r); void lcd_delay(unsigned long r);
void lcd_write_nibble(unsigned char nibble, unsigned char is_data); void lcd_write_nibble(unsigned char nibble, unsigned char is_data);
@ -66,36 +75,47 @@ void lcd_cmd(unsigned char cmd);
void lcd_data(unsigned char data); void lcd_data(unsigned char data);
void lcd_init(void); void lcd_init(void);
void lcd_print_str(const char *str); void lcd_print_str(const char *str);
void lcd_print_num(int num, unsigned int base); void lcd_print_num(unsigned int num, unsigned int base);
void display_mode(void); void display_mode(void);
void display_input(void); void display_input(void);
void display_operator_feedback(const char *op_symbol); void display_result(void);
unsigned int scan_keypad(void); unsigned int scan_keypad(void);
unsigned int scan_mode_button(void); unsigned int scan_mode_button(void);
unsigned int is_valid_digit(unsigned int key); unsigned int is_valid_digit(unsigned int key);
void change_mode(void); void change_mode(void);
void handle_mode_button(void);
void operate(unsigned int op); void operate(unsigned int op);
void perform_operation(void); void perform_operation(void);
unsigned char is_operator_active(unsigned int key, unsigned int mode_button); 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 ====== */ /* ===== Utility ===== */
void delay(volatile unsigned int d) { void delay(volatile unsigned int d) {
while (d--) while (d--) __NOP();
__NOP();
} }
void lcd_delay(unsigned long r) { void lcd_delay(unsigned long r) {
unsigned long i; volatile unsigned long i;
for (i = 0; i < r; i++) for (i = 0; i < r; i++)
; ;
} }
/* ===== LCD ==== */ /* ===== 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) { void lcd_write_nibble(unsigned char nibble, unsigned char is_data) {
unsigned long temp; unsigned long temp;
temp = (nibble & 0x0F) << LCD_DATA_SHIFT; temp = (nibble & 0x0F) << LCD_DATA_SHIFT;
LPC_GPIO0->FIOPIN = LPC_GPIO0->FIOPIN = (LPC_GPIO0->FIOPIN & ~LCD_DATA_MASK) | temp;
(LPC_GPIO0->FIOPIN & ~LCD_DATA_MASK) | temp;
if (is_data) if (is_data)
LPC_GPIO0->FIOSET = LCD_RS; LPC_GPIO0->FIOSET = LCD_RS;
@ -105,7 +125,7 @@ void lcd_write_nibble(unsigned char nibble, unsigned char is_data) {
LPC_GPIO0->FIOSET = LCD_EN; LPC_GPIO0->FIOSET = LCD_EN;
lcd_delay(100); lcd_delay(100);
LPC_GPIO0->FIOCLR = LCD_EN; LPC_GPIO0->FIOCLR = LCD_EN;
lcd_delay(500000); lcd_delay(250000);
} }
void lcd_cmd(unsigned char cmd) { void lcd_cmd(unsigned char cmd) {
@ -141,90 +161,62 @@ void lcd_print_str(const char *str) {
lcd_data(*str++); lcd_data(*str++);
} }
/* ===== Print number in base ===== */ void lcd_print_num(unsigned int num, unsigned int base) {
void lcd_print_num(int num, unsigned int base) {
char buffer[17]; char buffer[17];
int i = 0; int i = 0;
if (base != MODE_DEC) { if (num == 0) {
unsigned int unum = (unsigned int)num; lcd_data('0');
if (unum == 0) { return;
lcd_data('0');
return;
}
while (unum > 0 && i < 16) {
unsigned int digit = unum % base;
buffer[i++] = (digit < 10) ? ('0' + digit)
: ('A' + (digit - 10));
unum /= base;
}
} else {
if (num < 0) {
lcd_data('-');
num = -num;
}
if (num == 0) {
lcd_data('0');
return;
}
while (num > 0 && i < 16) {
buffer[i++] = '0' + (num % 10);
num /= 10;
}
} }
while (num > 0 && i < 16) {
unsigned int d = num % base;
buffer[i++] = (d < 10) ? ('0' + d) : ('A' + d - 10);
num /= base;
}
while (i > 0) while (i > 0)
lcd_data(buffer[--i]); lcd_data(buffer[--i]);
} }
/* ===== Display handlers ===== */ /* ===== Display Helpers ===== */
void display_mode(void) { void display_mode(void) {
lcd_cmd(0x80); lcd_cmd(0x80);
lcd_print_str("Mode: "); lcd_print_str("Mode: ");
if (current_base == MODE_BIN) if (current_base == MODE_BIN)
lcd_print_str("BIN "); lcd_print_str("BIN ");
else if (current_base == MODE_BASE4) else if (current_base == MODE_BASE4)
lcd_print_str("BASE4 "); lcd_print_str("BASE4 ");
else if (current_base == MODE_OCT) else if (current_base == MODE_OCT)
lcd_print_str("OCT "); lcd_print_str("OCT ");
else if (current_base == MODE_DEC) else if (current_base == MODE_DEC)
lcd_print_str("DEC "); lcd_print_str("DEC ");
else else {
lcd_print_str("HEX "); lcd_print_str("HEX");
if (hex_operator_mode)
lcd_print_str("[OPS]");
else
lcd_print_str(" ");
}
} }
void display_input(void) { void display_input(void) {
lcd_cmd(0xC0); lcd_cmd(0xC0);
lcd_print_str("Inp("); lcd_print_str("Input: ");
if (current_base == MODE_BIN)
lcd_print_str("2");
else if (current_base == MODE_BASE4)
lcd_print_str("4");
else if (current_base == MODE_OCT)
lcd_print_str("8");
else if (current_base == MODE_DEC)
lcd_print_str("10");
else
lcd_print_str("16");
lcd_print_str("): ");
lcd_print_num(input_num, current_base); lcd_print_num(input_num, current_base);
lcd_print_str(" "); lcd_print_str(" ");
} }
void display_operator_feedback(const char *op_symbol) { void display_result(void) {
lcd_cmd(0xC0); lcd_cmd(0xC0);
lcd_print_str("Op: "); lcd_print_str("Result: ");
lcd_print_str(op_symbol); lcd_print_num(result, current_base);
lcd_print_str(" "); lcd_print_str(" ");
delay(100000);
display_input();
} }
/* ====== Scan Keypad ====== */ /* ===== Keypad and Button ===== */
unsigned int scan_keypad(void) { unsigned int scan_keypad(void) {
unsigned int col, row; unsigned int col, row, row_bits;
unsigned int row_bits;
for (col = 0; col < 4; col++) { for (col = 0; col < 4; col++) {
LPC_GPIO0->FIOSET = COL_MASK; LPC_GPIO0->FIOSET = COL_MASK;
delay(50); delay(50);
@ -234,9 +226,9 @@ unsigned int scan_keypad(void) {
if (row_bits != 0x0F) { if (row_bits != 0x0F) {
for (row = 0; row < 4; row++) { for (row = 0; row < 4; row++) {
if ((row_bits & (1 << row)) == 0) { if (!(row_bits & (1 << row))) {
LPC_GPIO0->FIOSET = COL_MASK; LPC_GPIO0->FIOSET = COL_MASK;
return (col * 4 + row); return col * 4 + row;
} }
} }
} }
@ -245,12 +237,11 @@ unsigned int scan_keypad(void) {
return 0xFF; return 0xFF;
} }
/* ===== Mode button ===== */
unsigned int scan_mode_button(void) { unsigned int scan_mode_button(void) {
return ((LPC_GPIO2->FIOPIN & MODE_BUTTON) == 0) ? 1 : 0; return ((LPC_GPIO2->FIOPIN & MODE_BUTTON) == 0) ? 1 : 0;
} }
/* ===== Modes and Validation ===== */ /* ===== Mode and Button ===== */
void change_mode(void) { void change_mode(void) {
if (current_base == MODE_DEC) if (current_base == MODE_DEC)
current_base = MODE_BIN; current_base = MODE_BIN;
@ -264,8 +255,31 @@ void change_mode(void) {
current_base = MODE_DEC; current_base = MODE_DEC;
display_mode(); 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) { unsigned int is_valid_digit(unsigned int key) {
if (key >= 16) if (key >= 16)
return 0; return 0;
@ -280,73 +294,72 @@ unsigned int is_valid_digit(unsigned int key) {
return 1; return 1;
} }
/* ===== Operator Handling ===== */ /* ===== 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) { void operate(unsigned int op) {
stored_num = input_num; stored_num = input_num;
operation = op;
input_num = 0; input_num = 0;
operation = op;
result_displayed = 0; result_displayed = 0;
} }
/* perform_operation: arithmetic within the active base */
void perform_operation(void) { void perform_operation(void) {
if (operation == OP_ADD) result = base_arith(stored_num, input_num, operation, current_base);
result = stored_num + input_num; display_result();
else if (operation == OP_SUB)
result = stored_num - input_num;
else if (operation == OP_MUL)
result = stored_num * input_num;
else
result = input_num;
/* Base-aware modular arithmetic for non-DEC modes */
if (current_base != MODE_DEC) {
if (result < 0)
result = (result % current_base + current_base) % current_base;
else
result %= current_base;
}
lcd_cmd(0xC0);
lcd_print_str("Res(");
if (current_base == MODE_BIN)
lcd_print_str("2");
else if (current_base == MODE_BASE4)
lcd_print_str("4");
else if (current_base == MODE_OCT)
lcd_print_str("8");
else if (current_base == MODE_DEC)
lcd_print_str("10");
else
lcd_print_str("16");
lcd_print_str("): ");
lcd_print_num(result, current_base);
lcd_print_str(" ");
input_num = result; input_num = result;
operation = OP_NONE; operation = OP_NONE;
result_displayed = 1; result_displayed = 1;
} }
unsigned char is_operator_active(unsigned int key, unsigned int mode_button) { /* ===== Key Classifier ===== */
if (current_base == MODE_HEX) unsigned char is_operator_active(unsigned int key) {
return (mode_button && key >= 11 && key <= 15); if (key >= 11 && key <= 15) {
else if (current_base == MODE_HEX)
return (key >= 11 && key <= 15); return hex_operator_mode;
else
return 1;
}
return 0;
} }
/* ===== MAIN ===== */ /* ===== MAIN ===== */
int main(void) { int main(void) {
input_num = stored_num = result = 0;
current_base = MODE_DEC; current_base = MODE_DEC;
input_num = stored_num = result = 0;
operation = OP_NONE; operation = OP_NONE;
lcd_flag = 0;
result_displayed = 0; result_displayed = 0;
key = last_key = 0xFF; key = last_key = 0xFF;
stable = button_stable = 0; stable = 0;
button_stable = 0;
button_state = last_button_state = 0; button_state = last_button_state = 0;
hex_operator_mode = 0;
last_mode_press_time = 0;
/* Configure pins */ /* ===== SystemClock & SysTick Setup ===== */
SystemCoreClockUpdate();
SysTick_Config(SystemCoreClock / 1000); // 1ms tick
/* ===== Peripheral Init ===== */
LPC_PINCON->PINSEL0 = 0; LPC_PINCON->PINSEL0 = 0;
LPC_PINCON->PINSEL1 = 0; LPC_PINCON->PINSEL1 = 0;
LPC_PINCON->PINSEL3 = 0; LPC_PINCON->PINSEL3 = 0;
@ -360,85 +373,63 @@ int main(void) {
LPC_GPIO0->FIODIR |= (0xFF << SEG_SHIFT); LPC_GPIO0->FIODIR |= (0xFF << SEG_SHIFT);
LPC_GPIO1->FIODIR |= DIGIT_EN; LPC_GPIO1->FIODIR |= DIGIT_EN;
LPC_GPIO0->FIODIR |= LCD_DATA_MASK | LCD_RS | LCD_EN; LPC_GPIO0->FIODIR |= LCD_DATA_MASK | LCD_RS | LCD_EN;
lcd_init(); lcd_init();
display_mode(); display_mode();
display_input(); display_input();
for (;;) { /* ===== Main Loop ===== */
while (1) {
key = scan_keypad(); key = scan_keypad();
button_state = scan_mode_button(); button_state = scan_mode_button();
/* Debounce keypad */ // Debounce keypad
if (key == last_key) { if (key == last_key)
if (stable < 5) stable = (stable < 5) ? stable + 1 : stable;
stable++; else {
} else {
last_key = key; last_key = key;
stable = 0; stable = 0;
} }
/* Debounce mode button */ // Debounce button
if (button_state == last_button_state) { if (button_state == last_button_state)
if (button_stable < 5) button_stable = (button_stable < 5) ? button_stable + 1 : button_stable;
button_stable++; else {
} else {
last_button_state = button_state; last_button_state = button_state;
button_stable = 0; button_stable = 0;
} }
/* Handle mode change */ handle_mode_button();
if (button_stable == 3 && button_state == 1) {
change_mode();
button_stable = 5;
}
/* Handle key event */
if (stable == 3 && key != 0xFF) { if (stable == 3 && key != 0xFF) {
unsigned char op_allowed = is_operator_active(key, button_state); if (is_operator_active(key)) {
switch (key) {
if (op_allowed) { case 11: operate(OP_ADD); display_input(); break;
if (key == 11) { case 12: input_num = stored_num = result = 0;
operate(OP_ADD); operation = OP_NONE; display_input(); break;
display_operator_feedback("+"); case 13: operate(OP_SUB); display_input(); break;
} else if (key == 12) { case 14: operate(OP_MUL); display_input(); break;
input_num = stored_num = result = 0; case 15: perform_operation(); break;
operation = OP_NONE;
result_displayed = 0;
display_operator_feedback("CLR");
} else if (key == 13) {
operate(OP_SUB);
display_operator_feedback("-");
} else if (key == 14) {
operate(OP_MUL);
display_operator_feedback("*");
} else if (key == 15) {
perform_operation();
} }
} else if (is_valid_digit(key)) { } else if (is_valid_digit(key)) {
result_displayed = 0; result_displayed = 0;
input_num = input_num * current_base + key; input_num = input_num * current_base + key;
display_input(); display_input();
} }
stable = 5; stable = 5;
} }
/* Update 7-seg state display */ // Simple 7-seg base display
unsigned int seg_pattern;
if (operation == OP_NONE && result_displayed == 0)
seg_pattern = 0x06; // '1'
else if (operation != OP_NONE)
seg_pattern = 0x5B | 0x80; // '2' + dp
else if (result_displayed == 1)
seg_pattern = 0x4F | 0x80; // '3' + dp
else
seg_pattern = 0x3F; // '0'
LPC_GPIO0->FIOCLR = (0xFF << SEG_SHIFT); LPC_GPIO0->FIOCLR = (0xFF << SEG_SHIFT);
LPC_GPIO0->FIOSET = (seg_pattern << 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; LPC_GPIO1->FIOSET = DIGIT_EN;
delay(3000); delay(3000);