基于MCS-51的4位BCD计算器
作者:互联网
设计任务(功能简介)
基于AT89S52单片机设计一个四位BCD码计算器,具体功能为:
- 实现1~4位BCD码的加减乘除,整数运算
- 按键0-9分别代表数字0-9,A为加号,B为减号,C为乘号,D为除号,E是等号,F是高低位切换键
- 使用:先输入一个四位以内的数(LED显示管高四位显示该数),点击运算符,输入下一个数,点击等号显示结果,显示结果时,默认显示低位,点击高低位切换键可以查看高低位(高位时显示管最后两位为HH,低位显示LL)。
- 减法时高位为符号位,负数高位是1,正数高位是0;除法中高位显示商,低位显示余数
- 报错:输入数据多余四位时报错,未输入数据就使用运算符时报错,除法除数为0时报错,报错LED显示“ERROR”
主要硬件设备及其功能
AT89S52单片机(带仿真接口):主要进行控制,运算,存储数据。
8155实验模块 :作为外部扩展数据存储器,将矩阵键盘输入的信号发送给单片机 ,经单片机计算后将信号发送给数码管显示。
4*6矩阵键盘:将输入数据转化为电信号
六位动态数码管显示模块:将单片机的数字信号输出转化为led可视数据
硬件电路设计
六位动态数码显示管模块
数码管显示电路中,8155与数码管显示电路的拨码开关打在“ON”位置,数码管代码端和公共端与8155PA、PB口相连,PA口为位扫描口,控制点亮哪一个数码管,PB口为字形代码口,控制选中的数码管显示的具体字形,如图所示。
4*6矩阵键盘
键盘扫描电路中,8155与键盘扫描电路的拨码开关打在“ON”位置,PC0-3口为行扫描,PA口为列扫描,通过自定义编码得到键号,如图所示。
8155模块和AT89S52单片机连接电路
8155模块是扩展并行接口电路,
具有两个8位和一个6位I/O口,以及256个字节RAM、一个14位计数器。此电路中A口B口输出,C口输入,8155命令寄存器的内容为43H。
其与单片机的接口电路如图3-3所示,单片机P0口与8155AD相连,P2口通过锁存器与8155AD相连,单片机读写线分别与8155读写线相连(在试验箱内部连接完成)。
程序设计原理
主程序设计
程序开始,将8155初始化之后,初始化数码管显示六位0000 00,高四位为数据显示位,低二位为功能显示位。
首先输入第一个数据,为被操作数,将数据处理后储存于RAM中并在数码管进行左移位显示。若输入非法数据,即第一位输入数不是0~9的数值或是输入位数大于4位,则调用错误显示子程序,返回初始状态。当检测到输入数据为运算符,即加、减、乘、除时,进入各自的子程序,将显示译码器的内容清零后,重新键盘扫描,等待输入第二个被操作数,进行是否合法的判断(如果在除法运算中,则操作数为0时非法),左移位显示储存。若检测输入为等号后,第二个操作数存入RAM,由CPU进行运算。
CPU计算结果后,输出经过处理的信号给数码管显示。此时首先显示运算结果的低四位,可以通过设定的按键控制高低位的显示,也可以通过其他按键来结束此次计算,回到初始状态。此时功能位将显示高低位的标志“HH”和“LL”
键入判断子程序
矩阵键盘判断是否键入的原理是:首先使8条列线所连接的I/O引脚PA口输出低电平,四条行线所连接的I/O引脚PC输出高电平。当没有按键按下时,四条行线所连接的I/O引脚读取到的将全部是高电平;而当有按键按下时,由于该按键所在的行线与列线接通,行线将被下拉到低电平。此时读取行线所连接的引脚将不再全是高电平,由此可以判断出有按键按下。设置判断标志a作为是否键入的判断,有键入时置为0,用于方便跳出while(a)的循环(是否键入)。
键盘输入子程序
此矩阵键盘模块为非编码键盘,可自行对各个键进行编码。实际使用中,使用到的键盘仅仅为4*4,即仅用到PC0和PC1口所控制的键盘。因而将PC0定义为第一行,PC1定义为第二行,第一行所对应的PA口控制的键编码为0-7,第二行为8-15。建立数组将键实际值按照编码排列,在求实际值时仅需要调用此数组便可以将键所对应的实际值储存到显示缓存中。
数码管显示子程序
动态显示数码管的特点是,每时每刻只有一位数码管被点亮,各位依次轮流被点亮。因而只要每个数码管都没充分点亮,发光二极管持续发光一段时间,利用余辉和人眼驻留效应,通过适当间隔就可以观察到稳定的输出。数码管显示模块中,8155PA口用于数码管选择,PB口输出显示代码用于数据显示。
此子程序将键盘输入的真实数据保存在显示缓存的数组中,每次显示时只需要调用显示缓存中的数,将对应的真实数查表转换为显示代码后输出,即可完成一位数码管的显示。
通过PA口的数码管选择循环,此子程序便可以完成数码管的动态显示。在每个数码管显示之后,先延时产生余辉和驻留,然后选择到向左的下一个数码管时,需要将PB口的输出清除,即输出0xff时数码管上的led全灭。这样可以使得下一位数码管不会显示上一位数码管的值(因为PB还在输出时选择了下一位数码管),以防止动态显示的数据产生视觉上的乱码。
动态数码管的显示子程序需要在循环中运行,否则将导致一闪而过。
数据处理和计算子程序
因为键盘输入的数据真实值保存在显示缓存中,因而在处理输入的数据时,仅需要对各位进行加权即可获得真正的十进制4位数,假设所输入的数为a,b,c,d,则所获得的操作数/被操作数为1000a+100b+10c+d。
计算得出的结果分为高低位,皆为4位十进制数,处理方法高低位相同。假设这四位数为abcd(十进制),其需要经过处理分解为四个一位十进制数存入显示缓存中,以便让数码管显示。则:a=abcd/1000;
b=abcd%1000/100;
c=abcd%1000%100/10;
d=abcd%1000%100%10.
矩阵键盘运用了44=16个键,键盘的A、B、C、D所对应的分别为进入加、减、乘、除的按键。当输入4位操作数之后,通过对按键存入显示缓存中的真实值来判断进入了哪一个计算子程序或是非法输入(A、B、C、D分别对应着真实值10、11、12、13)。
在计算后处理高低位时,减法中高位为符号位,负数时显示为0001,正数显示为0000,低位为结果的绝对值;除法高位为商,低位为余数,当除数为0时报错。
错误显示子程序
当输入数据非法(输入非十进制数;输入数据大于4位)或者是除数等于0时,将报错,调用错误显示子程序。因为数码管的显示局限,将“ERROR”显示为“EAAOA”,即直接修改显示缓存里对应位的数值为相应真实值,通过数码管显示子程序显示出来。显示在高五位数码管中。
设置错误标志error,用于主程序中调用计算子程序返回后判断是否错误,返回主程序开头,进行新一次运算。在循环中调用数码管显示子程序显示“EAAOA”,当有键入时跳出循环,结束子程序。
结果高低位显示子程序
计算子程序将计算结果分为高低位分别储存。高位和低位都是4位的BCD码组成的数。结果高低位子程序初始默认显示低四位结果,可以通过键盘上按键E选择显示低位和高位的结果。六位数码管中高四位显示的是计算的结果,低两位是辅助判断位,当显示低位时为“LL”,高位时为“HH”。其中“L”储存在显示缓存中的真实值为15,“H”为16。
当按下除了E以外的其他键时,结束子程序,结束此次计算,回到主程序开头准备进行新一次的计算。
程序清单
#include<reg51.h>
#include<absacc.h>
#include<intrins.h>
#define com8155 XBYTE[0xff20]//8155控制字寄存器
#define pa8155 XBYTE[0xff21]//8155a口
#define pb8155 XBYTE[0xff22]//8155b口
#define pc8155 XBYTE[0xff23]//8155c口
#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};
//第一行是0-9,第二行依次为a,b,c,d,e,h,l,空显示
unsigned int ledbuff[6]={0,0,0,0,0,0};//显示缓存,保存真实值
unsigned int key_code[]={7,4,8,5,9,6,10,11,1,0,2,15,3,14,12,13};
//调用转换数组获取真实数值
code unsigned char stop[3] _at_ 0x3b;
int a;//判断输入标志,a=0时有键输入
int kk=1;//高低显示标志位
int tempbuff;//缓存键入的运算符
long int datas[5]={0,0,0,0,0};
//数据缓存,data[3]:高位 data[4]:低位
int i,count,error;//标志位
int keycode;//键码
void displayled(void);//数码管显示子程序
void keyscan(void);//键盘扫描子程序
void ifkeyin(void);判断是否输入子程序
void ledbuffclear(void);//清零子程序
void errordisplay(void);//错误显示子程序
void bcd_add(void);
void bcd_sub(void);
void bcd_mul(void);
void bcd_div(void);//依次为A加,B减,C乘,D除计算子程序
void showlowbit(void);//显示低位子程序
void showhighbit(void);//结果显示子程序
//延时函数
void delay(int xms){
int x,y;
for(x=xms;x>0;x--)
for(y=110;y>0;y--);
}
//主函数
void main(){com8155=0x43;
loop: error=0;
count=0;
ledbuffclear();
delay(50);//初始化
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];//输入数据处理
//get data and clear the buff;the operand is data[1].
// keyscan();
count=0;
switch(tempbuff){
case 10:bcd_add();break;
case 11:bcd_sub();break;
case 12:bcd_mul();break;
case 13:bcd_div();break;
default:{errordisplay();goto loop;}}
if(error==1)
goto loop;//错误标志位判断
showlowbit();//默认显示低四位
while(1){
keyscan();
if(ledbuff[2]==15)
{kk=-kk;
if(kk==1)showlowbit();
else showhighbit();
}
else goto loop;
}//结果高低位显示子程序
}
//数码管显示子程序
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;//避免乱码
}
}
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;//无输入,返回
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);//左移一位
line++;}while(ACC^0);
ledbuff[0]=key_code[keycode];//存真实值
while(a==0){
delay(10);
displayled();
ifkeyin();
}//等待闭合释放
ledbuff[5]=ledbuff[4];
ledbuff[4]=ledbuff[3];
ledbuff[3]=ledbuff[2];
ledbuff[2]=ledbuff[0];
ledbuff[1]=0;//左移显示
count++;
ledbuff[0]=0;//辅助输入位数显示
}
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”
error=1;
while(a){
displayled();
delay(5);
ifkeyin();}
}
void bcd_add(){
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];}//小于0高位为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;}//除数不为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();}}
标签:count,ledbuff,BCD,void,51,break,数码管,MCS,datas 来源: https://blog.csdn.net/freezing_smile/article/details/122385548