#include /* PORT MAPPING: * KEYPAD MATRIX (4x4): * Columns: P0.15 - P0.18 (Output, pulled high, scan low) * Rows: P0.19 - P0.22 (Input, pulled high internally) * * Layout: 0 1 2 3 * 4 5 6 7 * 8 9 A B * C D E F * * 7-SEGMENT DISPLAY: * Segments: P0.4 - P0.11 (a-g + dp) * Digit Enable: P1.23 (active high) * * LCD (16x2): * Data: P0.23 - P0.26 (D4-D7, 4-bit mode) * RS: P0.27 * EN: P0.28 * * MODE BUTTON: * P2.12 (Input, internal pull-up) * * KEY FUNCTIONS: * 0-9, A-F: Digit input (valid based on current base) * * OPERATOR KEYS: * DEC/BIN/OCT modes (direct press): * Key A: Addition (+) * Key B: Subtraction (-) * Key C: Multiplication (*) * Key D: Equals (=) * Key E: Clear (C) * * HEX mode (hold MODE + key): * MODE + A: Addition (+) * MODE + B: Subtraction (-) * MODE + C: Multiplication (*) * MODE + D: Equals (=) * MODE + E: Clear (C) * * P2.12 Button: * Short press: Mode selection (cycles: DEC->BIN->OCT->HEX) * Hold + key (HEX mode only): Operator input * * 7-SEGMENT STATE DISPLAY: * '1' - Input mode (entering numbers) * '2' with DP - Operation pending (waiting for 2nd number) * '3' with DP - Result ready (showing calculation result) * '0' - Cleared/Reset state (fallback) */ // 7-Segment patterns const unsigned char seven_seg[16] = { 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71 }; // Keypad defines #define COL_BASE 15 #define ROW_BASE 19 #define COL_MASK (0x0F << COL_BASE) #define ROW_MASK (0x0F << ROW_BASE) // 7-Segment defines #define SEG_SHIFT 4 #define DIGIT_EN (1 << 23) // LCD defines #define LCD_DATA_SHIFT 23 #define LCD_DATA_MASK (0x0F << LCD_DATA_SHIFT) #define LCD_RS (1 << 27) #define LCD_EN (1 << 28) // Mode button defines #define MODE_BUTTON (1 << 12) // Calculator states #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 int input_num = 0; int stored_num = 0; int result = 0; unsigned int current_base = MODE_DEC; unsigned int operation = OP_NONE; unsigned char result_displayed = 0; unsigned int key = 0xFF; unsigned int last_key = 0xFF; unsigned int stable = 0; unsigned int mode_held = 0; unsigned int mode_press_counter = 0; unsigned int key_pressed_with_mode = 0; unsigned int mode_current = 0; int is_operator_key = 0; int operator_mode = 0; unsigned int seg_pattern = 0; 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; if(digit < 10) buffer[i++] = '0' + digit; else buffer[i++] = 'A' + (digit - 10); unum = 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 = 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_status(void) { lcd_cmd(0xC0); if(operation != OP_NONE) { // Show operation pending lcd_print_str("Op:"); if(operation == OP_ADD) lcd_data('+'); else if(operation == OP_SUB) lcd_data('-'); else if(operation == OP_MUL) lcd_data('*'); lcd_print_str(" Val:"); lcd_print_num(stored_num, current_base); lcd_print_str(" "); } else if(result_displayed) { // Show result lcd_print_str("Res: "); lcd_print_num(result, current_base); lcd_print_str(" "); } else { // Show current input lcd_print_str("Inp: "); lcd_print_num(input_num, current_base); lcd_print_str(" "); } } 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 is_mode_button_pressed(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; } 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; input_num = 0; stored_num = 0; operation = OP_NONE; result = 0; result_displayed = 0; display_mode(); display_status(); } int main(void) { // Configure pins LPC_PINCON->PINSEL0 = 0; LPC_PINCON->PINSEL1 = 0; LPC_PINCON->PINSEL3 = 0; LPC_PINCON->PINSEL4 = 0; // Keypad: Columns output, Rows input LPC_GPIO0->FIODIR |= COL_MASK; LPC_GPIO0->FIODIR &= ~ROW_MASK; LPC_GPIO0->FIOSET = COL_MASK; // Mode button: Input with internal pull-up LPC_GPIO2->FIODIR &= ~MODE_BUTTON; // 7-Segment LPC_GPIO0->FIODIR |= (0xFF << SEG_SHIFT); LPC_GPIO1->FIODIR |= DIGIT_EN; // LCD LPC_GPIO0->FIODIR |= LCD_DATA_MASK | LCD_RS | LCD_EN; lcd_init(); display_mode(); display_status(); for(;;) { // Check if MODE button is currently pressed mode_current = is_mode_button_pressed(); // Scan keypad key = scan_keypad(); // Debounce keypad if(key == last_key) { if(stable < 5) stable++; } else { last_key = key; stable = 0; } // Track MODE button hold if(mode_current) { mode_press_counter++; mode_held = 1; } else { // MODE button released if(mode_held && !key_pressed_with_mode && mode_press_counter < 50) { // Short press without key combo = change mode change_mode(); } mode_held = 0; mode_press_counter = 0; key_pressed_with_mode = 0; } // Handle keypad input if(stable == 3 && key != 0xFF) { // Key pressed and stable // Check if this is an operator key (A-E) is_operator_key = (key >= 10 && key <= 14); // In HEX mode, operators require MODE button // In other modes, operator keys work directly operator_mode = 0; if(current_base == MODE_HEX) { operator_mode = (mode_held && is_operator_key); } else { operator_mode = is_operator_key; } if(operator_mode) { // OPERATOR INPUT key_pressed_with_mode = 1; if(key == 10) { // A = Addition stored_num = input_num; operation = OP_ADD; input_num = 0; result_displayed = 0; display_status(); } else if(key == 11) { // B = Subtraction stored_num = input_num; operation = OP_SUB; input_num = 0; result_displayed = 0; display_status(); } else if(key == 12) { // C = Multiplication stored_num = input_num; operation = OP_MUL; input_num = 0; result_displayed = 0; display_status(); } else if(key == 13) { // D = Equals 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; input_num = result; operation = OP_NONE; result_displayed = 1; display_status(); } else if(key == 14) { // E = Clear input_num = 0; stored_num = 0; operation = OP_NONE; result = 0; result_displayed = 0; display_status(); } } else { // DIGIT INPUT MODE if(is_valid_digit(key)) { result_displayed = 0; input_num = input_num * current_base + key; if(input_num > 32767) input_num = input_num % 32768; if(input_num < -32768) input_num = -32768; display_status(); } } stable = 5; // Prevent repeated triggers } // ===== STATE MACHINE DISPLAY ON 7-SEGMENT ===== if(operation == OP_NONE && result_displayed == 0) { seg_pattern = 0x06; // Display '1' } else if(operation != OP_NONE) { seg_pattern = 0x5B | 0x80; // Display '2' with DP } else if(result_displayed == 1) { seg_pattern = 0x4F | 0x80; // Display '3' with DP } else { seg_pattern = 0x3F; // Display '0' } // Update the 7-segment display LPC_GPIO0->FIOCLR = (0xFF << SEG_SHIFT); LPC_GPIO0->FIOSET = (seg_pattern << SEG_SHIFT); LPC_GPIO1->FIOSET = DIGIT_EN; delay(3000); } return 0; }