|
1、基本功能 (1)使用8位数码管显示键盘输入与运算结果。 (2)能进行+、—、*、/运算,保留8位整数、输入与输出超过8位时,蜂鸣器叫1S,以0.5S周期闪烁显示ERR-0;当除数为0时,蜂鸣器叫2S,以0.5S周期闪烁显示ERR-1。按清除按键,取消报警显示,进入待输入状态。 (3)能保留上次运算结果,并可将上次运算结果作为下次运算的第一个操作数。 2、扩展功能 (1) 在未输入数据时按下功能键,数码管显示错误提示:E。 (2) 按键发声。 (3) 计算结果为负数时可显示负数。 3、方案论证和比较 (1) 根据题目要求,对于控制器的选择有以下两种方案。 方案一:用计算器专用芯片进行设计并编程。这种方案计算效率高、速度快、而且成本也相对较低,是做计算器的常用方法。但是我对计算器专用芯片的了解不够,不足以实现设计计算器,所以该方案不能采用。 方案二:用 单片机实现。由于单片机集成了运算器 电路、控制电路、存储器、中断系统、定时器/计数器以及输入/输出电路等,所以用单片机设计控制电路省去了很多分立 元件。并且单片机是可编程芯片,可以运用c语言编写,即使是复杂的运算也可以调用C语言库函数实现。所以该设计用单片机实现,不仅功能易于实现,而且精度高,稳定性好,抗干扰能力强,并且成本较低。所以该设计采用单片机设计。 4、数码管显示 数码管显示采用两个4位一体共阳数码管,采用动态数码管显示,具有程序简单,易于控制,显示直观等特点。但只能显示数字和一些代码,不能显示汉字及一些常用的符号,并且硬件设计比较复杂。 数码管引脚: 5、键盘设计方案 该设计采用4*4矩阵键盘,这种键盘硬件简单,使用I/O口比独立键盘减少一半,这种键盘编程简单易于理解。 4x4矩阵键盘符号定义如下: 6、系统组成 该设计采用MCS-51系列单片机SCT89C51来设计计算器,通过扩展外围接口电路,实现计算器的设计。由键盘输入数值,再通过8051单片机输入到系统,并由I/O口输出送到数码管,由数码管显示输入数据与运算结果。设计以单片机为核心,包括显示模块、扩展模块、输入模块、发声模块。 7、程序流程图
9、程序设计 #include #include #include #define uchar unsigned char #define uint unsigned int ***it spk=P3^1; //蜂鸣器控制端口 uchar code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x86,0x8c,0x8c,0xbf,0x88,0xff}; uchar qwan,bwan,swan,wan,qian,bai,shi,ge; uchar j,flag,flag1,flag2;flag3,flag4; long a,b,c,d,e,mun; void number(long z); void key_scan(); void fengli(long x); void jia(); void jian(); void cheng(); void chu(); void deng(); void clear(); uchar x; void delay(uint a) { uchar j; while(a--) { for(j=0;j<125;j++); //1ms延时; } } void display(uchar m,uchar b,uchar c,uchar d, uchar e,uchar f,ucharg,uchar h) //显示函数 { P2=0x7f; P0=table[m]; delay(3); P2=0xbf; P0=table; delay(3); P2=0xdf; P0=table[c]; delay(3); P2=0xef; P0=table[d]; delay(3); P2=0xf7; P0=table[e]; delay(3); P2=0xfb; P0=table[f]; delay(3); P2=0xfd; P0=table[g]; delay(3); P2=0xfe; P0=table[h]; delay(3); } void main() { flag=flag1=flag2=flag3=flag4=0; while(1) { key_scan(); } } void key_scan() //逐行扫描获取键值 { P1=0xff; P1=0xf0; j=P1; if(j!=0xf0) { delay(20); //消抖 if(j!=0xf0) { P1=0xfe; j=P1; spk=0; //有键按下时蜂鸣器发声 delay(30); //延时30ms switch(j) { case(0xee):number(1);break; case(0xde):number(2);break; case(0xbe):number(3);break; case(0x7e):jia();break; } P1=0xfd; j=P1; spk=0; delay(30); switch(j) { case(0xed):number(4);break; case(0xdd):number(5);break; case(0xbd):number(6);break; case(0x7d):jian();break; } P1=0xfb; j=P1; spk=0; delay(30); switch(j) { case(0xeb):number(7);break; case(0xdb):number(8);break; case(0xbb):number(9);break; case(0x7b):cheng();break; } P1=0xf7; j=P1; spk=0; delay(30); switch(j) { case(0xe7):clear();flag=0;break; //清除键 case(0xd7):number(0);break; case(0xb7):{flag3=flag1;deng(); a=mun; flag=flag1=flag2=flag3=0;};break; //等号键 case(0x77):chu();break; } spk=1; //关闭蜂鸣器 delay(30); //延时30ms } } display(qwan,bwan,swan,wan,qian,bai,shi,ge); } void number(long z) //实现输入数的顺序显示 { if(flag==0) { z=z*1; a=z; } if(flag==1) { z=a*10+z; a=z; } if(flag==2) { z=a*10+z; a=z; } if(flag==3) { z=a*10+z; a=z; } if(flag==4) { z=a*10+z; a=z; } if(flag==5) { z=a*10+z; a=z; } if(flag==6) { z=a*10+z; a=z; } if(flag==7) { z=a*10+z; a=z; } fengli(a); while(P1==j) { display(qwan,bwan,swan,wan,qian,bai,shi,ge); } flag++; //记录按键次数 if(flag>8) //输入数据超过八位 显示错误提示:ERR-0 { qwan=15; bwan=15; swan=15; wan=10; qian=11; bai=12; shi=13; ge=0; } flag4=1; } void jia() { flag4--; if(flag4>=0) { flag2=flag1; flag=0; flag1=1; if(flag1==flag2) deng(); else { flag3=flag1; flag1=flag2; deng(); } } else { qwan=bwan=swan=wan=qian=bai=shi=15; //在未输入数据时按功能键提示错误:E ge=10; a=0; mun=0; flag1=0; } while(P1==j) { display(qwan,bwan,swan,wan,qian,bai,shi,ge); } } void jian() { flag4--; if(flag4>=0) { flag2=flag1; flag=0; flag1=2; if(flag1==flag2) deng(); else { flag3=flag1; flag1=flag2; deng(); } } else { qwan=bwan=swan=wan=qian=bai=shi=15; //在未输入数据时按功能键提示错误:E ge=10; a=0; mun=0; flag1=0; } while(P1==j) { display(qwan,bwan,swan,wan,qian,bai,shi,ge); } } void cheng() { flag4--; if(flag4>=0) { flag2=flag1; flag=0; flag1=3; if(flag1==flag2) deng(); else { flag3=flag1; flag1=flag2; deng(); } } else { qwan=bwan=swan=wan=qian=bai=shi=15; //在未输入数据时按功能键提示错误:E ge=10; a=0; mun=0; flag1=0; } while(P1==j) { display(qwan,bwan,swan,wan,qian,bai,shi,ge); } } void chu() { flag4--; if(flag4>=0) { flag2=flag1; flag=0; flag1=4; if(flag1==flag2) deng(); else { flag3=flag1; flag1=flag2; deng(); } } else { qwan=bwan=swan=wan=qian=bai=shi=15; //在未输入数据时按功能键提示错误:E ge=10; a=0; mun=0; flag1=0; } while(P1==j) { display(qwan,bwan,swan,wan,qian,bai,shi,ge); } } void deng() //根据flag1的值实现加减乘除运算 { if(flag1==0) { mun=a; } if(flag1==1) { mun=mun+a; } if(flag1==2) { mun=mun-a; } if(flag1==3) { mun=mun*a; } if(flag1==4) { mun=mun/a; } flag1=flag3; fengli(mun); while(P1==j) { display(qwan,bwan,swan,wan,qian,bai,shi,ge); } } //-------------------------------------------------------// void sepker(void) //蜂鸣器发声 { uchar i,j; for(i=0;i<20;i++) { spk=0; for(j=0;j<10;j++) { display(qwan,bwan,swan,wan,qian,bai,shi,ge); } delay(1000); spk=1; for(j=0;j<10;j++) { display(qwan,bwan,swan,wan,qian,bai,shi,ge); } delay(1000); } } //-----------------------------------------------------// void fengli(long x) //分离各位上的数 { long i; if(x/100000000<1&&x>=0) { qwan=x/10000000; bwan=x%10000000/1000000; swan=x%1000000/100000; wan=x%100000/10000 ; qian=x%10000/1000; bai=x%1000/100; shi=x%100/10; ge=x%10; //-------------------------------------------------------// if(x<10000000 &&x>1000000) qwan=15; if(x<1000000 && x>100000){qwan=bwan=15;} if(x<100000 && x>10000){qwan=bwan=swan=15;} if(x<10000 && x>1000){qwan=bwan=swan=wan=15;} if(x<1000 && x>100){qwan=bwan=swan=wan=qian=15;} if(x<100 && x>10){qwan=bwan=swan=wan=qian=bai=15;} if(x<10 &&x>=0){qwan=bwan=swan=wan=qian=bai=shi=15;} //--------------------------------------------------------// } if(x/100000000>=1&&x>=0) //结果为正超出范围显示错误提示:ERR-0 { qwan=15; bwan=15; swan=15; wan=10; qian=11; bai=12; shi=13; ge=0; sepker(); } if(x<0&&labs(x)/10000000<1) //负数结果显示处理 { qwan=labs(x)/10000000; bwan=labs(x)%10000000/1000000; swan=labs(x)%1000000/100000; wan=labs(x)%100000/10000 ; qian=labs(x)%10000/1000; bai=labs(x)%1000/100; shi=labs(x)%100/10; ge=labs(x)%10; i=labs(x); if(i>=1000000) qwan=13; else if(i>=100000) {qwan=15; bwan=13;} else if(i>=10000) {qwan=bwan=15;swan=13;} else if(i>=1000){qwan=bwan=swan=15;wan=13;} else if(i>=100){qwan=bwan=swan=wan=15;qian=13;} else if(i>=10){qwan=bwan=swan=wan=qian=15;bai=13;} else {qwan=bwan=swan=wan=qian=bai=15;shi=13;} } if(x<0&&labs(x)/10000000>=1) //结果为负超出范围错误提示:ERR-0 { qwan=15; bwan=15; swan=15; wan=10; qian=11; bai=12; shi=13; ge=0; sepker(); } } void clear() //清除函数 { P0=0xff; P2=0xff; a=0; mun=0; fengli(mun); } 10、原件清单 STC89C52-------------------1片 4位7段数码管--------------2个 小按键---------------------17个 三极管S8550----------------9个 蜂鸣器---------------------1个 晶振11.0592MHz ----------1个 电容30pf------------------2个 电容10uf------------------1个 电阻220R------------------8个 电阻1K--------------------2个 电阻10K-------------------1个 排阻10K-------------------1个 DIP40 IC座----------------1个 拨动开关-------------------1个 通用版1-------------------1块 通用版1/4-----------------1块 铜柱----------------------4只 排孔/排针-----------------若干 11、设计总结 这次的单片机设计是在这学期学了单片机后的第一次实际应用,在设计过程中学习了很多。同时也发现了很多问题,由于掌握的知识不足,有些问题不能得到解决,如数码管的整体闪烁,多任务处理,按键与蜂鸣器的配合使用、数码管小数位在运算中的控制等等。由于在焊接电路前有考虑到各元件的布局,从而选择用锡丝走线,保证了板子整体的简洁,使得线路不易出错,同时减小了虚焊的可能性,保证了板子在焊接好后能够正常工作。在通用板的左侧空出了多余的空间,便于以后功能扩展。由于键盘模块是可摘取,所以当键盘去掉后P1八个I/O口可进行其他功能扩展,另外从实物图背面可以看到P3各个没有用到的I/O口均留出了走线的空隙,可按需求进行功能扩展。为了节省材料数码管安装在排孔上便于拆卸。整体而言,这个设计不仅仅是一个计算器,去掉相应的模块,再进行适当的改动,可让该设计实现 电子时钟、作息时间控制系统……。 11、实物图 |