一、 实验题目 基于51单片机的简易计算器 二、 内容1、实验内容 该系统通过单片机控制,实现对4*4键盘扫描进行实时的按键检测,并把检测数据存储下来。整个计算器系统的工作过程为:首先存储单元初始化,显示初始值和键盘扫描,判断按键位置,得出按键值,单片机则对数据进行储存与相应处理转换,之后送入数码管动态显示。整个系统可分为三个主要功能模块:功能模块一,实时键盘扫描;功能模块二,数据转换为了数码管显示;功能模块三,数码管动态显示。 2、功能说明 s1 s2 s3 s4 1 2 3 + s5 s6 s7 s8 4 5 6 - s9 s10 s11 s12 7 8 9 * s13 s14 s15 s16 0 clr = / 本来计划用数码管显示,结果发的单片机数码管驱动芯片与预想的不一样,不是通过段选,位选的方式。然后就没看的特别懂,临时换成了lcd1602显示屏,驱动程序较为固定,且显示的也更加全面。 通过中断定时器零设置中断,定时10s,开机10秒后,执行中断,自动清零,相当于自动按下按键14。 三、 原理图见下页。
四、 实验记录因为在课堂上未记录实验现象,所以在课下在按照自己的单片机的引脚设置更改了程序后,再将程序下载到51单片机中,得到以下实验结果: 刚下入程序时,初始化后的显示如下: 然后进行一些简单的计算显示: 最多可以进行八位数的运算: 五、 修改后程序框图
六、总结 本来在实验课上由于前期准备不够充分,课上经历了更改显示方式,由数码管显示改为了1602液晶屏显示,且在实验课上仅完成了计算器的功能,能够实现加减乘除的运算,但是不能实现连续运算功能。在课下又经过充分的学习了解,成功的加上了定时器中断,实现了定时清屏功能。由此可见,充足的课前准备能够极大地提高效率。 本次实验满足了设计要求,包含有矩阵按键的使用,定时器中断,LCD1602外设,将要求用到的内容都成功的联系在了一起。虽然该例子中的定时器中断在实际生活中并不会这样使用,不过通过这种方式,也让我对定时器中断的使用有了更加深刻的认识,也能够通过定时器中断进行一些简单的设计。 通过本次实验,加深了对51单片机原理的理解与认知,尤其是对矩阵按键扫描判断,定时器中断,LCD1602外设的应用等方面的原理的学习也提高了一个层次。通过本次实验,提高了自己的逻辑分析能力,发现问题解决问题的能力。提高了对C语言编程的理解与应用,能够灵活的运用例程达到自己的设计要求,完成实验。 七、附录 - #include "REG52.h"
- typedef unsigned char uint8;
- typedef unsigned int uint16;
- typedef unsigned long ulong;
- uint8 key;//存放按键值
- uint8 num,number,t;
- uint8 fuhao;//定义具体的那个符号,是加减还是乘除。
- uint8 flag; //定义有没有按下符号键,这个是统称
- long a,b,c,d; //定义运算数据的第一个和第二个及等于的数变量
- uint8 k; //定义小数点后面显示的位数
- uint8 biao;
-
- sbit rs = P1^0;
- sbit rw = P1^1;
- sbit e = P1^2; //LCD使能端
- uint8 dat1[]={1,2,3,0x2b-0x30, 4,5,6,0x2d-0x30, 7,8,9,0x2a-0x30, 0,0x01-0x30,0x3d-0x30,0x2b-0x30 };//保存显示的数据
-
- void Delay(unsigned int); //声明延时函数
- void InterruptTimer0() ;
-
- void lcdwrc(uint8 c) //写指令数据
- {
- Delay(5);
- rs=0;
- rw=0;
- e=0;
- P0=c;
- e=1;
- Delay(5);
- e=0;
- }
- void lcdwrd(uint8 dat) //写显示数据
- {
- Delay(5);
- rs=1;
- rw=0;
- e=0;
- P0=dat;
- e=1;
- Delay(5);
- e=0;
- rs=0;
- }
-
- void lcdinit() //lcd初始化
- {
- Delay(7);
- lcdwrc(0x38);
- Delay(3);
- lcdwrc(0x38);
- Delay(3);
- lcdwrc(0x38);
- Delay(3);
- lcdwrc(0x38);
- lcdwrc(0x08);
- lcdwrc(0x01);
- lcdwrc(0x06);
- lcdwrc(0x0c);
- key=0;
- num=0;
- flag=0;
- fuhao=0;
- a=0;
- b=0;
- c=0;
- d=0;
- biao=0;
- }
-
- //函数名称:Delay
- //函数功能:延时函数
- //入口参数:uiCount-延时参数,每加1增加0.5ms
- void Delay(unsigned int uiCount)
- {
- unsigned char j = 244;
- for(;uiCount > 0;uiCount--) while(--j);
- }
-
- void keyscan() //矩阵按键扫描函数
- {
- P2=0xef; //令第一行为0,然后判断是哪一列按下
- if(P2!=0xef)
- {
- Delay(5);
- if(P2!=0xef)
- {
- key=P2&0x0f;
- switch(key)
- {
- case 0x0e: num=0;break; //1
- case 0x0d: num=1;break; //2
- case 0x0b: num=2;break; //3
- case 0x07: num=3;break; //加
- }
- }
- while(P2!=0xef);
- if(num==0||num==1||num==2) //确认第一行的数1,2,3
- {
- if(flag==0) //没有按下符号键
- {
- a=a*10+dat1[num];
- }
- else
- {
- b=b*10+dat1[num];
- }
-
- }
- if(num==3)
- {
- flag=1;
- fuhao=1;//加号+
- }
- lcdwrd(0x30+dat1[num]);
- }
-
-
- P2=0xdf; //令第二行为0,判断是哪一列按下
- if(P2!=0xdf)
- {
- Delay(5);
- if(P2!=0xdf)
- {
- key=P2&0x0f;
- switch(key)
- {
- case 0x0e: num=4;break; //4
- case 0x0d: num=5;break; //5
- case 0x0b: num=6;break; //6
- case 0x07: num=7;break; //减—
- }
- }
- while(P2!=0xdf);
- if(num==4||num==5||num==6)
- {
- if(flag==0) //没有按下符号键
- {
- a=a*10+dat1[num];
- }
- else
- {
- b=b*10+dat1[num];
- }
- }
- else
- {
- flag=1;
- fuhao=2;//代表减号
- }
- lcdwrd(0x30+dat1[num]);
- }
-
-
- P2=0xbf; //令第三行为0,判断哪一列按下
- if(P2!=0xbf)
- {
- Delay(5);
- if(P2!=0xbf)
- {
- key=P2&0x0f;
- switch(key)
- {
- case 0x0e: num=8;break; //7
- case 0x0d: num=9;break; //8
- case 0x0b: num=10;break; //9
- case 0x07: num=11;break; //乘*
- }
- }
- while(P2!=0xbf);
- if(num==8||num==9||num==10)
- {
- if(flag==0) //没有按下符号键
- {
- a=a*10+dat1[num];
- }
- else
- {
- b=b*10+dat1[num];
- }
- }
- else
- {
- flag=1;
- fuhao=3;//代表乘号*
- }
- lcdwrd(0x30+dat1[num]);
- }
-
-
- P2=0x7f; //令第四行为0,判断哪一列按下
- if(P2!=0x7f)
- {
- Delay(5);
- if(P2!=0x7f)
- {
- key=P2&0x0f;
- switch(key)
- {
- case 0x0e: num=12;break; //0
- case 0x0d: num=13;break; //清除rst
- case 0x0b: num=14;break; //等号=
- case 0x07: num=15;break; //除/
- }
- }
- while(P2!=0x7f);
- switch(num)
- {
- case 12:
- if(flag==0) //没有按下符号键
- {
- a=a*10+dat1[num];
- lcdwrd(0x30);
- }
- else
- {
- b=b*10+dat1[num];
- lcdwrd(0x30);
- }
- break;
-
- case 13:
- lcdwrc(0x01); //清屏指令
- a=0;
- b=0;
- flag=0;
- fuhao=0;
- break;
-
- case 15:
- flag=1;
- fuhao=4;
- lcdwrd(0x2f);//除号/
- break;
-
- case 14:
- if(fuhao==1)//加
- {
- lcdwrc(0x4f+0x80);
- lcdwrc(0x04);//设置光标左移,屏幕不移动
- c=a+b;
- while(c!=0) //一位一位显示
- {
- lcdwrd(0x30+c%10);//显示结果的最后一位在0x4f的位置
- c=c/10;//取前面的结果数据
- }
- lcdwrd(0x3d); //显示等于号=
- a=0;
- b=0;
- flag=0;
- fuhao=0;//全部清除为0
- }
- if(fuhao==2) //减
- {
- lcdwrc(0x4f+0x80);
- lcdwrc(0x04);//设置光标左移,屏幕不移动
- if(a>b)
- c=a-b;
- else
- c=b-a;
-
- while(c!=0) //一位一位显示
- {
- lcdwrd(0x30+c%10);//显示结果的最后一位在0x4f的位置
- c=c/10;//取前面的结果数据
- }
- if(a<b) lcdwrd(0x2d); //显示-号
- lcdwrd(0x3d); //显示等于号=
- a=0;
- b=0;
- flag=0;
- fuhao=0;//全部清除为0
- }
- if(fuhao==3)//乘法
- {
- lcdwrc(0x4f+0x80);
- lcdwrc(0x04);//设置光标左移,屏幕不移动
- c=a*b;
- while(c!=0) //一位一位显示
- {
- lcdwrd(0x30+c%10);//显示结果的最后一位在0x4f的位置
- c=c/10;//取前面的结果数据
- }
- lcdwrd(0x3d); //显示等于号=
- a=0;
- b=0;
- flag=0;
- fuhao=0;//全部清除为0
- }
-
- if(fuhao==4)
- {
- k=0;
- lcdwrc(0x4f+0x80);
- lcdwrc(0x04);//设置光标左移,屏幕不移动
- c=(long)(((float)a/b)*1000);//强制转换为long。
- while(c!=0) //一位一位显示
- {
- k++;
- lcdwrd(0x30+c%10);//显示结果的最后一位在0x4f的位置
- c=c/10;//取前面的结果数据
- if(k==3)
- {
- lcdwrd(0x2e);
- k=0;
- }
- }
- if(a/b<0) //如果a比b小的话那么除的结果最高位是0
- {
- lcdwrd(0x30);
- }
- lcdwrd(0x3d); //显示等号
- a=0;
- b=0;
- flag=0;
- fuhao=0;//全部清除为0
- }
- break;
-
- }
- }
-
- }
-
- void InterruptTimer0() interrupt 1 //定时器中断0
- {
- TH0=0xDC; //装初值
- TL0=0x00;
- number++;
- if(number==100) //定时1s
- {
- number=0;
- t++;
- if(t==10) //定时10s
- {
- t=0;
- lcdwrc(0x01); //清屏指令
- a=0;
- b=0;
- flag=0;
- fuhao=0;
- }
- }
- }
-
- void main() //主函数
- {
- TH0=0xDC; //装初值
- TL0=0x00;
- TMOD=0x01; //定时器0工作于16位,用于定时产生中断
- EA=1; //允许总中断
- ET0=1; //允许定时器0中断
- TR0=1; //开定时器0
- lcdinit();
- while(1)
- {
- keyscan();
- }
- }
复制代码
完整的Word格式实验报告文档51黑下载地址: |