Open the PIC user-interface to watch the program execution, setting breakpoints, etc. (I recommend to uncheck the 'update display' checkbox and to click the data and program memories to enforce repainting. This saves a lot of CPU cycles and makes the animation of the calculator go smoothly).
The keyboard is scanned by row and column. Press twice each key to send a number to LC Display. The maximum resolution is 2 digits.
The C source code has been written by Alex, Juliana, and Ricardo Ferreira, during the Computer Organization Undergraduate Course, Universidade Federal de Viçosa, Brazil.
This is the current source code in C compiled by using Picclite from Hitech.
// /usr/hitech/bin/picl -16f84 -C // -Zg henriquecalculator.c lcda0a1b4_7.c delay.c // /usr/hitech/bin/picl -16f84 -Ocalculator.hex // henriquecalculator.obj lcda0a1b4_7.obj delay.obj #includeRun the applet | Run the editor (via Webstart)#include "lcd.h" #include "delay.h" #define col0 RB4 #define col1 RB5 #define col2 RB6 #define col3 RB7 #define row0 RB3 #define row1 RB2 #define row2 RB1 #define row3 RB0 #define PRESSED 0 char index = 0, op = 0; char num = 0, result = 0; char estado[2]; char limpa; void SWITCH_LCD_ON() { TRISB = 0x00; } void SWITCH_LCD_OFF() { TRISB = 0xF0; } limpaLCD(){ SWITCH_LCD_ON(); lcd_clear(); SWITCH_LCD_OFF(); } void SendNumbertoLCD(char n) { char c; SWITCH_LCD_ON(); lcd_goto(index); c = (char)(n+48); lcd_putch(c); SWITCH_LCD_OFF(); ++index; } void showResult(){ num = result; limpa = 1; for (index = 8; index != 0; ){ SendNumbertoLCD((char)(num%10)); num = num/10; if (num==0) break; index-=2; } index = 0; } void resolveOp(){ switch(op){ case 5: break; case 1: result = result+num; break; case 2: result = result-num; break; case 3: result = result*num; break; case 4: result = result/num; break; default: result = num; break; } } void verificaEstado(char tecla) { switch(tecla){ case 1: if(limpa){ limpaLCD(); limpa = 0;} if( ! (estado[0] & 0x80) ) { SendNumbertoLCD(1); num = num*10 + 1; estado[0] |= 0x80; } break; case 2: if(limpa){ limpaLCD(); limpa = 0;} if( ! (estado[0] & 0x40) ) { SendNumbertoLCD(2); num = num*10 + 2; estado[0] |= 0x40; } break; case 3: if(limpa){ limpaLCD(); limpa = 0;} if( ! (estado[0] & 0x20) ) { SendNumbertoLCD(3); num = num*10 + 3; estado[0] |= 0x20; } break; case 4: if( ! (estado[0] & 0x10) ) { limpaLCD(); resolveOp(); showResult(); op = 1; num = 0; estado[0] |= 0x10; } break; case 5: if(limpa){ limpaLCD(); limpa = 0;} if( ! (estado[0] & 0x08) ) { SendNumbertoLCD(4); num = num*10 + 4; estado[0] |= 0x08; } break; case 6: if(limpa){ limpaLCD(); limpa = 0;} if( ! (estado[0] & 0x04) ) { SendNumbertoLCD(5); num = num*10 + 5; estado[0] |= 0x04; } break; case 7: if(limpa){ limpaLCD(); limpa = 0;} if( ! (estado[0] & 0x02) ) { SendNumbertoLCD(6); num = num*10 + 6; estado[0] |= 0x02; } break; case 8: if( ! (estado[0] & 0x01) ) { limpaLCD(); resolveOp(); showResult(); op = 2; num = 0; estado[0] |= 0x01; } break; case 9: if(limpa){ limpaLCD(); limpa = 0;} if( ! (estado[1] & 0x80) ) { SendNumbertoLCD(7); num = num*10 + 7; estado[1] |= 0x80; } break; case 10: if(limpa){ limpaLCD(); limpa = 0;} if( ! (estado[1] & 0x40) ) { SendNumbertoLCD(8); num = num*10 + 8; estado[1] |= 0x40; } break; case 11: if(limpa){ limpaLCD(); limpa = 0;} if( ! (estado[1] & 0x20) ) { SendNumbertoLCD(9); num = num*10 + 9; estado[1] |= 0x20; } break; case 12: if( ! (estado[1] & 0x10) ) { limpaLCD(); resolveOp(); showResult(); op = 3; num = 0; estado[1] |= 0x10; } break; case 13: if(limpa){ limpaLCD(); limpa = 0;} if( ! (estado[1] & 0x08) ) { SendNumbertoLCD(0); num = num*10 + 0; estado[1] |= 0x08; } break; case 14: if( ! (estado[1] & 0x04) ) { limpaLCD(); op = 0; result = 0; num = 0; estado[1] |= 0x04; } break; case 15: if( ! (estado[1] & 0x02) ) { limpaLCD(); resolveOp(); showResult(); op = 5; num = 0; estado[1] |= 0x02; } break; case 16: if( ! (estado[1] & 0x01) ) { limpaLCD(); resolveOp(); showResult(); op = 4; num = 0; estado[1] |= 0x01; } break; } return; } main(){ estado[0] = estado[1] = 0; TRISA = 0x00; // Output bits porta, xxxRE SWITCH_LCD_ON(); lcd_init(); //lcd_puts("Press 4 or 2="); SWITCH_LCD_OFF(); while(1){ //scan row0 row0 = 0; if(col3 == PRESSED) { verificaEstado(4); }else estado[0] &= 0xEF; if(col0 == PRESSED ) { verificaEstado(1); }else estado[0] &= 0x7F; if(col1 == PRESSED ) { verificaEstado(2); }else estado[0] &= 0xBF; if(col2 == PRESSED ) { verificaEstado(3); }else estado[0] &= 0xDF; row0 = 1; //scan row1 row1 = 0; if(col3 == PRESSED) { verificaEstado(8); }else estado[0] &= 0xFE; if(col0 == PRESSED ) { verificaEstado(5); }else estado[0] &= 0xF7; if(col1 == PRESSED ) { verificaEstado(6); }else estado[0] &= 0xFB; if(col2 == PRESSED ) { verificaEstado(7); }else estado[0] &= 0xFD; row1 = 1; //scan row2 row2 = 0; if(col3 == PRESSED) { verificaEstado(12); }else estado[1] &= 0xEF; if(col0 == PRESSED ) { verificaEstado(9); }else estado[1] &= 0x7F; if(col1 == PRESSED ) { verificaEstado(10); }else estado[1] &= 0xBF; if(col2 == PRESSED ) { verificaEstado(11); }else estado[1] &= 0xDF; row2 = 1; //scan row3 row3 = 0; if(col3 == PRESSED) { verificaEstado(16); }else estado[1] &= 0xFE; if(col0 == PRESSED ) { verificaEstado(13); }else estado[1] &= 0xF7; if(col1 == PRESSED ) { verificaEstado(14); }else estado[1] &= 0xFB; if(col2 == PRESSED ) { verificaEstado(15); }else estado[1] &= 0xFD; row3 = 1; } }