Tinkering With A Basic Calculator CloudX

  • img
Project Details

 

Let's learn how to design a simple calculator using a keypad and an LCD (Liquid Crystal Display). The circuit connection is very much a simple one; and we’ll be making use of the breadboard and a simple CloudX code to actualize the project.

Just punching away on my calculator the other day, it somewhat occurred to me it would definitely be a nice idea for us to learn the simple basics of a calculator design! With the skill, we can advance farther to design a more complicated one like the commercial ones out there in the market. 

In this lesson, we'll be implementing the calculator using a 4x4 Keypad and a 16x2 LCD. And to further simplify things, we'll be utilizing CloudX libraries specifically meant for ease of handling both the keypad and the LCD modules respectively. 

 

List Of Materials Needed 

(The material full kit can readily be sourced via this link.)

 CloudX Microcontroller and Softcard 

 16x2  LCD Display

 4x4 Keypad

  •  Resistor:
  1. (i)    1 kΩ
  2. (ii)   10 kΩ x 4 units

 


                 Section 1:  Hints and Brief Overview 


KeyPad
The keypad is a small keyboard that is used to input numeric, alphabetic or alphanumeric data into microcontroller systems. It is sometimes referred to as a Matrix Keypad due to how the push button switches, making up the architecture, are arranged in rows and columns. It is available in different shades and sizes ranging from a 2x2, a 4x3, a 4x4, and so on. 
Here, we’re making use of a 4x4 matrix keypad as shown below. 

 

It has the internal architecture as thus depicted below. 

 

Liquid Crystal Display (LCD)  
The LCD is used to display  alphanumeric  or  graphical  data. Here, we’re using a variant called 16x2 LCD module. That simply implies 16 columns and 2 rows of display capability.  

LCD Module

 

It has the pin-out as follows: 

 

 

                        Section 2: The Circuit and the Code

 

The Circuit

The whole project runs on the simple block diagram as follows:

Block Diagram

 

Just as demonstrated in the schematic diagram below:

The LCD module, being basically used in a 4-bit communication mode, interfaces with the MCU (microcontroller) such that its pins RS, EN, D4, D5, D6 and D7 connect up to the MCU’s pins P1, P2, P3, P4, P5 and P6 respectively.

1kΩ resistor is connected to the LCD Vo pin through to ground to set the display contrast. (However, one is at liberty to experiment with say a 10kΩ variable resistor to adjust the contrast to one’s more desired point).

 

Wiring

 

Schematic

Then, the matrix keypad does the interfacing with the Rows 1, 2, 3 and 4 connecting up to the MCU’s pins P7, P8, P9 and P10 respectively; whereas its Columns 1, 2, 3 and 4 connect up to MCU’s pins P11, P12, P13 and P14 respectively. 

The matrix keypad internal structure and microcontroller interfacing is illustrated as thus:

Row and Column Connection

The microcontroller module, being at the heart of the working here, can be powered on: 
(i)  either via the VIN and the GND points (ie. connecting them up to your external power-supply-unit’s  +ve and –ve terminals respectively) on the board. (The PSU can  range from  7 – 12 VDC);  
(ii)  or through your CloudX USB softcard module.

 

Refer to the table below to check out the details of the rest of other necessary connections.

Connection Table1
Connection Table2


 

 The Source Code

The code is written in simple and plain C language as follows:


#include <CloudX\LCD.h>
#include <CloudX\Keypad.h>
#include <CloudX\conversion.h>
#include <string.h>
#include <math.h>

#define noIndicator 0
#define error 10


//-------------------------------------------
//The below declare and define parameters for
//the keypad module configuration.
//-------------------------------------------
#define NumberOfRows 4 //sets keypad to four rows
#define NumberOfColumns 4 //sets keypad to three columns
char KeypadCharacters[NumberOfRows][NumberOfColumns] =
{
'1', '2', '3', '-',
'4', '5', '6', 'x',
'7', '8', '9', '/',
'C', '0', '=', '+'
};

char RowPins[NumberOfRows] = {7, 8, 9, 10};
char ColumnsPins[NumberOfColumns] = {11, 12, 13, 14};



char keys; //keys char for keeping record of pressed key
char _operator; //Function to be performed among two operands (numbers)
char number;
char _text[9];
char *text0;
byte operand1 = 0; //first number
byte operand2 = 0; //second number


//-------------------------------------------------------
//The below declare and define the custom-char arrays for
//both a division-symbol and an infinity-symbol.
//NB:
//Refer to CloudX Custom-Char Generator App to create any
//desired custom character for the LCD.
//-------------------------------------------------------
const char divisionSign[] = {0, 4, 0, 31, 0, 4, 0, 0};
const char infinitySign[] = {0, 10, 21, 21, 10, 0, 0, 0};



/*** RELEVANT FUNCTIONS USED FOR PROJECT ***/
void displayResult(int value); //displays the evaluation result
void displayFloatRes(float value); //displays evaluation result that is
//of float data-type

void mathOperation(unsigned char pointer); //handles the maths/arithmetic operation
void errorMessage(byte caseValue); //displays different error messages
byte getOperand(char charValue); //fetches the operands
char getOperator(char checkOperator); //detects the operator errors
void Get_keyPressed(); //scans and fetches any possible key-press



setup(){
//setup here

//The keypad-module configured utilizing the already declared parameters above//
Keypad_setting (PULLDOWNCOL, RowPins, ColumnsPins, NumberOfRows, NumberOfColumns, KeypadCharacters, noIndicator);

LCD_setting(1, 2, 3, 4, 5, 6); //RS, EN, D4, D5, D6, D7
LCD_cmd(cursorOff);
LCD_cmd(clear);
LCD_writeText(1, 4, "Calculator");
LCD_writeText(2, 3, "With CloudX");
delayMs(1500);
LCD_cmd(clear);
LCD_write(1, 1, '0');



loop(){
//Program here

//---------------------------------------------
//This routine fetches the first operand (num1)
//---------------------------------------------
Get_keyPressed();
LCD_cmd(clear); //clears LCD screen
LCD_write(1, 1, keys); //echoes the key pressed to LCD
operand1 = getOperand(keys); //gets int number from char value, it checks for wrong input as well
if(operand1 isNot error) //if correct input then proceed, num1==Error means wrong input
{

//----------------------------------------
//This routine gets the operator function
//----------------------------------------
Get_keyPressed();
if((keys is '+') or (keys is '-') or (keys is 'x') or (keys is '/'))
{
if(keys is '/')
LCD_writeCustomChar(0, 1, 3, divisionSign); //CGRAMAddress, row, col, customCharacter
else
LCD_write(1, 3, keys);
_operator = getOperator(keys);
}
else
{
LCD_writeCP(keys);
number = getOperand(keys);
if(number isNot error)
{
operand1 = (operand1*10) + number;
Get_keyPressed();
if(keys is '/')
LCD_writeCustomChar(0, 1, 4, divisionSign); //CGRAMAddress, row, col, customCharacter
else
LCD_write(1, 4, keys);

_operator = getOperator(keys);
}
else
_operator = getOperator(keys); //checks for wrong operator
}
if(_operator isNot error)
{
//-----------------------------------------------
//This routine fetches the second operand (num2)
//-----------------------------------------------
Get_keyPressed();
LCD_writeCP(' ');
LCD_writeCP(keys); //echoes the key pressed on LCD
operand2 = getOperand(keys); //Get int number from char value, it checks for wrong input as well
if(operand2 isNot error)
{
//----------------------------------------
//This routine fetches the equal-sign (=)
//----------------------------------------
Get_keyPressed();
if(keys is '=')
mathOperation(_operator);
else
{
LCD_writeCP(keys); //echoes the key pressed on LCD
number = getOperand(keys);
if(number isNot error)
{
operand2 = (operand2 * 10) + number;
Get_keyPressed();
if(keys is '=')
mathOperation(_operator);
}
else if(keys is '=') //if = is pressed, then proceed
mathOperation(_operator);

else if(keys is 'C') //if clear screen is pressed, then clear screen and reset
{
LCD_cmd(clear);
LCD_write(1, 1, '0');
}
else
errorMessage(0); //displays wrong input error
}
}
}
}
}
}


//////////////////////////////////////////////////////////////////
///////// The Relevant Function-Definitions //////////
//////////////////////////////////////////////////////////////////

void displayResult(int value)
{
intTostr(_text, value, DEC);
LCD_writeText(2, 1, "ANS: ");
LCD_writeTextCP(_text);
}

void displayFloatRes(float value)
{
text0 = floatTostr(value);
text0[8] = 0;
LCD_writeText(2, 1, "ANS: ");
LCD_writeTextCP(text0);
}

void mathOperation(unsigned char pointer)
{
switch(pointer) {
case '+' : displayResult(operand1 + operand2); break;
case '-' : displayResult(operand1 - operand2); break;
case 'x' : displayResult(operand1 * operand2); break;
case '/' : if(operand2 is 0) {
LCD_writeText(2, 1, "ANS: ");
LCD_writeCustomChar(1, 2, 6, infinitySign); //CGRAMAddress, row, col, customCharacter
LCD_writeText(2, 7, "infinity");
break;
}
else
{
displayFloatRes((float)operand1 / operand2);
break;
}
}
}

byte getOperand(char charValue)
{
byte operand;
switch(charValue)
{
case '0' : operand = 0; break;
case '1' : operand = 1; break;
case '2' : operand = 2; break;
case '3' : operand = 3; break;
case '4' : operand = 4; break;
case '5' : operand = 5; break;
case '6' : operand = 6; break;
case '7' : operand = 7; break;
case '8' : operand = 8; break;
case '9' : operand = 9; break;

//---------------------------------------
//This clears the screen and sets error;
//and resets the system.
//---------------------------------------
case 'C' : LCD_cmd(clear);
LCD_write(1, 1, '0');
operand = error;
break;

//-------------------------
//This signals wrong input.
//-------------------------
default : errorMessage(0);
operand = error;
break;
}
return operand;
}

char getOperator(char checkOperator) //detects the operator errors
{
if(checkOperator is 'C') //if clear-screen, then clear display and reset
{
LCD_cmd(clear); //clears display
LCD_write(1, 1, '0');
return error;
}
if((checkOperator isNot '+') and (checkOperator isNot '-') and (checkOperator isNot 'x') and (checkOperator isNot '/')) //if input is out of the allowable range, display error
{
errorMessage(1);
return error;
}
return checkOperator;
}

void errorMessage(byte caseValue) //displays different error messages
{
LCD_cmd(clear);
switch(caseValue)
{
case 0 : LCD_writeText(1, 1, "Wrong Input");
delayMs(500);
LCD_cmd(clear);
LCD_write(1, 1, '0');
break;

case 1 : LCD_writeText(1, 1, "Wrong Operator");
delayMs(500);
LCD_cmd(clear);
LCD_write(1, 1, '0');
break;

default : LCD_writeText(1, 1, "Wrong Input");
delayMs(500);
LCD_cmd(clear);
LCD_write(1, 1, '0');
break;
}
}

void Get_keyPressed()
{
do
keys = Keypad_getKey();
while(keys is 0);
}
 

 

Simulation

 

 That comes to an end the project. 

Share this with friends