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

416 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 DEC, BIN, OCT, and HEX input modes
*, with 4x4 keypad, LCD, 7-segment, and mode button.
* ---------------------------------------------------
* Decimal mode: Operators B-F active directly
* Hexadecimal mode: Operators B-F active with MODE button
* ===================================================
*/
// 7-Segment patterns for 0-F
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 (Output)
* Rows: P0.19P0.22 (Input, pull-up)
*
* 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
* ------------------------------------------------
*/
/* ===== 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_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;
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;
unsigned int shift_active;
/* ===== 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);
/* ===== Utility & LCD Handling ===== */
void delay(volatile unsigned int d) {
while (d--)
__NOP();
}
void lcd_delay(unsigned long r) {
unsigned long i;
for (i = 0; i < r; i++)
;
}
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]);
}
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_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();
}
/* ====== Keypad & Button 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;
}
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_OCT && key >= 8)
return 0;
if (current_base == MODE_DEC && key >= 10)
return 0;
return 1; // HEX accepts all 0-F
}
void change_mode(void) {
if (current_base == MODE_DEC)
current_base = MODE_BIN;
else if (current_base == MODE_BIN)
current_base = MODE_OCT;
else if (current_base == MODE_OCT)
current_base = MODE_HEX;
else
current_base = MODE_DEC;
display_mode();
}
/* ===== Operator Handling ===== */
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) {
// Init 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;
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();
for (;;) {
key = scan_keypad();
button_state = scan_mode_button();
if (key == last_key) {
if (stable < 5)
stable++;
} else {
last_key = key;
stable = 0;
}
if (button_state == last_button_state) {
if (button_stable < 5)
button_stable++;
} else {
last_button_state = button_state;
button_stable = 0;
}
if (button_stable == 3 && button_state == 1) {
change_mode();
button_stable = 5;
}
if (stable == 3 && key != 0xFF) {
/* =========================
* DECIMAL MODE: Operator works directly
* HEX MODE: Operator works with MODE_BUTTON held
* ========================= */
if ((current_base == MODE_DEC) ||
(current_base == MODE_HEX && button_state == 1)) {
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 =====
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->FIOSET = (seg_pattern << SEG_SHIFT);
LPC_GPIO1->FIOSET = DIGIT_EN;
delay(3000);
}
}