找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 16231|回复: 0
打印 上一主题 下一主题
收起左侧

基于单片机的简易八位计算器设计 课程设计报告

[复制链接]
跳转到指定楼层
楼主
基于单片机的简易计算器设计

一、设计任务和性能指标

1.1设计任务
利用单片机及外围接口电路(键盘接口和显示接口电路)设计制作一个计算器,用四位一体数码管显示计算数值及结果。要求用Protel 画出系统的电路原理图(要求以最少组件,实现系统设计所要求的功能),绘出程序流程图,并给出程序清单(要 求思路清晰,尽量简洁,主程序和子程序分开,使程序有较强的可读性)。
1.2性能指标
1加法:能够计算四位以内的数的加法。
2减法:能计算四位数以内的减法。
3乘法:能够计算两位数以内的乘法。
4除法:能够计算四位数的乘法
5有清零功能,能随时对运算结果和数字输入进行清零。


二、系统设计方案
按照系统设计的功能的要求,初步确定设计系统由单片机主控模块、四位一体数码管显示模块、键扫描接口电路共三个主要模块组成。主控芯片使用51系列AT89C51单片机,采用高性能的静态80C51设计,它由先进工艺制造,并带有非易失性Flash程序存储器。它是一种高性能、低功耗的8COMS微处理芯片,市场应用最多。
键盘电路采用4*4矩阵键盘电路。
显示模块采用四位一体共阳极数码管和SN74LS244锁存芯片构成等器件构成。


三、硬件系统设计
1.单片机最小系统
单片机最小系统就是支持主芯片正常工作的最小电路部分,包括主控芯片、复位电路和晶振电路。
主控芯片选取STC89C51RC芯片,因其具有良好的性能及稳定性,价格便宜应用方便。
晶振选取11.0592MHz,晶振旁电容选取30pF
采用按键复位电路,电阻分别选取100Ω和10K,电容选取10μF
单片机最小系统硬件电路图如图(1)所示。


图(1) 单片机最小系统
2.键盘接口电路
计算器所需按键有:
    数字键:’1’,’2’,’3’,’4’,’5’,’6’,’7’,’8’,’9’,’0’
    功能键:’+’, ’-‘, ’*’, ’/ ’ , ’ = ’, ’ C( 清零)’
共计16个按键,采用4*4矩阵键盘,键盘的行和列之间都有公共端相连,四行采用端口P0.0~P0.3,四列采用端口P3.0~P3.3,通过8个端口的的高低电平完成对矩阵键盘的控制。通过对16个按键进行编码,从而得到键盘的口地址,对比P1口德扫描结果和各按键的地址,我们就可以得到是哪个键按下,从而完成键盘的功能。
3.数码管显示电路
采用4位一体的数码管对计算数据和结果进行显示,这里选取共阳数码管,利用NPN三极管对数码管进行驱动,为了节省I/O资源,采取动态显示的方法来显示计算数据及结果。
    利用SN74LS244N锁存器来实现数码管的动态显示,P1口输出显示值,P2.0~P2.3为位选端口。通过锁存器对段选信号的锁存,最终得到对数码管输入数据的控制。
    以下为数码显示电路的硬件电路图,左图为数码管驱动电路,右图为段选信号锁存电路。

四.软件设计部分
根据选题要求,系统编程如下所示:
  1. #include "reg51.h"
  2. sbit P3_0=P3^0;
  3. sbit P3_1=P3^1;
  4. sbit P3_2=P3^2;
  5. sbit P3_3=P3^3;
  6. sbit P3_4=P3^4;
  7. sbit P3_5=P3^5;
  8. sbit P3_6=P3^6;
  9. sbit P3_7=P3^7;
  10. unsigned char sz[11],xs1[4],xs2[4],sj;
  11. int i,cs,bb,t1,t2,fh,s1,s2;
  12. void chushihua()
  13. {
  14.         bb=1;
  15.         xs1[0]=10;xs1[1]=10;xs1[2]=10;xs1[3]=10;
  16.         xs2[0]=10;xs2[1]=10;xs2[2]=10;xs2[3]=10;
  17.         t1=0;t2=0;s1=s2=0;
  18.         fh=0;
  19.         cs=1;
  20.         
  21. }
  22. void xianshi(unsigned char xs[4])
  23. {
  24.         int i,j;
  25.         unsigned char zy;
  26.         zy=0x08;
  27.         for (i=0;i<4;i++)
  28.         {
  29.                 P2=(0xff-zy);  
  30.                 P1=sz[xs[i]];        
  31.                 zy=(zy>>1);
  32.                 for (j=0;j<100;j++)        ;
  33.                
  34.         }
  35. //        for (i=0;i<100;i++);
  36.         return;

  37. }
  38. unsigned char saomiao()
  39. {
  40.         int i,j;
  41.         unsigned char pp;
  42.         for (i=0;i<1000;i++);
  43.         P0=0xfe;
  44.         P3=0x0f;
  45.         pp=P3;
  46.         if (P3_0==0)         {P3=0x0f;pp=P3;while (P3_0==0);for (i=0;i<1000;i++);return 7;}
  47.         if (P3_1==0)         {P3=0x0f;pp=P3;while (P3_1==0);for (i=0;i<1000;i++);return 8;}
  48.         if (P3_2==0)         {P3=0x0f;pp=P3;while (P3_2==0);for (i=0;i<1000;i++);return 9;}
  49.         if (P3_3==0)         {P3=0x0f;pp=P3;while (P3_3==0);for (i=0;i<1000;i++);return 11;}
  50.         //==========1
  51.         P0=0xfd;
  52.         P3=0x0f;
  53.         pp=P3;
  54.         if (P3_0==0)         {P3=0x0f;pp=P3;while (P3_0==0);for (i=0;i<1000;i++);return 4;}
  55.         if (P3_1==0)         {P3=0x0f;pp=P3;while (P3_1==0);for (i=0;i<1000;i++);return 5;}
  56.         if (P3_2==0)         {P3=0x0f;pp=P3;while (P3_2==0);for (i=0;i<1000;i++);return 6;}
  57.         if (P3_3==0)         {P3=0x0f;pp=P3;while (P3_3==0);for (i=0;i<1000;i++);return 12;}
  58.         //==========2
  59.         P0=0xfb;
  60.         P3=0x0f;
  61.         pp=P3;
  62.         if (P3_0==0)         {P3=0x0f;pp=P3;while (P3_0==0);for (i=0;i<1000;i++);return 1;}
  63.         if (P3_1==0)         {P3=0x0f;pp=P3;while (P3_1==0);for (i=0;i<1000;i++);return 2;}
  64.         if (P3_2==0)         {P3=0x0f;pp=P3;while (P3_2==0);for (i=0;i<1000;i++);return 3;}
  65.         if (P3_3==0)         {P3=0x0f;pp=P3;while (P3_3==0);for (i=0;i<1000;i++);return 13;}
  66.         //==========3
  67.         P0=0xf7;
  68.         P3=0x0f;
  69.         pp=P3;
  70.         if (P3_0==0)         {P3=0x0f;pp=P3;while (P3_0==0);for (i=0;i<1000;i++);return 16;}
  71.         if (P3_1==0)         {P3=0x0f;pp=P3;while (P3_1==0);for (i=0;i<1000;i++);return 0;}
  72.         if (P3_2==0)         {P3=0x0f;pp=P3;while (P3_2==0);for (i=0;i<1000;i++);return 15;}
  73.         if (P3_3==0)         {P3=0x0f;pp=P3;while (P3_3==0);for (i=0;i<1000;i++);return 14;}
  74.         //===========4
  75.         return 10;
  76. }
  77. void chuli(unsigned char x)
  78. {
  79.         int i;
  80.         if (x==16)
  81.         {
  82.                 cs=0;
  83.                 return ;
  84.         }
  85.         if (x>=0 && x<10)
  86.         {
  87.                 if (bb==1)
  88.                 {
  89.                         if (s1= =4) {cs=0;return ;}
  90.                         else
  91.                         {
  92.                                 for (i=3;i>0;i--)
  93.                                 xs1[i]=xs1[i-1];
  94.                                 xs1[0]=x;
  95.                                 s1++;
  96.                                 t1=t1*10+x;
  97.                         }
  98.                 }
  99.                 if (bb==2)
  100.                 {
  101.                         if (s2==4) {cs=0;return ;}
  102.                         else
  103.                         {
  104.                                 for (i=3;i>0;i--)
  105.                                 xs2[i]=xs2[i-1];
  106.                                 xs2[0]=x;
  107.                                 s2++;
  108.                                 t2=t2*10+x;
  109.                         }
  110.                 }        
  111.         }
  112.         if (x>10)
  113.         {
  114.                 if (bb==1) {fh=x;bb=2;return;}
  115.                 if (bb==2)
  116.                 {
  117.                         if (fh==11) t1=t1/t2;
  118.                         if (fh==12) t1=t1*t2;
  119.                         if (fh==13) t1=t1-t2;
  120.                         if (fh==14) t1=t1+t2;
  121.                         if (t1>=10000) {cs=0;return;}
  122.                         else
  123.                         {
  124.                                 if (t1>=0 && t1<10)         {xs1[0]=t1;xs1[1]=10;xs1[2]=10;xs1[3]=10;}
  125.                                 if (t1>=10 && t1<100)         {xs1[0]=t1%10;xs1[1]=t1/10;xs1[2]=10;xs1[3]=10;}
  126.                                 if (t1>=100 && t1<1000)         {xs1[0]=t1%10;xs1[1]=(t1-(t1/100)*100)/10;xs1[2]=t1/100;xs1[3]=10;}
  127.                                 if (t1>=1000 && t1<10000)         {xs1[0]=t1%10;xs1[1]=t1%100/10;xs1[2]=(t1-(t1/1000)*1000)/100;xs1[3]=t1/1000;}
  128.                                 bb=2;
  129.                                 s2=0;
  130.                                 t2=0;
  131.                                 xs2[0]=10;xs2[1]=10;xs2[2]=10;xs2[3]=10;
  132.                                 fh=x;
  133.                         }
  134.                 }
  135.         }

  136. }
  137. void main()
  138. {
  139.          sz[0]=0xfc;
  140.         sz[1]=0x60;
  141.         sz[2]=0xda;
  142.         sz[3]=0xf2;
  143.         sz[4]=0x66;
  144.         sz[5]=0xb6;
  145.         sz[6]=0xbe;
  146.         sz[7]=0xe0;
  147.         sz[8]=0xfe;
  148.         sz[9]=0xf6;
  149.         sz[10]=0x00;
  150.         cs=0;
  151.         
  152.         for (;;)
  153.         {
  154.                 if (cs==0) chushihua();
  155.                 if (cs==1) sj=saomiao();
  156.                 if (cs==1 && sj!=10) chuli(sj);
  157.                 if (cs==1 &&(bb==1 || bb==2 && s2==0)) xianshi(xs1);
  158.                 if (cs==1 &&(bb==2 && s2!=0)) xianshi(xs2);
  159.                
  160.         }
  161. }
  162. 软件设计好后,在KEIL上面进行仿真,把仿真得到的文件下载到Proteus里面进行仿真,得到Proteus仿真电路图如下所示:           

  163.            图(2)  计算器Proteus仿真电路图

  164. 五.硬件电路焊接及调试
  165.     根据电路图纸,焊接好硬件电路,把程序下载到单片机芯片,接通好电源,进行调试。在焊接好器件后,先不要将芯片插在芯片座上,要先验证先板上电源是否好用,有无短路等。接上USB电源,用万用表测量个芯片座对应电源和地之间的电压值,观察电压值是否正常。一切正常后方可将芯片插入芯片座,以继续测试其他功能。
  166.     将芯片插上后,对各个模块进行调试,按键是否工作正常,数码管是否显示正常等。编写相关部分的测试程序对其进行测试。
  167.     各部分硬件检测无误后,下载程序进行整体调试,一切正常后,结束调试过程。
  168.     用所设计的单片机进行数字计算,显示结果与任务要求一致,焊接电路符合要求。
  169. 六.课程设计心得
  170. 两周的时间,终于把单片机课程设计搞完了。整个体会还是比较多的。首先是题目的选择,各方面的原因,自己还是想选个简单点的题目,不过最后选来选去,还是选择了计算器。由于自己对单片机编程还不是很熟悉,结果在设计的时候遇到了一系列问题,程序总是调试部处理,不过还好,最后在同学的帮助下终于把程序调试出来了,虽然程序设计实现的功能与老师要求的不尽相同,不过勉强还算可以。从这里我知道了基本知识的重要性。其实进行程序设计的时候主要是对各功能模块的把握。计算器里面最难的一部分是矩阵键盘的扫描和编码,那个费了很大力气。
  171. 另外一点就是硬件焊接调试部分。焊接的时候到时轻松,一个下午就焊接好了,然后是调试部分。调试花费的时间还是比较长的。不过有了上个学期数字电路焊接调试的经验,这次单片机调试还算是比较顺利。我也是从电路板的正负电源检测起,一步一步来,最终得到了想要的结果。调试的时候主要遇到了两个问题。一个是键盘总是没有反应,为了这个自己调试了很久,前前后后把电路板检查了几次,最后才发现是键盘本身的问题,和同学们换了个好键盘才行。另一个问题是总是显示不出来1、4、7这三个数字。检测来检测去,发现来是在测试最小系统时在一个位选端接了高电平,对位选信号产生了影响。当把那个高电平去掉后,终于得到了正确的结果。
  172. 总的来说这次课程设计达到了完成了基本任务,达到了基本要求。通过亲身对程序设计和电路焊接调试的体会,自己对单片机有了进一步的了解,单片机编程能力也得到了提高。电路板的焊接与调试,使自己电路调试的方法和思想进一步加强了。这次单片机课程设计应该说是比较成功的。

  173. 参考文献:
  174.    【1】徐维祥、刘旭敏:,《单片微型机原理及应用》,大连理工大学出版社,1996年。
  175. 【2】李光飞、楼然苗、胡佳文、谢象佐.,《单片机课程设计与实例指导.》, 北京航空航天大学出版社,2004年。
  176. 【3】余永权,《89系列FLASH单片机原理及应用.》,电子工业出版社,2002。
  177. 【4】杨恢先、黄辉先,《单片机原理及应用》,人民邮电出版社,2006年。
  178. 【5】常敏、王涵、范江波,《单片机应用程序开发与实践》,电子工业出版社,2009年。






  179. #include   //头文件
  180. #define uint unsigned int //
  181. #define uchar unsigned char

  182. sbit lcden=P2^3; //定义引脚
  183. sbit rs=P2^4;
  184. sbit rw=P2^0;
  185. sbit busy=P0^7;

  186. char i,j,temp,num,num_1;
  187. long a,b,c;     //a,第一个数 b,第二个数 c,得数
  188. float a_c,b_c;
  189. uchar flag,fuhao;//flag表示是否有符号键按下,fuhao表征按下的是哪个符号

  190. uchar code table[]={
  191. 7,8,9,0,
  192. 4,5,6,0,
  193. 1,2,3,0,
  194. 0,0,0,0};
  195. uchar code table1[]={
  196. 7,8,9,0x2f-0x30,
  197. 4,5,6,0x2a-0x30,
  198. 1,2,3,0x2d-0x30,
  199. 0x01-0x30,0,0x3d-0x30,0x2b-0x30};

  200. void delay(uchar z) // 延迟函数
  201. {
  202. uchar y;
  203. for(z;z>0;z--)
  204.    for(y=0;y<110;y++);
  205. }

  206. void check() // 判断忙或空闲
  207. {
  208. do{
  209.     P0=0xFF;
  210.     rs=0;     //指令
  211.     rw=1;     //读
  212.     lcden=0;     //禁止读写
  213.     delay(1); //等待,液晶显示器处理数据
  214.     lcden=1;     //允许读写
  215.     }while(busy==1); //判断是否为空闲,1为忙,0为空闲
  216. }
  217. void write_com(uchar com) // 写指令函数
  218. {
  219. P0=com;    //com指令付给P0口
  220. rs=0;
  221. rw=0;
  222. lcden=0;
  223. check();
  224. lcden=1;
  225. }

  226. void write_date(uchar date) // 写数据函数
  227. {
  228.     P0=date;
  229. rs=1;
  230. rw=0;
  231. lcden=0;
  232. check();
  233. lcden=1;
  234. }

  235. void init() //初始化
  236. {
  237.     num=-1;
  238. lcden=1; //使能信号为高电平
  239. write_com(0x38); //8位,2行
  240. write_com(0x0c); //显示开,光标关,不闪烁*/
  241. write_com(0x06); //增量方式不移位 显竟獗暌贫 柚?
  242. write_com(0x80); //检测忙信号
  243. write_com(0x01); //显示开,光标关,不闪烁
  244. num_1=0;
  245. i=0;
  246. j=0;
  247. a=0;     //第一个参与运算的数
  248. b=0;     //第二个参与运算的数
  249. c=0;
  250. flag=0; //flag表示是否有符号键按下,
  251. fuhao=0; // fuhao表征按下的是哪个符号
  252. }
  253. void keyscan() // 键盘扫描程序
  254. {

  255. P3=0xfe;
  256. if(P3!=0xfe)
  257. {
  258.    delay(20); 延迟20ms
  259.    if(P3!=0xfe)
  260.    {
  261.     temp=P3&0xf0;
  262.     switch(temp)
  263.     {
  264.      case 0xe0:num=0;
  265.        break;
  266.      case 0xd0:num=1;
  267.        break;
  268.      case 0xb0:num=2;
  269.        break;
  270.      case 0x70:num=3;
  271.        break;
  272.     }
  273.    }
  274.    while(P3!=0xfe);
  275.    if(num==0||num==1||num==2)//如果按下的是'7','8'或'9
  276.    {
  277.        if(j!=0)
  278.         {
  279.           write_com(0x01);
  280.           j=0;
  281.          }
  282.        if(flag==0)//没有按过符号键
  283.     {
  284.      a=a*10+table[num];
  285.     }
  286.     else//如果按过符号键
  287.     {
  288.      b=b*10+table[num];
  289.     }
  290.    }
  291.    else//如果按下的是'/'
  292.    {
  293.     flag=1;
  294.     fuhao=4;//4表示除号已按
  295.    }
  296.    i=table1[num];
  297.    write_date(0x30+i);
  298. }

  299. P3=0xfd;
  300. if(P3!=0xfd)
  301. {
  302.    delay(5);
  303.    if(P3!=0xfd)
  304.    {
  305.     temp=P3&0xf0;
  306.     switch(temp)
  307.     {
  308.      case 0xe0:num=4;
  309.          break;
  310.       
  311.      case 0xd0:num=5;
  312.          break;
  313.       
  314.      case 0xb0:num=6;
  315.          break;
  316.       
  317.      case 0x70:num=7;
  318.          break;
  319.     }
  320.    }
  321.    while(P3!=0xfd);
  322.    if(num==4||num==5||num==6&&num!=7)//如果按下的是'4','5'或'6'
  323.    {
  324.     if(j!=0)
  325.         {
  326.           write_com(0x01);
  327.           j=0;
  328.          }
  329.        if(flag==0)//没有按过符号键
  330.     {
  331.      a=a*10+table[num];
  332.     }
  333.     else//如果按过符号键
  334.     {
  335.      b=b*10+table[num];
  336.     }
  337.    }
  338.    else//如果按下的是'/'
  339.    {
  340.     flag=1;
  341.     fuhao=3;//3表示乘号已按
  342.    }
  343.    i=table1[num];
  344.    write_date(0x30+i);
  345. }

  346. P3=0xfb;
  347. if(P3!=0xfb)
  348. {
  349.    delay(5);
  350.    if(P3!=0xfb)
  351.    {
  352.     temp=P3&0xf0;
  353.     switch(temp)
  354.     {
  355.      case 0xe0:num=8;
  356.          break;
  357.       
  358.      case 0xd0:num=9;
  359.          break;
  360.       
  361.      case 0xb0:num=10;
  362.          break;
  363.       
  364.      case 0x70:num=11;
  365.          break;
  366.     }
  367.    }
  368.    while(P3!=0xfb);
  369.    if(num==8||num==9||num==10)//如果按下的是'1','2'或'3'
  370.    {
  371.     if(j!=0)
  372.         {
  373.           write_com(0x01);
  374.           j=0;
  375.          }
  376.       if(flag==0)//没有按过符号键
  377.     {
  378.      a=a*10+table[num];
  379.     }
  380.     else//如果按过符号键
  381.     {
  382.      b=b*10+table[num];
  383.     }
  384.    }
  385.    else if(num==11)//如果按下的是'-'
  386.    {
  387.     flag=1;
  388.     fuhao=2;//2表示减号已按
  389.    }
  390.    i=table1[num];
  391.    write_date(0x30+i);
  392. }

  393. P3=0xf7;
  394. if(P3!=0xf7)
  395. {
  396.    delay(5);
  397.    if(P3!=0xf7)
  398.    {
  399.     temp=P3&0xf0;
  400.     switch(temp)
  401.     {
  402.      case 0xe0:num=12;
  403.          break;
  404.       
  405.      case 0xd0:num=13;
  406.          break;
  407.       
  408.      case 0xb0:num=14;
  409.          break;
  410.       
  411.      case 0x70:num=15;
  412.          break;
  413.     }
  414.    }
  415.    while(P3!=0xf7);
  416.    switch(num)
  417.    {
  418.     case 12:{write_com(0x01);a=0;b=0;flag=0;fuhao=0;}//按下的是"清零"
  419.      break;
  420.     case 13:{                //按下的是"0"
  421.        if(flag==0)//没有按过符号键
  422.        {
  423.         a=a*10;
  424.         write_date(0x30);
  425.         P1=0;
  426.        }
  427.        else if(flag==1)//如果按过符号键
  428.        {
  429.         b=b*10;
  430.         write_date(0x30);
  431.         }
  432.       }
  433.      break;
  434.     case 14:{j=1;
  435.            if(fuhao==1){write_com(0x80+0x4f);//按下等于键,光标前进至第二行最后一个显示处
  436.            write_com(0x04);     //设置从后住前写数据,每写完一个数据,光标后退一格
  437.            c=a+b;
  438.            while(c!=0)
  439.            {
  440.              write_date(0x30+c%10);
  441.              c=c/10;
  442.            }
  443.            write_date(0x3d);     //再写"="
  444.            a=0;b=0;flag=0;fuhao=0;
  445.            }
  446.       else if(fuhao==2){write_com(0x80+0x4f);//光标前进至第二行最后一个显示处
  447.             write_com(0x04);     //设置从后住前写数据,每写完一个数据,光标后退一格(这个照理说顺序不对,可显示和上段一样)
  448.            if(a-b>0)
  449.              c=a-b;
  450.            else
  451.              c=b-a;
  452.            while(c!=0)
  453.            {
  454.              write_date(0x30+c%10);
  455.              c=c/10;
  456.            }
  457.            if(a-b<0)
  458.              write_date(0x2d);
  459.            write_date(0x3d);     //再写"="           
  460.            a=0;b=0;flag=0;fuhao=0;
  461.           }
  462.       else if(fuhao==3){write_com(0x80+0x4f);
  463.             write_com(0x04);
  464.              c=a*b;
  465.              while(c!=0)
  466.              {
  467.              write_date(0x30+c%10);
  468.              c=c/10;
  469.              }
  470.              write_date(0x3d);     
  471.           a=0;b=0;flag=0;fuhao=0;
  472.              }
  473.       else if(fuhao==4){write_com(0x80+0x4f);
  474.             write_com(0x04);
  475.             i=0;
  476.             c=(long)(((float)a/b)*1000);
  477.             while(c!=0)
  478.              {
  479.                write_date(0x30+c%10);
  480.                c=c/10;
  481.            i++;
  482.            if(i==3)
  483.                write_date(0x2e);
  484.              }
  485.             if(a/b<=0)
  486.               write_date(0x30);
  487.             write_date(0x3d);                              
  488.             a=0;b=0;flag=0;fuhao=0;
  489.                     }
  490.       }
  491.      break;
  492.      case 15:{write_date(0x30+table1[num]);flag=1;fuhao=1;}
  493.      break;
  494.    }
  495. }
  496. }

  497. main()
  498. {
  499. init();

  500. ………余下代码请下载附件………

复制代码

完整的课程设计报告(论文)下载:
单片机计算器课程设计报告.doc (154 KB, 下载次数: 82)

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶1 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表