找回密码
 立即注册

QQ登录

只需一步,快速开始

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

基于单片机的计算器设计报告 只能计算加减乘除

[复制链接]
跳转到指定楼层
楼主
ID:442355 发表于 2018-12-8 20:16 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
这是基于单片机的简单计算器。只能计算加减乘除
目录

1 前言
1.1 设计目的
2 方案论证              1
2.1 方案构思              1
3 系统硬件设计及说明              1
3.1系统组成及总体框图              1
3.2元件简介              2
3.2.1 AT89S52特点              2
3.2.2 LCD1602液晶显示屏              4
4 设计原理分析              6
4.1  设计方案的确定              6
4.2计算器硬件方案及硬件资源分配              7
4.2.1 硬件资源分配              7
4.2.2 系统的硬件设计              7
4.2.3 键盘电路的设计              8
4.2.4 显示电路的设计              9
5 计算器的软件设计              10
5.1计算器的软件规划              10
5.2 汇编语言和C语言的特点及选择              10
5.3 按键键扫描程序设计
5.4 算术运算程序设计              11
5.5 显示程序设计              12
6 系统调试与存在的问题              14
6.1 硬件调试              14
6.2 软件调试              14
参考文献              15
附录一:仿真原理图              16
附录二:源程序              17

1 前言
1.1 设计目的
本设计旨在进一步掌握单片机理论知识,理解嵌入式单片机系统的硬软件设计,加强对实际应用系统设计的能力。通过本设计的学习,使我掌握单片机程序设计和微机接口应用的基本方法,并能综合运用本科阶段所学软、硬件知识分析实际问题,提高解决毕业设计实际问题的能力,为单片机应用和开发打下良好的基础。
1、对字符液晶显示模块的工作原理,如初始化、清屏、显示、调用及外特性有较清楚的认识,并会使用LCD(液晶显示模块)实现计算结果的显示;掌握液晶显示模块的驱动和编程,设计LCD和单片机的接口电路,以及利用单片机对液晶模块的驱动和操作;
2、在充分分析内部逻辑的概念,进行软件和调试,学会使用,并能够以其为平台设计出具有四则运算能力简易计算器的硬件电路和软件程序。
2方案论证
2.1 方案构思
采用AT89S52
单片机是单片微型机的简称,故又称为微控制器MCU(Micro Control Unit)。通常由单块集成电路芯片组成,内部包含有计算机的基本功能部件:中央处理器CPU,存储器和I/O接口电路等。因此,单片机只要和适当的软件及外部设备相结合,便可成为一个单片机控制系统。单片机广泛用于智能产品,智能仪表,测控技术,智能接口等,具有操作简单,实用方便,价格便宜等优点,而其中AT89S52以MCS-51为内核,是单片机中最典型的代表,应用于各种控制领域。
3系统硬件设计及说明
3.1系统组成及总体框图

图3.1 系统组成及总体框图

3.2元件简介
3.2.1 AT89S52特点

图3.2.1-1 单片机AT89S52

1、主要性能:
(1) ? 8031 CPU与MCS-51 兼容
  ? 8K字节可编程FLASH存储器(寿命:1000写/擦循环)
  ? 全静态工作:0Hz-33MHz
  ? 三级加密程序存储器
  ? 128*8位内部RAM
  ? 32条可编程I/O线
  ? 三个16位定时器/计数器
  ? 八个中断源
  ? 全双工UART串行通道
? 低功耗的闲置和掉电模式
? 掉电后中断可唤醒
? 看门狗定时器
? 双数据指针
? 掉电标识符
? 片内振荡器和时钟电路
(2) 管脚说明:
  VCC:供电电压。
GND:接地。

2、AT89S52的功能特性描述
AT89S52 是一种低功耗、高性能CMOS8位微控制器,具有 8K 在系统可编程Flash 存储器。使用Atmel 公司高密度非 易失性存储器技术制造,与工业80C51 产品指令和引脚完 全兼容。片上Flash允许程序存储器在系统可编程,亦适于 常规编程器。在单芯片上,拥有灵巧的8 位CPU 和在系统 可编程Flash,使得AT89S52为众多嵌入式控制应用系统提 供高灵活、超有效的解决方案。
AT89S52具有以下标准功能: 8k字节Flash,256字节RAM, 32 位I/O 口线,看门狗定时器,2 个数据指针,三个16 位 定时器/计数器,一个6向量2级中断结构,全双工串行口, 片内晶振及时钟电路。
此外, AT89S52 可降至0Hz 静态逻 辑操作,支持2种软件可选择节电模式。空闲模式下,CPU 停止工作,允许RAM、定时器/计数器、串口、中断继续工 作。掉电保护方式下,RAM内容被保存,振荡器被冻结, 单片机一切工作停止,直到下一个中断或硬件复位为止。8 位微控制器 8K 字节在系统可编程 Flash。同时该芯片还具有PDIP、TQFP和PLCC等三种封装形式,以适应不同产品的需求。

3、AT89S52引脚功能
AT89S52 单片机为40 引脚芯片见图3.2.1-2和课本。
图3.2.1-2 AT89S52引脚图

3.2.2 LCD1602液晶显示屏
1、应用简介
模块内部自带字符发生存储器(CGROM),字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是(41H),显示时模块把代码41H发给液晶模块,我们就能在液晶上看到字母“A”。
1602液晶模块内部的控制器共有11条控制指令,丰富的指令可以完成液晶的时序控制、工作方式式设置和数据显示等。
采用的LCD1602液晶模块是标准16针插座,接口电路如图3.2.3所示:关于LCD1602的详细资料见表3.2.3-1和表3.2.3-2。

图3.2.3 LCD接口电路

表3.2.3-1 LCD1602引脚说明
第1脚
VSS为地电源
第2脚
VDD接5V正电源
第3脚
V0为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度。
实际电路中采用2K电阻到地,比较理想。
第4脚
RS为寄存器选择,高电平选择数据寄存器、低电平选择指令寄存器。
第5脚
RW为读写信号线,高电平时进行读操作,低电平时进行写操作。
当RS和RW共同为低电平时  (00)可以写入指令或者显示地址;
当RS为低电平RW为高电平时(01)可以读入忙信号;
当RS为高电平RW为低电平时(10)可以写入数据。
第6脚
E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。
第7~14脚
D0~D7为8位双向数据线。
第15~16脚
背光阳极和背光阴极。


表3.2.3-2 LCD1602指令表
指令1
清显示     指令码01H, 光标复位到地址00H位置;
指令2
光标复位   指令码02H, 光标返回到地址00H位置 ;
指令3
光标和显示模式设置
I/D位 → 光标移动方向,高电平右移,低电平左移;
S  位 → 屏幕上所有文字是否左移或者右移,高电平有效,低电平无效;
指令4
显示开关控制
D  位 → 控制整体显示的开与关,高电平表示开显示,低电平表示关显示;
C  位 → 控制光标的开与关,高电平表示有光标,低电平表示无光标;   
    B  位 → 控制光标是否闪烁,高电平闪烁,低电平不闪烁 ;
指令5
光标或显示移位
S/C位 → 高电平时移动显示的文字,低电平时移动光标
指令6
功能命令设置
DL位---高电平时为4位数据总线,低电平时为8位总线;
N—位低电平时为单行显示,高电平时为双行显示;
F—位低电平时显示5x7的点阵字符,高电平时为5x10的点阵字符;
指令7
字符发生器RAM地址设置
指令8
DDRAM地址设置
指令9
读忙信号和光标地址
BF位 → 为忙标志位,高电平表示忙,此时模块不能接收命令或者数据
指令10
写数据
指令11
读数据

2 、LCD的特点:
(1)低压微功耗;
(2)平板型结构;
(3)被动显示型(无眩光,不刺激人眼,不会引起眼睛疲劳);
(4)显示信息量大(因为像素可以做得很小);
(5)易于彩色化(在色谱上可以非常准确的复现);
(6)无电磁辐射(对人体安全,利于信息保密);
(7)长寿命(这种器件几乎没有什么劣化问题,因此寿命极长,但是液晶背光寿命有限,不过背光部分可以更换)。
4 设计原理分析4.1  设计方案的确定
本设计需要使用LCD液晶显示屏和编码键盘。故选择静态显示和用编码键盘。使用LCD液晶显示屏显示运算结果。
    主程序进行初始化,其他的程序选择模块式的方式。首先对每个模块进行调试, 当模块调试成功后,逐一的加入主程序中,最后完成整个软件部分的设计。
4.2计算器硬件方案及硬件资源分配4.2.1 硬件资源分配
主要用到的硬件:AT89S52   LCD液晶显示屏  编码键盘
硬件分配:
1、P1、P3口:做为输出口,控制LCD液晶显示屏显示数据的结果。
2、P2口:做为输入口,与键盘连接,实现数据的输入。
3、LCD液晶显示屏显示输出。
4.2.2 系统的硬件设计
为了更好的实现系统得功能,硬件电路的设计应该遵循以下原则:
1、优化硬件电路
采用软件设计与硬件设计相结合的方法;尽管采用软件来实现硬件系统的功能时,也许响应时间会比单纯使用硬件时长,而且还要占用微处理器(MCU)的时间;但是,用软件实现硬件的功能可以简化硬件结构,提高电路的可靠性。所以,在设计本系统得时候,在满足可靠性和实时性的前提下,尽可能的通过软件来实现硬件功能。
2、可靠性及抗干扰设计
根据可靠性设计理论,系统所用芯片数量越少,系统的平均无故障时间越长。而且,所用芯片数量越少,地址和数据总线在电路板上受干扰的可能性也就越小。因此,系统的设计思想是在满足功能的情况下力争使用较少数量的芯片。
3、灵活的功能扩展
功能扩展是否灵活是衡量一个系统优劣的重要指标。一次设计往往不能完全考虑到系统的各个方面,系统需要不断完善以及进行功能升级。进行功能扩展时,应该在原有设计的基础上,通过修改软件程序和少量硬件完成。对于本系统而言,就是要求在系统硬件不变的情况下,能够通过修改软件程序,完成功能的升级和扩展。
根据第提出的系统设计方案,结合以上三条原则,确定了系统硬件的设计。计算器主要由以下一些功能模块构成:非编码键盘模块、LCD液晶显示屏模块等。
该系统的硬件设计采用了模块化的设计方法。AT89S52 单片机与LCD液晶显示屏显示电路是整个电路的核心,它们实现系统的功能要求。
简易计算器主要包括:键盘电路,显示电路。
下图为总体硬件结构。(如图4.2.2 所示为整个系统的原理图)
图4.2.2 计算器原理图
前面叙述了该系统的设计说明,系统采用了比较简单的设计方案,所以该系统的硬件设计的总外围电路不会产生过多的干扰。在下面的阐述中,对系统的外围电路分别予以介绍。键盘部分采用编码键盘,显示部分采用LCD液晶显示屏完全能够很好的实现显示方面的要求。
4.2.3 键盘电路的设计
键盘可分为两类:编码键盘和非编码键盘。编码键盘是较多按键(20个以上)和专用驱动芯片的组合,当按下某个按键时,它能够处理按键抖动、连击等问题,直接输出按键的编码,无需系统软件干预。通用计算机使用的标准键盘就是编码键盘。在智能仪器中,使用并行接口芯片8279或串行接口芯片HD7279均可以组成编码键盘,同时还可以兼顾数码管的显示驱动,其相关的接口电路和接口软件均可在芯片资料中得到。当系统功能比较复杂,按键数量很多时,采用编码键盘可以简化软件设计。非编码键盘成本低廉。
从成本角度出发,本设计选用的是非编码键盘。如图4.2.3

图4.2.3 编码键盘电路

4.2.4 显示电路的设计
当系统需要显示少量数据时,采用LCD液晶显示屏进行显示是一种经济实用的方法。P0口作为液晶显示的数据端口,P3.5-P3.7口作为其控制端口,控制LCD液晶显示屏显示输出数据。
最终电路如图4.2.4所示:
图4.2.4 LCD液晶显示屏显示

5  计算器的软件设计5.1计算器的软件规划
简易计算器的程序主要包括以下功能模块:
1、定时查键模块,分为读键程序、判键程序段、运算操作子程序等部分;
2、基于LCD液晶显示屏的显示模块;
3、主模块,为系统的初始化。
5.2 汇编语言和C语言的特点及选择

本设计是硬件电路和软件编程相结合的设计方案,选择合适的编程语言是一个重要的环节。在单片机的应用系统程序设计时,常用的是汇编语言和C语言。机硬件,程序可读性和可移植性比较差。而C语言虽然执行效率没有汇编语言高,但语言简洁,使用方便,灵活,运算丰富,表达化类型多样化,数据结构类型丰富,具有结构化的控制语句,程序设计自由度大,有很好的可重用性,可移植性等特点。

由于现在单片机的发展已经达到了很高的水平,内部的各种资源相当的丰富,CPU的处理速度非常的快。用C语言来控制单片机无疑是一个理想的选择。所以在本设计中采用C语言编写软件程序。主程序的设计详见附录三。

5.3 按键键扫描程序设

键扫程序的过程为:开始时,先判断是否有键闭合,无键闭合时,返回继续判断,有键闭合时,先去抖动,然后确定是否有键按下,若无键按下,则返回继续判断是否有键闭合,若有键按下,则判断键号,然后释放,若释放按键完毕,则返回,若没有释放按键,则返回继续释放。其流程图如图5.1所示。

图5.1 键扫程序流程图

5.4 算术运算程序设计

算术运算程序的过程为:先判断输入的运算符是+、-、*、/ 中的哪一个,若是+或-,则要判断运算结果是否溢出,溢出则显示错误信息,没溢出就显示运算结果,若是/,则要先判断除数是否为零,为零就显示错误信息,不为零则显示运算结果,若是-,则直接显示运算结果。其流程图如图5.2所示。


图5.2 算术运算程序设计流程图
5.5 显示程序设计

显示程序的过程为:显示开始时,先进行LCD的初始化,判断是否显示汉字或ACSII码或图形,若不显示,则返回,若显示的是汉字或ACSII码,则进行相应功能的设置,然后送地址和数据,再判断是否显示完,显示完则返回,没有显示完则继续送地址,若显示的是图形,则先进行相应功能的设置,再送行地址和列地址,然后送数据,最后判断是否显示完,显示完则返回,没有显示完则继续送行地址和列地址。其流程图如图5.3所示。


图5.3 显示程序流程图
6 系统调试与存在的问题6.1 硬件调试

常见故障:

1、逻辑错误:它是由设计错误或加工过程中的工艺性错误所造成的。这类错误包括错线、开路、短路等。

2、元器件失效:有两方面的原因:一是器件本身已损坏或性能不符合要求;二是组装错误造成元件失效,如电解电容、集成电路安装方向错误等。

3、可靠性差:因其可靠性差的原因很多,如金属化孔、接插件接触不良会造成系统时好时坏,经不起振动;走线和布局不合理也会引起系统可靠性差。

4、电源故障:若样机由电源故障,则加电后很容易造成器件损坏。电源故障包括电压值不符合设计要求,电源引线和插座不对,功率不足,负载能力差等。

调试方法:包括多级调试和联机调试。在调试过程中要针对可能出现的故障认真分析,直至检查出原因并排除。

本次硬件调试过程中,对所出现的问题进行了认真的分析和改正,最后能够很好的达到设计要求的效果。

6.2 软件调试

软件调试一般分为以下四个阶段:1、 编写程序并查错;2、在C语言的编译系统中编译源程序3、对程序进行编译连接,并及时发现程序中存在的错误;4、改正错误。

在本次调试中出现的问题有:

1、在程序中有的函数名未定义;

2、在抄录程序时,少录入一些字符,如:“;”、“{”、“-”等符号,而出现错误;

3、有一些函数名录入时少写一个字母或顺序颠倒;

4、没有注意函数名的调用及定义;

5、芯片引脚定义出错而导致没有实验现象。

在软件调试过程中,对出现的错误进行了认真的分析和修改,多次调试成功后,能够很好的达到既定的设计效果。


附录附录一:仿真原理图


单片机源程序如下:
  1. ----------------------------------*/
  2. |  1  |  2  |  3  |  +  |
  3. - - - - - - - - - - - - -
  4. |  4  |  5  |  6  |  -  |
  5. - - - - - - - - - - - - -
  6. |  7  |  8  |  9  |  *  |
  7. - - - - - - - - - - - - -
  8. | C   |  0  |  =  |  /  |
  9. ----------------------------------*/
  10. 只能实现基本加减运算,无法实现小数运算。
  11. // 加最大9999+9999=19998
  12. // 减最大9999-0   =9999
  13. // 乘最大9999*9999=99980001
  14. // 除 1/9=0.1111 保留小数点后4位
  15. #include<reg51.h>
  16. #define uint unsigned int
  17. #define uchar unsigned char
  18. //--------LCD1602-------------------
  19. //P10-17==== D0-7
  20. sbit rs=P3^0;                         //指令or数据
  21. sbit wela=P3^1;                       //读or写
  22. sbit lcden=P3^2;                                 //使能信号
  23. //--------LCD1602-------------------
  24. //--------KEY-----------------------
  25. //P2口
  26. //--------KEY-----------------------
  27. uchar code table[]= "                ";

  28. long  int data_a,data_b;                           //第一个数和第二个数
  29. long  int data_c;                                                      //计算结果

  30. uchar dispaly[10];                    //显示缓冲

  31. // 描述: 延时t us函数
  32. void LCD_Delay_us(unsigned int t)
  33. {
  34.               while(t--);                         //t=0,退出
  35. }
  36. // 描述: 延时t ms函数
  37. void LCD_Delay_ms(unsigned int t)
  38. {
  39.               unsigned int i,j;
  40.               for(i=0;i<t;i++)                                               //执行t次循环
  41.               for(j=0;j<113;j++)                                             //执行113次循环
  42.               ;
  43. }
  44. // 描述: 1602液晶写指令
  45. void write_com(uchar com)                              //1602液晶写指令
  46. {
  47.               rs=0;                               //写指令
  48.               lcden=0;                            //使能1602
  49.               P1=com;                             //写入指令com
  50.               LCD_Delay_ms(1);                     //延时1ms
  51.               lcden=1;                             //使能1602
  52.               LCD_Delay_ms(2);                    //延时2ms
  53.               lcden=0;                                          //使能1602
  54. }
  55. // 描述:1602液晶写数据
  56. void write_date(uchar date)                 //1602液晶写数据
  57. {
  58.               rs=1;                                //写数据
  59.               lcden=0;                             //使能1602
  60.               P1=date;                              //写入数据date
  61.               LCD_Delay_ms(1);                      //延时1ms
  62.               lcden=1;                         //使能1602
  63.               LCD_Delay_ms(2);                //延时2ms
  64.               lcden=0;                                      //使能1602
  65. }
  66. // 描述:指定x,y写入字符函数
  67. void W_lcd(unsigned char x,unsigned char y,unsigned char Data)
  68. {   
  69.               if (y == 0){write_com(0x80 + x);}      //第一行
  70.               else{write_com(0xc0 + x);}           //第二行
  71.               write_date( Data);                   //写入数据
  72. }
  73. //指定x,y写入字符串函数
  74. void LCD_Write_String(unsigned char x,unsigned char y,unsigned char *s)
  75. {   
  76. if (y == 0){write_com(0x80 + x);}                                //第一行
  77. else{write_com(0xC0 + x);}                                       //第二行
  78. while (*s)                                    
  79.               {write_date( *s); s++;}                                     //写入数据
  80. }
  81. // 描述:初始化液晶,及画面初始化
  82. void init_lcd(void)                        //初始化液晶,及画面初始化
  83. {
  84.               wela=0;                            //写液晶
  85.               lcden=0;                           //使能1602
  86.               write_com(0x38);                   //8 位总线,双行显示,5X7 的点阵字符
  87.               LCD_Delay_us(100);                //延时100us
  88.               write_com(0x0c);                    //开显示,无光标,光标不闪烁
  89.               write_com(0x06);                    //光标右移动
  90.               write_com(0x01);                     //清屏
  91.               write_com(0x80);                      //DDRAM 地址归0
  92. }
  93. // 描述: 反转法键盘扫描
  94. short keycheckdown()                                                               /* 反转法键盘扫描 */
  95. {

  96.               short temp1,temp2,temp,a=0xff;
  97.               P2=0xf0;                                                                                /* 输入行值(或列值) */
  98.               LCD_Delay_ms(20);                                                           /* 延时 */
  99.               temp1=P2;                                                                                        /* 读列值(或行值) */
  100.               P2=0xff;
  101.               LCD_Delay_ms(20);                                                            /* 延时 */
  102.               P2=0x0f;                                                                                          /* 输入列值(或行值) */
  103.               LCD_Delay_ms(20);                                                           /* 延时 */            
  104.               temp2=P2;                                                                                       /* 读行值(或列值) */
  105.               P2=0xff;
  106.               temp=(temp1&0xf0)|(temp2&0xf);                /* 将两次读入数据组合 */
  107.               switch(temp)                                                                          /* 通过读入数据组合判断按键位置 */
  108.               {


  109.                             case 0x77 :a=0x0d;break;            //  按键/  
  110.                             case 0x7b :a=0x0e; break;           // 按键=            
  111.                             case 0x7d :a=0;                 break;        / / 按键0
  112.                             case 0x7e :a=0x0f; break;            // 按键CE

  113.                             case 0xb7 :a=0x0c;break;            //               按键*
  114.                             case 0xbb :a=0x9;break;            //  按键9
  115.                             case 0xbd :a=0x8;break;               //  按键8
  116.                             case 0xbe :a=0x7;break;             //               按键7

  117.                             case 0xd7 :a=0x0b;break;            //  按键-
  118.                             case 0xdb :a=0x6;break;              //               按键6
  119.                             case 0xdd :a=0x5;break;              //               按键5
  120.                             case 0xde :a=0x4;break;              //               按键4

  121.                             case 0xe7 :a=0x0a; break;             // 按键+
  122.                             case 0xeb :a=3;break;                            //  按键3
  123.                             case 0xed :a=2;break;                            //  按键2
  124.                             case 0xee :a=1;break;                           //  按键1

  125.                             default :a=0xff;
  126.               }
  127.               return a;                                                                                              /* 返回按键值 */
  128. }
  129. void display_a() //显示数据a
  130. {
  131.               dispaly[3]=data_a%10000/1000;              //千
  132.               dispaly[2]=data_a%1000/100;                   //百
  133.               dispaly[1]=data_a%100/10;                    //十
  134.               dispaly[0]=data_a%10;                       //个

  135.               write_com(0x80+0);                            //显示数据a
  136.               if(data_a>999){              write_date('0'+dispaly[3]);}      //显示千位
  137.               if(data_a>99){              write_date('0'+dispaly[2]);}                            //显示百位
  138.               if(data_a>9){              write_date('0'+dispaly[1]);}     //显示十位
  139.                                           write_date('0'+dispaly[0]);      //显示个位
  140. }

  141. void display_b()                             //显示数据b
  142. {
  143.               write_com(0x80+7);                     //第一行
  144.               dispaly[3]=data_b%10000/1000;               //千
  145.               dispaly[2]=data_b%1000/100;                //百
  146.               dispaly[1]=data_b%100/10;                 //十
  147.               dispaly[0]=data_b%10;                          //个

  148. if(data_b>999){              write_date('0'+dispaly[3]); }     //显示千位  
  149. if(data_b>99) {              write_date('0'+dispaly[2]); }    //显示百位
  150. if(data_b>9)  {              write_date('0'+dispaly[1]); }     //显示十位
  151.                                                 write_date('0'+dispaly[0]);      //显示个位
  152. }

  153. //计算结果
  154. void display_c(x)
  155. {

  156.               if(data_c<100000000&&data_c>-1)           //溢出时显示错误
  157.               {            

  158.                             dispaly[8]=data_c%1000000000/100000000;                  //万万
  159.                             dispaly[7]=data_c%100000000/10000000;                  //千万
  160.                             dispaly[6]=data_c%10000000/1000000;                                //百万
  161.                             dispaly[5]=data_c%1000000/100000;                                //十万
  162.                             dispaly[4]=data_c%100000/10000;                                              //万
  163.                             dispaly[3]=data_c%10000/1000;                                              //千
  164.                             dispaly[2]=data_c%1000/100;                                                //百
  165.                             dispaly[1]=data_c%100/10;                                                  //十
  166.                             dispaly[0]=data_c%10;                                                      //个
  167.                             write_com(0x80+6+0x40);                  //第一行
  168.                             if(x==4)
  169.                             {   
  170.                             if(data_c>99999999)              {              write_date('0'+dispaly[8]);}    //显示万万
  171.                             if(data_c>9999999)              {              write_date('0'+dispaly[7]);}   //千万
  172.                             if(data_c>999999)              {              write_date('0'+dispaly[6]);}    //百万
  173.                             if(data_c>99999)              {              write_date('0'+dispaly[5]);}    //十万
  174.                                                                                                                 write_date('0'+dispaly[4]);    //万
  175.                                                                                                                 write_date('.');
  176.                                                                                                                 write_date('0'+dispaly[3]);    //千
  177.                                                                                                                 write_date('0'+dispaly[2]);    //百
  178.                                                                                                                 write_date('0'+dispaly[1]);    //十
  179.                                                                                                                 write_date('0'+dispaly[0]);    //个
  180.                             }
  181.               else{
  182.                             if(data_c>99999999)              {              write_date('0'+dispaly[8]);}    //显示万万
  183.                             if(data_c>9999999)              {              write_date('0'+dispaly[7]);}    //千万
  184.                             if(data_c>999999)              {              write_date('0'+dispaly[6]);}    //百万
  185.                             if(data_c>99999)              {              write_date('0'+dispaly[5]);}    //十万
  186.                             if(data_c>9999)                            {              write_date('0'+dispaly[4]);}    //万
  187.                             if(data_c>999)                            {              write_date('0'+dispaly[3]);}    //千
  188.                             if(data_c>99)                            {              write_date('0'+dispaly[2]);}    //百
  189.                             if(data_c>9)                            {              write_date('0'+dispaly[1]);}    //十
  190.                                                                                                                 write_date('0'+dispaly[0]);    //个
  191.                             }
  192.               }
  193.               else                                               //溢出时显示错误
  194.               {
  195.                             write_com(0x80+11+0x40); //第一行
  196.                             write_date('E');         //显示 E
  197.                             write_date('r');         //显示R
  198.                             write_date('r');                            //显示R
  199.                             write_date('o');                            //显示O
  200.                             write_date('r');                            //显示E
  201.               }
  202. }

  203. void eql(uchar x)//加减乘除运算
  204. {
  205.               switch(x)                            /*功能键选择*/
  206.                                           {  
  207.                                                         case 1:data_c=data_a+data_b;break;                               //加  /* + S=1 */ /* 数值转换函数 */                                                                                                                             
  208.                                                         case 2:if(data_a>=data_b){data_c=data_a-data_b;} /* - S=2 *///减
  209.                        else{data_c=data_b-data_a;W_lcd(5,1,'-');} //负数符号
  210.                                                                          break;               
  211.                                                         case 3:data_c=(data_a*data_b);break;                              /* * S=3 *///乘
  212.                                                         case 4:if(data_b==0){LCD_Write_String(0,1,"Error !");}else{data_c=(data_a*10000)/data_b;}break;                              /* / S=4       *///除//溢出时显示错误
  213.                                                         case 0:break;
  214.                                           }               
  215. }
  216. void main()
  217. {
  218.               uchar   key=0xff;               //键值初始化
  219.               uchar   n=0;                                                                      //第1个数可以按1-4次
  220.               uchar   m=5;                                                                       //第2个数可以按1-4次
  221.               uchar   x=0;
  222.               data_a=0;                       //前一个数
  223.               data_b=0;                       //后一个数
  224.               data_c=0;                       //结果
  225.               init_lcd();                                                                        //1602液晶初始化
  226.               display_a();
  227.     while(1)
  228.                 {
  229.                               key=keycheckdown();                                          /*动态扫描键盘,返回按键对应值,赋给j        key=0到f */
  230.                             if(0xff!=key)                                                        /*若返回值有效,进入内部处理程序*/
  231.                             {
  232.                               if(key<10)
  233.                               {
  234.                       if(n<4){data_a=data_a*10+key;m=5;display_a();}n++;  //首先输入第一个数
  235.                                 if(m<4){data_b=data_b*10+key;n=5;display_b();}m++;  //必须按了+-*/才能输入第二个数                           
  236.                               }
  237.           else
  238.           {              switch(key)                            /*功能键选择*/
  239.                                                                       {
  240.                                                                                     case 0xa:n=5;m=0;x=1;W_lcd(5,0,'+');break; //加  /* + S=1 */ /* 数值转换函数 */                                                                                                                             
  241.                                                                                     case 0xb:n=5;m=0;x=2;W_lcd(5,0,'-');break;                              /* - S=2 *///减
  242.                                                                                     case 0xc:n=5;m=0;x=3;W_lcd(5,0,'*');break;                              /* * S=3 *///乘
  243.                                                                                     case 0xd:n=5;m=0;x=4;W_lcd(5,0,'/');break;                              /* / S=4 *///除
  244.                                                                                     case 0xe:n=5;m=5;eql(x);W_lcd(12,0,'=');display_c(x);break;                 /* = */
  245.                                                                                     case 0xf:n=0;x=0;m=5; data_a=0;data_b=0;data_c=0;LCD_Write_String(0,0,table);LCD_Write_String(0,1,table);W_lcd(0,0,'0');break; /*     C*/
  246.                                                                       }                                             
  247.                               }
  248.                                           do{P2=0xf0;}while(P2!=0xf0);                            /*等待按键松开*/
  249.                               }//(0xff!=key)               
  250. ……………………

  251. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码

所有资料51hei提供下载:
单片机简单计算器.doc (292 KB, 下载次数: 69)


评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

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

使用道具 举报

沙发
ID:485799 发表于 2019-7-5 11:59 | 只看该作者
请问184行的if语句x=4是什么效果,我没看懂,溢出时的error显示好像也不大对
回复

使用道具 举报

板凳
ID:649892 发表于 2019-11-26 14:06 | 只看该作者
有没有原理图啊
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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