找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4067|回复: 0
收起左侧

单片机的简易计算器课程设计报告书

[复制链接]
ID:272736 发表于 2018-1-7 14:58 | 显示全部楼层 |阅读模式
课程设计报告书

课程名称:
题    目:
系 (院):电子工程学院自动化
学    期:2016-2017第一学期
专业班级:自动化141
姓    名:*
学    号:2014121036

评语:
成绩:
签名:
日期:

[摘要] 近几年单片机技术的发展很快,其中电子产品的更新速度迅猛。计算器是日常生活中比较的常见的电子产品之一。如何才能使计算器技术更加的成熟,充分利用已有的软件和硬件条件,设计出更出色的计算器呢。

本设计是以AT89C52单片机为核心的计算器模拟系统设计。矩阵按键输入、LCD1602液晶显

示,构成一套可以运算两个数之间的加减乘除的设计。最大运算是:9999*9999,可以运算负数。

科技的进步告别了以前复杂的模拟电路,一块几厘米平方的单片机可以省去很多繁琐的电路。现在应用较广泛的是科学计算器,与我们日常所用的简单计算器有较大差别,除了能进行加减乘除,科学计算器还可以进行正数的四则运算和乘方、开方运算,具有指数、对数、三角函数、反三角函数及存储等计算功能。计算器的未来是小型化和轻便化,现在市面上出现的使用太阳能电池的计算器,使用ASIC设计的计算器,如使用纯软件实现的计算器等,未来的智能化计算器将是我们的发展方向,更希望成为应用广泛的计算工具。


目录

第一章 前言
1.1 系统开发背景
1.2 系统开发意义
1.3 设计目的
第二章 方案论证
2.1 方案构思
2.2  方案比较与选择
第三章 系统硬件设计及说明
3.1系统组成及总体框图
3.2元件简介
3.2.1 AT89C52特点
3.2.2 LCD1602液晶显示屏
第四章 设计原理分析
4.1  设计方案的确定
4.2计算器硬件方案及硬件资源分配
4.2.1 硬件资源分配
4.2.2 系统的硬件设计
4.2.3 键盘电路的设计
4.2.4 显示电路的设计
第五章 计算器的软件设计
5.1计算器的软件规划
5.2 汇编语言和C语言的特点及选择
5.3 按键键扫描程序设计
5.4 算术运算程序设计
5.5 显示程序设计
第六章 系统调试与存在的问题
6.1 硬件调试
6.2 软件调试
结束语
致谢
参考文献
附录
附录一:硬件实物图
附录二:系统程序清单


第一章 前言
1.1 系统开发背景
随着社会的发展,科学的进步,人们的生活水平在逐步的提高,尤其是微电子技术的发展,犹如雨后春笋般的变化。电子产品的更新速度快就不足惊奇了。计算器在人们的日常中是比较的常见的电子产品之一。如何使计算器技术更加的成熟,充分利用已有的软件和硬件条件,设计出更出色的计算器,使其更好的为各个行业服务,成了如今电子领域重要的研究课题。
1.2 系统开发意义
今天,人们的日常生活中已经离不开计算器了,社会的各个角落都有它的身影,比如商店,办公室,学校……。因此设计一款简单实用的计算器会有很大的实际意义。
1.3 设计目的
本设计旨在进一步掌握单片机理论知识,理解嵌入式单片机系统的硬软件设计,加强对实际应用系统设计的能力。通过本设计的学习,使我掌握单片机程序设计和微机接口应用的基本方法,并能综合运用本科阶段所学软、硬件知识分析实际问题,提高解决毕业设计实际问题的能力,为单片机应用和开发打下良好的基础。
1、对字符液晶显示模块的工作原理,如初始化、清屏、显示、调用及外特性有较清楚的认识,并会使用LCD(液晶显示模块)实现计算结果的显示;掌握液晶显示模块的驱动和编程,设计LCD和单片机的接口电路,以及利用单片机对液晶模块的驱动和操作;
2、在充分分析内部逻辑的概念,进行软件和调试,学会使用,并能够以其为平台设计出具有四则运算能力简易计算器的硬件电路和软件程序。

第二章 方案论证

2.1 方案构思
本设计可以采用两种方案,一种是以FPGA为核心处理芯片,配备相应的外设;另外一种是以AT89S52处理器,配备相应的外设。
1、方案一:采用FPGA控制
FPGA是一种高密度的可编程逻辑器件,自从Xilinx公司1985年推出第一片FPGA以来,FPGA的集成密度和性能提高很快,其集成密度最高达500万门/片以上,系统性能可达200MHz。由于FPGA器件集成度高,方便易用,开发和上市周期短,在数字设计和电子生产中得到迅速普及和应用,并一度在高密度的可编程逻辑器件领域中独占鳌头。
但是而基于 SRAM编程的FPGA,其编程信息需存放在外部存储器上 ,需外部存储器芯片 ,且使用方法复杂 ,保密性差,而其对于一个简单的计算器而言,实用FPGA有点大材小用,成本太高。
2、方案二:采用AT89S52
单片机是单片微型机的简称,故又称为微控制器MCU(Micro Control Unit)。通常由单块集成电路芯片组成,内部包含有计算机的基本功能部件:中央处理器CPU,存储器和I/O接口电路等。因此,单片机只要和适当的软件及外部设备相结合,便可成为一个单片机控制系统。单片机广泛用于智能产品,智能仪表,测控技术,智能接口等,具有操作简单,实用方便,价格便宜等优点,而其中AT89S52以MCS-51为内核,是单片机中最典型的代表,应用于各种控制领域。

2.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.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.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.1 硬件调试

常见故障:

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

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

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

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

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

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

6.2 软件调试

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

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

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

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

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

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

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

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



结束语

在硬件的制作过程中我走了好多的弯路,主要是在系统还没有设计很有把握就开始动手制作了。后来发现与设计的要求还有偏差,反复的改过了几次,浪费了大量的时间和体力。感受到设计人员要有耐心,要认真的从要求开始研究。软件的编写过程中费了很大的力气,因为软件的编写要求很高,要很细心,一不小心就会调用错误,很深刻的体会到作为软件编程人员是绝不能粗心大意的。一个程序的完成的速度和质量高低与细心与否有着很大联系。编程时,我充分使用了结构化的思想。这样因为语句较少,程序调试比较方便,功能模块可以逐一的调试,充分体现了结构化编程的优势。当每个模块都完成时,将其功能加到一起就完成了整体的设计。


致谢
本次毕业设计得到导师XXX老师的热心指导,在这里对X老师表示最衷心的感谢。X老师平易近人,对学生的设计进度和学习很关心。在毕业设计的前期,首先给我们介绍了不少有用的资料和书籍;在硬件设计等方面给予悉心的指导;在调试的过程中X老师给每个出现的问题给予及时的指导。在写毕业设计论文的阶段,X老师让我们提前给他评审,不论内容字体,还是格式上的问题都一一指出。待人平和、工作认真、治学严谨他的给我留下很深刻的印象。更重要的是,他善于与学生沟通,不仅在毕业设计上给我及时的指导,更为我大学最后阶段的学习提出了许多宝贵的意见。这一切都在潜移默化地影响着我,为我以后进入工作岗位树立了良好的榜样。
同时还要感谢XXX老师,她关心同学们的进程,了解同学们在撰写过程中的麻烦,给我们提供很多帮助。
最后向所有帮助和关心过我的人表示衷心感谢!

参考文献

【1】张靖武,周灵杉.单片机系统的PROTEUS设计与仿真[M].北京:北京电子工业出版社
【2】靳达.求是科技.单片机应用系统开发实例导航[M].:人民邮电出版社,2006
【3】刘守义. 单片机应用技术[M].:西安电子科技大学出版社,2001
【4】林志琦.基于PROTEUS的单片机可视化软硬件仿真[M].北京:北京航空航天大学出版社,2006
【5】胡汉才.单片机原理及接口技术.清华大学出版社,1996
【6】徐江海.单片机实用教程[M].北京:机械工业出版社,2007.
【7】肖洪兵. 跟我学用单片机. 北京:北京航空航天大学出版社,2002.8
【8】夏继强. 单片机实验与实践教程. 北京:北京航空航天大学出版社, 2001
【9】谭浩强. C语言程序设计[M].北京:清华大学出版社,2000.
【10】刘福基. C语言程序设计与实训教程[M].北京:科学出版社,2004.
【11】张磊. C语言程序设计[M].北京:高等教育出版社,2005.
【12】严桂兰. C语言程序设计[M].厦门:厦门大学出版社,2006


附录附录一:硬件实物图
硬件实物图(正面)
自己拍自己的实物照片
硬件实物图(背面)
附录二:系统程序清单

单片机源程序如下:

  1. /*
  2. 接盘按键说明:
  3. --------------------------------------------------
  4.    - - - - - - - - - - - -- - - - - - -
  5.   |              1602液晶               |
  6.   |                                     |
  7.    - - - - - - - - - - -- - - - - - - -
  8.             - - - - - - - - - - - - -
  9.                                           |      89s52             |  
  10.             - - - - - - - - - - - - -

  11.             |  1  |  2  |  3  |  +  |
  12.             - - - - - - - - - - - - -
  13.             |  4  |  5  |  6  |  -  |
  14.             - - - - - - - - - - - - -
  15.             |  7  |  8  |  9  |  *  |
  16.             - - - - - - - - - - - - -
  17.                                           | C   |  0  |  =  |  /  |
  18. --------------------------------------------------*/
  19. //操作简介
  20. // 按第一个数,再按'+-*/',再按'='显示出结果,然后按C清屏
  21. // 加最大9999+9999=19998
  22. // 减最大9999-0   =9999
  23. // 乘最大9999*9999=99980001
  24. // 除 1/9=0.1111 保留小数点后4位
  25. #include<reg51.h>
  26. #define uint unsigned int
  27. #define uchar unsigned char
  28. //--------LCD1602-------------------
  29. //P10-17==== D0-7
  30. sbit rs=P3^0;        //指令or数据
  31. sbit wela=P3^1;      //读or写
  32. sbit lcden=P3^2;              //使能信号
  33. //--------LCD1602-------------------
  34. //--------KEY-----------------------
  35. //P2口
  36. //--------KEY-----------------------
  37. uchar code table[]= "                ";

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

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

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

  120.               short temp1,temp2,temp,a=0xff;
  121.               P2=0xf0;                                                                                    /* 输入行值(或列值) */
  122.               LCD_Delay_ms(20);                                                        /* 延时 */
  123.               temp1=P2;                                                                                    /* 读列值(或行值) */
  124.               P2=0xff;
  125.               LCD_Delay_ms(20);                                                        /* 延时 */
  126.               P2=0x0f;                                                                                    /* 输入列值(或行值) */
  127.               LCD_Delay_ms(20);                                                        /* 延时 */            
  128.               temp2=P2;                                                                                    /* 读行值(或列值) */
  129.               P2=0xff;
  130.               temp=(temp1&0xf0)|(temp2&0xf);              /* 将两次读入数据组合 */
  131.               switch(temp)                                                                      /* 通过读入数据组合判断按键位置 */
  132.               {


  133.                             case 0x77 :a=0x0d;break;//  按键/  
  134.                             case 0x7b :a=0x0e; break;// 按键=            
  135.                             case 0x7d :a=0;                 break;// 按键0
  136.                             case 0x7e :a=0x0f; break;// 按键CE

  137.                             case 0xb7 :a=0x0c;break;//               按键*
  138.                             case 0xbb :a=0x9;break; //  按键9
  139.                             case 0xbd :a=0x8;break; //  按键8
  140.                             case 0xbe :a=0x7;break; //               按键7

  141.                             case 0xd7 :a=0x0b;break;//  按键-
  142.                             case 0xdb :a=0x6;break; //               按键6
  143.                             case 0xdd :a=0x5;break; //               按键5
  144.                             case 0xde :a=0x4;break; //               按键4

  145.                             case 0xe7 :a=0x0a; break;// 按键+
  146.                             case 0xeb :a=3;break;              //  按键3
  147.                             case 0xed :a=2;break;              //  按键2
  148.                             case 0xee :a=1;break;              //  按键1

  149.                             default :a=0xff;
  150.               }
  151.               return a;                                                                                    /* 返回按键值 */
  152. }
  153. void display_a() //显示数据a
  154. {
  155.               dispaly[3]=data_a%10000/1000;    //千
  156.               dispaly[2]=data_a%1000/100;      //百
  157.               dispaly[1]=data_a%100/10;        //十
  158.               dispaly[0]=data_a%10;            //个

  159.               write_com(0x80+0);               //显示数据a
  160.               if(data_a>999){              write_date('0'+dispaly[3]);}      //显示千位
  161.               if(data_a>99){              write_date('0'+dispaly[2]);}                            //显示百位
  162.               if(data_a>9){              write_date('0'+dispaly[1]);}     //显示十位
  163.                                           write_date('0'+dispaly[0]);      //显示个位
  164. }

  165. void display_b() //显示数据b
  166. {
  167.               write_com(0x80+7); //第一行
  168.               dispaly[3]=data_b%10000/1000;    //千
  169.               dispaly[2]=data_b%1000/100;      //百
  170.               dispaly[1]=data_b%100/10;        //十
  171.               dispaly[0]=data_b%10;            //个

  172. if(data_b>999){              write_date('0'+dispaly[3]); }     //显示千位  
  173. if(data_b>99) {              write_date('0'+dispaly[2]); }    //显示百位
  174. if(data_b>9)  {              write_date('0'+dispaly[1]); }     //显示十位
  175.                                                 write_date('0'+dispaly[0]);      //显示个位
  176. }

  177. //计算结果
  178. void display_c(x)
  179. {

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

  182.                             dispaly[8]=data_c%1000000000/100000000;                  //万万
  183.                             dispaly[7]=data_c%100000000/10000000;                  //千万
  184.                             dispaly[6]=data_c%10000000/1000000;                                //百万
  185.                             dispaly[5]=data_c%1000000/100000;                                //十万
  186.                             dispaly[4]=data_c%100000/10000;                                              //万
  187.                             dispaly[3]=data_c%10000/1000;                                              //千
  188.                             dispaly[2]=data_c%1000/100;                                                //百
  189.                             dispaly[1]=data_c%100/10;                                                  //十
  190.                             dispaly[0]=data_c%10;                                                      //个
  191.                             write_com(0x80+6+0x40); //第一行
  192.                             if(x==4)
  193.                             {   
  194.                             if(data_c>99999999)              {              write_date('0'+dispaly[8]);}    //显示万万
  195.                             if(data_c>9999999)              {              write_date('0'+dispaly[7]);}   //千万
  196.                             if(data_c>999999)              {              write_date('0'+dispaly[6]);}    //百万
  197.                             if(data_c>99999)              {              write_date('0'+dispaly[5]);}    //十万
  198.                                                                                                                 write_date('0'+dispaly[4]);    //万
  199.                                                                                                                 write_date('.');
  200.                                                                                                                 write_date('0'+dispaly[3]);    //千
  201.                                                                                                                 write_date('0'+dispaly[2]);    //百
  202.                                                                                                                 write_date('0'+dispaly[1]);    //十
  203.                                                                                                                 write_date('0'+dispaly[0]);    //个
  204.                             }
  205.               else{
  206.                             if(data_c>99999999)              {              write_date('0'+dispaly[8]);}    //显示万万
  207.                             if(data_c>9999999)              {              write_date('0'+dispaly[7]);}    //千万
  208.                             if(data_c>999999)              {              write_date('0'+dispaly[6]);}    //百万
  209.                             if(data_c>99999)              {              write_date('0'+dispaly[5]);}    //十万
  210.                             if(data_c>9999)                            {              write_date('0'+dispaly[4]);}    //万
  211.                             if(data_c>999)                            {              write_date('0'+dispaly[3]);}    //千
  212.                             if(data_c>99)                            {              write_date('0'+dispaly[2]);}    //百
  213.                             if(data_c>9)                            {              write_date('0'+dispaly[1]);}    //十
  214.                                                                                                                 write_date('0'+dispaly[0]);    //个
  215.                             }
  216.               }
  217.               else  //溢出时显示错误
  218.               {
  219.                             write_com(0x80+11+0x40); //第一行
  220.                             write_date('E');         //显示 E
  221.                             write_date('r');         //显示R
  222.                             write_date('r');                            //显示R
  223.                             write_date('o');                            //显示O
  224.                             write_date('r');                            //显示E
  225.               }
  226. }

  227. void eql(uchar x)//加减乘除运算
  228. {
  229.               switch(x)                            /*功能键选择*/
  230.                                           {  
  231.                                                         case 1:data_c=data_a+data_b;break;                               //加  /* + S=1 */ /* 数值转换函数 */                                                                                                                             
  232.                                                         case 2:if(data_a>=data_b){data_c=data_a-data_b;} /* - S=2 *///减
  233.                        else{data_c=data_b-data_a;W_lcd(5,1,'-');} //负数符号
  234.                                                                          break;               
  235.                                                         case 3:data_c=(data_a*data_b);break;                              /* * S=3 *///乘
  236.                                                         case 4:if(data_b==0){LCD_Write_String(0,1,"Error !");}else{data_c=(data_a*10000)/data_b;}break;                              /* / S=4 *///除//溢出时显示错误
  237.                                                         case 0:break;
  238.                                           }               

  239. }

  240. void main()
  241. {
  242.               uchar   key=0xff;               //键值初始化
  243.               uchar   n=0;                                                                      //第1个数可以按1-4次
  244.               uchar   m=5;                                                                       //第2个数可以按1-4次
  245. ……………………

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

所有资料51hei提供下载:
2017年27-单片机的简易计算器设计.doc (526.87 KB, 下载次数: 30)
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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