1602 键盘显示
- 格式:doc
- 大小:1015.50 KB
- 文档页数:37
项目:1602LCD显示电话拨号键盘按键设计者:陈小玲1602液晶显示模块指令驱动程序设计介绍液晶显示器以其微功耗、体积小、显示内容丰富、超薄轻巧的诸多优点,在各类仪表和低功耗系统中得到广泛的应用。
根据显示内容可以分为字符型液晶,图形液晶。
根据显示容量又可以分为单行16字,2行16字,两行20字等等。
这里介绍常用的字16字X2行的字符型液晶模块的使用方法。
这是一种通用模块。
与数码管相比该模块有如下优点:1.位数多,可显示32位,32个数码管体积相当庞大了2.显示内容丰富,可显示所有数字和大、小写字母3.程序简单,如果用数码管动态显示,会占用很多时间来刷新显示,而1602自动完成此功能。
1602采用标准的16脚接口,其中:(模块背面有标注)第1脚:VSS为地电源第2脚:VDD接5V正电源第3脚:V0为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度(建议接地,弄不好有的模块会不显示)第4脚:RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。
第5脚:RW为读写信号线,高电平时进行读操作,低电平时进行写操作。
第6脚:E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。
第7~14脚:D0~D7为8位双向数据线。
第15~16脚:空脚(有的用来接背光)1602模块的设定,读写,与光标控制都是通过指令来完成,共有11条指令,如下:程序设计调试与实训:A键用于随机生成一道口诀题,数字键0-9用于输入结果(程序可限制最多只能输入俩位数),B键判断正误,如果正确则闪烁显示success,否则显示error, C键用于清除当前输入的答案,一遍重新输入,DJ键用于显示正确答案。
Proteus绘制的原理图编译的源代码://名称:1602LCD显示电话拨号键盘按键//说明:本例将电话拨号键盘上所拨号号码显示在1602液晶屏上。
main.c#include<reg52.h>#include"lcd.h"#define GPIO_KEY P1unsigned char KeyValue;//用来存放读取到的键值unsigned char KeyState;//用来存放按键状态unsigned char PuZh[]=" Pechin Science ";unsigned char dat[]="0123456789ABCDEF";void Delay10ms(); //延时50usvoid KeyDown(); //检测按键函数/******************************************************************************* * 函数名: main* 函数功能: 主函数* 输入: 无* 输出: 无*******************************************************************************/ void main(void){unsigned char i;LcdInit();KeyState=0;for(i=0;i<16;i++){// LcdWriteCom(0x80);LcdWriteData(PuZh[i]);}while(1){KeyDown();if(KeyState){KeyState=0;LcdWriteCom(0x80+0x40);LcdWriteData(dat[KeyValue]);}}}/******************************************************************************** 函数名: KeyDown* 函数功能: 检测有按键按下并读取键值* 输入: 无* 输出: 无*******************************************************************************/void KeyDown(void){char a;GPIO_KEY=0x0f;if(GPIO_KEY!=0x0f){Delay10ms();if(GPIO_KEY!=0x0f){KeyState=1;//测试列GPIO_KEY=0X0F;// Delay10ms();switch(GPIO_KEY){case(0X07): KeyValue=0;break;case(0X0b): KeyValue=1;break;case(0X0d): KeyValue=2;break;case(0X0e): KeyValue=3;break;// default: KeyValue=17; //检测出错回复17意思是把数码管全灭掉。
名称:LCD1602论坛:编写:shifang日期:2009.5修改:无内容:通过矩阵键盘输入,依次显示0-F16中字符引脚定义如下:1-VSS 2-VDD 3-V0 4-RS 5-R/W 6-E 7-14 DB0-DB7 15-BLA 16-BLK------------------------------------------------*/#include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义#include<intrins.h>sbit RS = P2^4; //定义端口sbit RW = P2^5;sbit EN = P2^6;#define RS_CLR RS=0#define RS_SET RS=1#define RW_CLR RW=0#define RW_SET RW=1#define EN_CLR EN=0#define EN_SET EN=1#define DataPort P0#define KeyPort P1unsigned char code dofly_code[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};//转换成液晶显示的字符/*------------------------------------------------uS延时函数,含有输入参数unsigned char t,无返回值unsigned char 是定义无符号字符变量,其值的范围是0~255 这里使用晶振12M,精确延时请使用汇编,大致延时长度如下T=tx2+5 uS------------------------------------------------*/void DelayUs2x(unsigned char t){while(--t);}/*------------------------------------------------mS延时函数,含有输入参数unsigned char t,无返回值unsigned char 是定义无符号字符变量,其值的范围是0~255 这里使用晶振12M,精确延时请使用汇编void DelayMs(unsigned char t){while(t--){//大致延时1mSDelayUs2x(245);DelayUs2x(245);}}/*------------------------------------------------判忙函数------------------------------------------------*/ bit LCD_Check_Busy(void){DataPort= 0xFF;RS_CLR;RW_SET;EN_CLR;_nop_();EN_SET;return (bit)(DataPort & 0x80);}/*------------------------------------------------写入命令函数------------------------------------------------*/ void LCD_Write_Com(unsigned char com) {while(LCD_Check_Busy()); //忙则等待RS_CLR;RW_CLR;EN_SET;DataPort= com;_nop_();EN_CLR;}/*------------------------------------------------写入数据函数------------------------------------------------*/ void LCD_Write_Data(unsigned char Data) {while(LCD_Check_Busy()); //忙则等待RS_SET;EN_SET;DataPort= Data;_nop_();EN_CLR;}/*------------------------------------------------清屏函数------------------------------------------------*/void LCD_Clear(void){LCD_Write_Com(0x01);DelayMs(5);}/*------------------------------------------------写入字符串函数------------------------------------------------*/void LCD_Write_String(unsigned char x,unsigned char y,unsigned char *s) {if (y == 0){LCD_Write_Com(0x80 + x);}else{LCD_Write_Com(0xC0 + x);}while (*s){LCD_Write_Data( *s);s ++;}}/*------------------------------------------------写入字符函数------------------------------------------------*/void LCD_Write_Char(unsigned char x,unsigned char y,unsigned char Data) {if (y == 0){LCD_Write_Com(0x80 + x);}elseLCD_Write_Com(0xC0 + x);}LCD_Write_Data( Data);}/*------------------------------------------------初始化函数------------------------------------------------*/void LCD_Init(void){LCD_Write_Com(0x38); /*显示模式设置*/DelayMs(5);LCD_Write_Com(0x38);DelayMs(5);LCD_Write_Com(0x38);DelayMs(5);LCD_Write_Com(0x38);LCD_Write_Com(0x08); /*显示关闭*/LCD_Write_Com(0x01); /*显示清屏*/LCD_Write_Com(0x06); /*显示光标移动设置*/DelayMs(5);LCD_Write_Com(0x0C); /*显示开及光标设置*/}/*------------------------------------------------按键扫描函数,返回扫描键值------------------------------------------------*/unsigned char KeyScan(void) //键盘扫描函数,使用行列反转扫描法{unsigned char cord_h,cord_l;//行列值中间变量KeyPort=0x0f; //行线输出全为0cord_h=KeyPort&0x0f; //读入列线值if(cord_h!=0x0f) //先检测有无按键按下{DelayMs(10); //去抖if((KeyPort&0x0f)!=0x0f){cord_h=KeyPort&0x0f; //读入列线值KeyPort=cord_h|0xf0; //输出当前列线值cord_l=KeyPort&0xf0; //读入行线值while((KeyPort&0xf0)!=0xf0);//等待松开并输出return(cord_h+cord_l);//键盘最后组合码值}}return(0xff); //返回该值}/*------------------------------------------------按键值处理函数,返回扫键值------------------------------------------------*/unsigned char KeyPro(void){switch(KeyScan()){case 0x7e:return 0;break;//0 按下相应的键显示相对应的码值case 0x7d:return 1;break;//1case 0x7b:return 2;break;//2case 0x77:return 3;break;//3case 0xbe:return 4;break;//4case 0xbd:return 5;break;//5case 0xbb:return 6;break;//6case 0xb7:return 7;break;//7case 0xde:return 8;break;//8case 0xdd:return 9;break;//9case 0xdb:return 10;break;//acase 0xd7:return 11;break;//bcase 0xee:return 12;break;//ccase 0xed:return 13;break;//dcase 0xeb:return 14;break;//ecase 0xe7:return 15;break;//fdefault:return 0xff;break;}}/*------------------------------------------------主函数------------------------------------------------*/void main(void){unsigned char i,j,num;LCD_Init();LCD_Write_Com(0x0F);//光标开,光标闪烁开LCD_Write_String(0,0,"Press the key !");while (1){num=KeyPro();if(num!=0xff){if((i==0)&&(j==0))//回到第一个字符时清屏LCD_Clear();//清屏LCD_Write_Char(0+i,0+j,dofly_code[num]);//依次显示输入字符i++;if(i==16)//如果第一行显示满,转到第二行{i=0;j++;if(j==2)//如果2行都显示满,清屏后重新从第一行显示{j=0;}}}}}。
摘要在日常生活中,我们经常要通过按键来实现对电子装置的控制,小到手表手机,中到电视电脑,大到各种复杂仪器,都需要通过按键来实现各种操作。
本次课程设计作为实践教学的一个重要环节,将以按键控制显示为主题,以1602液晶、MM74C922解码芯片、AT89C52单片机及其接口芯片为核心构造一个键盘控制显示系统,并使用Proteus软件对所设计的电路进行仿真,仿真结果是在1602液晶上显示所按下的键值。
关键词:Proteus仿真AT89C52 1602液晶MM74C922解码芯片第一章总体设计1.1电路结构分析本次设计的目标为单片机控制的键盘识别显示系统,主要采用AT89C52单片机作为核心,由矩阵键盘电路、译码芯片、液晶显示等模块构成,分别对按键信息和显示电路以及软、硬件各个部分进行控制;本设计采用C言编程来实现对单片机的控制。
实际运作时,单片机会将检测到的按键信号转换成数字,显示于1602液晶上。
系统主要结构可以拆分如下:①矩阵键盘:按键传送输入信息;此键盘采用的是4X4矩阵键盘,能输入0~9,+,—,=,空格,返回,清零。
②键盘识别:矩阵键盘连接的是MM74C922解码芯片,通过解码芯片来识别输入的按键位置。
③AT89C52:采用软件编程来实现按键信息的提取和转换;④1602液晶:用于显示最终被单片机转换过的按键信息。
由以上构思可以设计此按键显示电路。
1.2总体方案设计总体电路原理框图:如图 1.2所示图1.2总体电路原理方框图本次设计分两步来完成,第一步,解码芯片调试系统,将解码芯片接口连接到矩阵键盘作为AT89C52单片机的输入装置,然后以P2口作为输出端并连接一个数码管观察输出结果。
第二步,1602的液晶调试系统,此过程就是将数码管换成1602液晶在进行结果显示。
1.3蜂鸣器模块设计蜂鸣器模块设计如图 1.3所示图 1.3 蜂鸣器模块电路图蜂鸣器的驱动电流比较大一般要500MA~1000MA,所以不能直接接在AT82C52单片机的接口上,需要加一个三极管来进行驱动。
按键复用(1602液晶显示)按键复用(1602 液晶显示)AVR单片机单按键复用之程序AVR单片机中断法的按钮前一段就可以了,查询的居然卡住了。
先写一个51C的,在此基础上写了AVR GCC的,一直到今天才完成。
感觉二者还是有点区别的。
//查询法按键程序,单键复用。
P1.O接一按键,P1.1接一LED。
//11 05 13 E:\DPJ_C\OTHER\ONEKEY\ONEKEY.C#include <reg51.h>#define uchar unsigned charsbit LED1= P1^1;sbit LED2= P1^2;sbit KEY = P1^0;void delay(unsigned int ms ) {unsigned char i;while(ms--)for(i=0;i<123;i++);}void disp1(){LED1=1;}void disp2(){LED1=0;}void main(){uchar temp;while(1){while(!KEY){delay(10);if(KEY)temp=~temp;if(~temp)disp1();elsedisp2();}}}//查询法按键程序,单键复用。
PCO接一按键,PD0接一LED。
//11 05 13 E:\AVR\ONEKEY\onekey.c#include<avr/io.h>#include<util/delay.h>#define KEY PD0#define uchar unsigned charuchar temp,i;void disp1(){DDRC&=~_BV(PC0);//PB0端口低电平PORTC&=~_BV(PC0);//PB0高阻状态,LED无电流通过}void disp2(){DDRC|=_BV(PC0);//PC0端口高电平,输出PORTC&=~_BV(PC0);//PC0低电平输出,LED点亮}int main(){DDRD|=_BV(KEY); //PD0高电平,输出PORTD|=_BV(KEY);DDRD&=~_BV(KEY);while(1){while(!(PIND&_BV(KEY))){for(i=0;i<5;i++)_delay_ms(10);if((PIND&_BV(KEY)))//等待按键释放temp =~temp;if(temp==0xff)disp2();elsedisp1();}}}1602字符液晶详细资料和实例时间:2010-10-11 来源: 作者: 点击:816 字体大小:【大中小】1602字符液晶在实际的产品中运用的也比较多了,前几天留意了一下,发现宿舍门前的自动售水机就是采用的1602液晶进行显示的。
1602 LCD显示电话拨号键盘按键概述本文档介绍了1602 LCD显示电话拨号键盘按键的设计方案及其主要功能。
该方案主要由硬件部分和软件部分组成,硬件部分包括1602液晶显示屏、电话拨号键盘、Arduino板、面包板等;软件部分主要使用Arduino IDE编程,实现LCD屏幕显示、按键检测等功能。
该方案能够检测电话拨号键盘的按键状态并在1602 LCD显示屏上显示对应按键。
设计方案硬件部分硬件部分主要包括以下几个方面:1. 1602液晶显示屏1602液晶显示屏是本方案的显示设备,通过数根引脚与Arduino板相连。
在本方案中,主要利用它显示电话号码和被按下的按键。
2. 电话拨号键盘电话拨号键盘是本方案的主要输入设备,它可以检测到被按下的按键,并将这些信息通过引脚连接Arduino板。
3. Arduino板Arduino板是本方案的主要控制器,它和显示设备、输入设备之间互相连接,通过Arduino IDE编程,实现程序运行、数据传输等功能。
4. 面包板面包板主要是为了方便电路的连接和调试,以及充分利用现成的模块和元器件。
软件部分软件部分主要使用Arduino IDE编程,实现以下几个方面的功能:1. 显示屏幕显示利用Arduino IDE编程,控制1602液晶显示屏上显示电话号码、被按下的按键等相关信息。
2. 按键事件检测利用Arduino IDE编程,通过对电话拨号键盘输入端口的状态检测,实现对按键事件的识别。
主要功能1. 显示电话号码本方案所设计的1602 LCD显示屏,通过数根引脚与Arduino板相连。
在本方案中,主要利用它显示电话号码和被按下的按键。
2. 按键检测利用Arduino IDE编程,通过对电话拨号键盘输入端口的状态检测,实现对按键事件的识别。
当电话拨号键盘检测到按键事件,则通过Arduino板进行响应,并在1602 LCD显示屏上显示对应按键信息。
本文介绍了1602 LCD显示电话拨号键盘按键的设计方案及其主要功能。
#include<reg52.h>#define uchar unsigned char#define uint unsigned intsbit RS=P2^6;sbit RW=P2^5;sbit lcden=P2^7;sbit s1=P1^1; //功能键sbit s2=P1^2; //加一键sbit s3=P1^3; //减一键sbit a=P1^4;sbit c1=P2^0; //功能键sbit c2=P2^1; //加一键sbit c3=P2^2; //减一键uchar count,s1num,c1num,i,j;char nian,yue,ri,shi,fen,miao;uchar code table[]=" 2011-08-18 THU";uchar code table1[]=" 23:59:53";uchar code week1[]="MON";uchar code week2[]="TUE";uchar code week3[]="WED";uchar code week4[]="THU";uchar code week5[]="FRI";uchar code week6[]="SAT";uchar code week7[]="SUN";/*****************************************************************************/ void delay(uint z){uint x,y;for(x=z;x>0;x--)for(y=250;y>0;y--);}/*****************************************************************************/ void write_com(uchar com) //写指令{RS=0;RW=0;lcden=0;P0=com;delay(5);lcden=1;delay(5);lcden=0;}/*****************************************************************************/void write_date(uchar date) //写数据{RS=1;RW=0;lcden=0;P0=date;delay(5);lcden=1;delay(5);lcden=0;}/*****************************************************************************/ void init(){uchar num;lcden=0;write_com(0x38); //显示模式设置write_com(0x0c); //显示开关write_com(0x06); //显示光标设置write_com(0x01); //显示清零write_com(0x80);for(num=0;num<16;num++){write_date(table[num]);delay(20);}write_com(0x80+0x40);for(num=0;num<13;num++){write_date(table1[num]);delay(20);}TMOD=0x01;TH0=(65536-50000)/256;TL0=(65536-50000)%256;EA=1;ET0=1;TR0=1;}/*****************************************************************************/ void write_sfm(uchar add,uchar date) //秒,分,时计算{uchar shi,ge;shi=date/10;ge=date%10;write_com(0x80+0x40+add);write_date(0x30+shi);write_date(0x30+ge);}/*****************************************************************************/ void write_nyr(uchar add,uchar date) //月,日计算{uchar shi,ge;shi=date/10;ge=date%10;write_com(0x80+add);write_date(0x30+shi);write_date(0x30+ge);}/*****************************************************************************/ /*void write_nian(uchar add,uchar date) //千位计算{uchar shi,ge;// bai=date%1000/100;shi=date%100/10;ge=date%10;write_com(0x80+add);// write_date(0x30+qian);// write_date(0x30+bai);write_date(0x30+shi);write_date(0x30+ge);} *//*****************************************************************************/ void keyscan() //判断按键函数{a=0;if(s1==0) //判断功能键是否被按下{delay(5); //消抖if(s1==0){s1num++;while(!s1); //松手检测if(s1num==1) //功能键被按下一次{TR0=0; //时间停止write_com(0x80+0x40+12); //光标向前移一位write_com(0x0f); //光标闪烁}if(s1num==2) //功能键被按下两次{write_com(0x80+0x40+9);}if(s1num==3) //功能键被按下三次{write_com(0x80+0x40+6);}if(s1num==4) //功能键被按下四次{s1num=0;write_com(0x0c); //让光标不在闪烁TR0=1;}}}if(s1num!=0) //判断功能键是否被按下{if(s2==0) //判断加一键是否被按下{delay(5);if(s2==0) //确认加一键被按下{while(!s2);if(s1num==1) //判断指针指向“秒"{miao++;if(miao==60)miao=0;write_sfm(11,miao);write_com(0x80+0x40+11);}if(s1num==2) //判断指针指向“分"{fen++;if(fen==60)fen=0;write_sfm(8,fen);write_com(0x80+0x40+8);}if(s1num==3) //判断指针指向“时"{shi++;if(shi==24)shi=0;write_sfm(5,shi);write_com(0x80+0x40+5);}}}if(s3==0) //判断减一键是否被按下{delay(5);if(s3==0){while(!s3);if(s1num==1) //判断指针指向“秒"{miao--;if(miao==-1)miao=59;write_sfm(11,miao);write_com(0x80+0x40+11);}if(s1num==2) //判断指针指向“分"{fen--;if(fen==-1)fen=59;write_sfm(8,fen);write_com(0x80+0x40+8);}if(s1num==3) //判断指针指向“时"{shi--;if(shi==-1)shi=23;write_sfm(5,shi);write_com(0x80+0x40+5);}}}}}/*****************************************************************************/ void keyscan1() //调整日期{if(c1==0){delay(5);if(c1==0){c1num++;while(!c1);if(c1num==1) //指向”星期“{TR0=0; //时间停止write_com(0x80+15); //光标向前移一位write_com(0x0f); //光标闪烁}if(c1num==2) //指向”日“{write_com(0x80+11);}if(c1num==3) //指向”月“{write_com(0x80+8);}if(c1num==4) //指向”年“{write_com(0x80+5);}if(c1num==5){c1num=0;write_com(0x0c); //让光标不在闪烁TR0=1;}}}if(c1num!=0) //判断功能键是否被按下{if(c2==0) //判断加一键是否被按下{delay(5);if(c2==0) //防抖{while(!c2); //松手检测if(c1num==1) //指向“星期”{i++;if(i==8)i=1;switch(i){case 1:write_com(0x80+13); //移动指针for(j=0;j<3;j++){write_date(week5[j]);}break;case 2:write_com(0x80+13); //移动指针for(j=0;j<3;j++){write_date(week6[j]);}break;case 3:write_com(0x80+13); //移动指针for(j=0;j<3;j++){write_date(week7[j]);}break;case 4:write_com(0x80+13); //移动指针for(j=0;j<3;j++){write_date(week1[j]);}break;case 5:write_com(0x80+13); //移动指针for(j=0;j<3;j++){write_date(week2[j]);}break;case 6:write_com(0x80+13); //移动指针for(j=0;j<3;j++){write_date(week3[j]);}break;case 7:write_com(0x80+13); //移动指针for(j=0;j<3;j++){write_date(week4[j]);}break;}}if(c1num==2) //指向”日“{ri++;if(ri==32)ri=1;write_nyr(10,ri);write_com(0x80+10);}if(c1num==3) //指向”月“{yue++;if(yue==13)yue=1;write_nyr(7,yue);write_com(0x80+7);}if(c1num==4) //指向”年“{nian++;write_nyr(4,nian);write_com(0x80+4);}}}if(c3==0) //减一功能键按{delay(5);if(c3==0){while(!c3);if(c1num==1) //指向“星”{i++;if(i==8)i=1;switch(i){case 1:write_com(0x80+13); //移动指针for(j=0;j<3;j++){write_date(week3[j]);}break;case 2:write_com(0x80+13); //移动指针for(j=0;j<3;j++){write_date(week2[j]);}break;case 3:write_com(0x80+13); //移动指针for(j=0;j<3;j++){write_date(week1[j]);}break;case 4:write_com(0x80+13); //移动指针for(j=0;j<3;j++){write_date(week7[j]);}break;case 5:write_com(0x80+13); //移动指针for(j=0;j<3;j++){write_date(week6[j]);}break;case 6:write_com(0x80+13); //移动指针for(j=0;j<3;j++){write_date(week5[j]);}break;case 7:write_com(0x80+13); //移动指针for(j=0;j<3;j++){write_date(week4[j]);}break;}}if(c1num==2) //指向“日”{ri--;if(ri==0)ri=31;write_nyr(10,ri);write_com(0x80+10);}if(c1num==3) //指向“月”{yue--;if(yue==0)yue=12;write_nyr(7,yue);write_com(0x80+7);}if(c1num==4) //指向“年”{nian--;write_nyr(4,nian);write_com(0x80+4);}}}}}/*****************************************************************************/ void main(){init();while(1){keyscan();keyscan1();if(count==20) //定时1秒{count=0;miao++;if(miao==60){miao=0;fen++;if(fen==60){fen=0;shi++;if(shi==24){shi=0;ri++;i++;if(ri==32){ri=1;yue++;if(yue==13){yue=1;nian++;write_nyr(3,nian);}write_nyr(7,yue);}write_nyr(10,ri);if(i==8)i=1;switch(i){case 1:write_com(0x80+13); //移动指针for(j=0;j<3;j++){write_date(week5[j]);}break;case 2:write_com(0x80+13); //移动指针for(j=0;j<3;j++){write_date(week6[j]);}break;case 3:write_com(0x80+13); //移动指针for(j=0;j<3;j++){write_date(week7[j]);}break;case 4:write_com(0x80+13); //移动指针for(j=0;j<3;j++){write_date(week1[j]);}break;case 5:write_com(0x80+13); //移动指针for(j=0;j<3;j++){write_date(week2[j]);}break;case 6:write_com(0x80+13); //移动指针for(j=0;j<3;j++){write_date(week3[j]);}break;case 7:write_com(0x80+13); //移动指针for(j=0;j<3;j++){write_date(week4[j]);}break;}}write_sfm(5,shi);}write_sfm(8,fen);}write_sfm(11,miao);}}}/*****************************************************************************/ void timer0() interrupt 1{TH0=(65536-50000)/256;TL0=(65536-50000)%256;count++;}。
---------毕业论文(设计)题目__单片机课程设计________指导教师________ _________院系___ __________专业__ __________班级________ _________姓名______________________学号____ ___________2015年 9月 1 日至2015年 12月 7日(共12周)精品文档目录1.设计预达目标 (1)2.设计方案 (1)2.1单片机最小系统 (1)2.2输入按键系统 (2)2.3 1602LCD显示系统 (3)2.4设计原理图 (6)3. 分析与编程 (7)3.1系统流程图 (7)3.2 LCD显示程序流程图 (7)3.3 设计程序 (8)4.仿真 (15)5.在实现过程中遇到的问题及排除措施 (16)6.设计心得体会 (16)7.参考文献 (16)1602LCD显示电话拨号键盘按键摘要:介绍了基于单片机LCD1602显示屏的设计过程。
给出了其硬件原理图和系统仿真图。
关键词:单片机 1602LCD显示屏键盘系统一、设计预达目标要求以51单片机作为微控制器,通过1602LCD显示屏显示拨号键盘,键值包括数字0-9及“*”“#”等12个按键,数字显示为逐个显示方式。
二.设计方案首先构建单片机最小系统、键盘输入系统及1602LCD显示系统。
通过单片机扫描键值,将其结果输入到1602LCD显示屏上。
(一)单片机最小系统单片机最小系统主要由电源、复位、震荡电路以及扩展部分等部分组成。
1图2.1单片机最小系统(二)输入按键系统独立的键盘与单片机相连时,每个按键都需要单片机的一个I/O线,若按键较多时,占用的I/O口资源就会过多,为此就引入了矩阵键盘。
本次设计共有0~9、#、*共12个按键,因此引入3*4的矩阵键盘,共需要7个I/O口,7条线分别与单片机P3口相连。
{注:当作为输入时,上拉电阻将其电位拉高,若输入为低电平则可提供电流源;所以P0口如果作为输入时,处在高阻抗状态,只有外接一个上拉电阻才能有效。
LCD显示及键盘用法LCD1602及其控制器的基本显示方法向LCD输入的数据为ASCII码,需要通过数码扫描依次送到LCD显示,下面介绍LCD 控制器IP核LCD16X2A及其相关程序。
逻辑符号如下图:U_lcd_ctrl模块即为该控制器核在AltiumDesinger原理图中的符号表示。
其作用是接受前面用户自己的逻辑单元送来的ASCII码数据和控制信号,然后与外部的LCD显示器通讯,显示相应字符。
数据总线使用输入输出分离模式,IP核后面需要增加双向BUF控制单元(U8)。
L CD控制器端口说明如下:用户控制逻辑接口:CLK:控制器工作时钟,上升沿有效RST:复位信号,高电平有效DATA[7..0]:ASCII码数据总线ADDR[3..0]:字符在LCD屏幕上的地址(共两行,每行16个字符)ADDR=“0000”~“1111”对应每行的第0~15个字符LINE:LCD1602屏幕上的行选择信号,LINE=0时数据在第一行显示,LINE=1时数据在第二行显示BUSY:控制器忙信号,数据未显示稳定时BUSY=1;反之为0STROBE:数据输入有效使能,高电平有效LCD显示器接口:LCD_E:LCD显示器使能LCD_RW:LCD读写方向控制LCD_RS:LCD命令,数据选择LCD_DATA_TRI:LCD数据高阻态控制LCD_DATAO:LCD数据输出总线LCD_DATAI:LCD数据输入总线控制器工作原理如下:A控制器复位当RST信号有效时(高电平),控制器进入LCD复位与初始化操作,此时,BUSY信号持续高电平,表示控制器忙,LCD不能进行用户请求的操作。
RST信号由高变低后的大约80us之后,LCD控制器初始化完成,可以响应用户的操作请求,此时,BUSY信号变低。
LCD处于显示模式。
B字符显示上电后的LCD必须初始化一次,之后LCD控制器停留于“WAIT FOR DATA”状态。
在用户向LCD控制器申请字符显示操作时,ADDR、DATA、LINE信号必须保持稳定,同时使用STROBE信号触发显示操作。
#include<reg52.h>#include<intrins.h>#define uint unsigned int#define uchar unsigned charsbit lcdrw=P2^5;sbit key1=P3^0;sbit key2=P3^1;sbit key3=P3^2;sbit Gnd=P3^7;uchar counter,cycle;uchar key_counter = 0; //定义光标闪烁以及修改操作数的标记uchar second0,second1,minute0,minute1,hour0,hour1;uchar table[][3]={"SUN","MON","TUE","WEN","THU","FRI","SAT"};uchar year[4],day[2],month[2],date; //日期变量uchar small_mon,leap_year;void state() //检查日期状态函数(即判断是否闰年,是否小月的函数) {switch(month[0]){case 1: if(month[1] == 1) //若是11月,则是小月small_mon = 1;else //若是1月,则不是小月small_mon = 0;break;case 4:case 6:case 9: small_mon = 1;break;default:small_mon = 0;break;}if((year[3] * 1000 + year[2] * 100 + year[1] * 10 + year[0]) % 100 == 0){if((year[3] * 1000 + year[2] * 100 + year[1] * 10 + year[0]) % 400 == 0)leap_year = 1;}else if((year[3] * 1000 + year[2] * 100 + year[1] * 10 + year[0]) % 4 == 0)leap_year = 1;elseleap_year = 0;}void Dater() //日期函数{state();day[0]++;date=(date+1)%7;switch(day[0]){case 10:{if(day[1] == 2 && month[0] == 2 && month[1] == 0) //闰年时,把2月30号转变为3月1号{day[0] = 1;day[1] = 0;month[0]++;}else //日期各位满10进1{day[0] = 0;day[1]++;}}break;case 1:{if(day[1] == 3 && small_mon) //小月31号时把日期置为1号,月份+1{day[0] = 1;day[1] = 0;month[0]++;}}break;case 2:{if(day[1] == 3){day[0] = 1;day[1] = 0;month[0]++;}}break;case 9:{if(day[1] == 2 && !leap_year && month[0] == 2 && month[1] == 0) //平年时,把2月29号变为3月1号{day[0] = 1;day[1] = 0;month[0]++;}}break;default:break;}switch(month[0]){case 10:{month[0] = 0;month[1]++;}break;case 3:{if(month[1] == 1) {month[0] = 1;month[1] = 0;year[0]++;}}break;}if(year[0] > 9){year[0] = 0;year[1]++;if(year[1] > 9){year[1] = 0;year[2]++;if(year[2] > 9){year[2] = 0;year[3]++;if(year[3] > 9)year[3] = 0;}}}}void clock() //时钟函数{if (second0 > 9){second0 = 0;second1++;if (second1 > 5){second1 = 0;minute0++;if (minute0 > 9){minute0 = 0;minute1++;if (minute1 > 5){minute1 = 0;hour0++;if (hour0 == 4 && hour1 == 2) {hour0 = hour1 = 0;Dater();}else if (hour0 > 9){hour0 = 0;hour1++;}}}}}}void delay(uint z) //延时函数{for(x = z;x > 0;x--)for(y = 110;y > 0;y--) ;}void write_com(uchar com) //写指令到LCD液晶显示{lcdrs = 0;lcdrw = 0;P0 = com;delay(1);lcden = 1;delay(1);lcden = 0;}void write_data(uchar data0) //写数据到LCD液晶显示{lcdrs = 1;lcdrw = 0;P0 = data0;delay(1);lcden = 1;delay(1);lcden = 0;}void disp_time() //显示时间{write_com(0xc4);write_data(hour1 + 0x30);write_data(hour0 + 0x30);write_data(0x3a);write_data(minute1 + 0x30);write_data(minute0 + 0x30);write_data(0x3a);write_data(second1 + 0x30);write_data(second0 + 0x30);if(key_counter != 0 ){switch(key_counter){case 1:write_com(0x80+0x4b); //定位回光标闪烁位置break;case 2:write_com(0x80+0x48);break;case 3:write_com(0x80+0x45);break;case 4:write_com(0x80+0x0e);break;case 5:write_com(0x80+0x0b);break;case 6:write_com(0x80+0x08);break;case 7:write_com(0x80+0x03);break;}write_com(0x0f);delay(150);}void disp_date() //显示日期{write_com(0x81);for(cycle = 0; cycle < 3;cycle++) write_data(table[date][cycle]); write_data(0x20);for(cycle = 0;cycle < 4;cycle++) write_data(year[3 - cycle]+0x30); write_data(0x2f);write_data(month[1]+0x30); write_data(month[0]+0x30); write_data(0x2f);write_data(day[1]+0x30);write_data(day[0]+0x30);}void setting_detect(){Gnd=0;if(key1==0){delay(5);if(key1==0) //消除抖动{while(!key1); //等待松手TR0=0;key_counter++;do{disp_date();disp_time();if(key1==0) //按键“切换”delay(5);if(key1==0){while(!key1);key_counter++;}}if(key2==0) //按键“加”{delay(5);if(key2==0){while(!key2);switch(key_counter) {case 1:second0++;if(second0 > 9){second0 = 0;second1++;if(second1 == 6) second1 = 0;}break;case 2:minute0++;if(minute0 > 9){minute0 = 0;minute1++;if(minute1 == 6)minute1 = 0;}break;case 3:hour0++;if(hour1 == 2 && hour0 > 3){hour0 = 0;hour1 = 0;}else if(hour0 > 9){hour0 = 0;hour1++;}break;case 4:day[0]++;if(day[0] == 2 && day[1] == 3) {day[0] = 1;day[1] = 0;}if(day[0] == 10){day[0] = 0;day[1]++;}break;case 5:month[0]++;if(month[0] == 3 && month[1] == 1)month[0] = 1; month[1] = 0;}if(month[0] == 10) {month[0] = 0; month[1] = 1;}break;case 6:year[0]++;if(year[0] > 9) {year[0] = 0;year[1]++;if(year[1] > 9) {year[1] = 0;year[2]++;if(year[2] > 9) {year[2] = 0;year[3]++;if(year[3] > 9) year[3] = 0;}}}break;case 7:date=(date+1)%7; break;}}if(key3==0) //按键“减”{delay(5);if(key3==0){while(!key3);switch(key_counter) {case 1:if(second0 == 0){second0 = 9;if(second1 == 0) second1 = 5;elsesecond1--;}elsesecond0--;break;case 2:if(minute0 == 0){minute0 = 9;if(minute1 == 0) minute1 = 5;elseminute1--;}elseminute0--;break;case 3:if(hour0 == 0){if(hour1 == 0){hour0 = 3;hour1 = 2;}else{hour0 = 9;hour1--;}}elsehour0--;break;case 4:if(day[0] == 1 && day[1] == 0)day[1] = 3;if(day[0] == 0){day[0] = 9;day[1]--;}elseday[0]--;break;case 5:if(month[0] == 1 && month[1] == 0) {month[0] = 2; month[1] = 1;}else if(month[0] == 0) {month[0] = 9; month[1]--;}elsemonth[0]--;break;case 6:if(year[0] == 0){year[0] = 9;if(year[1] == 0){year[1] = 9;if(year[2] == 0){year[2] = 9;if(year[3] == 0)year[3] = 9;elseyear[3]--;}elseyear[2]--;}elseyear[1]--;}elseyear[0]--;break;case 7:date=(date+6)%7;break;}}}}while(key_counter != 8);key_counter = 0; //退出设置时关掉光标显示TR0=1;}}}void Lcd_init() //显示屏初始化{lcden = 0;write_com(0x01); //清屏write_com(0x02); //位置复位为左上方write_com(0x06); //光标右移write_com(0x0e); //显示开,有光标,闪烁write_com(0x38);}void timer0() interrupt 1 //定时器{TH0 = (65536-39970)/256;TL0 = (65536-39970)%6;counter++;if(counter == 25){counter = 0;clock();}void Timer_init() //定时器初始化{TMOD = 0x01;TH0 = (65536-29995)/256;TL0 = (65536-29995)%6;EA = 1;ET0 = 1;TR0 = 1;}void Date_init() //日期初始化{date = 6;day[0] = 7;day[1] = 0;month[0] = 7;month[1] = 0;year[0] = 2;year[1] = 1;year[2] = 0;year[3] = 2;}void Time_init() //时间初始化{second0 = 0;second1 = 3;minute0 = 0;minute1 = 3;hour0 = 2;hour1 = 1;counter = 0;}void main() //主函数{Lcd_init();Time_init();Date_init();Timer_init();while(1){disp_date();disp_time(); setting_detect();}}。
1602 液晶显示汉字程序利用1602 显示汉字也不是新鲜的内容,今天不想颓废了。
只是需要自己事先定义一下汉字的字模,就是显示出来的汉子字体结构。
要定义字模就需要知道1602 的CG RAM 地址和显示字符的地址DD RAM图1: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 第一行第一个字符的地址是( 0x80) ,后面的字符地址以此类推第二行第一个字符的地址为( 0x80 + 0x40) ,需要在第一行的基地址后面加上一个偏移量0x40 ,后面的地址在此基址上再依次加一。
void delay(unsigned int time_i){ int i;for (;tim>0;tim--){for (i=0;i<10;i++); } }void command_out (char out_data) {RW=0;RS=0;EN=1;DB=out_data;EN=0;delay(10);}void OUTD(char out_data){RS=1;RW=0;EN=1;DB= out_data;EN=0;delay(10);}OUTI() 是写入指令的函数,OUTD() 是写入数据的函数。
如:左上角第一个5*7 的显示数据为:0x00,0x01,0x81,0x12,0x24,0x41,0x81,0x10蓝色区域的相应位为1这样就可以写出全部 4 个 5*7 点阵的显示数据了,把它封装在一个数组中,如数组, hanzi[]={OxOO,OxO1,Ox81,Ox12,Ox24,Ox41,Ox81,Ox1O,} 之后利用命令:OUTI(0X40); for (i=0;i<64;i++){ OUTD(neu[i]);} 将这个数组中的数据赋值到 1602 内部 CGRAM 中。
基于51单片机的PS2键盘密码锁设计摘要:AT89S52是一种低功耗、高性能CMOS 8位微控制器,具有8K在系统可编程Flash 存储器,被广泛应用于各个领域。
LCD1602液晶显示器以其微功耗、体积小、超薄轻巧等诸多优点而备受人们喜爱。
本作品是以AT89S52作为主控芯片,LCD1602作为显示器,以PS2键盘作为输入设备的密码锁。
PS2键盘与AT89S52通过PS2接口协议进行通信,可以完成密码设置,密码重置及显示等诸多功能。
本作品还使用了24C02存储器来实现密码锁的掉电保存功能。
关键词:AT89S52;LCD1602;24C02;PS2键盘Abstract:AT89S52 is a low power,high performance CMOS 8 bit microcontroller, with 8K flash memory, is widely applied in various fields. LCD1602 liquid crystalDisplay with its low power consumption, small size, thin lightweight and many other advantages, is liked by people.This work is based on the AT89S52 as the main chip, the LCD1602 as display, PS2 keyboard as an input device of the cipher lock. PS2 keyboard and AT89S52 through PS2 interface protocolFor communication, can complete password, password reset and display and other functions. This work we also used the 24C02 memory to realize the password lock the power-down save function.Keywork: A T89C52; LCD1602; 24C02;PS/2 keyboard1 实验目的及意义在单片机系统中,经常使用的键盘都是专用键盘.此类键盘为单独设计制作的,成本高、使用硬件连接线多,且可靠性不高,这一状况在那些要求键盘按键较多的应用系统中更为突出.与此相比,在PC系统中广泛使用PS/2键盘具有价格低、通用可靠,且使用连接线少(仅使用2根信号线)的特点,并可满足多种系统的要求.因此在单片机系统中应用PS/2键盘是一种很好的选择.对于单片机初学者的我而言,AT89S52简单易学,非常适合我学习。
#include<reg52.h>#include<intrins.h>#define uchar unsigned char#define uint unsigned intsbit lcd_RS=P2^5;sbit lcd_RW=P2^6;sbit lcd_en=P2^7;void delay(uint z){uint i,j;for(i=0;i<200;i++)for(j=0;j<z;j++);}* 名称 : write_command(uchar com)*功能 : 1602命令函数* 输入 : 输入的命令值* 输出 : 无void write_command(uchar com) /*LCD写命令*/ {lcd_RS=0;lcd_RW=0;P0=com;delay(5);lcd_en=1;delay(5);lcd_en=0;}void lcd_init() /*LCD初始化*/{write_command(0X38);write_command(0X0e);write_command(0X06);write_command(0X01);}* 名称 : write_data(number)* 功能 : 1602写数据函数* 输入 : 需要写入1602的数据* 输出 : 无void write_data(number) /*LCD写数据操作*/ {lcd_RS=1;lcd_RW=0;P0=number;delay(5);lcd_en=1;delay(5);lcd_en=0;}uchar Keyscan() /*扫描子程序*/{uchar i,j,temp,buffer[4]={0xfe,0xfd,0xfb,0xf7};for(j=0;j<4;j++){P1=buffer[j];/*以下三个_nop_();作用为让P1 口的状态稳定*/_nop_();_nop_();_nop_();temp=0x10;for(i=0;i<4;i++){if(!(P1&temp)){return (i+j*4);}temp<<=1;}}}* 名称: L1602_char(uchar hang,uchar lie,char sign)* 功能: 改变液晶中某位的值,如果要让第一行,第五个字符显示"b" ,调用该函数如下L1602_char(1,5,'b')* 输入: 行,列,需要输入1602的数据* 输出: 无void L1602_char(uchar hang,uchar lie,uchar sign){uchar a;if(hang == 1) a = 0x80;if(hang == 2) a = 0xc0;a = a + lie - 1;write_command(a);write_data(sign);}void L1602_string(uchar hang,uchar lie,uchar *p) {uchar a;if(hang == 1) a = 0x80;if(hang == 2) a = 0xc0;a = a + lie - 1;write_command(a);while(1){if(*p == '\0') break;write_data(*p);p++;}}void main(){uchar key_data;lcd_init();L1602_string(1,1," 4*4 KeyBoard ");L1602_string(2,1,"You Press The ");while(1){ P1 = 0xf0;if(P1 != 0xf0){delay(5);if(P1 != 0xf0){key_data = Keyscan();}}L1602_char(2,15,key_data /10+48);L1602_char(2,16,key_data %10+48);}}。
1602液晶有提供了两种字符形式,一种是一般使用的固化的字符,直接写入字符的代码,即可显示该字符到LCD上面,比如我们需要显示A字母,就只需要lcd_rw(1, 0, 'A', 1);就可以了。
另外一种就是8个自定义的字符,存放在CGRAM中的数据,他们是0x00~0x07或者0x08~0x0f,只能使用一组。
字符地址代码 CGRAM 地址0x00(0x08) 0x00~0x070x01(0x09) 0x08~0x0F0x02(0x0A) 0x10~0x170x03(0x0B) 0x18~0x1F0x04(0x0C) 0x20~0x270x05(0x0D) 0x28~0x2F0x06(0x0E) 0x30~0x370x07(0x0F) 0x38~0x3F其中,0x08~0x0f的地址在使用5X8时,这个地址里边存放的跟0x00~0x07一样的数据,所以两组只能用一组。
在1602中,地址的设置有两种,一种是CGRAM地址设置,另外一种是DDRAM地址设置,他们的命令分别是一下。
DDRAM 地址设置指令:Bit D7 D6 D5 D4 D3 D2 D1 D0功能 1 A6 A5 A4 A3 A2 A1 A0该指令将7 位的DDRAM地址写入地址指针计数器AC当中,随后的操作就可以通过lcd_rw(1, 0, 'A', 1);对DDRAM进行读/写操作。
CGRAM 地址设置指令:Bit D7 D6 D5 D4 D3 D2 D1 D0功能 0 1 A5 A4 A3 A2 A1 A0该指令将6位的CGRAM 地址写入地址指针计数器AC 内,随后的操作是将CGRAM的读/写的数字操作。
我们首先是要将想显示的符号的值用字模工具或者手动的形式写入CGRAM中,分两个步骤:1,设定CGRAM的值;2,将数据写进去。
如果采用5X8的格式,那么我们就需要做一个8次的循环,每次设置了地址,接着就写入数据,程序的代码如下所示-----------------------------------------代码开始------------------------------------------void lcd_setchar(uchar usr_add, uchar usr_char[]) //usr_add为字符地址,usr_char为数组地址{uchar i;usr_add = ((usr_add<<3)&0x3f)|0x40; //左移以完成字符地址到CGRAM地址的转换//确保写入的值(命令)不能大于0x40,以免设置到别的参数for(i = 0; i < 8; i++) //一个字符有8行{lcd_rw(0, 0, (usr_add++), 1); //写入命令,usr_add已经加上了命令的设定值lcd_rw(1, 0, usr_char[i], 1); //写入数据}}-----------------------------------------代码结束------------------------------------------将这些字模的数据按照从上到下的顺序,排列成三组数组,分别为uchar LCD_year[] ={0x08, 0x0f, 0x12, 0x0f, 0x0a, 0x1f, 0x02, 0x02}; //年 uchar LCD_month[]={0x0f, 0x09, 0x0f, 0x09, 0x0f, 0x09, 0x0b, 0x11}; //月uchar LCD_date[] ={0x0f, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x09, 0x0f}; //日使用lcd_setchar(0x00, LCD_year);lcd_setchar(0x01, LCD_month);lcd_setchar(0x02, LCD_date);将字符写入之后,就可以使用lcd_rw(1, 0, 0x00, 1); //年lcd_rw(1, 0, 0x01, 1); //月lcd_rw(1, 0, 0x02, 1); //日来显示他们了。
摘要在日常生活中,我们经常要通过按键来实现对电子装置的控制,小到手表手机,中到电视电脑,大到各种复杂仪器,都需要通过按键来实现各种操作。
本次课程设计作为实践教学的一个重要环节,将以按键控制显示为主题,以1602液晶、MM74C922解码芯片、AT89C52单片机及其接口芯片为核心构造一个键盘控制显示系统,并使用Proteus软件对所设计的电路进行仿真,仿真结果是在1602液晶上显示所按下的键值。
关键词:Proteus仿真A T89C52 1602液晶MM74C922解码芯片第一章总体设计1.1电路结构分析本次设计的目标为单片机控制的键盘识别显示系统,主要采用AT89C52单片机作为核心,由矩阵键盘电路、译码芯片、液晶显示等模块构成,分别对按键信息和显示电路以及软、硬件各个部分进行控制;本设计采用C言编程来实现对单片机的控制。
实际运作时,单片机会将检测到的按键信号转换成数字,显示于1602液晶上。
系统主要结构可以拆分如下:①矩阵键盘:按键传送输入信息;此键盘采用的是4X4矩阵键盘,能输入0~9,+,—,=,空格,返回,清零。
②键盘识别:矩阵键盘连接的是MM74C922解码芯片,通过解码芯片来识别输入的按键位置。
③AT89C52:采用软件编程来实现按键信息的提取和转换;④1602液晶:用于显示最终被单片机转换过的按键信息。
由以上构思可以设计此按键显示电路。
1.2总体方案设计总体电路原理框图:如图 1.2所示图1.2总体电路原理方框图本次设计分两步来完成,第一步,解码芯片调试系统,将解码芯片接口连接到矩阵键盘作为AT89C52单片机的输入装置,然后以P2口作为输出端并连接一个数码管观察输出结果。
第二步,1602的液晶调试系统,此过程就是将数码管换成1602液晶在进行结果显示。
1.3蜂鸣器模块设计蜂鸣器模块设计如图 1.3所示图 1.3 蜂鸣器模块电路图蜂鸣器的驱动电流比较大一般要500MA~1000MA,所以不能直接接在AT82C52单片机的接口上,需要加一个三极管来进行驱动。
发声源程序如下:#define BEEP() P1^=0x80 //蜂鸣器定义void Sounder() //发生函数{INT8U i;for(i=0;i<100;i++){delay(3);BEEP();}}1.4电路图设计1.4.1解码芯片调试系统电路图如图1.3.1所示:图 1.4.1解码芯片调试系统电路图此电路图为解码芯片调试系统电路图,按键位置是由解码芯片进行识别。
当按下K0键时,解码芯片进行采集DCBA端输出0000,表示第一个键按下,OA允许输出端为高电平有效,此时蜂鸣器发声提示,数码管则显示0。
K9键按下时,解码芯片DCBA端输出0008,表示第九个键按下,OA允许输出端为高电平有效,此时蜂鸣器发声提示,数码管则显示9。
KF键按下时,解码芯片DCBA 端输出0015示第九个键按下,OA允许输出端为高电平有效,此时蜂鸣器发声提示,数码管则显示F。
仿真结果能完成上述功能,则证明调试成功。
1.4.2 总体电路图如图1.3.2所示图 1.4.2 总体电路图此电路为总体电路图设计,当有键按下时,解码芯片会对按键进行识别,并发送相应的代码到P3口,此时蜂鸣器发声提示,经过单片机的处理,按键的值会在1602液晶上进行显示。
如果仿真结果能完成上述功能,则证明调试成功。
第二章 硬件电路2.1 MM74C922解码芯片 2.1.1MM74C922特点及引脚功能MM74C922具有下列特点:1.功耗低,电压3—5V ;2.三态门输出,与LPTTL 兼容;3.输出锁存按下的最后的键;4.用一个电容器就可以消除键盘抖动;5.两键轮回;6.行具有上拉功能;7.具有芯片内或芯片外时钟;8.最大开关电阻为50K Ω。
MM74C922采用18脚双列直插封装,其引脚排列如图2.1.1所示。
各引脚功能如下:Y1—Y4为行键输入端;X1—X4为列键输入端;OSC 为振荡器的外接引线端,可用外部的输入脉冲或电容器;DA —DD 为数据输出端,可与微机直接接口;KBM 为键颤屏蔽端;OE _____为数据输出允许端,低电平有效;DAV为数据输出有效,高电平有效;VCC 为电源端, 接3—5V ;GND 为接地端。
VCC DA DC DD —OE DA V X1X2图2.1.1 MM74C922引脚排列图2.1.2 MM74C92真值表如表2.1.2所示键盘扫描可采用外部时钟或外接电容来执行。
译码器具有芯片的上拉电阻,使开关电阻可以高达50kΩ。
开关矩阵中不需要二极管就可以消除多重开关,内部消颤电路仅需要一个单一电容就可以实现。
当有键按下时,数据输出有效为高电平;当键释放后,数据输出有效返回到低电平。
即使有另外一个键按下,在正常消颤期间后,数据输出有效返回至高电平表明接受新的键输入。
在任何两个开关之间备有两键轮回功能。
即使某一键释放,内部锁存器仍然锁存住按下的最后的键值。
三态门输出便于总线的扩展和运行。
2.21602液晶2.2.1 1602液晶功能引脚如图2.2.1所示图 2.2.1 1602液晶功能引脚2.2.2液晶命令集及双行液晶DDRAM地址如表2.2.2所示表2.2.2 液晶命令集及双行液晶DDRAM地址RS为寄存器选择位RS=0时选择命令寄存/状态寄存器,RS=1时选择数据寄存器I/D=1递增,I/D=0递减S=0时显示屏不移动,S=1时,如果I/D=1且有字符写入时显示屏左移,否则右移D=1显示屏开开,D=0显示屏关C=1时光标处现在地址计数器所指的位置,C=0时光标不出现B=1时光标出现闪烁,B=0光标不闪烁S/C=0时,RL=0则光标左移,否则右移S/C=1时,RL=0则字符和光标左移,否则右移DL=1时数据长度为8位,DL=0时为使用D7~D4共4位,分两次发送一个字节N=0为单行显示,N=1时为双行显示F=1时为5x10点阵字体,F=0时为5x7点阵字体BF=1时LCD忙,BF=0时LCD就绪双行液晶的DDRAM地址2x20 LCD DDRAM(80~93/C0~E3)2.2.3基本操作时序1).读状态:输入:RS=L,W=H,E=H 输出:DB0~DB7=状态2)写指令:输入:RS=L,RW=L,DB0~DB7=指令码,E=高脉冲输出:无3) 读数据:输入:RS=H,RW=H,E=H 输出:DB0~DB7数据4) 写数据:输入:RS=H,RW=L,DB0~DB7数据,E=高脉冲输出:无2.2.3初始化过程1)延时15ms2)写指令38H(不检测忙信号)3)延时5ms4)写指令38H(不检测忙信号)5)延时5ms6)写指令38H(不检测忙信号)7)(以后每次写指令、读/写数据操作之前均需检测忙信号)8)写指令38H:显示模式设置9)写指令08H:显示关闭10)写指令01H:显示清屏11)写指令06H:显示光标移动设置12)写指令0CH:显示开及光标设置2.2.3读操作时序读操作时序如图2.2.4所示图 2.2.4读操作时序读操作程序如下:void Read_LCD_Command(INT8U cmd) //读命令{LCD_BUSY_WAIT();RS_0();RW_0();P2=cmd;delay(5);EN_1();EN_0();}void Read_LCD_Data(INT8U dat) //读数据{LCD_BUSY_WAIT();RS_1();RW_0();P2=dat;delay(5);EN_1();EN_0();}2.2.5写操作时序写操作时序图如图2.2.5图 2.2.5 写操作时序图写操作程序如下:void Write_LCD_Command(INT8U cmd) //写命令{LCD_BUSY_WAIT();RS_0();RW_0();P2=cmd;delay(3);EN_1();EN_0();}void Write_LCD_Data(INT8U dat) //写数据{LCD_BUSY_WAIT();RS_1();RW_0();P2=dat;delay(3);EN_1();EN_0();}2.3 AT89C52单片机AT89C52是一个低电压,高性能CMOS 8位单片机,片内含8k bytes的可反复擦写的Flash只读程序存储器和256 bytes的随机存取数据存储器(RAM),器件采用ATMEL公司的高密度、非易失性存储技术生产,兼容标准MCS-51指令系统,片内置通用8位中央处理器和Flash存储单元,功能强大的A T89C52单片机可为您提供许多较复杂系统控制应用场合。
AT89C52有40个引脚,32个外部双向输入/输出(I/O)端口,同时内含2个外中断口,3个16位可编程定时计数器,2个全双工串行通信口,2个读写口线,AT89C52可以按照常规方法进行编程,也可以在线编程。
其将通用的微处理器和Flash存储器结合在一起,特别是可反复擦写的Flash存储器可有效地降低开发成本。
实际引脚连线的部分如图2.3图 2.3 AT89C52单片机2.4 数码管译码电路中常用的显示器有LED(数码管)和LCD(液晶显示器)。
这两种显示器都具有线路简单、耗电少、成本低、寿命长等优点。
本系统输出结果选用1个七段数码管显示。
数码管有共阴共阳之分,本系统采用共阴型。
LED的外形结构如图2.4,外部有10个引脚,其中GND脚为公共端也称位选端,其余8个引脚称为段选端,当要使某一位数码管显示某一数字((0-9中的一个)必须在这个数码管的段选端加上与数字显示数字对应的8位段选码(也称字形码),在位选端加上低电平即可。
图2.4 LED数码管结构如下表2.4即两种数码管中数字显示对应的段码:第三章解码芯片调试系统3.1 解码芯片调试系统的4X4矩阵键盘设计,接线图如3.1所示图3.1 解码芯片调试系统的4X4矩阵键盘设计电路图3.2 解码芯片的接口设计,如图3. 2所示解码芯片的A、B、C、D口接P1.0~P1.4, OE口接地始终保持拉低,OA口接P1.7发送允许信号,X1~X4,Y1~Y4,分别与矩阵键盘的X,Y端口相接。
图 3.2 解码芯片接口设计电路图3.3 数码管的接口设计,如图3.3所示数码管的a~g端接在P2.0~P2.7端作为输出显示图 3.3 数码管的接口设计电路图3.4解码芯片软件流程图解码芯片软件流程图如图3.4所示图 3.4 解码芯片调试系统软件流程图3.5 解码芯片调试系统源程序代码 #include <reg52.h>#define INT8U unsigned char #define INT16U unsigned int#define BEEP() P3^=0x80 //蜂鸣器定义#define Key_Pressed ((P1 & 0X80)==0X80) //判断是否有键按下 #define Key_NO (P1 & 0X0F) //判断键值 INT8U code SEG_CODE[]= {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d, 0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71 };void delay(INT16U ms) //延时程序INT8U i,j;for(i=0;i<ms;i++){for(j=0;j<110;j++);}}void Sounder() //蜂鸣器{INT8U i;for(i=0;i<100;i++){delay(5);BEEP();}}void main(){P1=0XFF;P0=0x00;P2=0X00;P3=0XFF;while(1){if(Key_Pressed){P2=SEG_CODE[Key_NO]; //显示键值Sounder();}}此程序可以完成4X4矩阵键盘上任意键的显示即0~F的先显示,当有按键按下时,蜂鸣器会进行按键提示。