#include #include /* =================================================== * 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 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 & 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(int num, unsigned int base) { char buffer[17]; int i = 0; unsigned int unum; if (base == MODE_DEC) { if (num < 0) { lcd_data('-'); num = -num; } } unum = (unsigned int)num; if (unum == 0) { lcd_data('0'); return; } while (unum > 0 && i < 16) { unsigned int d = unum % base; buffer[i++] = (d < 10) ? ('0' + d) : ('A' + d - 10); unum /= 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 per base (optimized) ===== */ int base_arith(int a, int b, unsigned int op, unsigned int base) { int r = 0; switch (op) { case OP_ADD: r = a + b; break; case OP_SUB: r = a - b; break; case OP_MUL: r = a * b; break; default: r = a; break; } // For non-decimal modes, keep everything positive and base-limited if (base != MODE_DEC) { if (r < 0) r = ((r % base) + base) % base; else r = r % (base * base * base * base * base); // safe wraparound for multi-digit bases } 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); } }