独立按键:实现原理是通过轻触按键内部的金属弹片受力弹动来实现接通和断开。
“1,2”和“3,4”管脚之间距离短,初始不导通,“1,3”和“2,4”管脚之间距离长,初始值导通。
当按键按下时,距离短的会变为导通,距离长的会变为不导通,所以就可以利用按键这一特性来控制其他的事物。
例如管脚1接单片机的一个引脚,管脚2接地。当按键被按下时,就会给这个引脚一个低电平。如果不按,单片机的这个引脚默认的是高电平。
但是按键一般都会抖动,所以要进行消抖:硬件消抖和软件消抖
硬件消抖是通过充放电延时时间来进行消抖,但成本高,一个按键就需要(一个电阻与一个电源),所以一般选择软件消抖,软件消抖时间一般为10ms。
#include "reg52.h"
typedef unsigned int u16;
typedef unsigned char u8;
//定义4个按键管脚
sbit K1=P3^1;
sbit K2=P3^0;
sbit K3=P3^2;
sbit K4=P3^3;
sbit LED1=P2^0;
//宏定义如果按下则返回
#define K1_PRESS 1
#define K2_PRESS 2
#define K3_PRESS 3
#define K4_PRESS 4
//没按下
#define K_UNPRESS 0
void delay_10us(u16 ten_us)
{
while(ten_us--);
}
u8 Detection_Key(u8 mode)
{
static u8 key=1;
if(mode)
key=1;
if(key==1 && (K1==0 || K2==0 || K3==0 || K4==0))
{
key=0;
delay_10us(1000);//消抖
if(K1==0)
return K1_PRESS;
else if(K2==0)
return K2_PRESS;
else if(K3==0)
return K3_PRESS;
else if(K4==0)
return K4_PRESS;
}
else if(K1==1 && K2==1 && K3==1 && K4==1)
{
key=1;
}
return K_UNPRESS;
}
void main()
{
while(1)
{
u8 key=Detection_Key(0);//1代表长按和0代表只按一次
if(key==K1_PRESS)
{
LED1=!LED1;
}
}
while(1);
}
刚刚还试了加个蜂鸣器,只要按下按键LED1就亮并且蜂鸣器响,结果发现不仅LED1亮了连LED6也随着蜂鸣器响而在闪,问了客服才知道原来蜂鸣器和LED6共用IO口,原本就查查开发手册的事我还搞半天,我还以为是代码还是板子有问题,这件事让我懂得查手册是多么重要!
实验现象:http:// https://b23.tv/bjr97aj
**************************************************************************************************************
矩阵按键:
行列描述法:
先送一列为低电平,其余几列全为高电平(此时我们确 定了列数),然后立即轮流检测一次各行是否有低电平,若检测到某一行为低电 平(这时我们又确定了行数),则我们便可确认当前被按下的键是哪一行哪一列 的,用同样方法轮流送各列一次低电平,再轮流检测一次各行是否变为低电平,这样即可检测完所有的按键,当有键被按下时便可判断出按下的键是哪一个键。当然我们也可以将行线置低电平,扫描列是否有低电平。从而达到整个键盘的检测。
线翻转法:
使所有行线为低电平时,检测所有列线是否有低电平,如果 有,就记录列线值;然后再翻转,使所有列线都为低电平,检测所有行线的值, 由于有按键按下,行线的值也会有变化,记录行线的值。从而就可以检测到全部 按键。
代码如下:
#include "reg52.h"
typedef unsigned int u16;
typedef unsigned char u8;
#define KEY_Matrix_PORT P1//定义矩阵管脚
#define SMG_PORT P0//数码管管脚
void delay_10us(u16 ten_us)
{
while(ten_us--);
}
/****************************************************************************************
* 使用4*4按键
****************************************************************************************/
//行列描述法
u8 key_matrix_ranks(void)
{
u8 key=0;//键值
KEY_Matrix_PORT=0xf7;//第一列按键
if(KEY_Matrix_PORT!=0xf7)
{
delay_10us(1000);//消抖
switch(KEY_Matrix_PORT)
{
case 0x77:key=1;break;//S1
case 0xb7:key=5;break;//S5
case 0xd7:key=9;break;//S9
case 0xe7:key=13;break;//S13
}
}
KEY_Matrix_PORT=0xfb;//第二列按键
if(KEY_Matrix_PORT!=0xfb)
{
delay_10us(1000);//消抖
switch(KEY_Matrix_PORT)
{
case 0x7b:key=2;break;//S2
case 0xbb:key=6;break;//S6
case 0xdb:key=10;break;//S10
case 0xeb:key=14;break;//S14
}
}
KEY_Matrix_PORT=0xfd;//第三列按键
if(KEY_Matrix_PORT!=0xfd)
{
delay_10us(1000);//消抖
switch(KEY_Matrix_PORT)
{
case 0x7d:key=3;break;//S3
case 0xbd:key=7;break;//S7
case 0xdd:key=11;break;//S11
case 0xed:key=15;break;//S15
}
}
KEY_Matrix_PORT=0xfe;//第四列按键
if(KEY_Matrix_PORT!=0xfe)
{
delay_10us(1000);//消抖
switch(KEY_Matrix_PORT)
{
case 0x7e:key=4;break;//S4
case 0xbe:key=8;break;//S8
case 0xde:key=12;break;//S12
case 0xee:key=16;break;//S16
}
}
return key;
}
u8 gsmg_code[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,
0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//定义数组存放0-F段码,gsmg中g代表全局变量
void main()
{
u8 key=0;
while(1)
{
key=key_matrix_ranks();//接收键值
if(key!=0)//要确保key不能为0
{
SMG_PORT=gsmg_code[key-1];//数码管显示
}
}
while(1);
}
//线翻转法
u8 key_matrix_overturn(void)
{
u8 key=0;//键值
KEY_Matrix_PORT=0x0f;//行为低电平,测试列
if(KEY_Matrix_PORT!=0x0f)
{
delay_10us(1000);
if(KEY_Matrix_PORT!=0x0f)
{
switch(KEY_Matrix_PORT)
{
case 0x07:key=1;break;//第一列
case 0x0b:key=2;break;//第二列
case 0x0d:key=3;break;//第三列
case 0x0e:key=4;break;//第四列
}
KEY_Matrix_PORT=0xf0;//列为低电平,测试行
if( KEY_Matrix_PORT!=0xf0)
{
switch(KEY_Matrix_PORT)
{
case 0x70:key=key;break;//第一行
case 0xb0:key+=4;break;//第二行
case 0xd0:key+=8;break;//第三行
case 0xe0:key+=12;break;//第四行
}
}
}
}
else
{
key=0;
}
return key;
}
**************************************************************************************************************
74HC595芯片:
74HC595是一个8位串行输入、并行输出的位移缓存器,其中并行输出为三态输出(即高电平、低电平和高阻抗)
注意:74HC595是先传输字节的高位后传输低位,所以需要将字节低位移动到高位传输,在传输数据时,要注意移位寄存器时钟和存储寄存器时钟的先后顺序,将要写入的数据先传输到74HC595寄存器中,即在准备好每位数据时要将SRCLK进行一个上升沿变化,此时即可将数据传输到寄存器内,待循环8次即一个字节传输到寄存器中时,就可以来一个存储时钟上升沿,此时就可以将74HC595寄存器中的数据全部一次传输到595端口输出。要注意清除寄存器缓存的数据
代码如下:
#include "reg52.h"
typedef unsigned int u16;
typedef unsigned char u8;
//定义74HC595控制管脚
sbit rclk=P3^5; //存储寄存器时钟输入
sbit srclk=P3^6; //移位寄存器时钟输入
sbit ser=P3^4; //串行数据输入
#define LEDDZ_COL_PORT P0 //控制点阵列的端口
u8 ghc595_buf[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
//延时函数
void delay_10us(u16 ten_us)
{
while(ten_us--);
}
void hc595_write_data(u8 dat)
{
u8 i=0;
for(i=0;i<8;i++)
{
ser=dat>>7;//优先传输一个字节中的高位
dat<<=1;//将低位移动到高位
srclk=0;
delay_10us(1);
srclk=1;
delay_10us(1);//移位寄存器时钟上升沿将端口数据送入寄存器中
}
rclk=0;
delay_10us(1);
rclk=1;//存储寄存器时钟上升沿将前面写入到寄存器的数据输出
}
void main()
{
u8 i=0;
LEDDZ_COL_PORT=0x00;//全部IO口给低电平
while(1)
{
for(i=0;i<8;i++)
{
hc595_write_data(0x00);//清除上一次数据
hc595_write_data(ghc595_buf[i]);//写入数据
delay_10us(50000);//延时
}
}
while(1);
}
实验现象:http:// https://b23.tv/b2NNrVB
想显示其他图案或者字符的话可以用取模软件生成行的数据复制就行了!
显示数字0的代码:
#include "reg52.h"
typedef unsigned int u16;
typedef unsigned char u8;
//定义74HC595控制管脚
sbit rclk=P3^5; //存储寄存器时钟输入
sbit srclk=P3^6; //移位寄存器时钟输入
sbit ser=P3^4; //串行数据输入
#define LEDDZ_COL_PORT P0 //控制点阵列的端口
u8 gled_row[8]={0x00,0x7E,0x81,0x81,0x81,0x7E,0x00,0x00};//点阵行数据
u8 gled_cols[8]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};//点阵列
//延时函数
void delay_10us(u16 ten_us)
{
while(ten_us--);
}
void hc595_write_data(u8 dat)
{
u8 i=0;
for(i=0;i<8;i++)
{
ser=dat>>7;
dat<<=1;
srclk=0;
delay_10us(1);
srclk=1;
delay_10us(1);
}
rclk=0;
delay_10us(1);
rclk=1;
}
void main()
{
u8 i=0;
while(1)
{
for(i=0;i<8;i++)
{
LEDDZ_COL_PORT=gled_cols[i];
hc595_write_data(gled_row[i]);
delay_10us(100);
hc595_write_data(0x00);
}
}
while(1);
}
爱心同理,改一下数组就行了
爱心的代码:
u8 gled_row[8]={0x38,0x7C,0x7E,0x3F,0x3F,0x7E,0x7C,0x38};//爱心点阵行数据
16*16点阵图:
4片74HC595芯片,数据传入是第一个字节最终传到第4片,第二个字节最终传到第3片,第三个字节最终传到第2片,第四个字节最终传到第1片上。(因为第一片8位满了后再传入的就会把前面的挤出去)
汉字取模:横向取模,字节倒序,字体小四
16*16延时函数用:_nop_();(需要include