In this blog post, we learn how to build calculator using PIC Microcontroller. Calculator with PIC Microcontroller(16f877A ) is a complicated project. Complicated in the way that code is lengthy and logical.
Here I assumed you already know how to interface LCD and Keypad with PIC Microcontroller. But if you don’t know how to interface LCD and Keypad, it is my request first read below-mentioned articles,
- How to interface 16×2 LCD in 4-bit mode with PIC Microcontroller.
- How to interface keypad with PIC Microcontroller.
I will try to explain here how you can make a calculator using the PIC Microcontroller with the help of LCD and keypad. This calculator performs a mathematical operation on a single digit (You can give any single digit input from 0 to 9)
The mathematical operation perform in switch case as per the operators like for addition(+), subtraction(-), multiplication(x) and division(/) case will execute. The below code has been written for PIC16F877A using the C language and MPLAB with the HI-TECH C compiler.
Features of this PIC Microcontroller based Calculator:
- You can give any single digit input from 0 to 9.
- You can press the ‘ON/C’ button at any time to reset the calculator.
- In the PIC calculator project, mathematical operation perform in switch case as per the operators.
- An error message is displayed if the wrong input is detected. For example, if the calculator is expecting a number, but a function key is pressed then the ‘Wrong Input’ message is displayed.
- Similarly, the ‘Wrong Function’ message is displayed if the wrong key is pressed instead of a function key.
Working of PIC Microcontroller:
As you see the below image, for mathematical operation, first you need to enter the single-digit number then valid operators and in the last another single-digit number. The PIC Microcontroller will perform the mathematical operation as per the operator on the entered operands. The result will reflect on the LCD. If you will enter anything besides the mentioned steps you will get the warning message.
LCD and Keypad interfacing with PIC Microcontroller for Calculator:
In the PIC calculator project, LCD and keypad are used as output and input devices. Whenever the user performs mathematical operation with the help of keypad then the result will be displayed on LCD.
In this project pins RD0, RD1, and RD4 to RD7 are used for LCD interfacing with PIC Microcontroller. Also, PORTB is used for keypad interfacing with PIC Microcontroller. The 4 pins of PORTB are used to attach columns and 4 remaining pins of PORTB are used to attach rows of a keypad.
In the code, I am writing a scanning algorithm code that is used to check for any pressed key.
/* Name : main.c * Purpose : Main file for make calculator using keypad and PIC16F877. * Author : Amlendra Kumar * Website : https://aticleworld.com */ #include<htc.h> // Configuration word for PIC16F877A __CONFIG( FOSC_HS & WDTE_OFF & PWRTE_ON & CP_OFF & BOREN_ON & LVP_OFF & CPD_OFF & WRT_OFF & DEBUG_OFF); // Define CPU Frequency // This must be defined, if __delay_ms() or // __delay_us() functions are used in the code #define _XTAL_FREQ 20000000 // Define Pins for LCD #define LCD_E RD0 // Enable pin for LCD #define LCD_RS RD1 // RS pin for LCD #define LCD_Data_Bus_D4 RD4 // Data bus bit 4 #define LCD_Data_Bus_D5 RD5 // Data bus bit 5 #define LCD_Data_Bus_D6 RD6 // Data bus bit 6 #define LCD_Data_Bus_D7 RD7 // Data bus bit 7 // Define Pins direction registrers #define LCD_E_Dir TRISD0 #define LCD_RS_Dir TRISD1 #define LCD_Data_Bus_Dir_D4 TRISD4 #define LCD_Data_Bus_Dir_D5 TRISD5 #define LCD_Data_Bus_Dir_D6 TRISD6 #define LCD_Data_Bus_Dir_D7 TRISD7 // Define which port is being used for data bus #define LCD_PORT PORTD // Constants #define E_Delay 500 // Define pins for keypad #define RowA RB0 #define RowB RB1 #define RowC RB2 #define RowD RB3 #define C1 RB4 #define C2 RB5 #define C3 RB6 #define C4 RB7 #define Keypad_PORT PORTB #define Keypad_PORT_Dir TRISB // Function Declarations for LCD void WriteCommandToLCD(unsigned char); void WriteDataToLCD(char); void InitLCD(void); void WriteStringToLCD(const char*); void ClearLCDScreen(void); // Function declarations for keypad void InitKeypad(void); char GetKey(void); // define Error (to be used inside calculator functions) #define Error 13 // Some function declarations int get_num(char); char get_func(char); void DispError(int); void disp_num(int); int main(void) { char key; // Key char for keeping record of pressed key int num1 = 0; // First number char func = '+'; // Function to be performed among two numbers int num2 = 0; // Second number InitKeypad(); // Initialize Keypad InitLCD(); // Initialize LCD while(1) { //get numb1 key = GetKey(); ClearLCDScreen(); // Clear LCD screen WriteDataToLCD(key); // Echo the key pressed to LCD num1 = get_num(key); // Get int number from char value, it checks for wrong input as well if(num1!=Error) // If correct input then proceed, num1==Error means wrong input { //get function key = GetKey(); WriteDataToLCD(key); //Echo the key pressed to LCD func = get_func(key); //it checks for wrong func if(func!='e') //if correct input then proceed, func=='e' means wrong input { //get numb2 key = GetKey(); WriteDataToLCD(key); //Echo the key pressed to LCD num2 = get_num(key); //Get int number from char value, it checks for wrong input as well if(num2!=Error) //if correct input then proceed, num2==Error means wrong input { //get equal sign key = GetKey(); WriteDataToLCD(key); //Echo the key pressed to LCD if(key == '=') //if = is pressed then proceed { switch(func) //switch on function { case '+': disp_num(num1+num2); break; case '-': disp_num(num1-num2); break; case 'x': disp_num(num1*num2); break; case '/': disp_num(num1/num2); break; } } else //key other then = here means error wrong input { if(key == 'C') //if clear screen is pressed then clear screen and reset ClearLCDScreen(); // Clear LCD screen else DispError(0); //Display wrong input error } } } } } return 0; } // Function name: InitKeypad void InitKeypad(void) { Keypad_PORT = 0x00; // Set Keypad port pin values zero Keypad_PORT_Dir = 0xF0; // Last 4 pins input, First 4 pins output // Enable weak internal pull up on input pins OPTION_REG &= 0x7F; } // Scan all the keypad keys to detect any pressed key. char READ_SWITCHES(void) { RowA = 0; RowB = 1; RowC = 1; RowD = 1; //Test Row A if (C1 == 0) { __delay_ms(250); while (C1==0); return '7'; } if (C2 == 0) { __delay_ms(250); while (C2==0); return '8'; } if (C3 == 0) { __delay_ms(250); while (C3==0); return '9'; } if (C4 == 0) { __delay_ms(250); while (C4==0); return '/'; } RowA = 1; RowB = 0; RowC = 1; RowD = 1; //Test Row B if (C1 == 0) { __delay_ms(250); while (C1==0); return '4'; } if (C2 == 0) { __delay_ms(250); while (C2==0); return '5'; } if (C3 == 0) { __delay_ms(250); while (C3==0); return '6'; } if (C4 == 0) { __delay_ms(250); while (C4==0); return 'x'; } RowA = 1; RowB = 1; RowC = 0; RowD = 1; //Test Row C if (C1 == 0) { __delay_ms(250); while (C1==0); return '1'; } if (C2 == 0) { __delay_ms(250); while (C2==0); return '2'; } if (C3 == 0) { __delay_ms(250); while (C3==0); return '3'; } if (C4 == 0) { __delay_ms(250); while (C4==0); return '-'; } RowA = 1; RowB = 1; RowC = 1; RowD = 0; //Test Row D if (C1 == 0) { __delay_ms(250); while (C1==0); return 'C'; } if (C2 == 0) { __delay_ms(250); while (C2==0); return '0'; } if (C3 == 0) { __delay_ms(250); while (C3==0); return '='; } if (C4 == 0) { __delay_ms(250); while (C4==0); return '+'; } return 'n'; // Means no key has been pressed } // Function name: GetKey // Read pressed key value from keypad and return its value char GetKey(void) // Get key from user { char key = 'n'; // Assume no key pressed while(key=='n') // Wait untill a key is pressed key = READ_SWITCHES(); // Scan the keys again and again return key; //when key pressed then return its value } void ToggleEpinOfLCD(void) { LCD_E = 1; // Give a pulse on E pin __delay_us(E_Delay); // so that LCD can latch the LCD_E = 0; // data from data bus __delay_us(E_Delay); } void WriteCommandToLCD(unsigned char Command) { LCD_RS = 0; // It is a command LCD_PORT &= 0x0F; // Make Data pins zero LCD_PORT |= (Command&0xF0); // Write Upper nibble of data ToggleEpinOfLCD(); // Give pulse on E pin LCD_PORT &= 0x0F; // Make Data pins zero LCD_PORT |= ((Command<<4)&0xF0); // Write Lower nibble of data ToggleEpinOfLCD(); // Give pulse on E pin } void WriteDataToLCD(char LCDChar) { LCD_RS = 1; // It is data LCD_PORT &= 0x0F; // Make Data pins zero LCD_PORT |= (LCDChar&0xF0); // Write Upper nibble of data ToggleEpinOfLCD(); // Give pulse on E pin LCD_PORT &= 0x0F; // Make Data pins zero LCD_PORT |= ((LCDChar<<4)&0xF0); // Write Lower nibble of data ToggleEpinOfLCD(); // Give pulse on E pin } void InitLCD(void) { // Firstly make all pins output LCD_E = 0; // E = 0 LCD_RS = 0; // RS = 0 LCD_Data_Bus_D4 = 0; // Data bus = 0 LCD_Data_Bus_D5 = 0; // Data bus = 0 LCD_Data_Bus_D6 = 0; // Data bus = 0 LCD_Data_Bus_D7 = 0; // Data bus = 0 LCD_E_Dir = 0; // Make Output LCD_RS_Dir = 0; // Make Output LCD_Data_Bus_Dir_D4 = 0; // Make Output LCD_Data_Bus_Dir_D5 = 0; // Make Output LCD_Data_Bus_Dir_D6 = 0; // Make Output LCD_Data_Bus_Dir_D7 = 0; // Make Output ///////////////// Reset process from datasheet ////////////// __delay_ms(40); LCD_PORT &= 0x0F; // Make Data pins zero LCD_PORT |= 0x30; // Write 0x3 value on data bus ToggleEpinOfLCD(); // Give pulse on E pin __delay_ms(6); LCD_PORT &= 0x0F; // Make Data pins zero LCD_PORT |= 0x30; // Write 0x3 value on data bus ToggleEpinOfLCD(); // Give pulse on E pin __delay_us(300); LCD_PORT &= 0x0F; // Make Data pins zero LCD_PORT |= 0x30; // Write 0x3 value on data bus ToggleEpinOfLCD(); // Give pulse on E pin __delay_ms(2); LCD_PORT &= 0x0F; // Make Data pins zero LCD_PORT |= 0x20; // Write 0x2 value on data bus ToggleEpinOfLCD(); // Give pulse on E pin __delay_ms(2); /////////////// Reset Process End //////////////// WriteCommandToLCD(0x28); //function set WriteCommandToLCD(0x0c); //display on,cursor off,blink off WriteCommandToLCD(0x01); //clear display WriteCommandToLCD(0x06); //entry mode, set increment } void WriteStringToLCD(const char *s) { while(*s) WriteDataToLCD(*s++); // print first character on LCD } void ClearLCDScreen(void) // Clear the Screen and return cursor to zero position { WriteCommandToLCD(0x01); // Clear the screen __delay_ms(2); // Delay for cursor to return at zero position } /* * Functions used inside main for * making calculator are shown below */ int get_num(char ch) //convert char into int { int num = 0; switch(ch) { case '0': num = 0; break; case '1': num = 1; break; case '2': num = 2; break; case '3': num = 3; break; case '4': num = 4; break; case '5': num = 5; break; case '6': num = 6; break; case '7': num = 7; break; case '8': num = 8; break; case '9': num = 9; break; case 'C': ClearLCDScreen(); num = Error; break; //this is used as a clear screen and then reset by setting error default: DispError(0); num = Error; break; //it means wrong input } return num; } char get_func(char chf) //detects the errors in inputted function { if(chf=='C') //if clear screen then clear the LCD and reset { ClearLCDScreen(); //clear display return 'e'; } if( chf!='+' && chf!='-' && chf!='x' && chf!='/' ) //if input is not from allowed funtions then show error { DispError(1); return 'e'; } return chf; //function is correct so return the correct function } void DispError(int numb) //displays differet error messages { ClearLCDScreen(); //clear display switch(numb) { case 0: WriteStringToLCD("Wrong Input"); break; case 1: WriteStringToLCD("Wrong Function"); break; default: WriteStringToLCD("Wrong Input"); break; } } void disp_num(int numb) //displays number on LCD { unsigned char UnitDigit = 0; //It will contain unit digit of numb unsigned char TenthDigit = 0; //It will contain 10th position digit of numb if(numb<0) { numb = -1*numb; // Make number positive WriteDataToLCD('-'); // Display a negative sign on LCD } TenthDigit = (numb/10); // Find out Tenth Digit if( TenthDigit != 0) // If it is zero, then don't display WriteDataToLCD(TenthDigit+0x30); // Make Char of TenthDigit and then display it on LCD UnitDigit = numb - TenthDigit*10; WriteDataToLCD(UnitDigit+0x30); // Make Char of UnitDigit and then display it on LCD }
Proteus Simulation of calculator using Pic microcontroller:
Recommended Post:
- How to interface keypad with PIC Microcontroller.
- 16*2 LCD Interfacing with PIC Microcontroller in 4-bit Mode.
- 16*2 LCD Interfacing with PIC Microcontroller in 8-bit Mode.
- Push-button interfacing with PIC microcontroller.
- LED Interfacing with PIC Microcontroller.
- Read and Write to Internal EEPROM of PIC Microcontroller.
- Interfacing EEPROM with PIC Microcontroller – I2C Based.
- Interfacing RTC DS1307 with PIC Microcontroller.
- Display Custom Characters on LCD using PIC Microcontroller.
- Led blinking program in c for 8051.
- Interfacing of switch and led using the 8051
- Interfacing of Relay with 8051 microcontroller
- Moving message display on LCD using 8051
- LCD 4-bit mode c code for 8051.
- Create LCD custom characters for 16×2 alphanumeric LCD
- Interfacing of keypad with 8051
- Electronic digital lock using the 8051
- Interfacing of EEPROM with 8051 microcontrollers using I2C
- Embedded c interview questions.
- 8051 Microcontroller Pin Diagram and Pin Description.
- Can protocol interview questions.
- 8051 Architecture.