《单片机开发板 计算器 电梯 密码锁 万年历 交通灯课程设计宝贝及程序.docx》由会员分享,可在线阅读,更多相关《单片机开发板 计算器 电梯 密码锁 万年历 交通灯课程设计宝贝及程序.docx(44页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、编号:时间:2021年x月x日书山有路勤为径,学海无涯苦作舟页码:第44页 共44页开发板 实验报告 设 计 课 题:基于单片机的简易计算器指 导 老 师: 班 级: 学 号: 姓 名: 一 设计内容和目的本次实验的任务就是要以51系列单片机为核心实现一个简易计算器计算器,它的结构非常简单,外部主要由4*4矩阵键盘和一个液晶显示屏构成,内部由一块AT89C51单片机构成,通过软件编程可实现简单加减乘除。目的:做自己喜欢的实验,提高自学能力。二 方案论证经分析,计算器电路包括三个部分:显示电路、4*4键扫描电路、单片机微控制电路。具体如下:) LCD显示电路 LCD1602作为一个成熟的产品,使
2、用简单,模式固定,便于移植到各种类型的程序,但是初学者往往要注意结合LCD本身的时序图来完善初始化程序。又以其微功耗、体积小、显示内容丰富、超薄轻巧的诸多优点,故采用LCD.) 4*4键盘扫描电路(中断式,扫描式,反转式)用户设计行列键盘接口,一般常采用3 种方法读取键值。一种是中断式,外两种是扫描法和反转法。中断式:在键盘按下时产生一个外部中断通知CPU,并由中断处理程序通过不同的地址读取数据线上的状态,判断哪个案件被按下。本实验采用中断式实现用户键盘接口。扫描法:对键盘上的某一行送低电平,其他行为高电平,然后读取列值。若列值中有一位是低,则表明该行与低电平对应列的键被按下;否则,扫描下一行
3、。反转法:先将所有行扫描线输出低电平,读列值。若列值有一位是低,则表明有键按下,读列值;然后所有列扫描线输出低电平,再读行值。根据读到的值组合就可以查表1 得到的键码。这个就仁者见仁智者见智了,不过如果熟悉了扫描式,建议果断升级自己的硬件(很简单加个74LS08与门),故采用节省CPU的中断式扫描电路。 ) 单片机微控制电路微控制电路就是以AT89C51为核心的控制核心,主要注意晶振电路的接法和复位电路的接法。三 硬件电路的设计21 硬件设计电路框图51系列单片机系统4*4键盘LCD显示 晶振电路复位电路线路原理框图22 硬件设计电路的元件清单器件名称数量AT89C511按键1774LS081
4、10K电阻9电容22uF1LCD16021晶振12MHz1电容30pF25K电位器123 硬件设计电路图将4*4的键盘直接接在P1口上,用P0口作为LCD的显示输出,P3.2口的INT0作为外部中断位。24 硬件设计的补充说明四 软件设计程序及描述本程序组成可分为3个模块:矩阵键盘模块,LCD显示模块,和运算模块(源程序见底页)开始初始化参数初始化LCD显示有键输入?读取键码LCD显示数字键清零键功能键状态清零输入数值数值送显示缓冲YN等待数值输入结果送显示缓冲根据上次功能键和输入的数据计算结果本次功能键?等待数值输入结果送显示缓冲等待数值输入结果送显示缓冲五 硬软件的调试及方法我个人遇到的主
5、要问题出现在LCD1602上,要不是我自己买了块新的LCD恐怕我的结论,就只能在软件仿真实现了。硬件上:在不加芯片调试时,LCD1602只显示一排全黑,一般说明该元件是好的。(但也不一定,我那时就一直认为我的元件没坏);给15,16管脚分别接上+5v和0v,测试背光是否完好;给VEE接上电位器,检查对比度是否可调;一般LCD易出现的现象,我再做实验的时候遇到过以下几种情况:状态1 上电之后,1602的第一行全黑,即16个5x7黑块产生原因:液晶根本就没有进行初始化操作,需要检查连线或者程序。运气不好的情况下就是整块LCD是坏的。状态2 屏上显示两排灰格 产生原因:程序中对液晶初始化不正常,应是
6、部分初始化指令没有正常接收,建议按照标准初始化步骤调整程序,或者调整指令之间的延时(加大一些试试)-补充:也有可能是对比度太大,建议优先调整对比度电阻 状态3 显示乱码 这是我在实验室组合版上做的,原因是接线问题状态3 正确显示 六 实验结果与性能达标我的计算器只能准确进行得数为09的四则运算。1.加法计算 2.减法计算 3.乘法计算 4.除法计算 5.字符显示 实物与仿真不一致。这就是传说中的BUG了。我不明白。七 实验改进与心得体会很明显我的计算器处理数据及显示存在太大的局限性,我觉得主要还是我对程序中的运算模块理解不深,这点仍需大大加强。这个实验给我的感觉,硬件和软件上都不是很难。我的焊
7、工也不马虎,即使难看了点,但只要软件能行,就能完美运行。可惜,我就败在LCD1602,从学校拿了两块,幸好最后实在没办法,自己买了一块。最终证实我之前的实验就是LCD的损坏。没知识真可怕,我不懂真正排查LCD的好坏。不过也因祸得福,我在磕磕碰碰中,固执的认为LCD是好的,反而使我对LCD初始化,LCD字符显示,3种不同的矩阵键盘扫描的方法,及软件上的巧妙技巧有了更好的了解。我在这次实验上,感觉收获的更多. 下面是源代码:#include#define CLEARSCREEN LCD_write_command(0x01) #define uint unsigned int #define uc
8、har unsigned char/*定义接口*/ #define LCDIO P0#define KEYBOARD P1/保留sbit LCD1602_RS=P20; sbit LCD1602_RW=P21; sbit LCD1602_EN=P22; /*/code uchar mayuan16=0,1,2,3,4,5,6,7,8,9,0,/,*,-,+,=;/不错,这个比较明了unsigned char code keycode=0x11,0x21,0x41,0x81,0x12,0x22,0x42,0x82,0x14,0x24,0x44,0x84,0x18,0x28,0x48,0x88;/
9、键盘编码值()int i,j,k=1,s;/int t,t1,t2,a;/void delay(uchar);/延时/*定义函数*/void LCD_init(void);/初始化函数void delay_nms(unsigned int n);/延时函数void LCD_write_command(unsigned char command);/写入指令函数void LCD_write_dat(unsigned char dat);/写入数据函数void delay_10ms();initial();uchar keyscan();/键盘扫描函数calc(uchar);/计算函数uchar
10、num,temp,key,keynum;void main()/主函数LCD_init();delay_nms(100);while(1)initial();/有中断KEYBOARD =0xf0;/键盘的列值全置高电平/*开中断*/initial()EA=1;/总开关EX0=1;/中断方式0开启IT0=0;/*/*中断函数*/void inter0() interrupt 0unsigned char n;delay_10ms();/延时if(INT0=0)/没键按下EX0=0;/关中断n=keyscan();calc(n);EX0=1;/开中断KEYBOARD=0xf0;/键盘的列值全置高电
11、平/*/calc(uchar n)if(n10)/键值小于10t1=t1*10+n;LCD_write_command(0x00);/写命令语句LCD_write_dat(mayuann);/写数据函数elseif(n=10)LCD_init();t1=0;t2=0,t=0;k=1;elseif(n15)t2=t1;t1=0;j=n;LCD_write_command(0x00);LCD_write_dat(mayuann);elseLCD_write_command(0x00);LCD_write_dat(mayuann);switch(j)case 11:t=t2/t1;break;cas
12、e 12:t=t2*t1;break;case 13:t=t2-t1;break;case 14:t=t2+t1;break;if(t9)while(t9)s=t%10;t=t/10;ak=s;k+;if(t=1;i-)LCD_write_command(0x00);LCD_write_dat(ai+48);/*键盘扫描函数*/uchar keyscan()/键盘扫描KEYBOARD=0xf0;/键盘的列值全置高电平delay_10ms();/延时if(KEYBOARD!=0xf0)/有键按下temp=KEYBOARD;/保存键盘此刻的键植delay_10ms();/延时if(KEYBOARD
13、=temp)/再次确认键盘是否被按下uchar i;KEYBOARD=0x0f;/键盘的行值全置高电平delay_10ms();/10MS时间延时keynum=temp | KEYBOARD;/保存键盘的行值while(KEYBOARD!=0x0f);/松手检测for(i=0;i0;i-) for (j=0;j10;j+); void delay_10ms()/10MS延时unsigned char i,j;for(i=0;i10;i+)for(j=0;j120;j+);/*/ /*写指令函数*/ void LCD_write_command(unsigned char command) LC
14、DIO=command; LCD1602_RS=0; LCD1602_RW=0; LCD1602_EN=0; LCD1602_EN=1; delay_nms(10);/*/*写数据函数*/void LCD_write_dat(unsigned char dat)LCDIO=dat;LCD1602_RS=1;LCD1602_RW=0;LCD1602_EN=0;delay_nms(1);LCD1602_EN=1;/*/ /*初始化函数*/void LCD_init(void)CLEARSCREEN;/clear screenLCD_write_command(0x38);/set 8 bit da
15、ta transmission modeLCD_write_command(0x0c);/open display (enable lcd display)LCD_write_command(0x80);/set lcd first display addressCLEARSCREEN;/clear screen/*/为了方便初学者学习LCD,特留下字符显示代码,电路图与本实验一致。已通过实物测试,绝对没问题。#include unsigned char table1=0x03,0x07,0x0f,0x1f,0x1f,0x1f,0x1f,0x1f, 0x18,0x1E,0x1f,0x1f,0x
16、1f,0x1f,0x1f,0x1f, 0x07,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, 0x10,0x18,0x1c,0x1E,0x1E,0x1E,0x1E,0x1E, 0x0f,0x07,0x03,0x01,0x00,0x00,0x00,0x00, 0x1f,0x1f,0x1f,0x1f,0x1f,0x0f,0x07,0x01, 0x1f,0x1f,0x1f,0x1f,0x1f,0x1c,0x18,0x00, 0x1c,0x18,0x10,0x00,0x00,0x00,0x00,0x00;/心图案unsigned char table=0x10,0x06,0x
17、09,0x08,0x08,0x09,0x06,0x00;/字符 #define CLEARSCREEN LCD_write_command(0x01) /*定义接口*/ #define LCDIO P0sbit LCD1602_RS=P20; sbit LCD1602_RW=P21; sbit LCD1602_EN=P22; /*定义函数*/void LCD_write_command(unsigned char command);/写入指令函数void LCD_write_dat(unsigned char dat);/写入数据函数void LCD_set_xy( unsigned char
18、 x, unsigned char y );/设置显示位置函数void LCD_dsp_char( unsigned x,unsigned char y,unsigned char dat);/显示一个字符函数void LCD_dsp_string(unsigned char X,unsigned char Y,unsigned char *s);/显示字符串函数void LCD_init(void);/初始化函数void delay_nms(unsigned int n);/延时函数/*/ /*初始化函数*/void LCD_init(void)CLEARSCREEN;/clear scre
19、enLCD_write_command(0x38);/set 8 bit data transmission modeLCD_write_command(0x0c);/open display (enable lcd display)LCD_write_command(0x80);/set lcd first display addressCLEARSCREEN;/clear screen/*/ /*写指令函数*/ void LCD_write_command(unsigned char command) LCDIO=command; LCD1602_RS=0; LCD1602_RW=0; L
20、CD1602_EN=0; LCD1602_EN=1; delay_nms(10);/*/*写数据函数*/void LCD_write_dat(unsigned char dat)LCDIO=dat;LCD1602_RS=1;LCD1602_RW=0;LCD1602_EN=0;delay_nms(1);LCD1602_EN=1;/*/ /*设置显示位置*/void LCD_set_xy( unsigned char x, unsigned char y )unsigned char address;if (y = 1) address = 0x80 + x;else address =0xc0+
21、 x;LCD_write_command(address);/*/ /*显示一个字符*/void LCD_dsp_char( unsigned x,unsigned char y,unsigned char dat)LCD_set_xy( x, y );LCD_write_dat(dat);/*/ /*显示字符串函数*/void LCD_dsp_string(unsigned char X,unsigned char Y,unsigned char *s) LCD_set_xy( X, Y ); while (*s) LCD_write_dat(*s); s +; /*/ /* 延时*/voi
22、d delay_nms(unsigned int n) unsigned int i=0,j=0; for (i=n;i0;i-) for (j=0;j10;j+); /*/ /*主函数*/void main(void)unsigned char i,j,k,tmp;LCD_init();delay_nms(100);tmp=0x40;/设置CGRAM地址的格式字k=0;for(j=0;j8;j+) for(i=0;i8;i+) LCD_write_command(tmp+i); / 设置自定义字符的 CGRAM 地址 delay_nms(2); LCD_write_dat(table1k);
23、 / 向CGRAM写入自定义字符表的数据 k+; delay_nms(2); tmp=tmp+8; LCD_dsp_string(1,1,LCD TEST );/在第一行第一列显示LCD TEST LCD_dsp_string(1,2,SUCCESSFUL );/在第二行第一列显示SUCCESSFUL for (i=0;i4;i+) LCD_dsp_char( 12+i,1,i);/在第一行第12列位置显示心图案的上半部 delay_nms(1); for (i=4;i8;i+) LCD_dsp_char( 12+i-4,2,i);/在第二行第12列位置显示心图案的下半部 delay_nms(
24、1); while (1);/*/3.1 硬件连接图3-1所示为简易计算器的电路原理图。P3口用于键盘输入,接4*4矩阵键盘,键值与键盘的对应表如表-所示,p0口和p2口用于显示,p2口用于显示数值的高位,po口用于显示数值的低位。图3-1 简易计算器电路原理图键值与功能对应表键值0123456789+-/=ON/C功能0123456789+-=清零表3-13.2 计算器的软件设计#include /头文件#define uint unsigned int / #define uchar unsigned charsbit lcden=P23; /定义引脚sbit rs=P24;sbit rw
25、=P20;sbit busy=P07;char i,j,temp,num,num_1;long a,b,c; /a,第一个数 b,第二个数 c,得数float a_c,b_c;uchar flag,fuhao;/flag表示是否有符号键按下,fuhao表征按下的是哪个符号uchar code table=7,8,9,0,4,5,6,0,1,2,3,0,0,0,0,0;uchar code table1=7,8,9,0x2f-0x30,4,5,6,0x2a-0x30,1,2,3,0x2d-0x30,0x01-0x30,0,0x3d-0x30,0x2b-0x30;void delay(uchar
26、z) / 延迟函数uchar y;for(z;z0;z-) for(y=0;y110;y+);void check() / 判断忙或空闲do P0=0xFF; rs=0; /指令 rw=1; /读 lcden=0; /禁止读写 delay(1); /等待,液晶显示器处理数据 lcden=1; /允许读写 while(busy=1); /判断是否为空闲,1为忙,0为空闲void write_com(uchar com) / 写指令函数P0=com; /com指令付给P0口rs=0;rw=0;lcden=0;check();lcden=1;void write_date(uchar date) /
27、 写数据函数 P0=date;rs=1;rw=0;lcden=0;check();lcden=1;void init() /初始化 num=-1;lcden=1; /使能信号为高电平write_com(0x38); /8位,2行write_com(0x0c); /显示开,光标关,不闪烁*/write_com(0x06); /增量方式不移位 显竟獗暌贫 柚?write_com(0x80); /检测忙信号write_com(0x01); /显示开,光标关,不闪烁num_1=0;i=0;j=0;a=0; /第一个参与运算的数b=0; /第二个参与运算的数c=0;flag=0; /flag表示是否有符
28、号键按下, fuhao=0; / fuhao表征按下的是哪个符号void keyscan() / 键盘扫描程序P3=0xfe; if(P3!=0xfe) delay(20); 延迟20ms if(P3!=0xfe) temp=P3&0xf0; switch(temp) case 0xe0:num=0; break; case 0xd0:num=1; break; case 0xb0:num=2; break; case 0x70:num=3; break; while(P3!=0xfe); if(num=0|num=1|num=2)/如果按下的是7,8或9 if(j!=0) write_com
29、(0x01); j=0; if(flag=0)/没有按过符号键 a=a*10+tablenum; else/如果按过符号键 b=b*10+tablenum; else/如果按下的是/ flag=1; fuhao=4;/4表示除号已按 i=table1num; write_date(0x30+i);P3=0xfd;if(P3!=0xfd) delay(5); if(P3!=0xfd) temp=P3&0xf0; switch(temp) case 0xe0:num=4; break; case 0xd0:num=5; break; case 0xb0:num=6; break; case 0x7
30、0:num=7; break; while(P3!=0xfd); if(num=4|num=5|num=6&num!=7)/如果按下的是4,5或6 if(j!=0) write_com(0x01); j=0; if(flag=0)/没有按过符号键 a=a*10+tablenum; else/如果按过符号键 b=b*10+tablenum; else/如果按下的是/ flag=1; fuhao=3;/3表示乘号已按 i=table1num; write_date(0x30+i);P3=0xfb;if(P3!=0xfb) delay(5); if(P3!=0xfb) temp=P3&0xf0; s
31、witch(temp) case 0xe0:num=8; break; case 0xd0:num=9; break; case 0xb0:num=10; break; case 0x70:num=11; break; while(P3!=0xfb); if(num=8|num=9|num=10)/如果按下的是1,2或3 if(j!=0) write_com(0x01); j=0; if(flag=0)/没有按过符号键 a=a*10+tablenum; else/如果按过符号键 b=b*10+tablenum; else if(num=11)/如果按下的是- flag=1; fuhao=2;/2表示减号已按