单片机课程设计——利用矩阵键盘来控制1602液晶显示器的显示设计
- 格式:doc
- 大小:194.50 KB
- 文档页数:24
一、原理图:二、程序#include<reg51.h> //包含单片机寄存器的头文件#include<intrins.h> //包含_nop_()函数定义的头文件#include<math.h>sbit RS=P2^0; //寄存器选择位,将RS位定义为P2.0引脚sbit RW=P2^1; //读写选择位,将RW位定义为P2.1引脚sbit E=P2^2; //使能信号位,将E位定义为P2.2引脚sbit BF=P1^7; //忙碌标志位,#define NO_KEY_PRESS 0xff/********************************************************************************************************/unsigned char code tab[]={0xb7,0xee,0xde,0xbe,0xed,0xdd,0xbd,0xeb,0xdb,0xbb};unsigned long num1,num2,alg;unsigned char flag;void delay1ms(){unsigned char i,j;for(i=0;i<10;i++)for(j=0;j<15;j++);}/********************************************************************************************************/void delay(unsigned char n){unsigned char i;for(i=0;i<n;i++)delay1ms();}/*****************************************************函数功能:判断液晶模块的忙碌状态返回值:result。
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意思是把数码管全灭掉。
简易计算器摘要:计算器是人们的日常生活中是最常见的电子产品之一,它应用极广、发展迅猛,并且不断出现着拥有更加强大功能的计算器。
为了解和研究计算器,本次课设设计制作了一个简易计算器,能够在十四位的计算范围内进行“+”、“-”、“*”、“/”的基本运算,能进行负数以及小数点后两位的精确结果显示。
该计算器以AT89C51单片机芯片作为核心。
采用LCD1602工业字符液晶进行显示。
完成的计算器经过检验能够完整的实现预设功能,各种细节完善,具有很高的使用价值。
关键词:单片机;简易计算器;AT89C51;LCD1602Simple CalculatorAbstract:Calculator is People's Daily life is one of the most common electronic products, used very wide, developing rapidly, and constantly appear more powerful function with have calculators. In order to understand and study calculator, this class set design made a simple calculator, can the calculation in within 14 "+" and "-" and "*", "/" the basic computing, can carry out negative and two decimal places accurate results are shown. This calculator with AT89C51 chips as the core. Using liquid LCD1602 industrial characters displayed. Complete calculator after inspection can complete realization, various details preset functions to perfect, have high use value.Keywords:MCU; Simple calculator;AT89C51;LCD1602目录中文摘要............................................................1英文摘要............................................................2单片机课程设计......................................................4 1 课程设计任务.....................................................41.1 主要功能设计................................................41.2 任务目的....................................................42 整体设计方案......................................................42.1 方案论证....................................................42.2 系统框图....................................................53 硬件电路的设计...................................................63.1 计算机Protel总图............................................63.2 显示电路设计方案............................................93.3 键盘设计方案................................................93.4 复位电路设计...............................................103.5 晶振电路设计...............................................104 控制软件设计....................................................114.1 程序时序总图...............................................114.2 液晶显示软件设计...........................................124.3 键盘输入软件设计...........................................134.4 计算函数设置...............................................155 系统调试........................................................185.1 硬件调试...................................................185.2 软件调试...................................................18 参考文献...........................................................20 个人小结...........................................................21 附录...............................................................24 附录1..........................................................24 附录2..........................................................251课程设计任务1.1 主要功能设计以AT89C51单片机芯片为核心来制作一个简易计算器,外部由4*4矩阵键盘和一个LCD1602工业字符型液晶显示屏构成,内部由一块AT89C51单片机构成,通过软件编程可实现简单加减乘除。
摘要在日常生活中,我们经常要通过按键来实现对电子装置的控制,小到手表手机,中到电视电脑,大到各种复杂仪器,都需要通过按键来实现各种操作。
本次课程设计作为实践教学的一个重要环节,将以按键控制显示为主题,以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液晶显示计算器院系:机械工程学院班级:测控1003姓名:金飞完成时间:2012年11月18日摘要本设计由51单片机作为核心,4*4矩阵键盘作为输入,将数据输入到单片机内部处理,并通过1602液晶显示出来运算及其结果。
本设计具有成本低廉,操作简单。
可作为日常简单计算使用。
关键词:51单片机、矩阵键盘、1602液晶。
一、外观介绍:二、电路仿真:P0.0~P0.7引脚接lcd的D0-D7,P3口接矩阵键盘。
单片机的P2.4、P2.0、P2.3脚分别接到LCD的RS、R/W、E管。
三、显示电路,LCD1602A的引脚详细介绍:采用LCD1602A来显示,要求能显示两行。
它的D—7D引脚分别接到单片机的P0.0~P0.7引脚;RS、R/W、E管脚分别接到单片机的P2.4、P2.0、P2.3 。
具体连接见后面的电路图。
以下是1602的16进制ASCII码表三、矩阵键盘扫描电路P3口的P3.0,P3.1,P3.2和P3.3四根线作为按键的行输出线,用P3.4,P3.5,P3.6和P3.7作为按键的列输入线。
依次给某一行低电平,再判断哪一列是低电平。
于是就判断出哪行和哪列导通。
对于不同的组合可以确定所有按键位置,将位置赋值到一个变量中,以供使用。
具体来说:假如按下的是数字5键(编号6——位于第二行第二列),首先置第一行为低电平其他7位为高电平P0=0xfe,再检测高四位的电平(P0=P&0xf0 ),因为列没有一条与第一行相导通,所以P0的高位还是高电平的。
然后再换第二行P0=0xfd,同理检测高四位(P0=P&0xf0 )得出P0=0xd0,则5键所在位置为第二行第二列,然后num赋值为6。
四、程序分析可知共分为七个模块:键盘扫描部分,定义各个位置上的键值部分,延迟部分,存贮部分,液晶显示部分,运算部分,动态显示部分。
主程序流程图如下:否判断是否有键按下五、程序#include<reg51.h>#define uint unsigned int#define uchar unsigned charsbit lcden=P2^3;sbit rs=P2^4;sbit rw=P2^0;sbit busy=P0^7;char i,j,temp,num,num_1;long a,b,c;float a_c,b_c;uchar 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 z){uchar y;for(z;z>0;z--)for(y=0;y<110;y++);}void check(){do{P0=0xFF;rs=0;rw=1;lcden=0;delay(1);lcden=1;}while(busy==1);}void write_com(uchar com){P0=com;rs=0;rw=0;lcden=0;check();lcden=1;}void write_date(uchar date) {P0=date;rs=1;rw=0;lcden=0;check();lcden=1;}void init(){num=-1;lcden=1;write_com(0x01);write_com(0x38);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;fuhao=0;}void keyscan(){P3=0xfe;if(P3!=0xfe){delay(20);if(P3!=0xfe){temp=P3&0xf0;{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){if(j!=0){write_com(0x01);j=0;}if(flag==0){a=a*10+table[num];}Else{b=b*10+table[num];}}else{flag=1;fuhao=4;}i=table1[num];write_date(0x30+i);}P3=0xfd;if(P3!=0xfd){delay(5);if(P3!=0xfd){temp=P3&0xf0;{case 0xe0:num=4;break;case 0xd0:num=5;break;case 0xb0:num=6;break;case 0x70:num=7;break;}}while(P3!=0xfd);if(num==4||num==5||num==6&&num!=7) {if(j!=0){write_com(0x01);j=0;}if(flag==0){a=a*10+table[num];}else{b=b*10+table[num];}}Else{flag=1;fuhao=3;}i=table1[num];write_date(0x30+i);}P3=0xfb;if(P3!=0xfb){delay(5);if(P3!=0xfb){temp=P3&0xf0;{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) {if(j!=0){write_com(0x01);j=0;}if(flag==0){a=a*10+table[num];}Else{b=b*10+table[num];}}else if(num==11){flag=1;fuhao=2;}i=table1[num];write_date(0x30+i);}P3=0xf7;if(P3!=0xf7){delay(5);if(P3!=0xf7){switch(temp){case 0xe0:num=12;break;case 0xd0:num=13;break;case 0xb0:num=14;break;case 0x70:num=15;break;}}while(P3!=0xf7);switch(num){case 12:{write_com(0x01);a=0;b=0;flag=0;fuhao=0;} break;case 13:{if(flag==0){a=a*10;write_date(0x30);P1=0;}else if(flag==1){b=b*10;write_date(0x30);}}break;case 14:{j=1;if(fuhao==1){write_com(0x80+0x4f);write_com(0x04);c=a+b;while(c!=0){write_date(0x30+c%10);c=c/10;}write_date(0x3d);a=0;b=0;flag=0;fuhao=0;}else if(fuhao==2){write_com(0x80+0x4f);write_com(0x04);if(a-b>0)c=a-b;elsec=b-a;while(c!=0){write_date(0x30+c%10);c=c/10;}if(a-b<0)write_date(0x2d);write_date(0x3d);a=0;b=0;flag=0;fuhao=0;}else if(fuhao==3){write_com(0x80+0x4f);write_com(0x04);c=a*b;while(c!=0){write_date(0x30+c%10);c=c/10;}write_date(0x3d);a=0;b=0;flag=0;fuhao=0;}else if(fuhao==4){write_com(0x80+0x4f);write_com(0x04);i=0;c=(long)(((float)a/b)*1000);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);write_date(0x3d);a=0;b=0;flag=0;fuhao=0;}}break;case 15:{write_date(0x30+table1[num]);flag=1;fuhao=1;}break;}}}main(){init();while(1){keyscan();}}以下程序才对#include<reg52.h> //头文件#define uint unsigned int //#define uchar unsigned charsbit lcden=P2^5; //定义引脚sbit rs=P2^4;sbit rw=P2^0;sbit busy=P0^7;char chufa=0;char chenfa=0;char jiafa=0;char jianfa=0;/***sbit dula=P2^6;sbit wela=P2^7;***/uchar code table2[]="overflow";char i,j,temp,num,num_1;long a,b,c; //a,第一个数b,第二个数c,得数long a_c,b_c; //floatuchar 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 z) // 延迟函数{uchar y;for(z;z>0;z--)for(y=0;y<110;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) // 写数据函数{P0=date;rs=1;rw=0;lcden=0;check();lcden=1;}void init() //初始化{num=-1;/***dula=0;wela=0;***/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表示是否有符号键按下,fuhao=0; // fuhao表征按下的是哪个符号}void keyscan() // 键盘扫描程序{P3=0xfe;if(P3!=0xfe){delay(20); //延迟20msif(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'或'9if(j!=0){write_com(0x01);j=0;}if(flag==0)//没有按过符号键{a=a*10+table[num];}else//如果按过符号键{b=b*10+table[num];}}else//如果按下的是'/'{flag=1;fuhao=4;//4表示除号已按chufa++;if (chufa == 2){write_com(0x80);for(num=0;num<8;num++){write_date(table2[num]);delay(5);}//write_date(0x21);chufa = 0;}/*** chenfa++;if(chenfa==1){write_date(0x21);chenfa=0;}***/}i=table1[num];write_date(0x30+i);}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 0x70:num=7;break;}}while(P3!=0xfd);if(num==4||num==5||num==6)//如果按下的是'4','5'或'6' {if(j!=0){write_com(0x01);j=0;}if(flag==0)//没有按过符号键{a=a*10+table[num];}else//如果按过符号键{b=b*10+table[num];}}else//如果按下的是'/'{flag=1;fuhao=3;//3表示乘号已按chenfa++;if (chenfa == 2){write_com(0x80);for(num=0;num<8;num++){write_date(table2[num]);delay(5);}//write_date(0x21);chenfa = 0;}}i=table1[num];write_date(0x30+i);}P3=0xfb;if(P3!=0xfb){delay(5);if(P3!=0xfb){temp=P3&0xf0;switch(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+table[num];}else//如果按过符号键{b=b*10+table[num];}}else if(num==11)//如果按下的是'-' {flag=1;fuhao=2;//2表示减号已按jianfa++;if (jianfa == 2){write_com(0x80);for(num=0;num<8;num++){write_date(table2[num]);delay(5);}//write_date(0x21);jianfa = 0;}}i=table1[num];write_date(0x30+i);}P3=0xf7;if(P3!=0xf7){delay(5);if(P3!=0xf7){temp=P3&0xf0;switch(temp){case 0xe0:num=12;break;case 0xd0:num=13;case 0xb0:num=14;break;case 0x70:num=15;break;}}while(P3!=0xf7);switch(num){case 12:{write_com(0x01);a=0;b=0;flag=0;fuhao=0;}//按下的是"清零"break;case 13:{ //按下的是"0"if(flag==0)//没有按过符号键{a=a*10;write_date(0x30);P1=0;}else if(flag==1)//如果按过符号键{b=b*10;write_date(0x30);}}break;case 14:{j=1;rw=0;rs=0;if(fuhao==1){write_com(0x0f);//按下等于键,光标前进至第二行最后一个显示处0x80+0x4fwrite_com(0x04); //设置从后住前写数据,每写完一个数据,光标后退一格c=a+b;delay(10);while(c!=0){write_date(0x30+c%10);//c=c/10;write_date(0x3d); //再写"="a=0;b=0;flag=0;fuhao=0;}else if(fuhao==2){write_com(0x0f);//光标前进至第二行最后一个显示处0x80+0x4fwrite_com(0x04); //设置从后住前写数据,每写完一个数据,光标后退一格if(a-b>0)c=a-b;elsec=b-a;while(c!=0){write_date(0x30+c%10);c=c/10;}if(a-b<0)write_date(0x2d);write_date(0x3d); //再写"="a=0;b=0;flag=0;fuhao=0;}else if(fuhao==3){write_com(0x0f); //0x80+0x4fwrite_com(0x04);c=a*b;while(c!=0){write_date(0x30+c%10);c=c/10;}write_date(0x3d);//write_date(0x30);a=0;b=0;flag=0;fuhao=0;}else if(fuhao==4){write_com(0x40+0x4f); //0x80+0x4fwrite_com(0x04);i=0;c=(long)(((float)a/b)*1000);while(c!=0){write_date(0x30+c%10);c=c/10;if(i==3)write_date(0x2e);}if(a/b<=0)write_date(0x30);write_date(0x3d);a=0;b=0;flag=0;fuhao=0;}}break;case 15:{write_date(0x30+table1[num]);flag=1;fuhao=1;jiafa++;if (jiafa == 2){write_com(0x80);for(num=0;num<8;num++){write_date(table2[num]);delay(5);}//write_date(0x21);jiafa = 0;}}break;}}}/*void key(){P3=0xfe;if(P3!=0xfe){delay(5);if(P3!=oxfe){temp=P3&0xf0;}}}*/main(){init();while(1) {keyscan(); }}。
2、超详细矩阵键盘控制1602程序实例说明(带电路图)By 即墨天2 一、电路图/*----------------------------------------------//程序功能:通过矩阵键盘在LCD1602任意位置输入0~9,且可通过光标二次修改;------------ 能退格,能清除显示,还能自己任意定义16个按键的意义.//调试状态:仿真实现//时间:2014-7-25-----------------------------------------------*/#include <reg52.h>#include <intrins.h>#define uchar unsigned char#define uint unsigned intsbit Lcd_RS = P2^0;sbit Lcd_RW = P2^1;sbit Lcd_EN = P2^2;uchar code table[] = "51201314" ;uchar code table1[] = "20140815" ;uchar code key16[]={0xee,0xed,0xeb,0xe7,0xde,0xdd,0xdb,0xd7,0xbe,0xbd,0xbb,0xb7,0x7e,0x7d,0x7b,0x77} ; //该键盘特征码是在特定的接线下有效,请参见电路原理图uchar key_number;void delayMS(uint x){uchar i;while(x--) for(i = 0; i < 120; i++);}//----------------------------------------------//忙检查//-----------------------------------------------bit Busy_Check(){bit state;Lcd_RS = 0;Lcd_RW = 1;Lcd_EN = 1;delayMS(1);state=(bit)(P0&0x80); //屏蔽底7位,state的值仅有高位决定Lcd_EN = 0;delayMS(1);return state;}//---------------------------------------------//向LCD写数据//----------------------------------------------void LCD_Wdata(uchar dat){while(Busy_Check()); //忙等待Lcd_RS = 1;Lcd_RW = 0;Lcd_EN = 0;P0 = dat;Lcd_EN = 1; //高脉冲delayMS(1);Lcd_EN = 0;}//---------------------------------------------//向LCD写指令//----------------------------------------------void LCD_Wcmd(uchar cmd){while(Busy_Check()); //忙等待Lcd_RS = 0;Lcd_RW = 0;P0 = cmd;delayMS(1);Lcd_EN = 0;Lcd_EN = 1; //高脉冲delayMS(1);Lcd_EN = 0;}//---------------------------------------------------------//LCD初始化//---------------------------------------------------------void Init_Lcd(){LCD_Wcmd(0x38);//显示模式设置delayMS(1);LCD_Wcmd(0x0f);//开显示,显示光标,光标闪烁delayMS(1);LCD_Wcmd(0x06);//当读写一个字符后地址指针加一,且光标加一delayMS(1);LCD_Wcmd(0x01);//清屏delayMS(1);}//---------------------------------------------------------//键盘模块//---------------------------------------------------------bit pushkey() //判断是否有键按下{P1=0xf0;if(P1!=0xf0)return (1);elsereturn (0);}void key_scan()//矩阵扫描{ uchar keycode,p;delayMS(15); // 延时消抖if(P1!=0xf0){P1 = 0xf7; //键盘扫描码初值,逐行扫描,P1.3=0,扫描第4列while(1){keycode = P1; //读出数据,看是否在此行上的某列按键被按下if((keycode&0xf0)!=0xf0) break;// 如果扫描到按下的键,则退出P1=_cror_(P1,1); //否则,左移,扫描下一列}while((pushkey())); //等待按键释放for(p = 0 ; p<16 ;p++){if ( keycode== key16[p])key_number=p; //与特征值对比得与哪个键按下}}}void LCD_address(uchar hang,uchar lie )//显示字符先输入显示的位置{if (hang%2==1) LCD_Wcmd(0x80+(lie%16)-1);else LCD_Wcmd(0x80+0x40+(lie%16)-1);}void LCD_display(){ uchar j;LCD_address(1,1);while(table1[j]!='\0'){LCD_Wdata(table[j]);j++;}}void main(){ uchar n=0;Init_Lcd(); //初始化LCDLCD_display();while(1){if(pushkey())//判断是否有键按下{key_scan();switch(key_number){case 10: LCD_Wcmd(0x10);break; //光标左移(相当于A 被按下)case 11: LCD_Wcmd(0x14);break; //光标右移(相当于B被按下)case 12: n++; //光标下移(相当于C被按下)if((n%2)==1) //第二次被按下的时候,光标回到第一行{LCD_Wcmd(0x80+0x40);break;}else LCD_Wcmd(0x80);break;case 13: LCD_Wcmd(0x10);LCD_Wdata(0x00);LCD_Wcmd(0x10);break; //产生退格功能,按下一次后清除前一次的显示case 15: LCD_Wcmd(0x01);break;//清屏default: LCD_Wdata(key_number+0x30);break;}}} ;}。
4X4矩阵键盘+1602——51单片机的Proteus实验本文转载自小波电子工作室。
C语言源代码//======================================================依次可以从键盘输入0-f,在1602LCD上显示出来(此程序在所买开发板上验证通过)//======================================================//******** 小波电子工作室All rights reserved******//******** 个人主页:/niejinbo **//******** 文件名:lcd_key.1.c ************//******** 功能概要:4*4矩阵键盘扫描***********//******** MCU: STC89C52 晶振:11.0592Mhz **********//******** 设计者:聂金波************//******** 完成日期:2008-07-14 ************//******** 当前版本:0714.1 ************//******** 改进说明:暂无************//******** 补充说明: 从键盘输入0-F,在LCD上显示出来//*********头文件区*******************#include<reg52.h>#include<math.h>#include<absacc.h>#define uchar unsigned char#define uint unsigned int//*********定义变量区*******************sbit dula=P2^6; //关闭数码管显示之用sbit wela=P2^7;sbit lcden=P3^4; //LCD使能信号sbit lcdrs=P3^5; //LCD数据/命令选择信号uchar tab_key[50];uchar code tab[]="0123456789abcdef";uchar n=0,temp,key;//*********函数声明区********************void lcd_disp(); //LCD显示函数void lcd_init(); //LCD初始化函数void write_com(uchar); //写命令函数void write_data(uchar); //写数据函数void delay(uint); //延迟函数void key_scan(); //键盘扫描函数void key_manage1(); //键盘功能分配函数void key_manage2();void key_manage3();void key_manage4();void key_manage5();void key_manage6();void key_manage7();void key_manage8();void key_manage9();void key_manage10();void key_manage11();void key_manage12();void key_manage13();void key_manage14();void key_manage15();void key_manage16();//**********主函数开始**********void main(){lcd_init();write_com(1);while(1){key_scan();lcd_disp();}}//**********LCD显示函数开始***********void lcd_disp(){uchar a,i=0;write_com(0x80);for(i=0;i<n;i++){a=tab_key[i];write_data(tab[a]);}}//**********LCD初始化函数开始*********void lcd_init(){dula=0;wela=0; // 关闭数码管显示lcden=0;write_com(0x38); //设置显示模式:16X2,5X7,8位数据接口write_com(0x0c); //开显示,显示光标,光标闪烁write_com(0x06); //读写一个字符后,地址指针及光标加一,且光标加一整屏显示不移动write_com(0x80); //设置光标指针}//**********写命令函数开始************void write_com(uchar com){lcdrs=0; //低电平写命令P0=com; //写入命令delay(3); //延时约3mslcden=1; //LCD使能端置高电平delay(5); //延时约5mslcden=0; //LCD使能端拉低电平}//**********写数据函数开始************void write_data(uchar dat){lcdrs=1; //低电平写数据P0=dat; //写入命令delay(3); //延时约3mslcden=1; //LCD使能端置高电平delay(5); //延时约5mslcden=0; //LCD使能端拉低电平}//**********键盘扫描函数开始**** void key_scan(){//**********扫描第一行*********P3=0xfe;temp=P3;temp=temp&0xf0;if(temp!=0xf0){delay(100);if(temp!=0xf0){temp=P3;switch(temp){case 0xee:key_manage1();break;case 0xde:key_manage2();break;case 0xbe:key_manage3();break;case 0x7e:key_manage4();break;}while(temp!=0xf0){temp=P3;temp=temp&0xf0;}}}//**********扫描第二行*********P3=0xfd;temp=P3;temp=temp&0xf0;if(temp!=0xf0){delay(100);if(temp!=0xf0){temp=P3;switch(temp){case 0xed:key_manage5();break;case 0xdd:key_manage6();break;case 0xbd:key_manage7();break;case 0x7d:key_manage8();break;}while(temp!=0xf0){temp=P3;temp=temp&0xf0;}}}//**********扫描第三行********* P3=0xfb;temp=P3;temp=temp&0xf0;if(temp!=0xf0){delay(100);if(temp!=0xf0){temp=P3;switch(temp){case 0xeb:key_manage9();break;case 0xdb:key_manage10();break;case 0xbb:key_manage11();break;case 0x7b:key_manage12();break;}while(temp!=0xf0){temp=P3;temp=temp&0xf0;}}}//**********扫描第四行********* P3=0xf7;temp=P3;temp=temp&0xf0;if(temp!=0xf0){delay(100);if(temp!=0xf0){temp=P3;switch(temp){case 0xe7:key_manage13();break;case 0xd7:key_manage14();break;case 0xb7:key_manage15();break;case 0x77:key_manage16();break;}while(temp!=0xf0){temp=P3;temp=temp&0xf0;}}}}//*********延时函数开始************** void delay(uint k){uint i,j;for(i=k;i>0;i--)for(j=50;j>0;j--);}//******键盘功能分配函数群开始********// 键盘功能示意图// 设计者:聂金波//** 1 ** 2 ** 3 ** 4 **//** 5 ** 6 ** 7 ** 8 **//** 9 ** 0 ** s ** c **//** M1** M2** M3** M4**void key_manage1(){tab_key[n]=0;n++;}void key_manage2(){tab_key[n]=1;n++;}void key_manage3(){tab_key[n]=2;n++;}void key_manage4() {tab_key[n]=3;n++;}void key_manage5() {tab_key[n]=4;n++;}void key_manage6() {tab_key[n]=5;n++;}void key_manage7(){tab_key[n]=6;n++;}void key_manage8(){tab_key[n]=7;n++;}void key_manage9() {tab_key[n]=8;n++;}void key_manage10(){tab_key[n]=9;n++;}void key_manage11() {tab_key[n]=10;n++;}void key_manage12(){tab_key[n]=11;n++;}void key_manage13(){tab_key[n]=12;n++;}void key_manage14(){tab_key[n]=13;n++;}void key_manage15(){tab_key[n]=14;n++;}void key_manage16(){tab_key[n]=15;n++;}Proteus仿真图依次从键盘输入:abcd 277817639 (本人QQ号)4X4矩阵键盘-Proteus截图。
#include<reg51.h>#include<string.h>#include<intrins.h>#define uchar unsigned char#define uint unsigned int#define LCDIO P2#define delay4us() _nop_();_nop_();_nop_();_nop_();uchar buffer[6]={0};sbit sda=P3^7;sbit scl=P3^6;sbit beep=P3^5;bit flag=0,aa; //用户蹲渊义定时溢出标志位uchar DSY_BUFFER[16]=" ";uchar DSY_BUFFER1[16]=" ";uchar Userpassword[6]={0};sbit rs=P0^4;sbit rd=P0^3;sbit lcden=P0^2;sbit led=P3^0;uchar code table2[]="123456";uchar code table[]="Your Password...";void delayms(uint z){uint x,y;for(x=z;x>0;x--)for(y=110;y>0;y--);}void delay() //短延时,两个机器周期,做总线的延时用{;;}void write_com(uchar com){rs=0;rd=0;lcden=0;P2=com;delayms(3);lcden=1;delayms(3);lcden=0;}void write_date(uchar date){rs=1;rd=0;lcden=0;P2=date;delayms(3);lcden=1;delayms(3);lcden=0;}void Display_String(uchar *p,uchar com) { uchar i;write_com(com);for(i=0;i<16;i++){write_date(p[i]);}void init_lcd(){lcden=0;write_com(0x38);write_com(0x0c);write_com(0x06);write_com(0x01);write_com(0x80);Display_String(table,0x80);Display_String("Lock OK! ",0xc0); }void start(){sda=1;scl=1;delay4us();sda=0;delay4us();scl=0;}void stop(){sda=0;scl=1;delay4us();sda=1;delay4us();scl=0;void init() //初始化{sda=1;delay();scl=1;delay();}void ack(){sda=0;scl=1;delay4us();scl=0;sda=1;}void noack(){sda=1;scl=1;delay4us();scl=0;sda=0;}uchar recbyte(){uchar i,rd;rd=0x00;for(i=0;i<8;i++){scl=1;rd<<=1;rd|=sda;delay4us();scl=0;delay4us();}scl=0;delay4us();return rd;}uchar sendbyte(uchar wd){uchar i;bit ack0;for(i=0;i<8;i++){sda=(bit)(wd&0x80);_nop_();_nop_();scl=1;delay4us();scl=0;wd<<=1;}delay4us();sda=1;delay4us();ack0=!sda;scl=0;delay4us();return ack0;}uchar Recstring(uchar slave,uchar subaddr,uchar *buffer,uchar n) {uchar i;start();if(!sendbyte(slave)) return 0;if(!sendbyte(subaddr)) return 0;start();if(!sendbyte(slave+1)) return 0;for(i=0;i<n-1;i++){buffer[i]=recbyte();ack();}buffer[n-1]=recbyte();noack();stop();return 1;}uchar Sendstring(uchar slave,uchar subaddr,uchar *buffer,uchar n) {uchar i;start();if(!sendbyte(slave)) return 0;if(!sendbyte(subaddr)) return 0;for(i=0;i<n;i++){if(!sendbyte(buffer[i])) return 0;}stop();return 1;}void clear_password(){ uchar i;for(i=0;i<6;i++){Userpassword[i]=' ';}for(i=0;i<16;i++){DSY_BUFFER[i]=' ';}}uchar Keys_Scan(){uchar temp,keynum;P1=0x0F;delayms(5);temp=P1^0x0F;switch(temp){case 1:keynum=0;break;case 2:keynum=1;break;case 4:keynum=2;break;case 8:keynum=3;break;break;}P1=0xF0;delayms(5);temp=P1>>4^0x0F;switch(temp){case 1:keynum+=0;break;case 2:keynum+=4;break;case 4:keynum+=8;break;case 8:keynum+=12;break;break;}delayms(600);return keynum;}void main(){ uchar temp,i=0,j=0,k=0,n;uchar IS_valid_user;beep=1;init();init_lcd();delayms(5);aa=Sendstring(0xa0,1,table2,6);delayms(5);aa=Recstring(0xa0,1,buffer,6);delayms(10);P1=0x0f;while(1){if(P1!=0x0f){temp=Keys_Scan();switch(temp){case 0: case 1: case 2: case 3: case 4:case 5: case 6: case 7: case 8: case 9:if (i<=5) //密码限制在6位以内{Userpassword[i]=temp;DSY_BUFFER[i]='*';Display_String(DSY_BUFFER,0xc0);i++;}break;case 10: //按A键开锁for(k=0;k<6;k++){if(buffer[k]==(Userpassword[k]+48))flag=1;elseflag=0;}if (flag==1){ flag=0;i=0;led=0; //点亮LEDclear_password();Display_String("OPEN OK! ",0xc0);IS_valid_user = 1;j=0;}else{j++;led=1; //关闭LEDclear_password();Display_String("ERROR!Have try ",0xc0);write_com(0xcf);write_date(0x30+j); IS_valid_user=0;}i=0;break;case 11: //按B键上锁led=1;clear_password();Display_String(table,0x80);Display_String("Lock OK! ",0xc0);i=0;IS_valid_user=0;break;case 12: //按C键设置新密码//如果是合法用户则提示输入新密码if ( !IS_valid_user){i=0;Display_String("No rights ! ",0xc0);delayms(1000);Display_String("Your Password...",0x80);Display_String("Lock OK! ",0xc0);}else{i=0;Display_String("New Password: ",0x80);Display_String(" ",0xc0);}break;case 13: //按D键保存新密码if ( !IS_valid_user){ i=0;Display_String("No rights ! ",0xc0);delayms(1000);Display_String("Your Password...",0x80);Display_String("Lock OK! ",0xc0);}else{i = 0;init();delayms(5);for(k=0;k<6;k++){Userpassword[k]=Userpassword[k]+48;}aa=Sendstring(0xa0,1,Userpassword,6);delayms(5);aa=Recstring(0xa0,1,buffer,6);delayms(5);clear_password();Display_String(table,0x00);Display_String("Password Saved! ",0xc0);delayms(1000);Display_String("Do lock agian ? ",0xc0);}break;case 14: //按E键消除所有输入i=0;clear_password();Display_String(" ",0xc0);break;case 15: //清除一位if(i!=0)i--;for(n=0;n<i;n++){DSY_BUFFER1[n]='*';}Display_String(DSY_BUFFER1,0xc0);}P1=0x0f;}if(j==3){ Display_String("THIEFTHIEF",0xc0);j=0;beep=0;}}}。
摘要在日常生活中,我们对液晶显示(LCD)并不陌生LCD智能显示模块不但可以显示字符,汉字和图形,同时具有可编程功能,且与单片机接口比较方便,如液晶显示模块已作为很多电子产品的通用器件,如在计算器,万用表,电子表及很多家用电子产品中都可以看到,显示的主要是数字,专用符号和图形。
在单片机系统中应用中用液晶显示作为输出器件有很多优点,如显示质量高,不闪烁;数字接口式,使得和单片机的接口更加简单可靠,操作方便;体积小,重量轻;而且相对而言,液晶显示器的功耗主要消耗在其内部的电极和驱动TC上,因而耗电量比其它显示器要少得多。
关键字:单片机专用字符液晶显示器(LCD1602)目录摘要.................................................................................................................... 错误!未定义书签。
第一章绪论 ................................................................................................. 错误!未定义书签。
1.1 课题背景 (2)1.2课题设计目标 (2)1.3课题设计的主要工作 (3)第二章硬件设计 (4)2.1LCD1602简介 (5)2.1.1 LCD1602引脚功能 (7)2.2 IIC总线 (10)2.2.1 IIC总线的特点 (11)2.2.2 IIC协议总线信号时序 (9)2.2.3 IIC总线器件寻址方式 (7)2.3 系统电路图 (7)第三章软件设计 (7)3.1 系统框图 (7)3.2 程序清单 (7)第四章调试 (7)第五章总结 (7)参考文献 (7)致谢 (7)1绪论1.1课题背景当今时候是一个信息化的时代,信息的重要性不言而喻的,获取手段显得尤其重要。
《单片机原理及应用课程设计》报告——利用矩阵键盘来控制1602液晶显示器的显示设计2011年12 月7 日目录1.课程设计的目的12.课程设计的要求3.硬件设计3.1设计思想3.2主要元器件介绍3.3.功能电路介绍3.31 1602液晶显示器3.32 3*4矩阵键盘(1)矩阵式键盘的结构与工作原理(2)矩阵式键盘的按键识别方法4.软件设计4.1设计思想4.2软件流程图4.3源程序:5.调试运行6.设计心得体会:1.课程设计目的1.1巩固和加深对单片机原理和接口技术知识的理解;1.2培养根据课题需要选学参考书籍、查阅手册和文献资料的能力;1.3学会方案论证的比较方法,拓宽知识,初步掌握工程设计的基本方法;1.4掌握常用仪器、仪表的正确使用方法,学会软、硬件的设计和调试方法;1.5能按课程设计的要求编写课程设计报告,能正确反映设计和实验成果,能用计算机绘制电路图和流程图。
2.课程设计要求2.1在3*4矩阵键盘上输入信息2.2在1602芯片上显示时间信息。
2.3显示数据的设计与变换3.硬件设计3.1设计思想在3*4矩阵键盘上输入信息,通过中央处理器处理信息,再通过1602液晶显示器显示信息。
3.2主要元器件介绍(1)电源电路(2)STC89C82RC单片机一块。
(3)1602液晶显示器一块(4)杜邦线若干。
(5)3*4矩阵键盘3.3.功能电路介绍3.31 1602液晶显示器液晶显示模块具有体积小、功耗低、显示内容丰富等特点,现在字符型液晶显示模块已经是单片机应用设计中最常用的信息显示器件了。
1602可以显示2行16个字符,有8位数据总线D0-D7,和RS、R/W、EN三个控制端口,工作电压为5V,并且带有字符对比度调节和背光。
1602外观如下图所示1602引脚说明注意事项:从该模块的正面看,引脚排列从右向左为:15脚、16脚,然后才是1-14脚(线路板上已经标明)。
VDD:电源正极,4.5-5.5V,通常使用5V电压;VL:LCD对比度调节端,电压调节范围为0-5V。
接正电源时对比度最弱,接地电源时对比度最高,但对比度过高时会产生“鬼影”,因此通常使用一个10K的电位器来调整对比度,或者直接串接一个电阻到地;RS:MCU写入数据或者指令选择端。
MCU要写入指令时,使RS为低电平;MCU要写入数据时,使RS为高电平;R/W:读写控制端。
R/W为高电平时,读取数据;R/W为低电平时,写入数据;E:LCD模块使能信号控制端。
写数据时,需要下降沿触发模块。
D0-D7:8位数据总线,三态双向。
如果MCU的I/O口资源紧张的话,该模块也可以只使用4位数据线D4-D7接口传送数据。
本充电器就是采用4位数据传送方式;BLA: LED背光正极。
需要背光时,BLA串接一个限流电阻接VDD,BLK接地,实测该模块的背光电流为50mA左右;BLK: LED背光地端。
1602操作时序(1)读操作时序(2)写操作时序(3)基本操作时序图为DM-162液晶显示模块和单片机STC89C82RC的接口电路3.32 3*4矩阵键盘(1)矩阵式键盘的结构与工作原理在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式。
在矩阵式键盘中,每条水平线和垂直线在交叉处不直接连通,而是通过一个按键加以连接。
这样,一个端口(如P1口)就可以构成4*4= 16个按键,比之直接将端口线用于键盘多出了一倍,而且线数越多,区别越明显,比如再多加一条线就可以构成20键的键盘,而直接用端口线则只能多出一键(9键)。
由此可见,在需要的键数比较多时,采用矩阵法来做键盘是合理的。
矩阵式结构的键盘显然比直接法要复杂一些,识别也要复杂一些,列线通过电阻接正电源,并将行线所接的单片机的I/O口作为输出端,而列线所接的I/O口则作为输入。
这样,当按键没有按下时,所有的输出端都是高电平,代表无键按下。
行线输出是低电平,一旦有键按下,则输入线就会被拉低,这样,通过读入输入线的状态就可得知是否有键按下了。
具体的识别及编程方法如下所述。
(2)矩阵式键盘的按键识别方法确定矩阵式键盘上何键被按下介绍一种“行扫描法”。
行扫描法行扫描法又称为逐行(或列)扫描查询法,是一种最常用的按键识别方法。
1、判断键盘中有无键按下将全部行线Y0-Y3置低电平,然后检测列线的状态。
只要有一列的电平为低,则表示键盘中有键被按下,而且闭合的键位于低电平线与4根行线相交叉的4个按键之中。
若所有列线均为高电平,则键盘中无键按下。
2、判断闭合键所在的位置在确认有键按下后,即可进入确定具体闭合键的过程。
其方法是:依次将行线置为低电平,即在置某根行线为低电平时,其它线为高电平。
在确定某根行线位置为低电平后,再逐行检测各列线的电平状态。
若某列为低,则该列线与置为低电平的行线交叉处的按键就是闭合的按键。
4.软件设计4.1设计思想:把一个多功能的复杂程序划分为若干简单的,功能单一的程序模块,各程序模块完成明确的任务,实现某个具体功能。
在具体需要时调用相应的模块即可。
4.2软件流程图:4.3源程序:#include <reg52.h>#include <intrins.h>#define uchar unsigned char#define uint unsigned intuchar dis_buf; //显示缓存uchar temp;uchar key; //键顺序吗void delay0(uchar x); //x*0.14MSsbit LCD_RW = P2^5;sbit LCD_RS = P2^6;sbit LCD_EN = P2^7;uchar cdis1[16] = {" KEY NUMBER "};uchar cdis2[16] = {" KEY-CODE: H "};#define delayNOP(); {_nop_();_nop_();_nop_();_nop_();};/********************************************************** ***//**//* 延时子程序*//* *//********************************************************** ***/void delay(uchar x){ uchar j;while((x--)!=0){ for(j=0;j<125;j++){;}}}/********************************************************** ***//*检查LCD忙状态*//*lcd_busy为1时,忙,等待。
lcd-busy为0时,闲,可写指令与数据 *//*************************************************************/bit lcd_busy(){bit result;LCD_RS = 0;LCD_RW = 1;LCD_EN = 1;delayNOP();result = (bit)(P0&0x80);LCD_EN = 0;return(result);}/*******************************************************************//*写指令数据到LCD *//*RS=L,RW=L,E=高脉冲,D0-D7=指令码。
*//*******************************************************************/void lcd_wcmd(uchar cmd){while(lcd_busy());LCD_RS = 0;LCD_RW = 0;LCD_EN = 0;_nop_();_nop_();P0 = cmd;delayNOP();LCD_EN = 1;delayNOP();LCD_EN = 0;}/*******************************************************************//*写显示数据到LCD/*RS=H,RW=L,E=高脉冲,D0-D7=数据。
*//********************************************************** *********/void lcd_wdat(uchar dat){while(lcd_busy());LCD_RS = 1;LCD_RW = 0;LCD_EN = 0;P0 = dat;delayNOP();LCD_EN = 1;delayNOP();LCD_EN = 0;}/**********************************************************/* LCD初始化设定*//********************************************************** ***/void lcd_init(){delay(15);lcd_wcmd(0x38); //16*2显示,5*7点阵,8位数据delay(5);lcd_wcmd(0x38);delay(5);lcd_wcmd(0x38);delay(5);lcd_wcmd(0x0c); //显示开,关光标delay(5);lcd_wcmd(0x06); //移动光标delay(5);lcd_wcmd(0x01); //清除LCD的显示内容delay(5);}/********************************************************** ***//* 设定显示位置*//********************************************************** ***/void lcd_pos(uchar pos){lcd_wcmd(pos | 0x80); //数据指针=80+地址变量}/********************************************************** ***//* 键扫描子程序 (4*3 的矩阵) P1.4 P1.5 P1.6 P1.7为行*//* P1.1 P1.2 P1.3为列 */ /********************************************************** ***/void keyscan(void){delay(10);temp = 0;P3=0xF0; //高四位输入行为高电平列为低电平delay(1);temp=P3; //读P1口temp=temp&0xF0; //屏蔽低四位temp=~((temp>>4)|0xF0);if(temp==1) // p1.4 被拉低key=0;else if(temp==2) // p1.5 被拉低key=1;else if(temp==4) // p1.6 被拉低key=2;else if(temp==8) // p1.7 被拉低key=3;elsekey=16;P3=0x0F; //低四位输入列为高电平行为低电平delay(1);temp=P3; //读P1口temp=temp&0x0F;temp=~(temp|0xF0);if(temp==2) // p1.1 被拉低key=key+0;else if(temp==4) // p1.2 被拉低key=key+4;else if(temp==8) // p1.3 被拉低key=key+8;elsekey=16;dis_buf = key; //键值入显示缓存 dis_buf = dis_buf & 0x0f;if(dis_buf>9) //转换为ASCII码 dis_buf = dis_buf+0x37;elsedis_buf = dis_buf+0x30;P3=0xff;while(P3!=0xff){ P3=0xff;}delay(30);}/********************************************************** ***//*判断键是否按下*//********************************************************** ***/void keydown(void){P3=0xF0;if(P3!=0xF0) //判断按键是否按下如果按钮按下会拉低P1其中的一个端口{keyscan();}}/********************************************************** ***//* 主程序*//********************************************************** ***/main(){uchar m;P0=0xFF; //置P0口P1=0xFF; //置P1口delay(10); //延时lcd_init(); //初始化LCDlcd_pos(0); //设置显示位置为第一行的第1个字符m = 0;while(cdis1[m] != '\0'){ //显示字符lcd_wdat(cdis1[m]);m++;}lcd_pos(0x40); //设置显示位置为第二行第1个字符m = 0;while(cdis2[m] != '\0'){lcd_wdat(cdis2[m]); //显示字符m++;}dis_buf = 0x2d; //显示字符"-"while(1){keydown();lcd_pos(0x4c);lcd_wdat(dis_buf); //第一位数显示}}5.调试运行5.1程序调试正确后,在1602LCD上查看是否显示光标5.2在矩阵键盘上按下键盘,看在1620显示器上是不是有显示。