
题 目: 简易计算器
班 级:
姓 名:
学 号:
指导老师:
日 期: 2013 年 10月 11 日
一.前言
单片机课程设计是单片机原理课程的实践性环节。是在我们学习了《单片机原理》等课程的基础上进行的综合性训练,我们组这次训练的课题是基于单片机简易计算器。此次课程设计的课题是针对我们学习《单片机原理》这门课程的基础上,并在其辅助下完成的。此次进行的综合性训练,不仅培养了我如何合理运用课本中所学到的理论知识与实践紧密结合,解决实际问题的能力
二.课程设计的目的和要求
2.1课程设计的目的
首先,综合运用单片机原理与接口技术课程中所学到的理论知识来完成此次设计课题,培养我们查阅手册和文献资料的良好习惯,以及培养我们分析和解决实际问题的能力。其次,在学习了理论知识的基础上进一步熟悉常用电子器件的类型和特征,并掌握合理选用的原则。再次,就是学会电子电路的安装与调试技能,以及与同组的组员的团结合作的精神。
2.2课程设计要求
利用c51作为主控器组成一个四则运算的计算器。
三.总体设计
3.1基本工作原理
本设计利用ATC51单片机来控制液晶显示器和矩阵式键盘,实现了简易的计算器功能。通过键盘输入需要计算的计算式子,该式子会显示在液晶的第一行,当键入等于号后,计算结果会显示在液晶的第二行。本设计中液晶选用1602字符型液晶显示器,显示参与运算的数字以及最终的运算结果,键盘采用4*4矩阵式键盘。
3.2系统组成单元
处理单元
CPU选用ATC—51对整个系统进行控制:
它将数据输出到显示屏,实现键入、输出的显示;根据键盘输入调用相应键处理子程序,实现数据的计算;单片机的管脚如下所述:
ATC51的管脚分布如下:
VCC:供电电压。
GND:接地。
P0口:P0口为一个8位漏级开路双向I/O口,每脚可吸收8TTL门电流。 P1口:P1口是一个内部提供上拉电阻的8位双向I/O口,P1口缓冲器能接收输出4TTL门电流。
P2口:P2口为一个内部上拉电阻的8位双向I/O口,P2口缓冲器可接收,输出4个TTL门电流。
P3口:P3口管脚是8个带内部上拉电阻的双向I/O口,可接收输出4个TTL门电流。
RST:复位输入。当振荡器复位器件时,要保持RST脚两个机器周期的高电平时间。
ALE/PROG:当访问外部存储器时,地址锁存允许的输出电平用于锁存地址的地位字节。 /PSEN:外部程序存储器的选通信号。在由外部程序存储器取指期间,每个机器周期两次/PSEN有效。但在访问外部数据存储器时,这两次有效的/PSEN 3信号将不出现。
/EA/VPP:当/EA保持低电平时,则在此期间外部程序存储器(0000H-FFFFH),不管是否有内部程序存储器。
XTAL1:反向振荡放大器的输入及内部时钟工作电路的输入。
XTAL2:来自反向振荡器的输出。
电源电路部分
在各种电子设备中,直流稳压电源是必不可少的组成部分,它是电子设备唯一能量来源,它的设计思路是根据我们以前学过的模电电子技术,要想得到我们所要的+6V输出电压,就需将交流220V的电压经过变压器、整流电路、滤波电路和稳压电路四个部分。
LCD输出显示部分
1602采用标准的16脚接口,其管脚功能介绍如下:
1:VSS为电源地
2:VDD接5V电源正极
3:V0为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高。
4:RS为寄存器选择,高电平1时选择数据寄存器、低电平0时选择指令寄存器。 5:RW为读写信号线,高电平(1)时进行读操作,低电平(0)时进行写操作。 6:E(或EN)端为使能(enable)端。
7~14:D0~D7为8位双向数据端。
15~16:空脚或背灯电源。15脚背光正极,16脚背光负极
。
四.硬件设计键盘输入部分
矩阵式键盘由行线和列线组成,按键位于行和列的交叉点上,很明显,在所需按键数量较多时能节省很多的I/O口。
4.1简易计算器的电路原理图
4.2系统选用的主要元器件
4.2.1 ATC51简介
ATC51是一种带4K 字节FLASH 存储器(FPEROM—Flash Programmable and Erasable Read Only Memory)的低电压、高性能CMOS 8位 微处理器,俗称 单片机。ATC2051是一种带2K 字节闪存可编程可擦除 只读存储器的 单片机。 单片机的可擦除 只读存储器可以反复擦除1000次。该器件采用ATMEL高密度非易失 存储器制造技术制造,与工业标准的MCS-51指令集和输出管脚相兼容。由于将多功能8位CPU和闪烁 存储器组合在单个芯片中,ATMEL的ATC51是一种高效微控制器,ATC2051是它的一种精简版本。ATC51 单片机为很多 嵌入式控制系统提供了一种灵活性高且价廉的方案。
4.2.2 LCD显示器(1602)
工业字符型液晶,能够同时显示16x02即32个字符。(16列2行)
1602液晶也叫1602字符型液晶,它是一种专门用来显示字母、数字、符号等的点阵型液晶模块。它由若干个5X7或者5X11等点阵字符位组成,每个点阵字符位都可以显示一个字符,每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用,正因为如此所以它不能很好地显示图形(用自定义CGRAM,显示效果也不好)。
1602LCD是指显示的内容为16X2,即可以显示两行,每行16个字符液晶模块(显示字符和数字)。
4.2.3其他
按钮开关(SW-PB),排阻(9管脚,1k),电阻、电容、晶振、发光二极管等若干。
五.软件设计
该计算器系统的软件设计分为以下几个模块:(1)主程序模块,(2)键盘扫描及识别子程序,(3)显示子程序,(4)计算程序。
六.得体会
此次课程设计我和同学通过团队合作完成,从中知道以及团队合作的重要性。本次课程设计用到了单片机的多块模块,团队分工完成彼此的模块,从而提高团队合作的效率。实验的完成让我更加了解单片机的编程和单片机的各个模块的工作方式。
七.源程序
如下:
#include #include #define int8 unsigned char #define int16 unsigned int sbit EN=P2^3; //定义引脚 sbit RS=P2^4; sbit RW=P2^0; sbit busy=P0^7; char code num[]={ 7,8,9,'*', 4,5,6,'/', 1,2,3,'-', 'c',0,'=','+'}; char code num1[]={'0','1','2','3','4','5','6','7','8','9'}; static char ckey; //当前按键字符 long a,b;//前后两数 char flag;//是否有符号键按下 char f;//判断按下的是什么符号键(+,-,*,/) long result;//运算结果 static int16 c=0;//字符显示位置 void delay_ms(int8 z); // 延迟函数 void wait_busy();//忙等待 void write_cmd(int8 cmd);//写指令 void write_data(int8 dat);//写数据 void Initialize_LCD(); //1602 初始化 void LCD_ShowString(int8 r, int8 c,int8 *str); //在指定位置显示字符串 void keyboard();//键盘按键扫描 void digit_a(); //加减乘除处理 void digit_b();//a和b运算的结果在1602上显示 void digit_c();//把输入的数存入到a和b //------------------------------------------------------------------------------------------------------ //名称:lcd1602液晶屏控制与显示程序 //------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------- //延时 //------------------------------------------------------------------------------------------------------------- void delay_ms(int8 z) // 延迟函数 { int8 y; for(z;z>0;z--) for(y=0;y<110;y++); } //------------------------------------------------------------------------------------------------------- //忙等待 //------------------------------------------------------------------------------------------------------- void wait_busy() { do{ P0=0XFF; RS=0; RW=1; EN=0; delay_ms(1); EN=1; }while(busy==1); } //--------------------------------------------------------------------------------------------------------- //写指令 //--------------------------------------------------------------------------------------------------------- void write_cmd(int8 cmd) { P0=cmd; RS=0; RW=0; EN=0; wait_busy(); EN=1; } //----------------------------------------------------------------------------------------------------------- //写数据 //----------------------------------------------------------------------------------------------------------- void write_data(int8 dat) { P0=dat; RS=1; RW=0; EN=0; wait_busy(); EN=1; } //------------------------------------------------------------------------------------------------------------ //1602 初始化 //------------------------------------------------------------------------------------------------------------ void Initialize_LCD() { write_cmd(0x38); write_cmd(0x0c); write_cmd(0x06); write_cmd(0x80); write_cmd(0x01); a=0;b=0; flag=0; result=0; c=0; ckey=0; } //----------------------------------------------------------------------------------------------------------- //在指定位置显示字符串 //---------------------------------------------------------------------------------------------------------- void LCD_ShowString(int8 r, int8 c,int8 *str) { int8 i=0; code int8 DDRAM[]={0X80,0XC0}; write_cmd(DDRAM[r] | c); for(i=0;str[i] && i<16;i++) write_data(str[i]); for(;i<16;i++) write_data(' '); } //------------------------------------------------------------------------------ //键盘按键扫描 //------------------------------------------------------------------------------ void keyboard() { int16 h_code,l_code,key_code; P3=0xf0; h_code=P3; h_code=h_code&0xf0; delay_ms(200); P3=0x0f; l_code=P3; l_code=l_code&0x0f; delay_ms(200); key_code=h_code|l_code; if(key_code!=0xFF) { switch(key_code) { case 0xee: LCD_ShowString(0,c++,"7");ckey=num[0];digit_c(); break; //输入字符7 case 0xde: LCD_ShowString(0,c++,"8");ckey=num[1];digit_c(); break; //输入字符8 case 0xbe: LCD_ShowString(0,c++,"9");ckey=num[2];digit_c(); break; //输入字符9 case 0x7e: LCD_ShowString(0,c++,"*");flag=1;f=0; break; //输入字符* case 0xed: LCD_ShowString(0,c++,"4");ckey=num[4];digit_c();break; //输入字符4 case 0xdd: LCD_ShowString(0,c++,"5");ckey=num[5];digit_c(); break; //输入字符5 ; case 0xbd: LCD_ShowString(0,c++,"6");ckey=num[6];digit_c();break; //输入字符6 case 0x7d: LCD_ShowString(0,c++,"/");flag=1;f=1; break; //输入字符 case 0xeb: LCD_ShowString(0,c++,"1");ckey=num[8];digit_c(); break; //输入字符1 case 0xdb: LCD_ShowString(0,c++,"2");ckey=num[9]; digit_c(); break; //输入字符2 case 0xbb: LCD_ShowString(0,c++,"3");ckey=num[10];digit_c(); break; //输入字符3 case 0x7b: LCD_ShowString(0,c++,"-");flag=1;f=2; break; //输入字符- case 0xe7: flag=0;f=4;digit_a();break; //输入字符c case 0xd7: LCD_ShowString(0,c++,"0");ckey=num[13];digit_c();break; //输入字符0 case 0xb7: digit_a();break; //输入字符= case 0x77: LCD_ShowString(0,c++,"+");flag=1;f=3; break; //输入字符+ default : break; } if(c>15) { c=0; } } } //------------------------------------------------------------------------------- // 数据处理 //------------------------------------------------------------------------------- void digit_a() //加减乘除处理 { switch(f) { case 0: result=a*b; digit_b(); break; case 1: result=a/b; digit_b(); break; case 2: result=a-b; digit_b(); break; case 3: result=a+b; digit_b(); break; case 4: Initialize_LCD(); break; default:break; } } void digit_b() //a和b运算的结果在1602上显示 { int8 i=0,j=0,k; long r; r=result; while(0!=result) { result/=10; i++; } if(result==0) { write_cmd(0x80+0x4f); write_data(num1[0]); } for(;j { k=r/10; r%=10; write_cmd(0x80+0x4f-j); write_data(num1[r]); r=k; } write_cmd(0x80+0x4f-i-1); write_data('='); } void digit_c()//把输入的数存入到a和b { if(flag==0) { a=ckey+a*10; } else { b=ckey+b*10; } } //---------------------------------------------------------------------------- // 主函数 //------------------------------------------------------------------------------- void main() { Initialize_LCD(); while(1) { keyboard(); } }
