MIT-Curricular/ES/Project/code.c
2025-10-29 12:36:04 +05:30

433 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>
/* ===================================================
* SMART CALCULATOR - LPC176x
* Supports BIN, BASE4, OCT, DEC, and HEX modes with
* 4x4 keypad, LCD, and 7-segment display.
* ---------------------------------------------------
* DEC/BIN/BASE4/OCT : Operators BF work directly
* HEX : Operators BF require MODE pressed
* ===================================================
*/
// 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 Mapping =====
* Keypad (4x4):
* Columns: P0.15P0.18 (Outputs)
* Rows: P0.19P0.22 (Inputs, pull-ups)
*
* 7-Segment:
* Segments: P0.4P0.11
* Digit Enable: P1.23
*
* LCD:
* Data: P0.23P0.26, RS: P0.27, EN: P0.28
*
* Mode Button: P2.12 (active low)
*/
/* ===== MACROS ===== */
#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)
#define MODE_BIN 2
#define MODE_BASE4 4
#define MODE_OCT 8
#define MODE_DEC 10
#define MODE_HEX 16
#define OP_NONE 0
#define OP_ADD 1
#define OP_SUB 2
#define OP_MUL 3
/* ===== Global Variables (Predeclared) ===== */
int input_num;
unsigned int seg_pattern;
int stored_num;
int result;
unsigned int current_base;
unsigned int operation;
unsigned char lcd_flag;
unsigned char result_displayed;
unsigned int key, last_key, stable;
unsigned int button_state, last_button_state, button_stable;
/* ===== 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(int num, unsigned int base);
void display_mode(void);
void display_input(void);
void display_operator_feedback(const char *op_symbol);
unsigned int scan_keypad(void);
unsigned int scan_mode_button(void);
unsigned int is_valid_digit(unsigned int key);
void change_mode(void);
void operate(unsigned int op);
void perform_operation(void);
/* ===== Delays ===== */
void delay(volatile unsigned int d) {
while (d--)
__NOP();
}
void lcd_delay(unsigned long r) {
unsigned long i;
for (i = 0; i < r; i++)
;
}
/* ===== LCD ===== */
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(500000);
}
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(int num, unsigned int base) {
char buffer[17];
int i = 0;
if (base != MODE_DEC) {
unsigned int unum = (unsigned int)num;
if (unum == 0) {
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 (i > 0)
lcd_data(buffer[--i]);
}
/* ===== Display Handling ===== */
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 ");
}
void display_input(void) {
lcd_cmd(0xC0);
lcd_print_str("Inp: ");
lcd_print_num(input_num, current_base);
lcd_print_str(" ");
}
void display_operator_feedback(const char *op_symbol) {
lcd_cmd(0xC0);
lcd_print_str("Op: ");
lcd_print_str(op_symbol);
lcd_print_str(" ");
delay(100000);
display_input();
}
/* ===== Input Handling ===== */
unsigned int scan_keypad(void) {
unsigned int col, row;
unsigned int 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)) == 0) {
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 Switching ===== */
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();
}
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; // HEX accepts all 0-F
}
/* ===== Operations ===== */
void operate(unsigned int op) {
stored_num = input_num;
operation = op;
input_num = 0;
result_displayed = 0;
}
void perform_operation(void) {
if (operation == OP_ADD)
result = stored_num + input_num;
else if (operation == OP_SUB)
result = stored_num - input_num;
else if (operation == OP_MUL)
result = stored_num * input_num;
else
result = input_num;
lcd_cmd(0xC0);
lcd_print_str("Res: ");
lcd_print_num(result, current_base);
lcd_print_str(" ");
input_num = result;
operation = OP_NONE;
result_displayed = 1;
}
/* ===== MAIN ===== */
int main(void) {
// Initialize globals
input_num = stored_num = result = 0;
current_base = MODE_DEC;
operation = OP_NONE;
lcd_flag = 0;
result_displayed = 0;
key = last_key = 0xFF;
stable = button_stable = 0;
button_state = last_button_state = 0;
// Configure Pins
LPC_PINCON->PINSEL0 = 0;
LPC_PINCON->PINSEL1 = 0;
LPC_PINCON->PINSEL3 = 0;
LPC_PINCON->PINSEL4 = 0;
// Keypad setup
LPC_GPIO0->FIODIR |= COL_MASK;
LPC_GPIO0->FIODIR &= ~ROW_MASK;
LPC_GPIO0->FIOSET = COL_MASK;
// Mode button setup
LPC_GPIO2->FIODIR &= ~MODE_BUTTON;
// 7-Segment setup
LPC_GPIO0->FIODIR |= (0xFF << SEG_SHIFT);
LPC_GPIO1->FIODIR |= DIGIT_EN;
// LCD setup
LPC_GPIO0->FIODIR |= LCD_DATA_MASK | LCD_RS | LCD_EN;
lcd_init();
display_mode();
display_input();
for (;;) {
key = scan_keypad();
button_state = scan_mode_button();
// Debounce keypad
if (key == last_key) {
if (stable < 5)
stable++;
} else {
last_key = key;
stable = 0;
}
// Debounce mode button
if (button_state == last_button_state) {
if (button_stable < 5)
button_stable++;
} else {
last_button_state = button_state;
button_stable = 0;
}
// Cycle through modes
if (button_stable == 3 && button_state == 1) {
change_mode();
button_stable = 5;
}
// Handle keypad press
if (stable == 3 && key != 0xFF) {
unsigned char allow_operator = 0;
// Operators allowed directly for all modes except HEX (must hold mode)
if (current_base == MODE_HEX && button_state == 1)
allow_operator = 1;
else if (current_base != MODE_HEX)
allow_operator = 1;
// Operator Keys: BF (indices 1115)
if (allow_operator) {
if (key == 11) { // B = +
operate(OP_ADD);
display_operator_feedback("+");
} else if (key == 12) { // C = CLR
input_num = stored_num = result = 0;
operation = OP_NONE;
result_displayed = 0;
display_operator_feedback("CLR");
} else if (key == 13) { // D = -
operate(OP_SUB);
display_operator_feedback("-");
} else if (key == 14) { // E = *
operate(OP_MUL);
display_operator_feedback("*");
} else if (key == 15) { // F = =
perform_operation();
} else if (is_valid_digit(key)) {
result_displayed = 0;
input_num = input_num * current_base + key;
display_input();
}
} else {
if (is_valid_digit(key)) {
result_displayed = 0;
input_num = input_num * current_base + key;
display_input();
}
}
stable = 5;
}
// ===== STATE DISPLAY on 7-Segment =====
if (operation == OP_NONE && result_displayed == 0)
seg_pattern = 0x06; // '1' - Input mode
else if (operation != OP_NONE)
seg_pattern = 0x5B | 0x80; // '2' + DP - Waiting for 2nd operand
else if (result_displayed == 1)
seg_pattern = 0x4F | 0x80; // '3' + DP - Result shown
else
seg_pattern = 0x3F; // '0' - Reset
LPC_GPIO0->FIOCLR = (0xFF << SEG_SHIFT);
LPC_GPIO0->FIOSET = (seg_pattern << SEG_SHIFT);
LPC_GPIO1->FIOSET = DIGIT_EN;
delay(3000);
}
}