#include #include /* =================================================== * SMART MULTI-BASE CALCULATOR — LPC1768 * Supports BIN, BASE4, OCT, DEC, HEX with * keypad and LCD (no 7-segment). * * Features: * • SysTick 1 ms hardware timing * • HEX: double MODE press <2 s → operator mode * • Signed decimal arithmetic; modular in other bases * • NOKIA TUNE on GPIO beeper (loops continuously) * =================================================== */ /* ===== Pin & Mode Defines ===== */ #define COL_BASE 15 #define ROW_BASE 19 #define COL_MASK (0x0F << COL_BASE) #define ROW_MASK (0x0F << ROW_BASE) #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 BEEPER_PIN (1 << 4) /* P0.4 / CNA Pin 1 */ /* Modes / 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 /* ===== Predeclared Variables ===== */ int input_num, stored_num, result; unsigned int operation; unsigned int current_base; unsigned char hex_op_mode; unsigned char result_displayed; unsigned int key, last_key, stable; unsigned int button_state, last_button_state, button_stable; unsigned long last_mode_press_time; volatile unsigned long sys_millis; unsigned int col, row, row_bits, d, unum, i; char buf[17]; volatile unsigned int loop_idx, beep_i; unsigned int frequency_hz, duration_ms; unsigned int half_period_us; unsigned long start_time, end_time, now; /* ===== Nokia Tune Notes ===== */ typedef struct { unsigned int frequency; /* Hz */ unsigned int duration; /* ms */ } Note; const Note nokia_tune[] = { /* Complete Nokia Tune - Full sequence */ {330, 125}, {311, 125}, {370, 125}, {415, 250}, {311, 125}, {370, 125}, {415, 500}, {0, 100}, {330, 125}, {311, 125}, {370, 125}, {415, 250}, {311, 125}, {370, 125}, {415, 250}, {0, 100}, {330, 125}, {311, 125}, {370, 125}, {415, 250}, {311, 125}, {370, 125}, {415, 250}, {0, 100}, {330, 125}, {311, 125}, {370, 125}, {415, 500}, {0, 100}, {370, 125}, {415, 125}, {466, 125}, {523, 250}, {415, 125}, {466, 125}, {523, 250}, {0, 100}, {370, 125}, {415, 125}, {466, 125}, {523, 250}, {415, 125}, {466, 125}, {523, 250}, {0, 100}, {370, 125}, {415, 125}, {466, 125}, {523, 500}, {0, 100}, {330, 125}, {311, 125}, {370, 125}, {415, 250}, {311, 125}, {370, 125}, {415, 250}, {0, 100}, {330, 125}, {311, 125}, {370, 125}, {415, 250}, {311, 125}, {370, 125}, {415, 1000}, {0, 0} /* End marker */ }; /* ===== Forward 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 *s); void lcd_print_num(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); int base_arith(int a, int b, unsigned int op, unsigned int base); unsigned long millis(void); void beeper_init(void); void play_tone(unsigned int freq, unsigned int dur); void play_nokia_tune(void); /* =================================================== */ /* ===== Implementation */ /* =================================================== */ void delay(volatile unsigned int d){ while(d--) __NOP(); } void lcd_delay(unsigned long r){ volatile unsigned long i; for(i=0;iFIOPIN = (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 c){ lcd_write_nibble(c>>4,0); lcd_write_nibble(c,0); } void lcd_data(unsigned char d){ lcd_write_nibble(d>>4,1); lcd_write_nibble(d,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 *s){ while(*s) lcd_data(*s++); } void lcd_print_num(int num, unsigned int base){ i=0; if(base==MODE_DEC && num<0){ lcd_data('-'); num=-num; } unum=(unsigned int)num; if(unum==0){ lcd_data('0'); return; } while(unum>0 && i<16){ d=unum%base; buf[i++]=(d<10)?('0'+d):('A'+d-10); unum/=base; } while(i>0) lcd_data(buf[--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_op_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 scanning ---- */ unsigned int scan_keypad(void){ 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<FIOSET=COL_MASK; return col*4+row; } } } LPC_GPIO0->FIOSET=COL_MASK; return 0xFF; } /* ---- MODE button ---- */ unsigned int scan_mode_button(void){ return ((LPC_GPIO2->FIOPIN&MODE_BUTTON)==0)?1:0; } 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; input_num=stored_num=result=0; operation=OP_NONE; result_displayed=0; display_mode(); display_input(); } /* ---- Double-press / mode handler ---- */ void handle_mode_button(void){ now=millis(); if(button_stable==3 && button_state==1){ if(current_base==MODE_HEX){ if((now-last_mode_press_time)<2000){ hex_op_mode=!hex_op_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 core ---- */ 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; } if(base!=MODE_DEC){ if(r<0) r=((r%base)+base)%base; else r%= (base*base*base*base); } return r; } /* ---- Operator control ---- */ 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; } unsigned char is_operator_active(unsigned int key){ if(key>=11 && key<=15){ if(current_base==MODE_HEX) return hex_op_mode; else return 1; } return 0; } /* ---- Beeper Functions ---- */ void beeper_init(void){ LPC_GPIO0->FIODIR |= BEEPER_PIN; LPC_GPIO0->FIOCLR = BEEPER_PIN; } void play_tone(unsigned int freq, unsigned int dur){ start_time = millis(); end_time = start_time + dur; if(freq == 0){ while(millis() < end_time){ __NOP(); } return; } half_period_us = 500000 / freq; while(millis() < end_time){ LPC_GPIO0->FIOSET = BEEPER_PIN; for(beep_i = 0; beep_i < half_period_us; beep_i++) __NOP(); LPC_GPIO0->FIOCLR = BEEPER_PIN; for(beep_i = 0; beep_i < half_period_us; beep_i++) __NOP(); } LPC_GPIO0->FIOCLR = BEEPER_PIN; } void play_nokia_tune(void){ while(1){ loop_idx = 0; while(nokia_tune[loop_idx].frequency != 0){ frequency_hz = nokia_tune[loop_idx].frequency; duration_ms = nokia_tune[loop_idx].duration; play_tone(frequency_hz, duration_ms); loop_idx++; } delay(100000); } } /* =================================================== */ /* ===================== 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_op_mode=0; last_mode_press_time=0; sys_millis=0; SystemCoreClockUpdate(); SysTick_Config(SystemCoreClock/1000); /* GPIO mux: make pins GPIO */ LPC_PINCON->PINSEL0=0; LPC_PINCON->PINSEL1=0; LPC_PINCON->PINSEL3=0; LPC_PINCON->PINSEL4=0; LPC_PINCON->PINSEL0 &= ~0xFFF00000; /* Directions */ LPC_GPIO0->FIODIR |= COL_MASK | LCD_DATA_MASK | LCD_RS | LCD_EN | BEEPER_PIN; LPC_GPIO0->FIODIR &= ~ROW_MASK; LPC_GPIO0->FIOSET = COL_MASK; LPC_GPIO2->FIODIR &= ~MODE_BUTTON; beeper_init(); lcd_init(); display_mode(); display_input(); play_nokia_tune(); while(1); return 0; }