PIC16F84 calculator
Circuit Description
This applet demonstrates a
PIC16-based controller for simple calculator.
The circuit consists of the microcontroller,
a standard ASCII-mode liquid-crystal display,
and a multiplexed keyboard.
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
#include
#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;
}
}
|