闲的没事看一看玩一玩·········
矩阵按键
数码管是一种导体发光器件,其基本单元是发光二极管。按发光二极管单元连接方式可分为共阳极数码管和共阴极数码管
共阴极数码管是指将所有发光二极管的阴极接到一起形成共阴极的数码管,共阴极的数码管在应用时将公共级的COM接到地线GND上,当某一字段发光二极管的阳极为高电平时,相应的字段就点亮,当某一字段的阳极为低电平时,相应字段就不亮。
但是,IC芯片驱动能力往往是较小的,如果采用共阴极接法,因为它的驱动在非公共端,就有可能受限于IC芯片输出电流不够而显示昏暗,要外加上拉电阻或者是增加三极管加大驱动能力。
共阳极数码管是指将所有发光二极管的阳极接到一起形成公共阳极 (COM) 的数码管,共阳极数码管在应用时应将公共极COM接到 +5V,当某一字段发光二极管的阴极为低电平时,相应字段就点亮,当某一字段的阴极为高电平时,相应字段就不亮
与共阴极相反,一般共阳极数码管更为常用,因为将驱动数码管的工作交到公共端(一般接驱动电源),加大驱动电源的功率自然要比加大IC芯片I/O口的驱动电流简单许多。另一方面,这样也能减轻主芯片的负担。
我的开发板上使用的数码管是2个4位一体的共阴极数码管(即8个LED的阳极全部并联在一起引出,阴极分别引出A、B…DP),如果要让共阴极数码管显示数字0,即对应的段ABCDEF要给它高电平,其他的段给低电平。下面是共阴极数码管的 0 - F 段码数据表示。
0x3f | 0x06 | 0x5b | 0x4f | 0x66 | 0x6d |
---|---|---|---|---|---|
0 | 1 | 2 | 3 | 4 | 5 |
0x7d | 0x07 | 0x7f | 0x6f | 0x77 | 0x7c |
6 | 7 | 8 | 9 | A | B |
0x39 | 0x5e | 0x79 | 0x71 | 0x00 | |
C | D | E | F | 无显示 |
上面的数码管电路使用的是两个四位一体的共阴数码管组成,假设我们控制SMG1最左边的那个数码管默认显示0,因为单片机的IO口外部都增加了外部上拉电阻,因此P22、P23、P24引脚默认就是高电平,根据38译码器输出特点,此时Y7脚(LED8)输出有效,即低电平。而数码管的段选a-dp连接在了74HC245驱动芯片输出口,由P0端口控制。所以只要控制P0口输出高电平,SMG1最左边的那个数码管默认就可以显示。(如果有兴趣的话可以去了解一下38译码器的工作原理)。
74HC245作为驱动芯片使用,目的是让数码管能获得更大的电流,为防止因电流过大烧坏数码管,在74HC245芯片输出管脚又串联了2个4位的100欧排阻后连接数码管段码a-dp脚。
#include "reg52.h"
typedef unsigned int u16;//对系统默认数据进行重定义
typedef unsigned char u8;
#define SMG_A_DP_PORT P0 //使用宏定义数码管段码口
//定义数码管位选信号控制脚
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;
//共阴极数码管显示0~F的段码数据
u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
//延时函数
void delay_10us(u16 ten_us)
{
while(ten_us--);
}
//功能函数
void smg_display(void)
{
u8 i=0;
for(i=0;i<8;i++)
{
switch(i)//λѡ
{
case 0: LSC=1;LSB=1;LSA=1;break;
case 1: LSC=1;LSB=1;LSA=0;break;
case 2: LSC=1;LSB=0;LSA=1;break;
case 3: LSC=1;LSB=0;LSA=0;break;
case 4: LSC=0;LSB=1;LSA=1;break;
case 5: LSC=0;LSB=1;LSA=0;break;
case 6: LSC=0;LSB=0;LSA=1;break;
case 7: LSC=0;LSB=0;LSA=0;break;
}
SMG_A_DP_PORT=gsmg_code[i];//传送段选数据
delay_10us(100000);
SMG_A_DP_PORT=0x00;
}
}
void main()
{
while(1)
{
smg_display();
}
}
按键是一种电子开关,使用时按下开关按钮就可以使开关接通,当松手时,开关断开。
按键管脚两端距离长的表示默认是导通状态,距离短的默认是断开状态,如果按键按下,初始导通状态变为断开,初始断开状态变为导通。
由于机械弹性的作用,按键开关在闭合时不会马上稳定的接通,在断开时也不会一下子断开,因而在闭合和断开的一瞬间均伴随着一连串的抖动。抖动时间的长短由按键的机械特性决定的,一般为 5ms 到 10ms。按键稳定闭合时间的长短则由操作人员的按键动作决定的,一般为零点几秒到数秒。按键抖动会引起按键被误读多次。为确保CPU对按键的一次闭合仅做一次处理,必须进行消抖。
消抖一般分为硬件消抖和软件消抖两种方式。
我们一般采用的是软件消抖,简单来说就是先读取按键的状态,如果得到按键按下之后,延时 10ms,再次读取按键的状态,如果按键还是按下状态,那么说明按键已经按下了,其中延时10ms就是软件消抖处理。
我的开发板上的是44的矩阵按键,模块电路图如下
从图中可以看出,44 矩阵按键引出的8根控制线直接连接到51单片机的P1口上。电路中的P17连接矩阵键盘的第一行,P13连接矩阵键盘的第一列。
#include"reg52.h"
typedef unsigned int u16;//对系统默认数据进行重定义
typedef unsigned char u8;
#define KEY_MATRIX_PORT P1//使用宏定义矩阵按键控制口
#define SMG_A_DP_PORT P0//使用宏定义数码管段码口
//共阴极数码管显示0~F的段码数据
u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
//延时函数
void delay_10us(u16 ten_us)
{
while(ten_us--);
}
u8 key_matrix_ranks_scan(void)
{
u8 key_value=0;
KEY_MATRIX_PORT=0xf7;//给第一列赋值为0,其余全为1
if(KEY_MATRIX_PORT!=0xf7)//判断第一列按键是否按下
{
delay_10us(1000);//消抖
switch(KEY_MATRIX_PORT)//保存第一列按键按下后的键值
{
case 0x77: key_value=1;break;
case 0xb7: key_value=5;break;
case 0xd7: key_value=9;break;
case 0xe7: key_value=13;break;
}
}
while(KEY_MATRIX_PORT!=0xf7);//等待按键松开
KEY_MATRIX_PORT=0xfb;//给第二列赋值为0,其余全为1
if(KEY_MATRIX_PORT!=0xfb)//判断第二列按键是否按下
{
delay_10us(1000);//消抖
switch(KEY_MATRIX_PORT)//保存第二列按键按下后的键值
{
case 0x7b: key_value=2;break;
case 0xbb: key_value=6;break;
case 0xdb: key_value=10;break;
case 0xeb: key_value=14;break;
}
}
while(KEY_MATRIX_PORT!=0xfb);//等待按键松开
KEY_MATRIX_PORT=0xfd;//第三列赋值为0,其余全为1
if(KEY_MATRIX_PORT!=0xfd)//判断第三列按键是否按下
{
delay_10us(1000);//消抖
switch(KEY_MATRIX_PORT)//保存第三列按键按下后的键值
{
case 0x7d: key_value=3;break;
case 0xbd: key_value=7;break;
case 0xdd: key_value=11;break;
case 0xed: key_value=15;break;
}
}
while(KEY_MATRIX_PORT!=0xfd);//等待按键松开
KEY_MATRIX_PORT=0xfe;//第四列赋值为0,其余全为1
if(KEY_MATRIX_PORT!=0xfe)//判断第四列按键是否按下
{
delay_10us(1000);//消抖
switch(KEY_MATRIX_PORT)//保存第三列按键按下后的键值
{
case 0x7e: key_value=4;break;
case 0xbe: key_value=8;break;
case 0xde: key_value=12;break;
case 0xee: key_value=16;break;
}
}
while(KEY_MATRIX_PORT!=0xfe);//等待按键松开
return key_value;
}
void main()
{
u8 key=0;
while(1)
{
key=key_matrix_ranks_scan();
if(key!=0)
{
SMG_A_DP_PORT=gsmg_code[key-1];//得到的按键值减1换算成数组下标对应0~F段码
}
}
}
实验的核心就是通过行列扫描,然后判断每一列中的按键按下的情况,并返回对应的键值。复习了硬件的知识,玩一玩还阔以~