1、3.3 输入操作输入操作 作为作为51单片机片内并行单片机片内并行I/O口输入信号口输入信号,属于数字信号的属于数字信号的“高、低电平高、低电平”或脉冲信号的或脉冲信号的“上升沿、下降沿上升沿、下降沿”两大类,这两类信号可以两大类,这两类信号可以通过通过:“闸刀闸刀型型开关开关”、“按钮按钮型型开关开关”两类开两类开关来模拟。关来模拟。3.3.1 闸刀型输入信号闸刀型输入信号 常见的闸刀型开关有拨码开关、自锁按钮开关、面板用数字式拨码开关、电路板用数字式拨码开关等。【例【例3-7】闸刀开关型输入信号。编程实现闸刀开关型输入信号。编程实现相应的开关闭合时,相应的灯亮。相应的开关闭合时,相应的灯亮
2、。#include sbit LED0=P10;sbit LED1=P11;sbit LED2=P12;sbit LED3=P13;sbit K0=P14;sbit K1=P15;sbit K2=P16;sbit K3=P17;void main()while(1)K0=1;K1=1;K2=1;K3=1;LED0=K0;LED1=K1;LED2=K2;LED3=K3;思考:思考:为什么在读键状态之前要先置为什么在读键状态之前要先置1?修改:修改:(1)开关闭合时灯灭。)开关闭合时灯灭。(2)K0控制控制LED3,K1控制控制LED2,K2控制控制LED1,K3控制控制LED0。3.3.2 单个
3、单个按钮型开关按钮型开关输入信号输入信号 开关去抖动的处理分为硬件去抖动和软件去抖动。硬件去抖动增加硬件投入。单片机一般采用软件去抖动。软件去抖动是执行一段软件延时程序(10ms左右)。需关注两个问题:去抖动、判断按键是否抬起。【例【例3-8】按钮开关。编程实现按钮开关。编程实现S1按钮按一按钮按一下,下,4个灯一组亮、灭交替。个灯一组亮、灭交替。#include#define uchar unsigned char#define uint unsigned int sbit S1=P32;void dlxms(uint xms)uint t1,t2;for(t1=0;t1xms;t1+)fo
4、r(t2=0;t2110;t2+);void main()P1=0 x0f;while(1)S1=1;if(S1=0)dlxms(10);if(S1=0)dlxms(10);P1=P1;while(S1=0);dlxms(10);【例【例3-9】开始是所有的灯都亮,按一下开始是所有的灯都亮,按一下S1,灯变为,灯变为500ms闪烁,再按一下,变为全闪烁,再按一下,变为全亮。亮。分析:分析:相当于相当于S1为一个控制开关,控制着为一个控制开关,控制着灯灯的亮、灭闪烁的亮、灭闪烁;与与例题例题3-8不同。定义一个位单元,不同。定义一个位单元,按键每动作一次,该位单元取反:该单按键每动作一次,该位单
5、元取反:该单元为元为0时,灯全亮,该单元为时,灯全亮,该单元为1时,灯闪时,灯闪烁。烁。include#define uchar unsigned char#define uint unsigned int sbit S1=P32;bit key=0;/定义一个位,存储按键的动作(偶、奇)void dlxms(uint xms)uint t1,t2;for(t1=0;t1xms;t1+)for(t2=0;t2110;t2+);void keyscan()/键检索 S1=1;if(S1=0)dlxms(10);if(S1=0)dlxms(10);key=key;/取反 while(S1=0);v
6、oid main()P1=0 x00;while(1)keyscan();/调用键检索 if(key=0)P1=0 x00;else dlxms(500);P1=P1;3.3.3 多个按钮型开关键盘1.键号、键值和键值表(1)键号:用户在设计键盘程序时,为每一个按键定义一个号码,该号码称为键号。(2)键值:用户在设计键盘程序时,每一个按键根据某种得法得到与其他按键不一样的值,该数值称为按键的键值。(3)键值表:用户在设计键盘程序时,将所有按键的键值,按照一定的顺利,在code区建立一个表格,该表格称为键值表。3.3.3 多个按钮型开关键盘2.独立式键盘接口技术 当按键的数量比较少(8)时,可采
7、用独立式按键硬件结构。独立式按键是指直接采用一根 I/O口线构成的单个按键电路。每个独立式按键单独占用一根I/O口线,每根I/O口线上的按键的工作状态不会影响其他I/O口线的工作状态。【例3-10】独立式按键示例。P1口作为并行接口按键的输入口,P3口接共阳极LED显示器,编程显示按键的键号07。分析:1位共阳极静态显示。0号键按下时,P1口的内容为11111110B;7号键按下时,P1口的内容为01111111B。#include#define uchar unsigned char#define uint unsigned intuchar data keycode=8;/键值的初值设为8
8、uchar data dir_buf;/显示缓冲区code uchar dirtab=0 xc0,0 xf9,0 xa4,0 xb0,0 x99,0 x92,0 x82,0 xf8,0 xbf;/显示的代码表code uchar keytab8=0 xfe,0 xfd,0 xfb,0 xf7,0 xef,0 xdf,0 xbf,0 x7f;/键值表void dl_xms(uint xms)/延时xms毫秒 uint t1,t2;for(t1=xms;t10;t1-)for(t2=110;t20;t2-);void dir()/显示函数 P3=dirtabdir_buf;void keyscan
9、()/键盘扫描函数 uchar key1;P1=0 xff;key1=P1;/读键盘的值 if(key1!=0 xff)/如果有键按下 dl_xms(10);/延时消抖动 P1=0 xff;key1=P1;/再读键盘的值 if(key1!=0 xff)/继续按下 keycode=0;while(key1!=keytabkeycode)/查表得键号 keycode=keycode+1;if(keycode=8)break;while(P1!=0 xff);/等待键抬起 void main()dir_buf=8;/缓冲区送8,显示-dir();while(1)keyscan();dir_buf=k
10、eycode;/键号送显示缓冲区 dir();3.矩阵键盘接口 当按键的数量比较多时,采用行列式键盘。行列式键盘又称为矩阵式键盘。(1)行列式键盘的硬件结构:行列式键盘的结构比较简单,按键设置在行、列的交点上。(2)矩阵键盘行列扫描法分三步进行。1)第一步判断是否有按键按下。将全部行线置低电平,然后检测列线的电平状态。有且只有一列的电平为低电平,则表示键盘中有键按下。若所有列线均为高电平,则键盘中无键按下。2)第二步是判断闭合按键具体所在的位置。逐行将行线置低电平,然后检测列线的电平状态。低电平列线相连的按键就是闭合按键。3)第三步确定闭合按键的键值编码。将所有行线电平状态与所有列线电平状态进
11、行组合,就可以得到该闭合按键的键值编码。有按键按下时,只有一条行线的电平是低电平,其余行线的电平是高电平;只有一条列线的电平是低电平,其余列线的电平是高电平。+行线P14、P15、P16、P17分别与单片机引脚P1.4、P1.5、P1.6、P1.7相连,列线P10、P11、P12、P13分别与单片机引脚P1.0、P1.1、P1.2、P1.3相连。若采用行列扫描法,先判断是否有按键按下。给P1口赋值0 x0f,所有列线置高电平,所有的行线置低电平,读列线的电平状态。若所有列线都是高电平,则表示没有按键按下;反之,有按键按下。再确定闭合按键具体的位置,采用逐行送低电平的方法。(1)给P1口赋值0
12、xef,然后读列线的电平状态。若有按键按下,则与该按键相连列线的电平为低电平。按键的键值编码就是行线和列线的电平状态组合,即为P1口8个引脚的电平状态。由之可得,加号键的键值编码是11100111(0 xe7),数字3的键值编码是11101011(0 xeb),数字2的键值编码是11101101(0 xed),数字1的键值编码是11101110(0 xee)。(2)若第一行没有按键按下,列线的电平状态都是高电平,P1口的值没有变化,还是0 xef。这时检测第二行是否有按键按下。给P1口赋值0 xdf,若有按键按下,通过读列线的电平状态可确定按键具体位置。减号键的键值编码是11010111(0
13、xd7),数字6的键值编码是11011011(0 xdb),数字5的键值编码是11011101(0 xdd),数字4的键值编码是11011110(0 xde)。(3)若第一行和第二行都没有按键按下,给P1口赋值0 xbf,检测第三行是否有按键按下。第三行按键按下时的编码分别是:乘号键的键值编码是10110111(0 xb7),数字9的键值编码是10111011(0 xbb),数字8的键值编码是10111101(0 xbd),数字7的键值编码是10111110(0 xbe)。(4)若第一行、第二行和第三行都没有按键按下,给P1口赋值0 x7f,检测第四行是否有按键按下。第四行的按键按下时的编码分
14、别是:除号键的键值编码是01110111(0 x77),等于号键值编码是01111011(0 x7b),数字0的键值编码是01111101(0 x7d),CE清除键键值编码是01111110(0 x7e)。线翻转发法主要分分三步进行。第一步将所有列线置低电平,所有行线置高电平,然后读所有行线电平状态。如果所有行线电平状态是高电平,则表示没有按键按下;反之,则表示有按键按下,保留所有行线电平状态。行线电平状态即为行线相关的闭合按键的键值编码高半部分或低半部分。有且只有一条行线的电平由高电平变为低电平,这种现象称为电平翻转,这是这种方法命名由来。第二步将所有行线置低电平,所有列线置高电平,然后读所
15、有列线电平状态。如果所有列线电平状态是高电平,则表示没有按键按下。如果存在一条列线的电平由高电平变为低电平,则表示有按键按下,保留所有列线电平状态。列线电平状态即为列线相关的闭合按键的键值编码的低半部分或高半部分。第三步确定闭合按键的键值编码。将第一步得到的行线相关键值编码的高半部分或低半部分与第二步得到的列线相关的键值编码低半部分或高半部分进行组合,就得到了闭合按键完整的键值编码。若采用线翻转发法,先给P1口赋值0 xf0,所有行线置高电平,所有的列线置低电平,读行线的电平状态。若有按键按下,有且只有一条行线的电平是低电平,行线电平状态即为与行线相关的闭合按键的键值编码高4位。高4位键值编码
16、键号编码键号编码键号编码键号编码111102111031110加号1110411015110161101减号1101710118101191011乘号1011清除键011100111等于号0111除号0111 再给P1口赋值0 x0f,所有列线置高电平,所有的行线置低电平,读列线的电平状态。若有按键按下,有且只有一条列线的电平是低电平,列线电平状态即为与列线相关的闭合按键的键值编码低4位。键号编码键号编码键号编码键号编码111102110131011加号0111411105110161011减号0111711108110191011乘号0111清除键111001101等于号1011除号0111
17、低4位键值编码 将闭合按键键值高4位编码和低4位编码进行组合,就可得到闭合按键键值的编码。与行列扫描法相比,线翻转发法会占用更多的数据储存空间。但是,行列扫描法实现代码较长,线反转法实现程序较简单。闭合按键键值编码键号高4位低4位 键号高4位低4位 键号高4位低4位 键号高4位低4位111101110211101101311101011加号111001110 xee0 xed0 xeb0 xe7411011110511011101611011011减号110101110 xde0 xdd0 xdb0 xd7710111110810111101910111011乘号101101110 xbe0
18、xbd0 xbb0 xb7清除键01111110001111101等于号01111011除号011101110 x7e0 x7d0 x7b0 x77【例3-11】44矩阵键盘示例。P1.4P1.7接列线,P1.0P1.3接行线。P2口接LED显示数码管,显示按键的号码0F。分析:当键盘的结构在行和列的数量之和8时,将行的信息放在高位(或低位),将列的信息放在低位(或高位),二者组成一个字节就可以了。通用的算法是,将行的信息转变为行号(00001111),将列的信息转变为列号(00001111)。然后,将行号作为高4位(或低4位),将列号作为低4位(或高4位),二者组成一个字节。#include
19、#define uchar unsigned char#define uint unsigned intuchar data dir_buf;/显示缓冲区uchar key;/计算所得键值uchar i2;/键号code uchar dirtab=0 x3f,0 x06,0 x5b,0 x4f,0 x66,0 x6d,0 x7d,0 x07,0 x7f,0 x6f,0 x77,0 x7c,0 x39,0 x5e,0 x79,0 x71,0 x40;/显示的代码表code uchar keytab=0 xee,0 xed,0 xeb,0 xe7,0 xde,0 xdd,0 xdb,0 xd7,0
20、 xbe,0 xbd,0 xbb,0 xb7,0 x7e,0 x7d,0 x7b,0 x77;/键值表void delay(uint);void keyscan();/键盘扫描函数void dir();/显示函数void main()i2=16;dir_buf=16;/显示-while(1)keyscan();/键扫描程序 dir_buf=i2;/显示-dir();void dir()/显示函数 P2=dirtabdir_buf;void delay(uint xms)/延时xms uint t1,t2;for(t1=xms;t10;t1-)for(t2=110;t20;t2-);void k
21、eyscan()/键扫描 uchar code_h,code_l,i1;/code_h为行输出值,code_l为列输入值 P1=0 xf0;/所有的行输出0 code_l=P1;/读列值 code_l=code_l&0 xf0;/屏蔽掉低4位 if(code_l!=0 xf0)/如果有键按下 delay(6);/延时,消抖动,再读 code_l=P1;code_l=code_l&0 xf0;/屏蔽掉低4位 if(code_l!=0 xf0)/有键按下吗?code_h=0 xfe;for(i1=0;i14;i1+)P1=code_h;code_l=P1;code_l=code_l&0 xf0;i
22、f(code_l=0 xf0)code_h=(code_h1)|0 x01;else break;P1=0 xff;/等待键抬起 while(P1!=0XFF);code_h=code_h&0 x0f;/行的信息屏蔽掉高4位 key=code_h+code_l;/得到计算键值(列值在高4位上,行值在 低4位上)for(i2=0;i216;i2+)/i2是键号 if(key=keytabi2)break;3.4 实验 实验实验1 闸刀型开关输入闸刀型开关输入/8段段LED静态显示输出静态显示输出 实验目的:掌握51单片机并行I/O的输入/输出基本操作,掌握闸刀型开关输入信号的编程方法,掌握8段L
23、ED显示的编程方法。电路分析:P1.0接闸刀型开关K0,P3接共阳极显示数码管。编程实现K0闭合时,显示“H”;K0断开时,显示“F”。#include sbit K0=P10;unsigned char data dir_buf;code uchar dirtab=0 x8E,0 xf989;/F与H的显示代码 void dir()P3=dirtabdir_buf;void main()while(1)K0=1;if(K0=0)dir_buf=1;else dir_buf=0;dir();实验实验2 按钮型开关输入按钮型开关输入/8段段LED静态显示输出静态显示输出实验目的:掌握51单片机并
24、行I/O输入/输出基本操作,掌握按钮型开关输入信号的编程方法,掌握8段LED显示的编程方法。电路分析:P3.2 和P3.3分别接按钮开关K0和K1,P1口和P2口接共阴极显示数码管。开始显示数字“50”,K0和K1分别是+1键和-1键。按K0时,显示数字加一;按K1时,显示数字减一。K0和K1的管理采用查询方式。include#define uchar unsigned char#define uint unsigned intsbit K0=P32;sbit K1=P33;uchar data dir_buf2;/显示缓冲区uchar code dirtable18=0 x3f,0 x06,
25、0 x5b,0 x4f,0 x66,0 x6d,0 x7d,0 x07,0 x7f,0 x6f;/显示的代码表uchar i;void delay(uint xms)uint t1,t2;for(t1=0;t1xms;t1+)for(t2=0;t2120;t2+);void display()P1=dirtabledir_buf0;/P2口显示 P2=dirtabledir_buf1;/P3口显示void key()uchar key1;K0=1;K1=1;key1=P3;key1=key1&0 x0c;while(key1!=0 x0c)delay(6);key1=P3;key1=key1&0 x0c;while(key1!=0 x0c)if(K0=0)i=i+1;else i=i-1;K0=1;K1=1;key1=P3;key1=key1&0 x0c;while(key1!=0 x0c)/判断按键是否抬起 key1=P3;key1=key1&0 x0c;void main()i=50;while(1)key();dir_buf0=i/10;dir_buf1=i%10;display();