# 4-bit BCD calculator based on MCS-51

A four digit BCD code calculator is designed based on AT89S52 single chip microcomputer. The specific functions are as follows:

• Realize the addition, subtraction, multiplication and division of 1 ~ 4-bit BCD code and integer operation
• Keys 0-9 represent numbers 0-9, respectively. A is the plus sign, B is the minus sign, C is the multiplication sign, D is the division sign, E is the equal sign, and F is the high and low switching key
• Use: first input a number within four digits (the number is displayed in the high four digits of the LED display tube), click the operator, enter the next number, click the equal sign to display the result. When the result is displayed, the low order is displayed by default, and click the high and low switch key to view the high and low order (the last two digits of the display tube are HH in the high order, and LL in the low order).
• In subtraction, the high bit is sign bit, the high bit of negative number is 1, and the high bit of positive number is 0; In the division method, the high order shows the quotient, and the low order shows the remainder
• ERROR reporting: if there are more than four digits of input data, an ERROR will be reported. If there is no input data, an ERROR will be reported using the operator. If the division divisor is 0, an ERROR will be reported, and the ERROR reporting LED will display "ERROR"

### Main hardware equipment and functions

AT89S52 single chip microcomputer (with simulation interface): it mainly controls, calculates and stores data.
8155 experimental module: as an external extended data memory, the signal input by the matrix keyboard is sent to the single chip microcomputer, and the signal is sent to the nixie tube display after being calculated by the single chip microcomputer.
4 * 6 matrix keyboard: convert input data into electrical signals
Six digit dynamic nixie tube display module: convert the digital signal output of single chip microcomputer into led visual data

### Hardware circuit design

#### Six digit dynamic digital display tube module

In the nixie tube display circuit, the dial switch of 8155 and the nixie tube display circuit is set to the "ON" position, the nixie tube code end and the common end are connected with 8155PA and Pb ports, the PA port is the bit scanning port, which controls which nixie tube is lit, and the PB port is the font code port, which controls the specific font displayed by the selected nixie tube, as shown in the figure.

#### 4 * 6 matrix keyboard

In the keyboard scanning circuit, 8155 and the dial switch of the keyboard scanning circuit are set to the "ON" position, PC0-3 port is row scanning, PA port is column scanning, and the key number is obtained through user-defined coding, as shown in the figure.

#### Connecting circuit between 8155 module and AT89S52 single chip microcomputer

8155 module is an extended parallel interface circuit,
It has two 8-bit and one 6-bit I/O ports, 256 byte RAM and A 14 bit counter. In this circuit, the contents of port A, port B output, port C input and 8155 command register are 43H.
The interface circuit with the single chip microcomputer is shown in Figure 3-3. Port P0 of the single chip microcomputer is connected with 8155AD, port P2 is connected with 8155AD through latch, and the single chip microcomputer read-write line is connected with 8155 read-write line respectively (connected inside the test box).

### Programming principle

#### Main program design

At the beginning of the program, after initializing 8155, initialize the nixie tube to display six bits 0000 00, the high four bits are the data display bits, and the low two bits are the function display bits.
First, input the first data as the operand, process the data, store it in RAM and shift it to the left on the nixie tube. If illegal data is input, that is, the first input number is not a value of 0 ~ 9 or the number of input digits is greater than 4, call the error display subroutine to return to the initial state. When it is detected that the input data is an operator, i.e. addition, subtraction, multiplication and division, enter their respective subroutines, clear the contents of the display decoder, re scan the keyboard, wait for the input of the second operand, judge whether it is legal (if it is in the division operation, it is illegal when the operand is 0), shift left, display and store. If the detection input is equal sign, the second operand is stored in RAM and calculated by CPU.
After the CPU calculates the result, it outputs the processed signal to the nixie tube for display. At this time, the lower four digits of the calculation result are displayed first. You can control the display of high and low digits through the set keys, or you can end the calculation and return to the initial state through other keys. At this time, the function bit will display the high and low flags "HH" and "LL"

#### Type judgment subroutine

The principle of matrix keyboard to judge whether to type is: first, make the PA port of I/O pin connected by 8 column lines output low level, and the PC of I/O pin connected by 4 row lines output high level. When no key is pressed, all the I/O pins connected to the four lines will read high level; When a key is pressed, because the row line where the key is located is connected with the column line, the row line will be pulled down to the low level. At this time, the pins connected to the reading line will no longer be high level, so it can be judged that a key is pressed. Set the judgment flag a as the judgment of whether to type or not. If yes, set it to 0 to facilitate jumping out of the loop of while (a) (whether to type or not).

#### Keyboard input subroutine

This matrix keyboard module is a non coding keyboard, which can code each key by itself. In actual use, the keyboard used is only 4 * 4, that is, only the keyboard controlled by PC0 and PC1 ports is used. Therefore, PC0 is defined as the first line, PC1 is defined as the second line, the key code of PA port control corresponding to the first line is 0-7, and the second line is 8-15. Create an array and arrange the key actual values according to the code. When calculating the actual value, you only need to call this array to store the actual value corresponding to the key in the display cache.

#### Nixie tube display subroutine

The characteristic of dynamic display nixie tube is that only one nixie tube is lit every moment, and everyone is lit in turn. Therefore, as long as each nixie tube is not fully lit and the LED continues to light for a period of time, a stable output can be observed at appropriate intervals by using the afterglow and human eye dwell effect. In the nixie tube display module, 8155PA port is used for nixie tube selection, and PB port outputs display code for data display.
This subroutine saves the real data input by the keyboard in the array of display cache. Each time it is displayed, it only needs to call the number in the display cache, convert the corresponding real number look-up table into display code and output, so as to complete the display of one digit nixie tube.
Through the nixie tube selection cycle of PA port, this subroutine can complete the dynamic display of nixie tube. After each nixie tube is displayed, first delay to generate afterglow and dwell, and then select the next nixie tube to the left, it is necessary to clear the output of PB port, that is, when 0xff is output, all the LEDs on the nixie tube are off. In this way, the next nixie tube will not display the value of the previous nixie tube (because PB also selects the next nixie tube when outputting), so as to prevent the dynamic displayed data from generating visual garb led code.
The display subroutine of dynamic nixie tube needs to run in the cycle, otherwise it will flash.

#### Data processing and calculation subroutine

Because the real value of the data input by the keyboard is saved in the display cache, when processing the input data, you only need to weight each bit to obtain the real decimal 4 digits. Assuming that the input numbers are a, B, C and D, the obtained operand / operand is 1000a+100b+10c+d.
The calculated results are divided into high and low bits, all of which are 4-digit decimal numbers, and the processing methods are the same for high and low bits. Assuming that the four digits are abcd (decimal), it needs to be processed and decomposed into four one digit decimal numbers, which are stored in the display cache for nixie tube display. Then: a=abcd/1000;
b=abcd%1000/100;
c=abcd%1000%100/10;
d=abcd%1000%100%10.
The matrix keyboard uses 44 = 16 keys, and the keys A, B, C and D of the keyboard correspond to the keys to enter addition, subtraction, multiplication and division respectively. After inputting the 4-bit operand, determine which calculation subroutine or illegal input is entered by storing the real value of the key in the display cache (A, B, C and D correspond to the real values 10, 11, 12 and 13 respectively).
In the post-processing high and low order, the high order in the subtraction is the sign bit, the negative number is 0001, the positive number is 0000, and the low order is the absolute value of the result; In division, the high order is quotient and the low order is remainder. When the divisor is 0, an error is reported.

#### Error display subroutine

When the input data is illegal (input non decimal number; input data is greater than 4 digits) or the divisor is equal to 0, an ERROR will be reported and the ERROR display subroutine will be called. Because of the display limitation of the nixie tube, "ERROR" is displayed as "EAAOA", that is, the value of the corresponding bit in the display cache is directly modified to the corresponding real value, which is displayed through the nixie tube display subroutine. It is displayed in the high five digit nixie tube.
Set the error flag error, which is used to call the subroutine in the main program to determine whether it is wrong or not, and then return to the beginning of the main program for a new operation. In the loop, the digital tube shows the subroutine to display "EAAOA". When the key is entered, it will jump out of the loop and end the subroutine.

#### Result high and low display subroutine

The calculation subroutine divides the calculation results into high and low positions and stores them respectively. Both high and low bits are numbers composed of 4-bit BCD codes. Results the high and low subroutines initially display the low four digit results by default. You can select to display the low and high digit results by pressing E on the keyboard. The upper four digits of the six digit nixie tube display the calculation results, and the lower two digits are auxiliary judgment bits. When it displays low, it is "LL" and high, it is "HH". The true value of "L" stored in the display cache is 15 and "H" is 16.
When other keys except E are pressed, end the subroutine, end the calculation, return to the beginning of the main program and prepare for a new calculation.

### Program list

```#include<reg51.h>
#include<absacc.h>
#include<intrins.h>
#define com8155 XBYTE[0xff20]//8155 control word register
#define pa8155 XBYTE[0xff21]//8155a port
#define pb8155 XBYTE[0xff22]//8155b port
#define pc8155 XBYTE[0xff23]//8155c port
#define uchar unsigned char
#define uint unsigned int
unsigned char ledcode[]={
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,
0x77,0x7c,0x39,0x5e,0x79,0x76,0x38,0x00};
//The first line is 0-9, and the second line is a,b,c,d,e,h,l, empty display
unsigned int ledbuff[6]={0,0,0,0,0,0};//Show cache, save real value
unsigned int key_code[]={7,4,8,5,9,6,10,11,1,0,2,15,3,14,12,13};
//Call the transform array to get the real value
code unsigned char stop[3] _at_ 0x3b;
int a;//Judge the input flag. There is a key input when a=0
int kk=1;//High and low display flag bit
int tempbuff;//Cache typed operators
long int datas[5]={0,0,0,0,0};
//Data cache, data[3]: high data[4]: low data
int i,count,error;//Flag bit
int keycode;//Key code
void displayled(void);//Nixie tube display subroutine
void keyscan(void);//Keyboard scanning subroutine
void ifkeyin(void);Determine whether to input subroutine
void ledbuffclear(void);//Clearing subroutine
void errordisplay(void);//Error display subroutine
void bcd_sub(void);
void bcd_mul(void);
void bcd_div(void);//The calculation subroutines are A plus, B minus, C multiplication and D division
void showlowbit(void);//Display low order subroutine
void showhighbit(void);//Result display subroutine

//Delay Functions
void delay(int xms){
int x,y;
for(x=xms;x>0;x--)
for(y=110;y>0;y--);
}
//Main function
void main(){com8155=0x43;
loop:  error=0;
count=0;
ledbuffclear();
delay(50);//initialization
while(1){
keyscan();
if(ledbuff[2]>9){
if(ledbuff[2]<15){
tempbuff=ledbuff[2];
ledbuff[2]=ledbuff[3];
ledbuff[3]=ledbuff[4];
ledbuff[4]=ledbuff[5];
count=count-1;
while(count<4){
ledbuff[count+2]=0;
count++;
}
break;/* */
}
errordisplay();
goto loop;}
//if(count==4)break;
}
count=0;
calc:	datas[0]=1000*ledbuff[5]+100*ledbuff[4]+10*ledbuff[3]+ledbuff[2];//Input data processing
//get data and clear the buff;the operand is data[1].
//	keyscan();
count=0;
switch(tempbuff){
case 11:bcd_sub();break;
case 12:bcd_mul();break;
case 13:bcd_div();break;
default:{errordisplay();goto loop;}}
if(error==1)
goto loop;//Error flag bit judgment

showlowbit();//The lower four digits are displayed by default
while(1){

keyscan();
if(ledbuff[2]==15)
{kk=-kk;
if(kk==1)showlowbit();
else  showhighbit();
}
else goto loop;

}//Result high and low display subroutine
}

//Nixie tube display subroutine
void displayled(){
int temp ;
int j;
temp=0x01;
j=0;
for(i=0;i<6;i++)
{
temp=~temp;
pa8155=temp;
switch(ledbuff[j])
{
case 0:pb8155=~ledcode[0];break;
case 1:pb8155=~ledcode[1];break;
case 2:pb8155=~ledcode[2];break;
case 3:pb8155=~ledcode[3];break;
case 4:pb8155=~ledcode[4];break;
case 5:pb8155=~ledcode[5];break;
case 6:pb8155=~ledcode[6];break;
case 7:pb8155=~ledcode[7];break;
case 8:pb8155=~ledcode[8];break;
case 9:pb8155=~ledcode[9];break;
case 10:pb8155=~ledcode[10];break;
case 11:pb8155=~ledcode[11];break;
case 12:pb8155=~ledcode[12];break;
case 13:pb8155=~ledcode[13];break;
case 14:pb8155=~ledcode[14];break;
case 15:pb8155=~ledcode[15];break;//"L"
case 16:pb8155=~ledcode[16];break;//"H"

}
delay(1);
j++;
temp=~temp;
temp=_crol_(temp,1);
pb8155=0xff;//Avoid garbled code

}
}

void keyscan(){
int line=0;
int temp;
lk_1:   delay(10);
do{displayled();
ifkeyin();
delay(10);
}while(a);//if key-in
delay(10);//20ms
ifkeyin();//another scan
if(a==1)
goto lk_1;//No input, return

pa8155=0xfe;
ACC=pa8155;

do{
temp=pc8155;
temp=temp&0x0f;
if(temp==0x0e)
{keycode=line;
break;}
if(temp==0x0d)
{keycode=8+line;
break;}
pa8155=_crol_(pa8155,1);//Shift left one bit
line++;}while(ACC^0);
ledbuff[0]=key_code[keycode];//Existential real value

while(a==0){
delay(10);
displayled();
ifkeyin();
}//Wait for closed release

ledbuff[5]=ledbuff[4];
ledbuff[4]=ledbuff[3];
ledbuff[3]=ledbuff[2];
ledbuff[2]=ledbuff[0];
ledbuff[1]=0;//Move left display
count++;
ledbuff[0]=0;//Auxiliary input digit display
}

void ifkeyin(){int b;
a=1;
pa8155=0x00;
b=pc8155&0x0f;
if(b!=0x0f)
a=0;}

void ledbuffclear(){ledbuff[0]=0;
ledbuff[1]=0;
ledbuff[2]=0;
ledbuff[3]=0;
ledbuff[4]=0;
ledbuff[5]=0;}

void errordisplay(){
ledbuff[0]=0;
ledbuff[1]=10;
ledbuff[2]=0;
ledbuff[3]=10;
ledbuff[4]=10;
ledbuff[5]=14;//"ERROR" is displayed when an ERROR is entered
error=1;
while(a){
displayled();
delay(5);
ifkeyin();}
}

ledbuffclear();
count=0;
while(1){
keyscan();

if(ledbuff[2]>9){
if(ledbuff[2]==14){
ledbuff[2]=ledbuff[3];
ledbuff[3]=ledbuff[4];
ledbuff[4]=ledbuff[5];
count=count-1;
while(count<4){
ledbuff[count+2]=0;
count++;
}
break;
}
errordisplay();
break;
}
//if(count==4)break;
}
datas[1]=1000*ledbuff[5]+100*ledbuff[4]+10*ledbuff[3]+ledbuff[2];
datas[2]=datas[1]+datas[0];
datas[3]=datas[2]/10000;
datas[4]=datas[2]%10000;}
void bcd_sub(){ledbuffclear();
count=0;
while(1){
keyscan();
if(ledbuff[2]>9){
if(ledbuff[2]==14){
ledbuff[2]=ledbuff[3];
ledbuff[3]=ledbuff[4];
ledbuff[4]=ledbuff[5];
count=count-1;
while(count<4){
ledbuff[count+2]=0;
count++;
}
break;
}
errordisplay();
break;}
//if(count==4)break;
}
datas[1]=1000*ledbuff[5]+100*ledbuff[4]+10*ledbuff[3]+ledbuff[2];
datas[2]=datas[0]-datas[1];
if(datas[2]<0){
datas[3]=1;
datas[4]=-datas[2];}//If it is less than 0, the high order is 0001
else{
datas[3]=0;
datas[4]=datas[2];}}

void bcd_mul(){ledbuffclear();
count=0;
while(1){
keyscan();
if(ledbuff[2]>9){
if(ledbuff[2]==14){
ledbuff[2]=ledbuff[3];
ledbuff[3]=ledbuff[4];
ledbuff[4]=ledbuff[5];
count=count-1;
while(count<4){
ledbuff[count+2]=0;
count++;
}
break;
}
errordisplay();
break;}
//if(count==4)break;
}
datas[1]=1000*ledbuff[5]+100*ledbuff[4]+10*ledbuff[3]+ledbuff[2];
datas[2]=datas[0]*datas[1];
datas[3]=datas[2]/10000;
datas[4]=datas[2]%10000;}

void bcd_div(){ledbuffclear();
count=0;
while(1){
keyscan();
if(ledbuff[2]>9)
{
if(ledbuff[2]==14){
ledbuff[2]=ledbuff[3];
ledbuff[3]=ledbuff[4];
ledbuff[4]=ledbuff[5];
count=count-1;
while(count<4){
ledbuff[count+2]=0;
count++;
}
break;
}
errordisplay();
break;
}
//if(count==4)break;
}
datas[1]=1000*ledbuff[5]+100*ledbuff[4]+10*ledbuff[3]+ledbuff[2];
datas[3]=datas[0]/datas[1];
datas[4]=datas[0]%datas[1];
if(datas[1]==0){
errordisplay();
error=1;}//Divisor is not 0
}

void showlowbit(){ledbuffclear();
ledbuff[5]=datas[4]/1000;
ledbuff[4]=datas[4]%1000/100;
ledbuff[3]=datas[4]%1000%100/10;
ledbuff[2]=datas[4]%1000%100%10;
ledbuff[1]=16;
ledbuff[0]=16;//"L"
while(a){ifkeyin();
displayled();}}

void showhighbit(){ledbuffclear();
ledbuff[5]=datas[3]/1000;
ledbuff[4]=datas[3]%1000/100;
ledbuff[3]=datas[3]%1000%100/10;
ledbuff[2]=datas[3]%1000%100%10;
ledbuff[1]=15;
ledbuff[0]=15;//"H"
while(a){ifkeyin();
displayled();}}
```

Keywords: Single-Chip Microcomputer

Added by nickmanners on Sat, 08 Jan 2022 15:17:49 +0200