基于单片机简单计算器设计毕业设计

 目 目

  录

 第一部分

 设计任务与调研 …………………………………………………………3

  第二部分

 设计说明 ……………………………………………………………………4 第三部分

 设计成果 ……………………………………………………………………11 第四部分

 结束语 ………………………………………………………………………15 第五部分

 致谢 …………………………………………………………………………16 第六部分

 参考文献 …………………………………………………………………17

 第一部分

 设计任务与调研

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

 1.1 主要任务 本设计是以 AT89S52 单片机为核心的计算器模拟系统设计,输入采用 4×6 矩阵键盘,可以进行加、减、乘、除 9 位带符号数字运算,并在 LCD1602 上显示结果。

 1.2 设计思路 本设计是基于 AT89C51 单片机的简单运用,设计一个简单的计算器,利用 keil进行编程调试,然后利用 Protel99se 进行仿真,能够实现加,减,乘,除的简单运算。

  第二部分

 设计说明

  2.1 硬件电路 2.1.1 硬件电路结构框图

  1 2.1.2AT89C51 介绍

 AT89C51 单片机是把那些作为控制应用所必需的基本内容都集成在一个尺寸有限的集成电路芯片上。如果按功能划分,它由如下功能部件组成,即微处理器、数据存储器、程序存储器、并行 I/O 口、串行口、定时器/计数器、中断系统及特殊功能寄存器。他们都是通过片内单一总线连接而成,其基本结构依旧是 CPU 加上外围芯片的传统结构模式。但对各种功能部件的控制是采用特殊功能寄存器的集中控制方式。

 1)微处理器

 该单片机中有一个 8 位的微处理器,与通用的微处理器基本相同,同样包括了运算器和控制器两部分,只是增加了面向控制的处理功能,不仅可处理数据,还可以进行位变量的处理。

 2)数据存储器 片内为 18 个字节,2 片外最多可外扩至 64k 字节,用来存储程序在运行期间的工作变量、运算的中间结果、数据暂存和缓冲、标志位等,所以称为数据存储器。

 AT89C51122221 20191817161514131211109876543403938373635343332313029282726252423P1.2P1.3P1.4P1.5P1.6P1.7RST/ VPD( RXD )P3.0( TXD )P3.1(INTO )P3.2(INT1)P3.3(T0)P3.4(T1)P3.5( WR )P3.6(RD )P3.7XTAL 2XTAL 1VSSVCCP0.0(AD 0)P0.1(AD 1)P0.6(AD 6)P0.5(AD 5)P0.4(AD 4)

 P0.3(AD 3)P0.2(AD 2)P0.7(AD 7)P2.0(A8)P2.1(A9)P2.2(A10)P2.3(A11)P2.4(A12)P2.5(A13)P2.6(A14)P2.7(A15)PSENALE / PROGEA/VPPP1.0P1.1图 2—2 AT89C51 芯片引脚图 图 2—1 硬件电路结构框图 按键输入模块 AT89C51 单片机 显示模块

 3)程序存储器

 由于受集成度限制,片内只读存储器一般容量较小,如果片内的只读存储器的容量不够,则需要扩展片外的只读存储器,片外最多可外扩至 64k 字节。

 4)中断系统

 具有 5 个中断源,2 个中断优先权 5)定时器/计数器

  片内有 2 个 16 位的定时器/计数器,具有四种工作方式 6)串行口

  1 个全双工的串行口,具有四种工作方式。可用来进行串行通讯,扩展并行 I/O口,甚至与多个单片机相连接构成多机系统,从而使单片机的功能更强且应用更广 。

 7)I/O 口

  4 个并行 8 位 I/O 口 8)特殊功能寄存器 共有 21 个,用于对片内的各功能的部件进行管理、控制、监视。实际上是一些控制寄存器和状态寄存器,是一个具有特殊功能的 RAM 区。

 由上可见,AT89C51 单片机的硬件结构具有功能部件种类全,功能强等特点。特别值得一提的是该单片机 CPU 中的微处理器实际上是一个完整的 1 位微计算机。这个 1 位微计算机有自己的 CPU、位寄存器、I/O 口和指令集。其在开关决策、逻辑电路仿真、过程控制方面非常有效;而 8 位机在数据采集、运算处理方面有明显的长处。MCS-51 单片机中 8 位机和 1 位机的硬件资源复合在一起,二者相辅相成,它是单片机技术上的一个突破,也是 MCS-51 单片机在设计上的精美之处。

 2.1.3 引脚说明 MCS-51 是标准的 40引脚双列直插式集成电路芯片,引脚分布可参照单片机引脚。

 P0.0~P0.7

 P0 口 8 位双向线(在引脚的 32~39 号端子); P1.0~P1.7

 P1 口 8 位双向线(在引脚的 1~8 号端子); P2.0~P2.7

 P2 口 8 位双向线(在引脚的 21~28 号端子); P3.0~P3.7

 P3 口 8 位双向线(在引脚的 10~17 号端子)。

 (1)

 P0 口有三个功能:

 (1)外部扩展存储器时,当作数据总线(如图中的 D0~D7 为数据总线接口)

 (2)外部扩展存储器时,当作地址总线(如图中的 A0~A7 为地址总线接口)

 (3)不扩展时,可作一般的 I/O 口使用,但内部无上拉电阻,作为输入输出时应在外部接上拉电阻。

 ( (2 )P1 口功能 P1 口只作 I/O 口使用,其内部有上拉电阻。

 (3)P2 口功能

 1、扩展外部存储器时,当作地址总线使用; 2、作一般 I/O 口使用,其内部有上拉电阻。

 (4)P3 口功能 1、除了作为 I/O 口使用外(其内部有上拉电阻),还有一些特殊功能,由特殊寄存器来设置。

 2、当作为输入时,上拉电阻将其电位拉高,若输入为低电平则可提供电流源,所以如果 P0 口作为输入时,或处在高阻抗状态,只有外接一个上拉电阻才能有效。

 (5)ALE/PROG 地址锁存控制信号

  在系统扩展时,ALE 用于控制把 P0 口的输出低 8 位地址送锁存器锁存起来,以实现低位地址和数据的隔离。

  PROG 为编程脉冲的输入端,在 AT89C51 单片机内部有一个 4kB 的程序存储器(ROM),ROM 的作用就是用来存放用户需要执行的程序。我们如何把编写好的程序存入这个 ROM 中的呢?实际上是通过编程脉冲输入采能写进去,而这个脉冲的输入端口就是 PROG。

 (6)PSEN 外部程序存储器读选通信号

  在读外部 ROM 时 PSEN 低电平有效,以实现外部 ROM 单元的读操作:

 1、内部 ROM 读取时,PSEN 不动作; 2、外部 ROM 读取时,在每个机器周期会动作两次; 3、外部 RAM 读取时,两个 PSEN 脉冲被跳过不会输出; 4、外接 ROM 时,与 ROM 的 OE 脚相接。

 (7)EA/VPP 访问程序存储器控制信号 1、接高电平时:CPU 读取内部程序存储器(ROM)

 2、接低电平时:CPU 读取外部程序存储器(ROM)。8031 单片机内部是没有ROM 的,因此在应用 8031 单片机时,这个脚时一直接低电平的。

 (8)RST 复位信号 当输入的信号连续 2 个机器周期以上高电平时即为有效,用以完成单片机的复位初始化操作,当复位后程序计数器 PC=0000H,即复位后将从程序存储器的0000H 单元读取第一条指令码。

 (9)XTAL1 和 XTAL2

  外接晶振引脚。当使用芯片内部时钟时,此二引脚用于外接石英晶体和微调电容;当使用外部时钟时,用于接外部时钟脉冲信号。

 (10)VCC

 电源+5V 输入

 (11)GND

 接地

 4 2.1.4 按键模块设计

 矩阵式按键输入模块,其特点是:电路和软件稍复杂,但相比之下,当键数越多时,越节约 I/O 口,比较节省资源 键盘可分为两类:编码键盘和非编码键盘。编码键盘是较多按键(20 个以上)和专用驱动芯片的组合,当按下某个按键时,它能够处理按键抖动、连击等问题,直接输出按键的编码,无需系统软件干预。通用计算机使用的标准键盘就是编码键盘。在智能仪器中,使用并行接口芯片 8279 或串行接口芯片 HD7279 均可以组成编码键盘,同时还可以兼顾数码管的显示驱动,其相关的接口电路和接口软件均可在芯片资料中得到。当系统功能比较复杂,按键数量很多时,采用编码键盘可以简化软件设计。但大多数智能仪器和电子产品的按键数目都不太多(20 个以内),为了降低成本和简化电路通常采用非编码键盘。非编码键盘的接口电路有设计者根据需要自行决定,按键信息通过接口软件来获取

  5 2.1.5 显示模块设计

 本设计采用的是 LCD1602 液晶显示屏。模块内部自带字符发生存储器(CGROM),字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是(41H),显示时模块把代码 41H 发给液晶模块,我们就能在液晶上看到字母“A”。

 1602 液晶模块内部的控制器共有 11 条控制指令,丰富的指令可以完成液晶的时序控制、工作方式式设置和数据显示等 图 2—3 编码键盘电路

 LCD 的特点:

 (1)低压微功耗; (2)平板型结构;

 (3)被动显示型(无眩光,不刺激人眼,不会引起眼睛疲劳); (4)显示信息量大(因为像素可以做得很小); (5)易于彩色化(在色谱上可以非常准确的复现); (6)无电磁辐射(对人体安全,利于信息保密);

 (7)长寿命(这种器件几乎没有什么劣化问题,因此寿命极长,但是液晶背光寿命有限,不过背光部分可以更换)

 2 2.2 软件电路

  1 2.2.1 键盘扫描的程序设计

 键盘扫描子程序,首先读出 P1 的低四位,然后读出 P1 口的高四位。然后键值并显示缓存。然后将键如的值转换为 ASCII 码然后就可以软件来设置硬件按键各个键代表的内容。

  读键程序使用的是反转法读键,不管键盘矩阵的规模大小,均进行两次读键。第一次所有行线均输出低电平,从所有读入键盘信息(列信息);第二次所有列线均输出低电平,从所有行线读入键盘信息(行信息)。数字键按下则将相应的数字送入缓存区,功能键按下则执行相应的程序 2 2.2.2 显示模块的程序设计

 显示模块程序首先要对显示模块进行初始化;然后控制光标的图 2—4 LCD 液晶显示屏

 位置;定义液晶显示的控制端口,用 SBIT 指令完成;然后设置清屏、关闭显示、归位、开显示、显示位置的首地址等等。

 2.2.3 程序运行流程图

  2.2.4 加减乘除子运算流程图

 图 2—5 程序运行流程图

 否 是 图 2—5 加减乘除子运算流程图

 矩阵赋值 "+"==num

 "*"==num

 "/"==num "="==num a=0;b=0 复位 i=0 firstflag==0?(输入数值的是第一个数据?)

 把第一个数据赋值给 a,并把标志位置 1,到下一个数据输入时可以跳转赋值给 b

 sscanf(temp,"%d",&a) 否 赋值完成后把缓冲区清零,防止下次输入影响结果sscanf(temp,"%d",&b);

  for(s=0;s<8;s++) 运算 C=a+b;c=a-b; C=a*b;c=a/b 输出结果

 c ‘=’键按下? 是

 第三部分

 设计成果

  仿真图

 程序 #include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义 #include<stdio.h>

 #define KeyPort P1 #define DataPort P0 //定义数据端口 程序中遇到 DataPort 则用 P0 替换

 sbit LATCH1=P2^2;//定义锁存使能端口 段锁存

 sbit LATCH2=P2^3;//位锁存

 unsigned

 char

  code

 dofly_DuanMa[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};// 显示段码值 0~9 // unsigned char code dofly_WeiMa[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//分别对应相应的数码管点亮,即位码

  unsigned char TempData[8]; //存储显示值的全局变量

 extern unsigned char TempData[8]; //存储显示值的全局变量

 extern unsigned char code dofly_DuanMa[10]; //显示函数,用于动态扫描数码管

  输入参数 FirstBit 表示需要显示的第一位,如赋值 2 表示从第三个数码管开始显示

 如输入 0 表示从第一个显示。

  Num 表示需要显示的位数,如需要显示 99 两位数值则该值输入 2 //按键扫描函数,返回扫描键值 // unsigned char KeyScan(void);

  //键盘扫描函数,使用行列反转扫描法

 //按键值处理函数,返回扫键值 // unsigned char KeyPro(void);

  void Display(unsigned char FirstBit,unsigned char Num); //定时器初始化子程序 //

 void Init_Timer0(void); //uS 延时函数,含有输入参数 unsigned char t,无返回值

 unsigned char 是定义无符号字符变量,其值的范围是

 0~255 这里使用晶振 12M,精确延时请使用汇编,大致延时

 长度如下 T=tx2+5 uS

 // void DelayUs2x(unsigned char t);// mS 延时函数,含有输入参数 unsigned char t,无返回值

 unsigned char 是定义无符号字符变量,其值的范围是

 0~255 这里使用晶振 12M,精确延时请使用汇编 // void DelayMs(unsigned char t);//主程序// main() {

  unsigned char num,i,sign; //数值

 unsigned char temp[8];

 //最大输入 8 个

  bit firstflag;

 int a=0,b=0;

 unsigned char s;

  Init_Timer0();

  //初始化定时器 0

 while (1)

  //主循环

 {

  num=KeyPro();

 //扫描键盘

 if(num!=0xff)

 //如果扫描是按键有效值则进行处理

  {

  if(i==0)

 //输入是第一个字符的时候需要把改行清空,方便观看 {

  for(s=0;s<8;s++) //赋值完成后把缓冲区清零,防止下次输入影响结果

  TempData[s]=0;

  }

 if(("+"==num)|| (i==8) || ("-"==num) || ("x"==num)|| ("/"==num) || ("="==num))//输入数字最大值 8,输入符号表示输入结束

  {

  i=0;

 //计数器复位

 if(firstflag==0)

 //如果是输入的第一个数据,赋值给 a,并把标志位置 1,到下一个数 据输入时可以跳转赋值给 b

 {

  sscanf(temp,"%d",&a);//从一个字符串输入到变量

 firstflag=1;

  }

 else

 sscanf(temp,"%d",&b);

  for(s=0;s<8;s++) //赋值完成后把缓冲区清零,防止下次输入影响结果

  temp[s]=0;

  if(num!="=")

 //判断当前符号位并做相应处理

 sign=num;

 //如果不是等号记下标志位

  else

  {

 firstflag=0;

  //检测到输入=号,判断上次读入的符合

  switch(sign)

  {

  case "+":a=a+b;

  break;

  case "-":a=a-b;

 break;

 case "x":a=a*b;

  break;

 case "/":a=a/b;

 break;

  default:break;

  }

 sprintf(temp,"%d",a);

 //打印十进制到临时缓冲区

  for(s=0;s<8;s++)

  //由于打印的是 ASCII 码值

 {

 if(temp[s]==0)

 //所以需要转换,如果为 0 表示 null 数码管上则不能显示, 所以赋值 0

  TempData[s]=0;

 else if(temp[s]==0x2d)//表示负号,数码管显示负号 0x40

  TempData[s]=0x40;

  else

  TempData[s]=dofly_DuanMa[temp[s]-"0"];//其他 0-9 负号则进行 ASCII 到

 数字处理,如当前是"3",用"3"-"0"=3

 //"3"的 16 进制是0x33,"0"的 16 进制是 0x30

 }

  sign=0;a=b=0;

 //用完后所有数据清零

  for(s=0;s<8;s++)

  temp[s]=0;

 }

 }

  else if(i<16)

  {

  temp[i]=num+"0";

  TempData[i]=dofly_DuanMa[num];//输出数据

  i++;

  //输入数值累加

 } }

  } }

 //按键扫描函数,返回扫描键值//

 unsigned char KeyScan(void)

 //键盘扫描函数,使用行列反转扫描法

 {

  unsigned char cord_h,cord_l;//行列值中间变量

  KeyPort=0x0f;

 //行线输出全为 0

  cord_h=KeyPort&0x0f;

  //读入列线值

  if(cord_h!=0x0f)

 //先检测有无按键按下

  {

 DelayMs(10);

 //去抖

 if((KeyPort&0x0f)!=0x0f)

  {

 cord_h=KeyPort&0x0f;

 //读入列线值

  KeyPort=cord_h|0xf0;

 //输出当前列线值

 cord_l=KeyPort&0xf0;

 //读入行线值

 while((KeyPort&0xf0)!=0xf0);//等待松开并输出

  return(cord_h+cord_l);//键盘最后组合码值

 }

 }return(0xff);

  //返回该值 }

 unsigned char KeyPro(void) {

  switch(KeyScan())

 {

  case 0x7e:return 1

 ;break;//0 按下相应的键显示相对应的码值

 case 0x7d:return 2

 ;break;//1

 case 0x7b:return 3

 ;break;//2

 case 0x77:return "+";break;//3

 case 0xbe:return 4

 ;break;//4

 case 0xbd:return 5

 ;break;//5

 case 0xbb:return 6

 ;break;//6

 case 0xb7:return "-";break;//7

 case 0xde:return 7

 ;break;//8

 case 0xdd:return 8

 ;break;//9

 case 0xdb:return 9

 ;break;//a

 case 0xd7:return "x";break;//b

 case 0xee:return 0

 ;break;//c

  case 0xed:return ".";break;//d

 case 0xeb:return "=";break;//e

 case 0xe7:return "/";break;//f

 default:return 0xff;break;

 } }

 //显示函数,用于动态扫描数码管

  输入参数 FirstBit 表示需要显示的第一位,如赋值 2 表示从第三个数码管开始显示如输入 0 表示从第一个显示。

  Num 表示需要显示的位数,如需要显示 99 两位数值则该值输入 2 //

 void Display(unsigned char FirstBit,unsigned char Num) {

 static unsigned char i=0;

 DataPort=0;

  //清空数据,防止有交替重影

 LATCH1=1;

  //段锁存

  LATCH1=0;

  DataPort=dofly_WeiMa[i+FirstBit]; //取位码

 LATCH2=1;

  //位锁存

  LATCH2=0;

  DataPort=TempData[i]; //取显示数据,段码

  LATCH1=1;

  //段锁存

  LATCH1=0;

 i++;

  if(i==Num)

 i=0;

 }

 //定时器初始化子程序

 //void Init_Timer0(void) {

  TMOD |= 0x01;

  //使用模式 1,16 位定时器,使用"|"符号可以在使用多个定时器时不受影响// TH0=0x00;

  //给定初值

 // TL0=0x00;

  EA=1;

 //总中断打开

  ET0=1;

  //定时器中断打开 TR0=1;

  //定时器开关打开 } //定时器中断子程序 // void Timer0_isr(void) interrupt 1

 {

  TH0=(65536-2000)/256;

 //重新赋值 2ms

  TL0=(65536-2000)%256;

 Display(0,8); }

 //uS 延时函数,含有输入参数 unsigned char t,无返回值

 unsigned char 是定义无符号字符变量,其值的范围是

 0~255 这里使用晶振 12M,精确延时请使用汇编,大致延时

 长度如下 T=tx2+5 uS

  // void DelayUs2x(unsigned char t) {

  while(--t); } //mS 延时函数,含有输入参数 unsigned char t,无返回值

 unsigned char 是定义无符号字符变量,其值的范围是

 0~255 这里使用晶振 12M,精确延时请使用汇编 // void DelayMs(unsigned char t) {

 while(t--)

 { //大致延时 1mS

  DelayUs2x(245);

 DelayUs2x(245);

 } }

 第四部分

 结束语

 通过此次毕业设计,让我进一步了解了对单片机的编程、电路的分析以及系统控制原理等专业知识的分析方法和解决实际问题的全面综合的锻炼。

 尤其是对编程方面有了进一步认识与掌握,通过查阅资料不断的总结和对比发现自己的不足。

  此次设计是一次很好的在单片机的基本原理、应用系统开发以及汇编语言的锻炼机会。此次设计无论从电路设计和程序编写都比较正规。

  通过这次毕业设计,使我得到了一次用专业知识、专业技能分析和解决问题全面系统的锻炼。使我在单片机的基本原理、单片机应用系统开发过程,以及在常用编程设计思路技巧(特别是 c 语言)的掌握方面都能向前迈了一大步,为日后成为合格的应用型人才打下良好的基础。

 第五部分

 致谢

 历时将近一个月的时间终于将这篇设计写完,在设计的编程过程中遇到了无数的困难和障碍,都在同学和老师的帮助下度过了。尤其要感谢我的设计指导老师,他对我进行了无私的指导和帮助,不厌其烦的帮助进行设计的修改和改进。另外,在校图书馆查找资料的时候,图书馆的老师也给我提供了很多方面的支持与帮助。在此向帮助和指导过我的各位老师表示最衷心的感谢!

 感谢这篇设计所涉及到的各位学者。本设计引用了数位学者的研究文献,如果没有各位学者的研究成果的帮助和启发,我将很难完成本篇设计的写作。

 由于我的学术水平有限,所写设计难免有不足之处,恳请各位老师和学友批评和指正

 第六部分

 参考文献

 [1] MCS-51/96 单片机原理及应用[M] .孙函芳. 北京:

 北京航空航天大学出版社 ,

 1994 年. [2] C 语言程序设计[M].谭浩强.北京.清华大学出版社.2000 [3] 单片机原理与应用技术

 [M] .北京:清华大学出版社,李珍. [4] 单片机原理与应用设计 [M] . 张毅刚等. .北京:电子工业出版社,2005.

  [5] 模拟电子技术基础(第三版)[M]. 周良权,傅恩锡,李世馨. 北京:高等教育出版社,2005 [6] Protel99SE 在电子技术实验中的应用[J]. 侯文芳. 科技信息,2011,第 2 期

推荐访问:毕业设计 单片机 计算器