第5章单片机的开关检测、键盘输入与显示的接口设计单片机原理及接口技术(C51编程)(第2版)目录CONTENTS5.1单片机控制发光二极管显示5.2开关状态检测5.3单片机控制LED数码管的显示5.4单片机控制LED点阵显示器显示5.5单片机控制液晶显示模块1602LCD的显示5.6键盘接口设计5.1单片机控制发光二极管显示发光二极管常用来指示系统工作状态,制作节日彩灯、广告牌匾等。大部分发光二极管工作电流1~5mA之间,其内阻为20~100Ω。电流越大,亮度也越高。为保证发光二极管正常工作,同时减少功耗,限流电阻选择十分重要,若供电电压为+5V,则限流电阻可选1~3kΩ。5.1.1单片机与发光二极管的连接第2章已介绍,P0口作通用I/O用,由于漏极开路,需外接上拉电阻。而P1~P3口内部有30kΩ左右上拉电阻。下面讨论P1~P3口如何与LED发光二极管驱动连接问题。单片机并行端口P1~P3直接驱动发光二极管,电路见图5-1。与P1、P2、P3口相比,P0口每位可驱动8个LSTTL输入,而P1~P3口每一位驱动能力,只有P0口一半。5.1.1单片机与发光二极管的连接图5-1发光二极管与单片机并行口的连接5.1.1单片机与发光二极管的连接当P0口某位为高电平时,可提供400µA的拉电流;当P0口某位为低电平(0.45V)时,可提供3.2mA的灌电流,而P1~P3口内有30kΩ左右上拉电阻,如高电平输出,则从P1、P2和P3口输出的拉电流Id仅几百µA,驱动能力较弱,亮度较差,见图5-1(a)。如端口引脚为低电平,能使灌电流Id从单片机外部流入内部,则将大大增加流过的灌电流值,见图5-1(b)。AT89S51任一端口要想获得较大的驱动能力,要用低电平输出。如一定要高电平驱动,可在单片机与发光二极管间加驱动电路,如74LS04、74LS244等。5.1.2I/O端口的编程举例对I/O端口编程控制时,要对I/O端口特殊功能寄存器声明,在C51的编译器中,这项声明包含在头文件reg51.h中,编程时,可通过预处理命令#includereg51.h,把这个头文件包含进去。下面通过案例介绍如何编程对发光二极管输出控制。5.1.2I/O端口的编程举例【例5-1】制作流水灯,原理电路见图5-2,8个发光二极管LED0~LED7经限流电阻分别接至P1口的P1.0~P1.7引脚上,阳极共同接高电平。编写程序来控制发光二极管由上至下的反复循环流水点亮,每次点亮一个发光二极管。5.1.2I/O端口的编程举例图5-2单片机控制的流水灯5.1.2I/O端口的编程举例参考程序:#includereg51.h#includeintrins.h//包含移位函数_crol_()的头文件#defineucharunsignedchar#defineuintunsignedintvoiddelay(uinti)//延时函数{uchart;while(i--){for(t=0;t120;t++);}}5.1.2I/O端口的编程举例voidmain()//主程序{P1=0xfe;//向P1口送出点亮数据while(1){delay(500);//500为延时参数,可根据实际需//要调整P1=_crol_(P1,1);//函数_crol_(P1,1)把P1中的数据//循环左移1位}}5.1.2I/O端口的编程举例(1)while(1)两种用法:“while(1);”:while(1)后有分号,是使程序停留在这指令上;“while(1){……;}”:反复循环执行大括号内程序段,本例用法,即控制流水灯反复循环显示。5.1.2I/O端口的编程举例(2)C51函数库中的循环移位函数:循环移位函数包括:循环左移函数“_crol_”。循环右移函数“_cror_”。本例用循环左移“_crol_(P1,1)”,函数。括号第1个参数为循环左移对象,即对P1中的内容循环左移;第2个参数为左移位数,即左移1位。编程中一定要把含有移位函数的头文件intrins.h包含在内,例如第2行“#includeintrins.h”。5.1.2I/O端口的编程举例在【例5-1】基础上,编写控制发光二极管反复循环点亮的流水灯。【例5-2】电路见图5-2,制作由上至下再由下至上反复循环点亮显示的流水灯,3种方法实现。数组的字节操作实现建立1个字符型数组,将控制8个LED显示的8位数据作为数组元素,依次送P1口。参考程序:01OPTION5.1.2I/O端口的编程举例#includereg51.h#defineucharunsignedcharuchartab[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f,0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};/*前8个数据为左移点亮数据,后8个为右移点亮数据*/voiddelay(){uchari,j;for(i=0;i255;i++)for(j=0;j255;j++);}5.1.2I/O端口的编程举例voidmain()//主函数{uchari;while(1){for(i=0;i16;i++){P1=tab[i];//向P1口送出点亮数据delay();//延时,即点亮一段时间}}}5.1.2I/O端口的编程举例移位运算符实现使用移位运算符“”、“”,把送P1口显示控制数据进行移位,从而实现发光二极管依次点亮。参考程序:02OPTION#includereg51.h#defineucharunsignedcharvoiddelay(){uchari,j;for(i=0;i255;i++)for(j=0;j255;j++);}5.1.2I/O端口的编程举例voidmain(){//主函数uchari,temp;while(1){temp=0x01;//左移初值赋给tempfor(i=0;i8;i++){P1=~temp;//temp中的数据取反后送P1口delay();//延时temp=temp1;//temp中数据左移一位}5.1.2I/O端口的编程举例temp=0x80;//赋右移初值给tempfor(i=0;i8;i++){P1=~temp;//temp中的数据取反后送P1口delay();//延时temp=temp1;//temp中数据右移一位}}}5.1.2I/O端口的编程举例程序说明:注意使用移位运算符“”、“”与使用循环左移函数“_crol_”和循环右移函数“_cror_”区别。左移移位运算“”是将高位丢弃,低位补0;右移移位运算、“”是将低位丢弃,高位补0。而循环左移函数“_crol_”是将移出的高位再补到低位,即循环移位;同理循环右移函数“_cror_”是将移出的低位再补到高位。5.1.2I/O端口的编程举例用循环左、右移位函数实现使用C51提供的库函数,即循环左移n位函数和循环右移n位函数,控制发光二极管点亮。参考程序:03OPTION#includereg51.h#includeintrins.h//包含循环左、右移位函数的头文件#defineucharunsignedcharvoiddelay(){uchari,j;for(i=0;i255;i++)for(j=0;j255;j++);}5.1.2I/O端口的编程举例voidmain(){//主函数uchari,temp;while(1){temp=0xfe;//初值为11111110for(i=0;i7;i++){P1=temp;//temp中的点亮数据送P1//口,控制点亮显示delay();//延时temp=_crol_(temp,1);//temp数据循环左移1位}5.1.2I/O端口的编程举例for(i=0;i7;i++){P1=temp;//temp中的数据送P1口输出delay();//延时temp=_cror_(temp,1);//temp中数据循环右移1位}}}目录CONTENTS5.1单片机控制发光二极管显示5.2开关状态检测5.3单片机控制LED数码管的显示5.4单片机控制LED点阵显示器显示5.5单片机控制液晶显示模块1602LCD的显示5.6键盘接口设计5.2.1开关检测案例1用I/O端口来进行开关状态检测,开关一端接到I/O端口引脚上,并通过上拉电阻接+5V上,开关另一端接地,当开关打开时,I/O引脚为高电平,当开关闭合时,I/O引脚为低电平。【例5-3】如图5-3,单片机的P1.4~P1.7接4个开关S0~S3,P1.0~P1.3接4个发光二极管LED0~LED3。编程将P1.4~P1.7上的4个开关状态反映在P1.0~P1.3引脚控制的4个发光二极管上,开关闭合,对应发光二极管点亮。例如P1.4引脚上开关S0状态,由P1.0脚上LED0显示,P1.6引脚上开关S2状态,由P1.2脚的LED2显示。5.2.1开关检测案例1图5-3开关、LED发光二极管与P1口的连接5.2.1开关检测案例1参考程序如下:#includereg51.h#defineucharunsignedcharvoiddelay()//延时函数{uchari,j;for(i=0;i255;i++)for(j=0;j255;j++);}5.2.1开关检测案例1voidmain(){//主函数while(1){unsignedchartemp;//定义临时变量tempP1=0xff;//P1口低4位置1,作为输入;高4位置1,发光二极管熄灭temp=P1&0xf0;//读P1口并屏蔽低4位,送入temp中temp=temp4;//temp内容右移4位,P1口高4位移至低4位P1=temp;//temp中的数据送P1口输出delay();}}5.2.2开关检测案例2【例5-4】如图5-4,P1.0和P1.1引脚接有两只开关S0和S1,两引脚上的高低电平共4种组合,4种组合分别点亮P2.0~P2.3引脚控制的4只LED,即S0、S1均闭合,LED0亮,其余灭;S1闭合、S0打开,LED1亮,其余灭;S0闭合、S1打开,LED2亮,其余灭;S0、S1均打开,LED3亮,其余灭。编程实现此功能。5.2.2开关检测案例2图5-4开关检测指示器2接口电路与仿真5.2.2开关检测案例2参考程序:#includereg51.h//包含头文件reg51.hvoidmain(){//主函数main()charstate;do{P1=0xff;//P1口为输入state=P1;//读入P1口的状态,送入statestate=state&0x03;//屏蔽P1口的高6位5.2.2开关检测案例2switch(state){//判P1口低2位开关状态case0:P2=0x01;break;//P1.1、P1.0=00,点亮P2.0脚LEDcase1:P2=0x02;break;//P1.1、P1.0=01,点亮P2.1脚LEDcase2:P2=0x04;break;//P1.1、P1.0=10,点亮P2.2脚LEDcase3:P2=0x08;break;//P1.1、P1.0=11,点亮P2.3脚LED}}while(1);}程序段中用到循环结构控制语句do-while以及switch-case语句。目录CONTENTS5.1单片机控制发光二极管显示5.2开关状态检测5.3单片机控制LED数码管的显示5.4单片机控制LED点阵显示器显示5.5单片机控制液晶显示模块1602LCD的显示5.6键盘接口设计5.3.1LED数码管显示原理LED数码管:“8”字型,7段(不包括小数点)或8段(包括小数点),每段对应一个发光二极管,共阳极和共阴极两种,见图5-5。共阳极数码管的阳极连接在一起,接+5V;共阴极数码管阴极连在一起接地。对于共阴极数码管,当某发光二极管阳极为高电平时,发光二极管点亮,相应段被显示。同样,共阳极数码管阳极连在一起,公共阳极