题 目:基于单片机简易计算器的设计
院 (系):信息与通信学院
专 业: 电子信息工程
摘 要
简易计算器是一种非常广泛日常工具,对现代社会越来越流行。它可以进行一些简易的计算。本系统提供详细的时、分、秒、年、月、日的时间信息,同时还可进行简易的计算信息,还具有时间校准等功能。该电路采用AT89S52单片机作为核心,功耗小,能在3V的低压工作,电压可选用3~5V电压供电。本系统硬件部分由AT89S52单片机、LCD1602液晶屏、键盘、指示灯系统等部分构成。软件部分在keil环境下用C51语言编写,包括时间设置、时间显示、简易计算显示等。
目录
摘要1
引言 3
1 单片机及其应用3
11单片机介绍3
12单片机的应用4
13 AT89S52单片机4
2 液晶屏LCD1602原理及应用 7
21液晶屏LCD1602介绍及工作原理 7
22 液晶屏LCD1602的功能及应用7
3 设计思路、仿真及调试12
31设计方法12
32硬件设计 12
321按键调整电路12
322复位电路13
323 液晶屏LCD1602显示电路13
324 LED指示电路13
325 4*4键盘的设计14
326 简易计算器的总电路14
33软件设计 15
34软件仿真15
35硬件调试16
4 结束语 17
谢辞18
参考文献19
附件20
引言 众所周知单片机是一种集成在电路芯片,是采用超大规模集成电路技术把具有数据处理能力的中央处理器CPU随机存储器RAM、只读存储器ROM、多种I/O口和中断系统、定时器/计时器等功能(可能还包括显示驱动电路、脉宽调制电路、模拟多路转换器、A/D转换器等电路)集成到一块硅片上构成的一个小而完善的计算机系统。本设计要制作的就是单片机于生活中最为常见的异种应用——简易计算器。本简易计算器AT89S52单片机作为核心,可以显示简易的计算和时间,时间可以人为设定;另外还可以显示当前的日历,显示格式为年(四位),月(两位),日(两位)。设置时间时的位切换、设定数值、启动定时器、切换日历通过外部中断来实现。简易计算器不仅可以进行简易的计算还可以显示时间。简易计算器显示电路由LCD1602组成, 制作一个单片机计时装置需要的材料需要有软硬件的支持,硬件方面AT89C51单片机,晶振,电源,液晶屏LCD1602。 单片机是一种集成在电路芯片,是采用超大规模集成电路技术把具有数据处理能力的中央处理器CPU随机存储器RAM、只读存储器ROM、多种I/O口和中断系统、定时器/计时器等功能(可能还包括显示驱动电路、脉宽调制电路、模拟多路转换器、A/D转换器等电路)集成到一块硅片上构成的一个小而完善的计算机系统。
1.1 单片机介绍: 单片微型计算机简称单片机,是典型的嵌入式微控制器(Microcontroller Unit),常用英文字母的缩写MCU表示单片机,它最早是被用在工业控制领域。单片机由芯片内仅有CPU的专用处理器发展而来。最早的设计理念是通过将大量外围设备和CPU集成在一个芯片中,使计算机系统更小,更容易集成进复杂的而对体积要求严格的控制设备当中。INTEL的Z80是最早按照这种思想设计出的处理器,从此以后,单片机和专用处理器的发展便分道扬镳 单片机是靠程序运行的,并且可以修改。通过不同的程序实现不同的功能,尤其是特殊的独特的一些功能,这是别的器件需要费很大力气才能做到的,有些则是花大力气也很难做到的。一个不是很复杂的功能要是用美国50年代开发的74系列,或者60年代的CD4000系列这些纯硬件来搞定的话,电路一定是一块大PCB板!但是如果要是用美国70年代成功投放市场的系列单片机,结果就会有天壤之别!只因为单片机的通过你编写的程序可以实现高智能,高效率,以及高可靠性! 单片机的硬件特性:单片机集成度高。单片机包括CPU、4KB容量的ROM(8031 无)、128 B容量的RAM、 2个16位定时/计数器、4个8位并行口、全双工串口行口。系统结构简单,使用方便,实现模块化。
1.2 单片机的应用 目前单片机渗透到我们生活的各个领域,几乎很难找到哪个领域没有单片机的踪迹。导弹的导航装置,飞机上各种仪表的控制,计算机的网络通讯与数据传输,工业自动化过程的实时控制和数据处理,广泛使用的各种智能IC卡,民用豪华轿车的安全保障系统,录像机、摄像机、全自动洗衣机的控制,以及程控玩具、电子宠物等等,这些都离不开单片机。更不用说自动控制领域的机器人、智能仪表、医疗器械了。因此,单片机的学习、开发与应用将造就一批计算机应用与智能化控制的科学家、工程师。单片机广泛应用于仪器仪表、家用电器、医用设备、航空航天、专用设备的智能化管理及过程控制等领域,大致可分如下几个范畴: (1)在智能仪器仪表上的应用 (2)在工业控制中的应用 (3)在家用电器中的应用 (4)在计算机网络和通信领域中的应用 (5)单片机在医用设备领域中的应用 (6)在各种大型电器中的模块化应用 (7)单片机在汽车设备领域中的应用 此外,单片机在工商,金融,科研、教育,国防航空航天等领域都有着十分广泛的用途。
1.3 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内容被保存,振荡器被冻结,单片机一切工作停止,直到下一个中断或硬件复位为止。 主要性能 1、与MCS-51单片机产品兼容 2 、8K字节在系统可编程Flash存储器 3 、1000次擦写周期 4 、全静态操作:0Hz~33Hz 5 、三级加密程序存储器 6 、32个可编程I/O口线 7 、三个16位定时器/计数器 8、八个中断源 9、全双工UART串行通道 10、 低功耗空闲和掉电模式 l 1、掉电后中断可唤醒 l 2、看门狗定时器 l3、 双数据指针 l4、 掉电标识符 引脚结构 P0 口:P0口是一个8位漏极开路的双向I/O口。作为输出口,每位能驱动8个TTL逻辑电平。对P0端口写“1”时,引脚用作高阻抗输入。当访问外部程序和数据存储器时,P0口也被作为低8位地址/数据复用。在这种模式下,P0具有内部上拉电阻。在flash编程时,P0口也用来接收指令字节;在程序校验时,输出指令字节。程序校验时,需要外部上拉电阻。 P1 口:P1 口是一个具有内部上拉电阻的8 位双向I/O 口,p1 输出缓冲器能驱动4 个TTL 逻辑电平。对P1 端口写“1”时,内部上拉电阻把端口拉高,此时可以作为输入口使用。作为输入使用时,被外部拉低的引脚由于内部电阻的原因,将输出电流(IIL)。此外,P1.0和P1.2分别作定时器/计数器2的外部计数输入(P1.0/T2)和时器/计数器2的触发输入(P1.1/T2EX),具体如下表所示。在flash编程和校验时,P1口接收低8位地址字节。 引脚号第二功能 P1.0 T2(定时器/计数器T2的外部计数输入),时钟输出 P1.1 T2EX(定时器/计数器T2的捕捉/重载触发信号和方向控制) P1.5 MOSI(在系统编程用) P1.6 MISO(在系统编程用) P1.7 SCK(在系统编程用) P2 口:P2 口是一个具有内部上拉电阻的8 位双向I/O 口,P2 输出缓冲器能驱动4 个TTL 逻辑电平。对P2 端口写“1”时,内部上拉电阻把端口拉高,此时可以作为输入口使用。作为输入使用时,被外部拉低的引脚由于内部电阻的原因,将输出电流(IIL)。在访问外部程序存储器或用16位地址读取外部数据存储器(例如执行MOVX @DPTR)时,P2 口送出高八位地址。在这种应用中,P2 口使用很强的内部上拉发送1。在使用8位地址(如MOVX @RI)访问外部数据存储器时,P2口输出P2锁存器的内容。在flash编程和校验时,P2口也接收高8位地址字节和一些控制信号。P3 口:P3 口是一个具有内部上拉电阻的8 位双向I/O 口,p2 输出缓冲器能驱动4 个TTL 逻辑电平。对P3 端口写“1”时,内部上拉电阻把端口拉高,此时可以作为输入口使用。作为输入使用时,被外部拉低的引脚由于内部电阻的原因,将输出电流(IIL)。 P3口亦作为AT89S52特殊功能(第二功能)使用,如下表所示。在flash编程和校验时,P3口也接收一些控制信号。 引脚号第二功能 P3.0 RXD(串行输入) P3.1 TXD(串行输出) P3.2 INT0(外部中断0) P3.3 INT0(外部中断0) P3.4 T0(定时器0外部输入) P3.5 T1(定时器1外部输入) P3.6 WR(外部数据存储器写选通) P3.7 RD(外部数据存储器写选通) RST: 复位输入。晶振工作时,RST脚持续2 个机器周期高电平将使单片机复位。看门狗计时完成后,RST 脚输出96 个晶振周期的高电平。特殊寄存器AUXR(地址8EH)上的DISRTO位可以使此功能无效。DISRTO默认状态下,复位高电平有效。ALE/PROG:地址锁存控制信号(ALE)是访问外部程序存储器时,锁存低8 位地址的输出脉冲。在flash编程时,此引脚(PROG)也用作编程输入脉冲。在一般情况下,ALE 以晶振六分之一的固定频率输出脉冲,可用来作为外部定时器或时钟使用。然而,特别强调,在每次访问外部数据存储器时,ALE脉冲将会跳过。如果需要,通过将地址为8EH的SFR的第0位置“1”,ALE操作将无效。这一位置“1”,ALE 仅在执行MOVX 或MOVC指令时有效。否则,ALE 将被微弱拉高。这个ALE 使能标志位(地址为8EH的SFR的第0位)的设置对微控制器处于外部执行模式下无效。PSEN:外部程序存储器选通信号(PSEN)是外部程序存储器选通信号。 当AT89S52从外部程序存储器执行外部代码时,PSEN在每个机器周期被激活两次,而在访问外部数据存储器时,PSEN将不被激活。EA/VPP:访问外部程序存储器控制信号。为使能从0000H 到FFFFH的外部程序存储器读取指令,EA必须接GND。为了执行内部程序指令,EA应该接VCC。在flash编程期间,EA也接收12伏VPP电压。XTAL1:振荡器反相放大器和内部时钟发生电路的输入端。XTAL2:振荡器反相放大器的输出端。 2 LCD1602的原理及其应用 2.1 液晶屏LCD1602的介绍: LCD1602已很普遍了,具体介绍我就不多说了,市面上字符液晶绝大多数是基于HD44780液晶芯片的,控制原理是完全相同的,因此HD44780写的控制程序可以很方便地应用于市面上大部分的字符型液晶。字符型LCD通常有14条引脚线或16条引脚线的LCD,多出来的2条线是背光电源线VCC(15脚)和地线GND(16脚),其控制原理与14脚的LCD完全一样。 2.2 液晶屏LCD1602的功能及应用 1602LCD采用标准的14脚(无背光)或16脚(带背光)接口,各引脚接口说明如表10-13所示: 编号 | 符号 | 引脚说明 | 编号 | 符号 | 引脚说明 | 1 | VSS | 电源地 | 9 | D2 | 数据 | 2 | VDD | 电源正极 | 10 | D3 | 数据 | 3 | VL | 液晶显示偏压 | 11 | D4 | 数据 | 4 | RS | 数据/命令选择 | 12 | D5 | 数据 | 5 | R/W | 读/写选择 | 13 | D6 | 数据 | 6 | E | 使能信号 | 14 | D7 | 数据 | 7 | D0 | 数据 | 15 | BLA | 背光源正极 | 8 | D1 | 数据 | 16 | BLK | 背光源负极 |
表10-13:引脚接口说明表 第1脚:VSS为地电源。 第2脚:VDD接5V正电源。 第3脚:VL为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度。 第4脚:RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。 第5脚:R/W为读写信号线,高电平时进行读操作,低电平时进行写操作。当RS和R/W共同为低电平时可以写入指令或者显示地址,当RS为低电平R/W为高电平时可以读忙信号,当RS为高电平R/W为低电平时可以写入数据。 第6脚:E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。 第7~14脚:D0~D7为8位双向数据线。 第15脚:背光源正极。 第16脚:背光源负极。 10.8.2.3 1602LCD的指令说明及时序 1602液晶模块内部的控制器共有11条控制指令,如表10-14所示: 序号 | 指令 | RS | R/W | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | 1 | 清显示 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 2 | 光标返回 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | * | 3 | 置输入模式 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | I/D | S | 4 | 显示开/关控制 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | D | C | B | 5 | 光标或字符移位 | 0 | 0 | 0 | 0 | 0 | 1 | S/C | R/L | * | * | 6 | 置功能 | 0 | 0 | 0 | 0 | 1 | DL | N | F | * | * | 7 | 置字符发生存贮器地址 | 0 | 0 | 0 | 1 | 字符发生存贮器地址 | 8 | 置数据存贮器地址 | 0 | 0 | 1 | 显示数据存贮器地址 | 9 | 读忙标志或地址 | 0 | 1 | BF | 计数器地址 | 10 | 写数到CGRAM或DDRAM) | 1 | 0 | 要写的数据内容 | 11 | 从CGRAM或DDRAM读数 | 1 | 1 | 读出的数据内容 |
表10-14:控制命令表 1602液晶模块的读写操作、屏幕和光标的操作都是通过指令编程来实现的。(说明:1为高电平、0为低电平) 指令1:清显示,指令码01H,光标复位到地址00H位置。 指令2:光标复位,光标返回到地址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:读数据。 与HD44780相兼容的芯片时序表如下: 读状态 | 输入 | RS=L,R/W=H,E=H | 输出 | D0—D7=状态字 | 写指令 | 输入 | RS=L,R/W=L,D0—D7=指令码,E=高脉冲 | 输出 | 无 | 读数据 | 输入 | RS=H,R/W=H,E=H | 输出 | D0—D7=数据 | 写数据 | 输入 | RS=H,R/W=L,D0—D7=数据,E=高脉冲 | 输出 | 无 |
表10-15:基本操作时序表 读写操作时序如图10-55和10-56所示: 图10-56 写操作时序 10.8.2.4 1602LCD的RAM地址映射及标准字库表 液晶显示模块是一个慢显示器件,所以在执行每条指令之前一定要确认模块的忙标志为低电平,表示不忙,否则此指令失效。要显示字符时要先输入显示字符地址,也就是告诉模块在哪里显示字符,图10-57是1602的内部显示地址。 图10-57 1602LCD内部显示地址 例如第二行第一个字符的地址是40H,那么是否直接写入40H就可以将光标定位在第二行第一个字符的位置呢?这样不行,因为写入显示地址时要求最高位D7恒定为高电平1所以实际写入的数据应该是01000000B(40H)+10000000B(80H)=11000000B(C0H)。 在对液晶模块的初始化中要先设置其显示模式,在液晶模块显示字符时光标是自动右移的,无需人工干预。每次输入指令前都要判断液晶模块是否处于忙的状态。 1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,如图10-58所示,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B(41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母“A” 图10-58 字符代码与图形对应图 3 设计思路、仿真及调试 3.1 设计方法 本电路设计采用AT89S52单片机为核心,利用晶振产生频率为1HZ的时钟脉冲信号,利用液晶屏LCD1602显示计算及其时间信息,通过对AT89S52单片机的编程控制液晶屏LCD1602的显示。显示计算和简易计算的信息同在LCD1602,通过按键切换选择。外部按键可及时设定或调整时间或计算的信息。 3.2 硬件设计 本系统以AT89S52单片机为核心,本系统选用12MHZ的晶振,,使得单片机有合理的运行速度。起振电容30pF对振荡器的频率高低、振荡器的稳定性和起振的快速性影响较合适,复位电路为按键高电平复位。
3.2.1按键调整电路 第 1 页 共 34 页
桂林电子科技大课程设计(论文)专用纸 第 1 页 共 34 页 S0为调秒的按键,当按下S0时秒加1,S1为调分的按键,当按S1时分加1,S2按键为调时,当按下S2时,时加1,S3按键为调日,当按下S3时日加1,S4为调月,当按下S4时月加1,S5为调年,当按下S5时年加1;S6为时间显示建,S7为计算显示键。 3.2.2复位电路 3.2.3液晶屏LCD1602显示 3.2.4 LED指示电路 当单片机通电时LED亮 3.2.5 4*4键盘的设计 键盘功能如下: 3.2.6简易计算器的总电路 硬件设计中用Protel99se画原理图和PCB图 如图1所示原理图: 图1 3.3 软件设计 本电路软件设计采用C语言编写程序(具体程序在附件中给出)。程序设计主要包括简易计算的编程,按键编程,时间控制编程,液晶屏LCD1602的显示编程。
3.4 软件仿真 在硬件设计完成后,利用软件对其进行仿真,以尽可能的减少做板的次数。本次我采用Proteus软件仿真。 如图2所示,简易计算器的时间显示 如图3所示 简易计算器的计算显示软件仿真正常,可进行硬件制作。 图2 图3 3.5 硬件调试 做好电路板,按键使用正确,时间显示正常,计算功能也正常!如下图: 4 结论 在用单片机实现简易计算的设计中使用到了AT89s52、LCD1602及其4*4键盘的使用。在设计过程中我通过在网上和图书馆查阅资料,收集了关于单片机和液晶屏LCD1602显示方面的资料,通过对这些资料的学习,我了解了单片机的基本结构和单片机在生活和生产中所发挥的作用;液晶屏LCD1602的原理和使用。本次课程设计完成的主要工作和任务如下:对设计方案的理论研究,单片机的合理选型,硬件电路的设计,电路板的制作,元器件的焊接,软件的编写和调试以及课设论文的制作。通过设计简易计算器的过程中我掌握了单片机的基本原理及其各种应用,对它的各种硬件接口与软件设计方法有较深入的认识。通过对电路原理图、pcb图的绘制,电路仿真、电路板的制作掌握了对proteus仿真软件的使用。
附 件 硬件电路原理图:
单片机源程序如下: - #include <reg52.h>
- #define uchar unsigned char
- #define uint unsigned int
- sbit rs=P0^0;
- sbit rw=P0^1;
- sbit e=P0^2;
- sbit k0=P1^0;
- sbit k1=P1^1;
- sbit k2=P1^2;
- sbit k3=P1^3;
- sbit k4=P1^4;
- sbit k5=P1^5;
- sbit k6=P1^6;
- sbit k7=P1^7;
- unsigned char code digit[ ]={"0123456789"}; //定义字符数组显示数字
- unsigned char s,m,h,day,month,year,count;
- void write_dat(uchar dat);
- void write_com(uchar com);
- void keyscan();
- /**********************
- 功能说明:
- 显示编码,加上0x30,
- 分别为'1','2','3','+',
- '4','5','6','-',等
- **********************/
- uchar code table1[]=
- {
- 1,2,3,0x2b-0x30,
- 4,5,6,0x2d-0x30,
- 7,8,9,0x2a-0x30,
- 0,0x3d-0x30,0x01-0x30,0x2f-0x30
- };
-
- uchar k=0,flag=0,num,fuhao,i;
-
- long a,b,c;
-
-
- void delay(uint z)
- {
- uint x,y;
- for(x=z;x>0;x--)
- for(y=110;y>0;y--);
- }
- /*****************************************************
- 函数功能:指定字符显示的实际地址
- 入口参数:x
- ***************************************************/
- void WriteAddress(unsigned char x)
- {
- write_com(x|0x80); //显示位置的确定方法规定为"80H+地址码x"
- }
- /******************************************************************************
- 函数功能:显示小时
- ******************************************************************************/
- void DisplayHour()
- {
- unsigned char i,j;
- i=h/10; //取整运算,求得十位数字
- j=h%10; //取余运算,求得各位数字
- WriteAddress(0x45); //写显示地址,将十位数字显示在第2行第0列
- write_dat(digit[i]); //将十位数字的字符常量写入LCD
- write_dat(digit[j]); //将个位数字的字符常量写入LCD
-
- }
- /******************************************************************************
- 函数功能:显示分钟
- ******************************************************************************/
- void DisplayMinute()
- {
- unsigned char i,j;
- i=m/10; //取整运算,求得十位数字
- j=m%10; //取余运算,求得各位数字
- WriteAddress(0x48); //写显示地址,将十位数字显示在第2行第3列
- write_dat(digit[i]); //将十位数字的字符常量写入LCD
- write_dat(digit[j]); //将个位数字的字符常量写入LCD
-
- }
- /******************************************************************************
- 函数功能:显示秒
- ******************************************************************************/
- void DisplaySecond()
- {
- unsigned char i,j;
- i=s/10; //取整运算,求得十位数字
- j=s%10; //取余运算,求得各位数字
- WriteAddress(0x4b); //写显示地址,将十位数字显示在第2行第6列
- write_dat(digit[i]); //将十位数字的字符常量写入LCD
- write_dat(digit[j]); //将个位数字的字符常量写入LCD
- }
-
-
- /******************************************************************************
- 函数功能:显示小时
- ******************************************************************************/
- void DisplayYear()
- {
- unsigned char i,j;
- i=year/10; //取整运算,求得十位数字
- j=year%10; //取余运算,求得各位数字
- WriteAddress(0x07); //写显示地址,将十位数字显示在第2行第0列
- write_dat(digit[i]); //将十位数字的字符常量写入LCD
- write_dat(digit[j]); //将个位数字的字符常量写入LCD
-
- }
- /******************************************************************************
- 函数功能:显示分钟
- ******************************************************************************/
- void DisplayMonth()
- {
- unsigned char i,j;
- i=month/10; //取整运算,求得十位数字
- j=month%10; //取余运算,求得各位数字
- WriteAddress(0x0a); //写显示地址,将十位数字显示在第2行第3列
- write_dat(digit[i]); //将十位数字的字符常量写入LCD
- write_dat(digit[j]); //将个位数字的字符常量写入LCD
-
- }
- /******************************************************************************
- 函数功能:显示秒
- ******************************************************************************/
- void DisplayDay()
- {
- unsigned char i,j;
- i=day/10; //取整运算,求得十位数字
- j=day%10; //取余运算,求得各位数字
- WriteAddress(0x0d); //写显示地址,将十位数字显示在第2行第6列
- write_dat(digit[i]); //将十位数字的字符常量写入LCD
- write_dat(digit[j]); //将个位数字的字符常量写入LCD
- }
- void keyscan2()
- {if(k0==0)
- {delay(5);
- if(k0==0)
- {
- s++;
- if(s==60)
- s=0;
- }
- }
- if(k1==0)
- {delay(5);
- if(k1==0)
- {m++;
- if(m==60)
- m=0;
- }
- }
- if(k2==0)
- {delay(5);
- if(k2==0)
- {h++;
- if(h==60)
- h=0;
- }
- }
-
- if(k3==0)
- {delay(5);
- if(k3==0)
- {day++;
- if(day==30)
- day=0;
- }
- }
- if(k4==0)
- {delay(5);
- if(k4==0)
- {month++;
- if(month==13)
- month=0;
- }
- }
- if(k5==0)
- {delay(5);
- if(k5==0)
- {year++;
- if(year==99)
- year=0;
- }
- }
-
- }
-
- void keyscan()
- {
- uchar temp;
- P3=0xfe;
- temp=P3;
- temp=temp&0xf0;
- while(temp!=0xf0)
- {
- delay(5);
- temp=P3;
- temp=temp&0xf0;
- while(temp!=0xf0)
- {
- temp=P3;
- switch(temp)
- {
- case 0xee:num=0;
- break;
- case 0xde:num=1;
- break;
- case 0xbe:num=2;
- break;
- case 0x7e:num=3;
- break;
- }
- while(temp!=0xf0)
- { temp=P3;
- temp=temp&0xf0;
- }
- }
-
- /*当按下1,2,3,松手后执行下面这段语句*/
- if(num==0||num==1||num==2)
- {
-
- if(flag==0)
- a=a*10+table1[num];//如果没有按符号键,符号前的数值为a
- else if(flag==1)
- b=b*10+table1[num]; //如果按了符号键,符号后的数值为b
-
- if(k==1) //如果之前按了'='号,再按键时清屏,进行下一次计算
- {
- k=0;
- write_com(0x01);
- }
- }
- else if(num==3) //判断按下'+'
- {
- flag=1;
- fuhao=1;
- }
-
- i=table1[num]; //显示按下的键
- write_dat(0x30+i);
-
- }
- P3=0xfd;
- temp=P3;
- temp=temp&0xf0;
- while(temp!=0xf0)
- {
- delay(5);
- temp=P3;
- temp=temp&0xf0;
- while(temp!=0xf0)
- {
- temp=P3;
- switch(temp)
- {
- case 0xed:num=4;
- break;
- case 0xdd:num=5;
- break;
- case 0xbd:num=6;
- break;
- case 0x7d:num=7;
- break;
- }
- while(temp!=0xf0)
- { temp=P3;
- temp=temp&0xf0;
- }
- }
- if(num==4||num==5||num==6) //判断是否按下'4','5','6'
- {
- if(k==1)
- {
- k=0;
- write_com(0x01);
- }
- if(flag==0)
- a=a*10+table1[num];
- else if(flag==1)
- b=b*10+table1[num];
- }
- else if(num==7)
- {
- flag=1;
- fuhao=2;
- }
- i=table1[num]; //显示按下的键
- write_dat(0x30+i);
-
- }
- P3=0xfb;
- temp=P3;
- temp=temp&0xf0;
- while(temp!=0xf0)
- {
- delay(5);
- temp=P3;
- temp=temp&0xf0;
- while(temp!=0xf0)
- {
- temp=P3;
- switch(temp) //
- {
- case 0xeb:num=8;
- break;
- case 0xdb:num=9;
- break;
- case 0xbb:num=10;
- break;
- case 0x7b:num=11;
- break;
- }
- while(temp!=0xf0)
- { temp=P3;
- temp=temp&0xf0;
- }
- }
- if(num==8||num==9||num==10) //判断是否按下'7','8','9'
- {
- if(k==1)
- {
- k=0;
- write_com(0x01);
- }
- if(flag==0)
- a=a*10+table1[num];
- else if(flag==1)
- b=b*10+table1[num];
-
- }
- else if(num==11) //判断是否按下'*'
- {
- flag=1;
- fuhao=3;
-
- }
- i=table1[num];
- write_dat(0x30+i);
-
- }
- P3=0xf7;
- temp=P3;
- temp=temp&0xf0;
- while(temp!=0xf0)
- {
- delay(5);
- temp=P3;
- temp=temp&0xf0;
- while(temp!=0xf0)
- {
- temp=P3;
- switch(temp)
- {
- case 0xe7:num=12; // 0键
- break;
- case 0xd7:num=13; // '='
- break;
- case 0xb7:num=14; //清零键
- break;
- case 0x77:num=15; //'/'
- break;
- }
- while(temp!=0xf0)
- { temp=P3;
- temp=temp&0xf0;
- }
- }
- switch(num)
- {
- case 12:
- {
- if(k==1)
- {
- k=0;
- write_com(0x01);
- }
- if(flag==0)
- a=a*10;
- else if(flag==1)
- b=b*10;
-
- write_dat(0x30);
- }
- break;
- case 13: //按=键
- {
- k=1;
- if(fuhao==1) //如果符号键是+,执行+运算
- {
-
- write_com(0x80+0x4f);
- write_com(0x04);
- c=a+b;
- while(c!=0)
- {
- write_dat(0x30+c%10);
- c=c/10;
-
-
- }
- write_dat(0x3d);
- fuhao=0;
- a=0;b=0;flag=0;
- }
- if(fuhao==2)
- {
- write_com(0x80+0x4f);
- write_com(0x04);
- if(a>=b)
- {
- c=a-b;
- while(c!=0)
- {
- write_dat(0x30+c%10);
- c=c/10;
- }
-
- }
- else if(a<b)
- {
- c=b-a;
- while(c!=0)
- {
- write_dat(0x30+c%10);
- c=c/10;
- }
- write_dat(0x2d);
- }
-
- write_dat(0x3d);
- a=0;b=0;flag=0;fuhao=0;
-
- }
- if(fuhao==3) //如果符号键是*
- {
- write_com(0x80+0x4f);
- write_com(0x04);
- c=a*b;
- while(c!=0)
- {
- write_dat(0x30+c%10);
- c=c/10;
- }
- write_dat(0x3d);
- a=0;b=0;flag=0;fuhao=0;
-
- }
- if(fuhao==4) //如果符号键是/
- {
- i=0;
- write_com(0x80+0x4f);
- write_com(0x04);
- c=(long)(((float)a/b)*1000000); //结果保留6位小数
- while(c!=0
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载: |