基于51单片机的简易计算器

课程设计(论文) 说明书

题 目:基于单片机简易计算器的设计 院 (系): 专 业: 学生姓名:学 号: 指导教师:

职 称:

2011年 12月 18日

摘 要

简易计算器是一种非常广泛日常工具,对现代社会越来越流行。它可以进行一些简易的计算。本系统提供详细的时、分、秒、年、月、日的时间信息,同时还可进行简易的计算信息,还具有时间校准等功能。该电路采用AT89S52单片机作为核心,功耗小,能在3V 的低压工作,电压可选用3~5V电压供电。本系统硬件部分由AT89S52单片机、LCD1602液晶屏、键盘、指示灯系统等部分构成。软件部分在keil 环境下用C51语言编写,包括时间设置、时间显示、简易计算显示等。

关键字:AT89S52;液晶屏LCD1602;键盘

Abstract

Simple calculator is a very broad everyday tool for modern society is more and more popular. It can carry on some simple calculation. This system provides detailed, minutes and seconds, year, month, day time information, and at the same time but also for simple calculation information, but also has time calibration etc. Function. This circuit AT89S52 SCM as the core, power consumption is small, can be in 3 V of low-pressure work, voltage can choose 3 ~ 5 V voltage power supply. This system hardware part AT89S52 SCM by LCD1602 LCD screen, keyboard, indicator system, part. Software in under the environment of keil with C51 language, including time set, time display, simple calculation shows, etc. In the programming process found on existing knowledge to finish writing task difficult, the teachers and students of help to finish the program part of the code.

Keyword :AT89S52;AT89S52 devices; LCD1602 LCD screen; keyboard

目 录

摘要………………………………………………………………………………………….. 1

引言………………………………………………………………………………… ………. 3 1 单片机及其应用……………………………………………………………………... 3

1.1单片机介绍………………………………………………………………………………3 1.2单片机的应用……………………………………………………………………………4 1.3 AT89S52单片机…………………………………………………………………………4

2 液晶屏LCD1602原理及应用…………………………………………………….... 7

2.1液晶屏LCD1602介绍及工作原理………………….... ……………… …………………..7 2.2 液晶屏LCD1602的功能及应用…………………………………………………………7

3 设计思路、仿真及调试……………………………………………………………... 12

3.1设计方法…………………………………………………………………………………12 3.2硬件设计……………………………………………………………………. ………….12 3.2.1按键调整电路…………………………………………………………………………12 3.2.2复位电路………………………………………………………………………..... 13 3.2.3 液晶屏LCD1602显示电路…... …………………………………………………13 3.2.4 LED指示电路……………………………………………………………………. 13 3.2.5 4*4键盘的设计………………………………………………………………..... 14 3.2.6 简易计算器的总电路............................................14 3.3软件设计……………………………………………………………… ……………………15 3.4软件仿真…………………………………………………………………………………15 3.5硬件调试……………………………………………………………………..………….. 16

4 结束语…………………………………………………….. ………………………….. 17 谢辞…………………………………………………………..……………………………... 18 参考文献………………………………………………………..………………………….19 附件……………………………………………………………………….…………………20

引言

众所周知单片机是一种集成在电路芯片,是采用超大规模集成电路技术把具有数据处理能力的中央处理器CPU 随机存储器RAM 、只读存储器ROM 、多种I/O口和中断系统、定时器/计时器等功能(可能还包括显示驱动电路、脉宽调制电路、模拟多路转换器、A/D转换器等电路)集成到一块硅片上构成的一个小而完善的计算机系统。本设计要制作的就是单片机于生活中最为常见的异种应用——简易计算器。本简易计算器AT89S52单片机作为核心,可以显示简易的计算和时间,时间可以人为设定;另外还可以显示当

前的日历,显示格式为年(四位),月(两位),日(两位)。设置时间时的位切换、设定数值、启动定时器、切换日历通过外部中断来实现。简易计算器不仅可以进行简易的计算还可以显示时间。简易计算器显示电路由LCD1602组成, 制作一个单片机计时装置需要的材料需要有软硬件的支持,硬件方面AT89C51单片机,晶振,电源,液晶屏LCD1602。

1 单片机及其应用

单片机是一种集成在电路芯片,是采用超大规模集成电路技术把具有数据处理能力的中央处理器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所示:

指令9:读忙信号和光标地址 BF:为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙。 指令10:写数据。 指令11:读数据。

与HD44780相兼容的芯片时序表如下:

图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按键调整电路

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 仿真软件的使用。

谢 辞

本论文是在袁华老师悉心指导下完成的。袁华老师渊博的专业知识,严谨的治学态度,精益求精的工作作风,诲人不倦的高尚师德,严以律己、宽以待人的崇高风范,朴实无华、平易近人的人格魅力对我影响深远。不仅使我树立了远大的学术目标、掌握了基本的研究方法,还使我明白了许多待人接物与为人处世的道理。本课设论文从选题到完成,每一步都是在袁华老师的指导下完成的,倾注了袁华老师大量的心血。在此,谨向袁华老师表示崇高的敬意和衷心的感谢!

在此也感谢大学的老师教育我,使我完成本次课设,感谢他们带给我知识,同时也感谢我的同学们,对我的支持!

参考文献:

[1] 余锡存, 曹国华,单片机原理及接口技术. 西安:西安电子科技大学出版社,2000 [2] 郭天祥,新概念51单片机c 语言教程。北京:电子工业出版社,2009

[3] 马忠梅,单片机的C 语言应用程序设计. 北京:北京航空航天大学出版社,1997。 [4]张毅刚著,《单片机原理及应用》,北京,高等教育出版社,2008 [5] 谭浩强,C 程序设计(第二版)[M].北京:清华大学出版社,2003。

附 件

硬件电路原理图:

软件编程程序: #include #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 DisplaySecond() {

unsigned char i,j;

i=s/10; //取整运算,求得十位数字

j=s%10; //取余运

函数功能:显示分钟 算,求得各位数字

******************************************************************************/

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 }

/****************************************************************************** 函数功能:显示秒

******************************************************************************/

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; write_dat(0x30+c%10); c=c/10; }

write_dat(0x3d); } a=0;b=0;flag=0;fuhao=0;

}

else if(a

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) {

}

if(fuhao==4) //如果符号键是/ {

i=0; write_com(0x80+0x4f);

write_com(0x04);

c=(long)(((float)a/b)*1000000); //结果保留6位小数

while(c!=0) {

write_dat(0x30+c%10); c=c/10; i++;

if(i==6) // 显示完六位小数后,显示· write_dat(0x2e); }

if(a/b

write_dat(0x30); write_dat(0x3d); a=0;b=0;flag=0;fuhao=0;

} } break; case 14:

{ write_com(0x01); a=0;b=0;flag=0;fuhao=0; }

break;

case 15: { flag=1; fuhao=4; write_dat(0x30+table1[num]);

} break; }

} }

/*******led1602*******/ void write_com(uchar com) {

rs=0;//选择写指令 rw=0; P2=com; e=1;

delay(5);//无延时不能正常工作 e=0;

}

void write_dat(uchar dat) {

rs=1;//选择写数据 rw=0; P2=dat; e=1;

delay(5);//无延时不能正常工作 e=0; }

void init() //初始化 {

delay(15); write_com(0x38); delay(6); write_com(0x38); delay(6); write_com(0x38); write_com(0x38);

write_com(0x0c); //开显示,关光标 write_com(0x06);//光标移动 设置 write_com(0x01);//清屏 } void geshi() { WriteAddress(0x00);

write_dat('D');

WriteAddress(0x01); write_dat('a');

WriteAddress(0x02); write_dat('t'); //将分号的字符常量写入LCD WriteAddress(0x03);

write_dat('e');

WriteAddress(0x04); write_dat(':'); WriteAddress(0x05);

write_dat('2');

WriteAddress(0x06); write_dat('0'); WriteAddress(0x09); write_dat('-'); WriteAddress(0x0c); write_dat('-'); WriteAddress(0x40); write_dat('T'); WriteAddress(0x41); write_dat('i'); WriteAddress(0x42);

write_dat('m');

WriteAddress(0x43); //写地址,将第二个分号显示在第2行第7列 write_dat('e'); //将分号的字符常量写入LCD

WriteAddress(0x44); //写地址,将第二个分号显示在第2行第10列 write_dat(':'); //将分号的字符常量写入LCD

WriteAddress(0x47); write_dat(':'); WriteAddress(0x4a);

write_dat(':'); }

void main() {

init(); TMOD=0x01; //使用定时器T0的模式1 TH0=(65536-46083)/256; //定时器T0的高8位设置初值 TL0=(65536-46083)%256; //定时器T0的低8位设置初值 EA=1; //开总中断

ET0=1; //定时器T0中断允许 TR0=1; //启动定时器T0 count=0; //中断次数初始化为0 s=0; //秒初始化为0 m=0; //分钟初始化为0 h=0; //小时初始化为0

year=0; month=0; day=0;

while(1) { keyscan(); if(k6==0)

{ k6=0;

write_com(0x01); while(1) {

keyscan2();

geshi(); delay(5); DisplayHour(); delay(5); DisplayMinute(); delay(5); DisplaySecond(); delay(5); DisplayYear();

delay(5);

DisplayMonth();

delay(5); DisplayDay();

delay(5); if(k7==0)

{ k6=1;

write_com(0x01); break; }

} }

} }

/*******************************************************

函数功能:定时器T0的中断服务函数 ********************************************************/

void Time0(void ) interrupt 1 using 1 //定

时器T0的中断编号为1,使用第1组工作寄存器 {

count++; //每产生1次中断,中断累计次数加1 if(count==20) //如果中断次数计满20次

{

count=0; //中断累计次数清0 s++;

//秒加1

if(s==60) //如果计满60秒

{

s=0; //秒清0

m++;

//分钟加1

}

if(m==60) //如果计满60分

{ m=0; //分钟清0

h++;

//小时加1

}

if(h==24) { h=0; day++; }

if(day==30)

{ day=0; month++; }

if(month==13) { month=0; year++; }

if(year==99) { year=0;

}

TH0=(65536-46083)/256; //定时器T0高8位重新赋初值

TL0=(65536-46083)%256;

//定时器T0低8位重新赋初值

} }

课程设计(论文) 说明书

题 目:基于单片机简易计算器的设计 院 (系): 专 业: 学生姓名:学 号: 指导教师:

职 称:

2011年 12月 18日

摘 要

简易计算器是一种非常广泛日常工具,对现代社会越来越流行。它可以进行一些简易的计算。本系统提供详细的时、分、秒、年、月、日的时间信息,同时还可进行简易的计算信息,还具有时间校准等功能。该电路采用AT89S52单片机作为核心,功耗小,能在3V 的低压工作,电压可选用3~5V电压供电。本系统硬件部分由AT89S52单片机、LCD1602液晶屏、键盘、指示灯系统等部分构成。软件部分在keil 环境下用C51语言编写,包括时间设置、时间显示、简易计算显示等。

关键字:AT89S52;液晶屏LCD1602;键盘

Abstract

Simple calculator is a very broad everyday tool for modern society is more and more popular. It can carry on some simple calculation. This system provides detailed, minutes and seconds, year, month, day time information, and at the same time but also for simple calculation information, but also has time calibration etc. Function. This circuit AT89S52 SCM as the core, power consumption is small, can be in 3 V of low-pressure work, voltage can choose 3 ~ 5 V voltage power supply. This system hardware part AT89S52 SCM by LCD1602 LCD screen, keyboard, indicator system, part. Software in under the environment of keil with C51 language, including time set, time display, simple calculation shows, etc. In the programming process found on existing knowledge to finish writing task difficult, the teachers and students of help to finish the program part of the code.

Keyword :AT89S52;AT89S52 devices; LCD1602 LCD screen; keyboard

目 录

摘要………………………………………………………………………………………….. 1

引言………………………………………………………………………………… ………. 3 1 单片机及其应用……………………………………………………………………... 3

1.1单片机介绍………………………………………………………………………………3 1.2单片机的应用……………………………………………………………………………4 1.3 AT89S52单片机…………………………………………………………………………4

2 液晶屏LCD1602原理及应用…………………………………………………….... 7

2.1液晶屏LCD1602介绍及工作原理………………….... ……………… …………………..7 2.2 液晶屏LCD1602的功能及应用…………………………………………………………7

3 设计思路、仿真及调试……………………………………………………………... 12

3.1设计方法…………………………………………………………………………………12 3.2硬件设计……………………………………………………………………. ………….12 3.2.1按键调整电路…………………………………………………………………………12 3.2.2复位电路………………………………………………………………………..... 13 3.2.3 液晶屏LCD1602显示电路…... …………………………………………………13 3.2.4 LED指示电路……………………………………………………………………. 13 3.2.5 4*4键盘的设计………………………………………………………………..... 14 3.2.6 简易计算器的总电路............................................14 3.3软件设计……………………………………………………………… ……………………15 3.4软件仿真…………………………………………………………………………………15 3.5硬件调试……………………………………………………………………..………….. 16

4 结束语…………………………………………………….. ………………………….. 17 谢辞…………………………………………………………..……………………………... 18 参考文献………………………………………………………..………………………….19 附件……………………………………………………………………….…………………20

引言

众所周知单片机是一种集成在电路芯片,是采用超大规模集成电路技术把具有数据处理能力的中央处理器CPU 随机存储器RAM 、只读存储器ROM 、多种I/O口和中断系统、定时器/计时器等功能(可能还包括显示驱动电路、脉宽调制电路、模拟多路转换器、A/D转换器等电路)集成到一块硅片上构成的一个小而完善的计算机系统。本设计要制作的就是单片机于生活中最为常见的异种应用——简易计算器。本简易计算器AT89S52单片机作为核心,可以显示简易的计算和时间,时间可以人为设定;另外还可以显示当

前的日历,显示格式为年(四位),月(两位),日(两位)。设置时间时的位切换、设定数值、启动定时器、切换日历通过外部中断来实现。简易计算器不仅可以进行简易的计算还可以显示时间。简易计算器显示电路由LCD1602组成, 制作一个单片机计时装置需要的材料需要有软硬件的支持,硬件方面AT89C51单片机,晶振,电源,液晶屏LCD1602。

1 单片机及其应用

单片机是一种集成在电路芯片,是采用超大规模集成电路技术把具有数据处理能力的中央处理器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所示:

指令9:读忙信号和光标地址 BF:为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙。 指令10:写数据。 指令11:读数据。

与HD44780相兼容的芯片时序表如下:

图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按键调整电路

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 仿真软件的使用。

谢 辞

本论文是在袁华老师悉心指导下完成的。袁华老师渊博的专业知识,严谨的治学态度,精益求精的工作作风,诲人不倦的高尚师德,严以律己、宽以待人的崇高风范,朴实无华、平易近人的人格魅力对我影响深远。不仅使我树立了远大的学术目标、掌握了基本的研究方法,还使我明白了许多待人接物与为人处世的道理。本课设论文从选题到完成,每一步都是在袁华老师的指导下完成的,倾注了袁华老师大量的心血。在此,谨向袁华老师表示崇高的敬意和衷心的感谢!

在此也感谢大学的老师教育我,使我完成本次课设,感谢他们带给我知识,同时也感谢我的同学们,对我的支持!

参考文献:

[1] 余锡存, 曹国华,单片机原理及接口技术. 西安:西安电子科技大学出版社,2000 [2] 郭天祥,新概念51单片机c 语言教程。北京:电子工业出版社,2009

[3] 马忠梅,单片机的C 语言应用程序设计. 北京:北京航空航天大学出版社,1997。 [4]张毅刚著,《单片机原理及应用》,北京,高等教育出版社,2008 [5] 谭浩强,C 程序设计(第二版)[M].北京:清华大学出版社,2003。

附 件

硬件电路原理图:

软件编程程序: #include #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 DisplaySecond() {

unsigned char i,j;

i=s/10; //取整运算,求得十位数字

j=s%10; //取余运

函数功能:显示分钟 算,求得各位数字

******************************************************************************/

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 }

/****************************************************************************** 函数功能:显示秒

******************************************************************************/

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; write_dat(0x30+c%10); c=c/10; }

write_dat(0x3d); } a=0;b=0;flag=0;fuhao=0;

}

else if(a

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) {

}

if(fuhao==4) //如果符号键是/ {

i=0; write_com(0x80+0x4f);

write_com(0x04);

c=(long)(((float)a/b)*1000000); //结果保留6位小数

while(c!=0) {

write_dat(0x30+c%10); c=c/10; i++;

if(i==6) // 显示完六位小数后,显示· write_dat(0x2e); }

if(a/b

write_dat(0x30); write_dat(0x3d); a=0;b=0;flag=0;fuhao=0;

} } break; case 14:

{ write_com(0x01); a=0;b=0;flag=0;fuhao=0; }

break;

case 15: { flag=1; fuhao=4; write_dat(0x30+table1[num]);

} break; }

} }

/*******led1602*******/ void write_com(uchar com) {

rs=0;//选择写指令 rw=0; P2=com; e=1;

delay(5);//无延时不能正常工作 e=0;

}

void write_dat(uchar dat) {

rs=1;//选择写数据 rw=0; P2=dat; e=1;

delay(5);//无延时不能正常工作 e=0; }

void init() //初始化 {

delay(15); write_com(0x38); delay(6); write_com(0x38); delay(6); write_com(0x38); write_com(0x38);

write_com(0x0c); //开显示,关光标 write_com(0x06);//光标移动 设置 write_com(0x01);//清屏 } void geshi() { WriteAddress(0x00);

write_dat('D');

WriteAddress(0x01); write_dat('a');

WriteAddress(0x02); write_dat('t'); //将分号的字符常量写入LCD WriteAddress(0x03);

write_dat('e');

WriteAddress(0x04); write_dat(':'); WriteAddress(0x05);

write_dat('2');

WriteAddress(0x06); write_dat('0'); WriteAddress(0x09); write_dat('-'); WriteAddress(0x0c); write_dat('-'); WriteAddress(0x40); write_dat('T'); WriteAddress(0x41); write_dat('i'); WriteAddress(0x42);

write_dat('m');

WriteAddress(0x43); //写地址,将第二个分号显示在第2行第7列 write_dat('e'); //将分号的字符常量写入LCD

WriteAddress(0x44); //写地址,将第二个分号显示在第2行第10列 write_dat(':'); //将分号的字符常量写入LCD

WriteAddress(0x47); write_dat(':'); WriteAddress(0x4a);

write_dat(':'); }

void main() {

init(); TMOD=0x01; //使用定时器T0的模式1 TH0=(65536-46083)/256; //定时器T0的高8位设置初值 TL0=(65536-46083)%256; //定时器T0的低8位设置初值 EA=1; //开总中断

ET0=1; //定时器T0中断允许 TR0=1; //启动定时器T0 count=0; //中断次数初始化为0 s=0; //秒初始化为0 m=0; //分钟初始化为0 h=0; //小时初始化为0

year=0; month=0; day=0;

while(1) { keyscan(); if(k6==0)

{ k6=0;

write_com(0x01); while(1) {

keyscan2();

geshi(); delay(5); DisplayHour(); delay(5); DisplayMinute(); delay(5); DisplaySecond(); delay(5); DisplayYear();

delay(5);

DisplayMonth();

delay(5); DisplayDay();

delay(5); if(k7==0)

{ k6=1;

write_com(0x01); break; }

} }

} }

/*******************************************************

函数功能:定时器T0的中断服务函数 ********************************************************/

void Time0(void ) interrupt 1 using 1 //定

时器T0的中断编号为1,使用第1组工作寄存器 {

count++; //每产生1次中断,中断累计次数加1 if(count==20) //如果中断次数计满20次

{

count=0; //中断累计次数清0 s++;

//秒加1

if(s==60) //如果计满60秒

{

s=0; //秒清0

m++;

//分钟加1

}

if(m==60) //如果计满60分

{ m=0; //分钟清0

h++;

//小时加1

}

if(h==24) { h=0; day++; }

if(day==30)

{ day=0; month++; }

if(month==13) { month=0; year++; }

if(year==99) { year=0;

}

TH0=(65536-46083)/256; //定时器T0高8位重新赋初值

TL0=(65536-46083)%256;

//定时器T0低8位重新赋初值

} }


相关文章

  • 基于单片机的简易波形发生器的设计
  • ·市场纵横 基于单片机的简易波形发生器的设计 甘肃 兰州 730070)石 蕊 赵海阔 赵宇杰 刘 昊(兰州城市学院, 摘 要:波形发生器是随着不断进步的计算机技术和微电子技术在测量仪器中的应用而形成和发展起来的一类新型信号源.产生任意波形 ...查看


  • 基于C51单片机的简易计算器设计
  • 基于单片机的简易设计原理 专业:通信专业 班级:通信1班 姓名:刘民 学号:1304041127 摘要:按下键盘,通过键盘扫描程序,在LCD 液晶显示屏上显示按键的操作过程,最终显示计算结果,实现计算器的基本功能.本文详细介绍LCD 显示屏 ...查看


  • 单片机简易计算器的设计-C语言
  • 基于AT89C51单片机简易计算器的设计 [摘 要]单片机的出现是计算机制造技术高速发展的产物,它是嵌入式控制系统的核心,如今,它已广泛的应用到我们生活的各个领域,电子.科技.通信.汽车.工业等.本设计是基于51系列单片机来进行的数字计算器 ...查看


  • 简易电子琴课程设计
  • 课程设计任务书 学生姓名: 专业班级: 指导教师: 工作单位: 信息工程学院 题 目: 简易电子琴电路的设计仿真与实现 初始条件: 可选元件:集成运算放大器LM324.电阻.电位器.电容若干,直流电源,或自备元器件. 可用仪器:示波器,万用 ...查看


  • 电子信息工程毕业设计题目大全
  • 1 压力容器液位测量 2 多功能遥控小车 3基于RS232的仓库多点温度.湿度.气 4压检测系统 5自动控制升降旗系统 6基于RS485的温度报警系统 7基于模糊算法的水温控制系统的设计 8多分机电话交换机 9简易火灾自动报警系统 10基于 ...查看


  • 毕业设计_基于单片机的简易逻辑分析仪
  • 基于单片机的简易逻辑分析仪 目 录 第1节 引 言„„„„„„„„„„„„„„„„„„„„„„„„„„„„„3 1.1 系统概述„„„„„„„„„„„„„„„„„„„„„„„„„„„3 1.1.1系统的特点„„„„„„„„„„„„„„„„„ ...查看


  • 基于单片机的简易频率计设计
  • 龙源期刊网 http://www.qikan.com.cn 基于单片机的简易频率计设计 作者:廖小芳 来源:<科技视界>2015年第26期 [摘 要]提出了一种基于单片机开发的简易数字频率计的设计.系统以单片机STC89C52为 ...查看


  • 基于51单片机电子秤设计
  • 摘要 电子秤是日常生活中常用的称重设备,广泛应用于超市.大中型商场.物流配送中心.电子秤在结构和原理上取代了以杠杆平衡为原理的传统机械式称量工具.相比传统的机械式称量工具,电子秤具有称量精度高.装机体积小.应用范围广.易于操作使用等优点,在 ...查看


  • 通信工程毕业设计题目精选
  • 我7岁1就始做做开发的推批销,就更加员会到挣体的不轻钱.易活生的艰了.人家做辛个小8时我就做1,6小时. 个为失败少理找由 多成为找功法 大多方数想要改革这人世界个 不晓得即时却小事做从起 信工程通毕业计题设精选目 . 1智压力能传感系统器 ...查看


热门内容