单片机课程设计报告

《单片机原理及接口技术》课程设计

 

题目:      简易计算器设计                      

班    级:      电子1547      

姓    名:  苏丹丹、李静、齐倩                       

学    号: 05号、17号、11   

指导教师:       张老师        

时    间:     20##12     

        西安航空学院电气学院


目录

一、选题的背景和意义-------------------1

1.1选题的背景-------------------------------------1

1.2选题的意义-------------------------------------1

二、总体设计-------------------------------1

2.1设计任务---------------------------------------1

2.2方案选择---------------------------------------1

三、硬件设计-------------------------------2

3.1 元器件名称--------------------------------------------------------2

3.2 计算器按键介绍--------------------------------------------------2

3.3硬件系统框图、单元电路--------------------------3

四、软件设计-------------------------------3

4.1 软件调试步骤-----------------------------------------------------3

4.2软件设计流程图---------------------------------------------------4

五、结束语------------------------------------5

六、参考文献--------------------------------5

七、附录---------------------------------------6


 一、背景和意义

1.1、选题的背景:

     当今时代,是一个新技术层出不穷的时代。在电子领域,尤其是自动化智能控制领域,传统的分立元件或数字逻辑电路构成的控制系统正以前所未见的速度被单片机智能控制系统所取代。单片机具有体积小、功能强、成本低、应用面广等优点,可以说,智能控制与自动控制的核心就是单片机。目前,一个学习与应用单片机的高潮正在工厂、学校及企事业单位大规模地兴起。过去习惯于传统电子领域的工程师、技术员正面临着全新的挑战,如不能在较短时间内学会单片机,势必会被时代所遗弃,只有勇敢地面对现实,挑战自我,加强学习,争取在较短的时间内将单片机技术融会贯通,才能跟上时代的步伐。

1.2、选题的意义:

     单片机课程设计是单片机原理课程的实践性环节。是在我们学习了《单片机原理》等课程的基础上进行的综合性训练,我们组这次训练的课题是基于单片机简易计算器。此次进行的综合性训练,不仅培养了我如何合理运用课本中所学到的理论知识与实践紧密结合,独立解决实际问题的能力。

二、总体设计

       本设计主要是依据单片机的原理来进行简易计算器的设计,设计采用了80C51单片机作为计算器的主控制器,LM020 L作为显示器,4×4 keypad-smallcalc键盘作为输入按键,通过软硬件相结合,来实现整数的“加”、“减”、“乘”、“除”运算。

2.1设计任务 

本设计主要通过单片机的原理和应用,以电子技术基础的基本理论为指导,利用Protues仿真软件和Keil编程软件来设计简易计算器。

其主要设计要求有: 

1、对计算器硬件系统的设计; 

2、运用keil进行计算器软件系统的设计; 

3、在protues仿真平台上,对软件进行调试及仿真;    

4、软硬件结合之后,进行整体电路的调试与测试。

2.2 方案选择

 (1)方案一 

   根据功能和指标要求,本系统选用MCS-51系列单片机AT89C51为主控机。通过扩展必要的外围接口电路,实现对计算器的设计。计算器电路包括三个部分:显示电路、4*4键扫描电路、单片机微控制电路。用七段数码管作为显示电路,矩阵键盘作为输入电路。

(2)方案二 

根据计算器的功能要求,选择AT89C51为主控机,通过扩展必要的外围接/口电路,实现对计算器的设计。外部主要由4*4矩阵键盘和一个液晶显示屏构成,内部由一块AT89C51单片机构成。计算器电路包括四个部分:选用LCD作为显示部分,矩阵键盘作为输入部分,运算模块,单片机控制部分。

最终选择方案二。

三、硬件设计

3.1 元器件名称

(1)80C51.BUS

(2)74LS00

(3)74LS373

(4)6264

(5)7407

(6)KEYPAD-SMALLCALC

3.2 计算器按键介绍

计算器所需按键有:数字键:’1’,’2’,’3’,’4’,’5’,’6’,’7’,’8’,’9’,’0’     功能键:’+’, ’-‘ , ’*’, ’/ ’ , ’ = ’, ’ C( 清零)’ 共计16个按键,采用4*4矩阵键盘,键盘的行和列之间都有公共端相连,四行和四列的8个公共端分别接P1.0~P1.7,这样扫描P1口就可以完成对矩阵键盘的扫描,通过对16个按键进行编码,从而得到键盘的口地址,对比P1口的扫描结果和各按键的地址,我们就可以得到是哪个键按下,从而完成键盘扫描的功能。键盘电路设计 键盘输入采用4*4的矩阵键盘。4*4键盘分别与PC0~PC7相连。PC0~PC3作为输入口(回送线),PC4~PC7作为输出口(扫描线)。16个按键分别用于控制数字“0~9”以及数学运算符号“+、-、*、/”。

3.3硬件系统框图、单元电路

四、软件设计

4.1 软件调试步骤   

1)打开软件后,在Project菜单中选择New Project命令,打开一个新项目。保存此项目,输入工程文件名后,并保存工程文件的目录。

2)为项目文件选择一个目标器件,即选择8051的类型。在Data base 列表框中选择“ATML 89C51”,确定。

3)上述设置好后,创建源程序文件并输入程序代码。输入好代码后点击“文件/保存”。

4)把源文件添加到项目中,用鼠标指在目标工作区的目标1,点击右键在弹出的菜单中选择添加文件到源代码组,在弹出的添加文件框中,选择需要添加到项目中的文件。

5)开始编译,对项目文件进行编译。若没有错误后进行硬件调试。

4.2软件设计流程图

 


菱形: 键码是?菱形: 功能键?菱形: 有键输入                                                     

 

五、结束语

      课程设计是培养学生综合运用所学知识,发现、提出、分析和解决实际问题,锻炼实践能力的重要环节,是对学生实际工作能力的具体训练和考察过程。随着科学技术发展的日新日异,单片机已经成为当今计算机应用中空前活跃的领域, 在生活中可以说得是无处不在。因此作为电子信息工程专业的学生来说掌握单片机的开发技术是十分重要的。 

        我的题目是简易计算器,对于我们这些实践中的新手来说,这是一次考验。怎么才能找到课堂所学与实际应用的最佳结合点?怎样让自己的业余更接近专业?怎样让自己的计划更具有序性,而不会忙无一用?这都是我们所要考虑和努力的。这次课程设计我学到很多很多的东西,学会了怎么样去制定计划,怎么样去实现这个计划,并掌握了在执行过程中怎么样去克服心理上的不良情绪。不仅巩固了以前所学过的知识,而且学到了很多在书本上所没有学到过的知识,掌握了一种系统的研究方法,可以进行一些简单的编程。通过这次课程设计使我懂得了理论与实际相结合是很重要的,只有理论知识是远远不够的,只有把所学的理论知识与实践相结合起来,从理论中得出结论,才能真正为社会服务,从而提高自己的实际动手能力和独立思考的能力。同时在设计的过程中发现了自己的不足之处,对以前所学过的知识理解得不够深刻,掌握得不够牢固,对单片机汇编语言掌握得不够好。     这次课程设计通过我们小组的努力终于顺利完成了,在设计中遇到了很多编程问题,最后在老师的辛勤指导下,终于迎刃而解,在此我表示感谢!同时,对给过我帮助的所有同学和指导老师再次表示忠心的感谢!

六、参考文献

1、《典型模块设计实例导航》编著:求是科技

2、《基于Proteus的8051单片机实例教程》主编:李学礼

3、《单片机c语言程序设计实训100例》主编:彭伟

4、《单片机实训教程》主编:贡雪梅

5、《Proteus教程》主编:朱清慧

6、《单片机技术“做中学”案例教程》主编:陈石胜

七、附录

仪器名称及数量

       

                       显示、乘法、除法

 

                        

加法、减法

c语言程序编程

#include <reg51.h>

#include <ctype.h>

#include "calc.h"

static data long lvalue;

static data long rvalue;

static data char currtoken;

static data char lasttoken;

static data char lastpress; 

static xdata char outputbuffer[MAX_DISPLAY_CHAR];//输出缓冲

 //----------------------------------------------

 //主程序 //-------------

void main()

 { 

//变量初始化

 lvalue=0; 

rvalue=0; 

currtoken='='; 

lasttoken='='; 

//初始化LCD

 initialise();  

calc_putput(OK); 

calc_evaluate();

 }

 //-----------------------------------------

//获取按键值并进行计算处理

//-----------------------------------------

 void calc_evaluate()

char data key;

 int data i;

 char xdata number[MAX_DISPLAY_CHAR]; 

char xdata *bufferptr; 

//清除缓冲 

for(i=0;i<=MAX_DISPLAY_CHAR;i++)    number[i]=' ';  

bufferptr=number;  

while(1) 

 {   

key=calc_getkey();

if(calc_testkey(key))  

  {    

 if(bufferptr!=&number[MAX_DISPLAY_CHAR-2])    

 {     

 *bufferptr=key;     

 calc_display(number);    

  bufferptr++;    

 }    

}    

else  

  {   

  if(lasttoken=='0')        lvalue=calc_asciidec(number);

     else      rvalue=calc_asciidec(number);  

   //清除数字缓冲

  bufferptr=number;    

 for(i=0;i<=MAX_DISPLAY_CHAR;i++)      number[i]=' ';    

 //处理操作符    

 currtoken=key;   

  if(currtoken=='C')     calc_opfunctions(currtoken);    

 else      calc_opfunctions(lasetoken);   

  //清除输出缓冲   

  for(i=0;i<=MAX_DISPLAY_CHAR;i++)      outpufbuffer[i]=' ';     

bufferptr=number;    

 if(currtoken!0x3D)      lasttoken=currtoken;  

  }    

 lastpress=key;  

 }

 } 

//-------------------------------------------

 //   根据运算符按键进行运算处理

 //-------------------------------------------- void calc_opfunctions (char token)

 {  

char data result; 

 switch(token)

  { 

  case '+':if(currtoken=='='||isdigit(lastpress)) 

{   

 lvalue+=rvalue;  

  result=calc_chkerror(lvalue); 

  } 

  else result=SLEEP;  

 break;  

 case '-':if(currtoken=='='||isdigit(lastpress))  

 {   

 Lvalue-=rvalue;   

 result=calc_chkerror(lvalue);  

 }  

 else result=SLEEP; 

  break;   

case '*':if(currtoken=='='||isdigit(lastpress)) 

  {   

 lvalue*=rvalue;   

 result=calc_chkerror(lvalue);  

 } 

  else result=SLEEP; 

  break;  

 case '/':if(currtoken=='='||isdigit(lastpress)) 

 {

if (rvalue)

 {    

lvalue/=rvalue;   

 result=calc_chkerror(lvalue);  

 }  

 else result=SLEEP;  

}

else result=SLEEP; 

 break; 

 //取消  

case 'C':lvalue=0;      rvalue=0;           currtoken='0';           lasttoken='0';    

 result=OK;    

 break; 

 default:result=SLEEP;

  }

  calc_output(result);

 } 

//--------------------------------------------------------

 //   检查待显示数据的上界和下界

 //   例如,99999999 and -99999999 

//--------------------------------------------------------

 int calc_chkerror (long num)

 { 

 if(num>=-99999999&&num<=99999999)   return OK;  else    return ERROR;

 } 

//-----------------------------------------------------------

 //   根据操作状态输出 

//----------------------------------------------------------

void calc_output {int status}

- {  switch(status)

  { 

  case OK:calc_deaplay(calc_decascii(lvalue));      break;  

 case SLEEP:    break; 

  case ERROR:calc_display("Exception");       break; 

  default:calc_display("Exception")       break; 

 } 

//----------------------------------------------------

 //将ASCII字符串转换为浮点数 

//----------------------------------------------------

 long calc_asciidec (char *buffer)

 {

   long data value; 

 long data digit; 

 value=0; 

 while(*buffer!=' ')

  {  

 digit=*buffer-'0'; 

  value=value*10+digit; 

  buffer++;

  } 

 return value;

 } 

//----------------------------------------------------

 //将浮点数转换为ASCII字符串 

//---------------------------------------------------- 

char *calc_decascii(long num)

 {

  long data temp=num;

  char xdata *avvayptr=&outputbuffer[MAX_DISPLAY_CHAR]; 

 long data divisor=10;

 long data result; 

 char data remainder,asciival; 

 int data i; 

  //如果计算结果为0。,则在缓冲中插入0并结束

  if(!temp) 

 {  

 *arrayptr='0';   goto done; 

 } 

  if(temp<0) //处理负数

  {  

 outputbuffer[0]='-';   temp-=2*temp;

  } 

 for(i=0;i<sizeof(outputbuffer);i++) 

 { 

  remainber=temp%divisor;  

 result=temp/divisor; 

  if((!remainder)&&(!result))    *arrayptr=' ';  

 else 

  {    

asciival=remainder+'0';  

  *arrayptr=asciival; 

  } 

  temp/=10; 

  //为“—”号保留位置 

  if(arrayptr!=&outputbuffer[1])    arrayptr--; 

 }  

done:return outputbuffer;

 } 

//------------------------------------------------ 

//测试按键时数字还是操作符,如果是数字则返回1.是操作符时返回0 

//------------------------------------------------ 

char calc_testkey (char key)

 {

  if(isdigit(key))   return 1;  else   teturn 0;

 } 

//------------------------------------------------ 

//调用input例程搜索按键,并返回按键的ASCII码值

 //------------------------------------------------ 

char calc_getkey()

 { 

 char data mykey; 

 do

  { 

  mykey=input(); 

 }  while(mykey==0);

  return mykey;

 } 

//------------------------------------------------ 

//调用Output和Clearscreen例程向LCD输出ASCII

 //------------------------------------------------ 

void calc_display (char buf[MAX_DISPLAY_CHAR]) 

 int data i=0;

  clearscreen(); 

 for(i;i<=MAX_DISPLAY_CHAR;i++) 

 { 

  if(buf[i]!=' ')    output(buf[i]); 

 }

 } 

//----------------------calc.h---------------------

 //本例头文件 

//-------------------------------------------------

 typedef unsigned short WORD;

 typedef unsigned char  BYTE; 

//------------------------------------------------ 

//定义适合屏幕显示的ASCII字符的最大个数

 //------------------------------------------------

 #define MAX_DISPLAY_CHAR 9 

//------------------------------------------------

 //错误处理状态 

//------------------------------------------------ 

enum ERROR {OK=0,SLEEP=1,ERROR=2};

 //------------------------------------------------

 //函数声明 

//------------------------------------------------

 void calc_evaluate(); 

void calc_opfunctions  (char token); 

char calc_testkey  (char ch); 

long calc_asciidec  (char *buffer);

 char *calc_decascii  (long num);

 int calc_chkerror  (long num);

 void calc_output  (int status);

 char calc_getkey(); 

void calc_display(char buf[MAX_DISPLAY_CHAR]); 

void initialise();

 char input(); 

char output(char ch);

 void clearscreen; 

//---------------------------lcd.c-------------------------

 //单行液晶显示程序 

//--------------------------------------------------------- 

#include<reg51.h>

 #include<absacc.h> 

#define uchar unsigned char 

#define LCD_CMD_WR      0x00

 #define LCD_DATA_WR    0x01

 #define LCD_BUSY_RD     0x02

 #define LCD_DATA_RD     0x03

 #define LCD_PAGE        0x80 

#define LCD_CLS            1

 #define LCD_HOME           2

 #define LCD_SETMODE        4 

#define LCD_SETVISIBLE     8

 #define LCD_SHIFT         16 

#define LCD_SETFUNCTION   32

 #define LCD_SETCGADDR     64

 #define LCD_SETDDADDR    128

 sbit bflag=ACC^7;//忙标志位 

void wrcmd(uchar); 

void output(char);

 void busywait(); 

//------------------------------------------------

 //初始化LCD 

//------------------------------------------------ 

void initialise() 

 wrcmd(0x30);   //1行8位

  wrcmd(LCD_SETVISIBLE+4);  //显示开,关光标  

wrcmd(LCD_SETDDADDR+15);  //从右边开始显示 

 wrcmd(LCD_SETMODE+3);     //  递增左移

 } 

//------------------------------------------------

//清屏并将显示位置起点设置在最右边

 //------------------------------------------------ 

void clearscreen()

 {

  wrcmd(LCD_CLS);  

 wrcmd(LCD_SETDDADDR+15);  

 } 

//------------------------------------------------

 //向LCD写命令 

//------------------------------------------------

 void wrcmd(uchar cmd)

 { 

 uchar volatile pdata *p=LCD_CMD_WR; 

 P2=LCD_PAGE; 

 *p=cmd;

  //上面三行可用下面的代码替换 

 //XBYTE[0x8000]=cmd; 

 busywait(); } 

//------------------------------------------------

 //向LCD写一个字符 

//------------------------------------------------

 void output(char ch)

 {

  char volatile pdata *p=LCD_DATA_WR; 

 P2=LCD_PAGE; 

 *p=ch; 

 //上面三行可用下面的代码替换 

 //XBYTE[0x8001]=ch; 

 busywait();

 } 

//------------------------------------------------

 //忙等待 

//------------------------------------------------

 void busywait()

 { 

 uchar volatile pdata *p=LCD_BUSY_RD; 

 P2=LCD_PAGE;  

//上面两行可改成:

  //uchar volatile pdata *p=0x8002; 

 Do

  { 

  ACC=*p; 

 } while(bflag==1);

  //上述所有代码也可用以下代码替换

  /* 

 do 

 {  

 ACC=XBYTE[0x8002];

  }  while(bflag==1);  

*/

 } 

//------------------keypad.c------------------- 

//键盘扫描函数char input();返回按键的ASCII码

 //---------------------------------------------

 #include<reg51.h> 

#include<intrins.h>  

char code keycodes[]=

 {

  '7','8','9','/',

  '4','5','6','*',

  '1','2','3','-', 

 'C','0','=','+' 

}; 

char data keyflags[16]; 

//------------------------------------------------

 //获取键盘按键子程序 

//------------------------------------------------

 char input()

 { 

 char *pKeyflag=keyflags;      //标识按键指针 

 char RowAddr=0xef;                     //键盘行地址1110 1111 

 char ColData=0;                        //列数据 

 char i,j,Tmp=0; 

 for(i=0;i<4;i++) 

 {  

 P2=RowAddr;   //在P2端口设置行地址  

 _nop_();  

 Tmp=P1&0x0f;  //从P1端口读取列数据  

 for(j=0;j<4;j++)  

 {   

 ColData=Tmp;      //保存当前列数据    

if((Tmp&0x01)==0x00)   //如果有键按下  

  {   

  Tmp=*pKeyflag;

*pKeyflag=1;               //标识按键    

 if(Tmp==0)                     //有新按键按下    

 {     

 P2=0xff;    

  return keycodes[pKeyflag-keyflags];

     }   

 }  

  else *pKeyflag=0;   

 pKeyflag++;   

 Tmp=ColData>>1;  

 } 

  RowAddr<<=1;

  } 

 P2=0xff; 

 return 0; 

}

相关推荐