实验四 单片机设计实验.docx
- 文档编号:11587867
- 上传时间:2023-03-19
- 格式:DOCX
- 页数:20
- 大小:82.98KB
实验四 单片机设计实验.docx
《实验四 单片机设计实验.docx》由会员分享,可在线阅读,更多相关《实验四 单片机设计实验.docx(20页珍藏版)》请在冰豆网上搜索。
实验四单片机设计实验
单片机实验报告
实验名称:
实验四——16键计算器
学生姓名:
xxx
专业:
电子信息工程
班级:
电信09-x
学号:
0903403xxxx
日期:
2011年12月27日
实验四单片机设计实验
一、实验目的
1、掌握单片机定时器、中断、键盘扫描、动态显示及数值计算的综合运用能力;
2、掌握编程的运用能力;
3、设计一只简易的16键计算器。
二、实验内容
编程实现上图的简易16键4位十进制整数计算器的功能。
要求:
1.设计4*4的键盘,其中10个数字键0~9,其余6个为“+”“-”“*”“/”“=”
和“C”
2.设计4位LED接口电路或LCD显示电路
3.实现2位数的简单运算
三、系统硬件设计电路图
四、软件设计:
(代码如下)
#include
#include
#defineuintunsignedint
#defineucharunsignedchar
sbitlcden=P2^3;//定义引脚E使能
sbitrs=P2^4;
sbitrw=P2^0;
sbitbusy=P0^7;
sbitp33=P3^3;
chari,j,temp,num,num_1;
longa,b,c;//第一个操作数a,第一个操作数b,结果c
bitbans=0,bmun2=0;
ucharflag,fuhao;//flag表示是否有符号键按下,fuhao表示按下的是哪个符号
ucharcodetable[]={
7,8,9,0,
4,5,6,0,
1,2,3,0,
0,0,0,0
};
ucharcodetable1[]={
7,8,9,0x2f-0x30,//按键标值0x2f-0x30是将字符转化为数字,与后面的0x30+i抵消,得i值
4,5,6,0x2a-0x30,
1,2,3,0x2d-0x30,
0x01-0x30,0,0x3d-0x30,0x2b-0x30//0x01是清屏命令
};
voiddelay(ucharz)
{
ucharx,y;
for(x=0;x for(y=0;y<110;y++); } voidcheck()//判断忙或空闲 { do { P0=0xFF; rs=0; rw=1;//读rsrw值为01时,读取忙标志和RAM地址 lcden=0;//E=0,禁止读写 delay (1);//等待,液晶显示器处理数据 lcden=1;//E=1,允许读写 } while(busy==1);//判断是否为空闲,1为忙,0为空闲 } voidwrite_com(ucharcom)//写指令函数 { P0=com;//com指令付给P0口 rs=0; rw=0; lcden=0; check(); lcden=1; } voidwrite_date(uchardate)//写数据函数 { P0=date; rs=1; rw=0; lcden=0; check(); lcden=1; } voidinit()//初始化 { lcden=1;//使能信号为高电平 write_com(0x38);//功能设置命令: 8位,2行DDRAM的地址 write_com(0x0e);//显示开,光标开,不闪烁 write_com(0x06);//增量方式不移位 write_com(0x80);//设置访问地址 num_1=0; i=0; j=0; a=0;//第一个参与运算的数 b=0;//第二个参与运算的数 c=0;//结果值 flag=0;//flag表示是否有符号键按下, fuhao=0;//fuhao表示按下的是哪个符号 } voidans() { bans=1; if(fuhao==1) { if(j==1) { write_com(0x80+0x4f);//按下等于键,光标前进至第二行最后一个显示处 write_com(0x04);//设置从后住前写数据,每写完一个数据,光标后退一格 } c=a+b; a=c; if(j==1) { while(c! =0) { write_date(0x30+c%10); c=c/10; } a=0;b=0;flag=0;fuhao=0; } } elseif(fuhao==2) { if(j==1) { write_com(0x80+0x4f);//光标前进至第二行最后一个显示处 write_com(0x04);//设置从后住前写数据,每写完一个数据,光标后退一格(这个照理说顺序不对,可显示和上段一样) } if(a-b>0) {c=a-b;} else {c=b-a;} a=a-b; if(j==1) { if(c==0) { write_date(0x30); } while(c! =0) { write_date(0x30+c%10); c=c/10; } if(a-b<0) write_date(0x2d); a=0;b=0;flag=0;fuhao=0; } } elseif(fuhao==3) { if(j==1) { write_com(0x80+0x4f); write_com(0x04); } c=a*b; a=c; if(j==1) { while(c! =0) { write_date(0x30+c%10); c=c/10; } a=0;b=0;flag=0;fuhao=0; } } elseif(fuhao==4) { if(j==1) { write_com(0x80+0x4f); write_com(0x04); } i=0; c=(long)(((float)a/b)*1000); a=a/b; if(j==1) { while(c! =0) { write_date(0x30+c%10); c=c/10; i++; if(i==3)//设置小数点位数 write_date(0x2e); } if(a/b<=0) write_date(0x30); a=0;b=0;flag=0;fuhao=0; } } } voidsummun() { if(flag==0)//没有按过符号键 { a=a*10+table[num]; } else//如果按过符号键 { b=b*10+table[num]; bmun2=1; } } voidkeyscan(void)//键盘扫描程序 { P1=0xfe; if(P1! =0xfe) { delay(20);//20ms if(P1! =0xfe) { temp=P1&0xf0; switch(temp) { case0xe0: num=0; break; case0xd0: num=1; break; case0xb0: num=2; break; case0x70: num=3; break; } } while(P1! =0xfe); if(num==0||num==1||num==2)//如果按下的是'7','8'或'9' { if(j! =0) { write_com(0x01);//清屏命令 j=0; } summun(); } else//如果按下的是'/' { flag=1; if(bmun2==1) { bmun2=0; b=0; ans(); flag=1; } fuhao=4;//4表示除号已按 } i=table1[num]; write_date(0x30+i);//将数字转化为字符,对应前面的table1中的i-0x30 } P1=0xfd; if(P1! =0xfd) { delay(5); if(P1! =0xfd) { temp=P1&0xf0; switch(temp) { case0xe0: num=4; break; case0xd0: num=5; break; case0xb0: num=6; break; case0x70: num=7; break; } } while(P1! =0xfd); if(num==4||num==5||num==6)//如果按下的是'4','5'或'6' { if(j! =0) { write_com(0x01);//清屏命令 j=0; } summun(); } else//如果按下的是'*' { flag=1; if(bmun2==1) { bmun2=0; ans(); b=0; flag=1; } fuhao=3;//3表示乘号已按 } i=table1[num]; write_date(0x30+i); } P1=0xfb; if(P1! =0xfb) { delay(5); if(P1! =0xfb) { temp=P1&0xf0; switch(temp) { case0xe0: num=8; break; case0xd0: num=9; break; case0xb0: num=10; break; case0x70: num=11; break; } } while(P1! =0xfb); if(num==8||num==9||num==10)//如果按下的是'1','2'或'3' { if(j! =0) { write_com(0x01);//清屏 j=0; } summun(); } elseif(num==11)//如果按下的是'-' { flag=1; if(bmun2==1) { bmun2=0; ans(); b=0; flag=1; } fuhao=2;//2表示减号已按 } i=table1[num]; write_date(0x30+i); } P1=0xf7; if(P1! =0xf7) { delay(5); if(P1! =0xf7) { temp=P1&0xf0; switch(temp) { case0xe0: num=12; break; case0xd0: num=13; break; case0xb0: num=14; break; case0x70: num=15; break; } } while(P1! =0xf7); switch(num) { case12: { write_com(0x01); a=0; b=0; flag=0; fuhao=0; }//按下的是"清零" break; case13: //按下的是"0" { summun(); i=table1[num]; write_date(0x30+i); } break; case14: { j=1; write_date(0x3d); ans(); } break; case15: { write_date(0x30+table1[num]); if(bmun2==1) { bmun2=0; ans(); b=0; flag=1; } flag=1; fuhao=1; } break; } } P1=0xf0; } voidmain()//主函数 { init(); EX1=1; EA=1; IT1=1; p33=1; P1=0xf0; while (1) { if(p33==0) { keyscan(); } } } voidint0()interrupt2 { if(p33==1) { p33=0; } } 仿真结果如下: (1)加法 (2)减法 (3)乘法 (4)除法 (5)连加 (6)连减 (7)连乘 (8)连除(这个不正常! ! ! ) 五、实验心得体会: 通过这次实验,我纠结了好久,但也有不少收获。 首先,在这个16键计算器的电路图的设计的时候,在用Proteus画图的过程中我学会了一些小技巧,比如: 按A键在弹出的PropertyAssignmentTool对话框中的Sting那一栏填入“net=R0#”(假设导线的标号为R00-R07),然后再点击OK,在图上靠近导线的地方点击左键就会出现标号,并且自动加1(默认情况下)。 但是我在画图方面还有一些疑惑,例如画总线。 在编程的时候,我发现如果有代码中有中文(不是注释),把它复制到Keil软件中编译的时候,中文不会显示出来,到编译的时候出错,提示“1.C(376): errorC100: unprintablecharacter0xD6skipped”。 此外,我还了解了LCD1602的一些基本功能和使用方法,也懂得运用LCD1602模块的操作指令。 在编写代码过程中,我上网查阅过ASCII码表,也查找过LCD1602的介绍和相关简易计算器的设计资料。 我还掌握了矩阵键盘的实现方法,其扫描的先读入行值再读入列值。 经过不断的修改代码,虽然能完成加减乘除,三个数连加,连乘,连减,但是三个数连除出错,还有待完善。 总的来说,这次设计性实验真的不简单。 同时,我也意识到只有在实践中才能发现问题,在解决问题的过程中会有意想不到的收获! 多动手实践,多思考,多借鉴,更加细心一点,更加耐心一点,一定会有所提高!
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 实验四 单片机设计实验 实验 单片机 设计