主要目的
学会按键扫描
1.延时函数
延时函数部分详见链接: 单片机控制一盏灯的亮与灭程序解释
void delay (uint k) //定义延时函数
{
uint i,j;
for(i<0;i<k;i++)
{
for(j=0;j<113;j++)
{
;
}
}
}
这个程序里面的延时函数的目的是按键消抖。
2.按键扫描模块
这是本次实验的重点,将详细介绍。
先来观察矩阵按键模块的连接
总共8个口。
先实现关于列的扫描,设置初始值(0xf0),从高到低为
端口 | Value |
---|---|
P3.7 | 1 |
P3.6 | 1 |
P3.5 | 1 |
P3.4 | 1 |
P3.3 | 0 |
P3.2 | 0 |
P3.1 | 0 |
P3.0 | 0 |
那么当按下按键0,4,8,c时,P3.4变成了0,于是P3就变成了0xe0
端口 | Value |
---|---|
P3.7 | 1 |
P3.6 | 1 |
P3.5 | 1 |
P3.4 | 0 |
P3.3 | 0 |
P3.2 | 0 |
P3.1 | 0 |
P3.0 | 0 |
从而由0xe0我们可以判断是那一列按键按下,但还是不知道具体是哪一个按键按下,于是我们需要继续进行行扫描。
此时初始化P3
端口 | Value |
---|---|
P3.7 | 0 |
P3.6 | 0 |
P3.5 | 0 |
P3.4 | 0 |
P3.3 | 1 |
P3.2 | 1 |
P3.1 | 1 |
P3.0 | 1 |
同时现在当按键0按下后
端口 | Value |
---|---|
P3.7 | 0 |
P3.6 | 0 |
P3.5 | 0 |
P3.4 | 0 |
P3.3 | 1 |
P3.2 | 1 |
P3.1 | 1 |
P3.0 | 0 |
经过行列扫描之后就可以确定具体是哪个按键按下,有了上面的基础之后,我们来学习按键扫描的程序。
void keyscan() //这个实验的重点
{ uchar a;
P3=0xf0;
if(P3!=0xf0)
{
delay(10);
if(P3!=0xf0)
{
P3=0xf0; //进行列扫描
switch(P3)
{
case(0xe0):keynumber=0;break; //11100000
case(0xd0):keynumber=1;break;//11010000
case(0xb0):keynumber=2;break;//10110000
case(0x70):keynumber=3;break;//01110000
}
P3=0x0f;
switch(P3)
{
case(0x0e):keynumber=keynumber;break; //switch case后面是冒号
case(0x0d):keynumber=keynumber+4;break;
case(0x0b):keynumber=keynumber+8;break;
case(0x07):keynumber=keynumber+12;break;
}
while ((a<50)&&(P3!=0x0f))
{
delay(10);
a++ ;
}
}
}
}
程序的逻辑是
让P3的高四位为0,进行列检测,为什么是列检测呢,很简单,因为区分不出行。
如果按键按下,延时10ms,判断是不是按键抖动,延时之后继续判断,发现仍然不为0xf0,说明按键确实按下了,然后还是给P3幅初始值0xf0,接下来进行switch,case,不同P3情况下,对设置的keynumber进行赋值,记得每一个case结束要加break。
只有列扫描,无法判断是哪个按键按下,接下来进行行扫描。
基本原理和上面一样,但是注意按键值的变化。
最后当两个情况同时不成立后跳出循环。这两个情况就是a>50和P3=0xf0,具体解释就是a>50,按键还没有松开,就认为松开了,P3=0xf0按键按下之后松开了。
3.数码管显示模块
这一部分也相对简单,我的博客里面也有相应的博文。在这里主要就是P0口接的是数码管。这里进行段选和位选。段选是根据keynumber的值,位选这里选了六个数码管,则对应11000000,再转换为16进制。
void display(uchar num)
{
P0=table[num];
duan=1;
duan=0;
P0=0xc0;//11000000
wei=1;
wei=0;
}
4.主函数
主要是设置段和位初始状态,之后调用前面的按键扫描和数码管显示模块。
void main()
{
duan=0;
wei=0;
while(1)
{
keyscan();
display(keynumber);
}
}
完整代码
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int //注意宏定义不能加分号
sbit duan = P2^6;
sbit wei = P2^7;
uchar keynumber;
uchar code table[]= {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void delay (uint k) //定义延时函数
{
uint i,j;
for(i<0;i<k;i++)
{
for(j=0;j<113;j++)
{
;
}
}
}
void keyscan() //这个实验的重点
{ uchar a;
P3=0xf0;
if(P3!=0xf0)
{
delay(10);
if(P3!=0xf0)
{
P3=0xf0; //进行列扫描
switch(P3)
{
case(0xe0):keynumber=0;break; //11100000
case(0xd0):keynumber=1;break;//11010000
case(0xb0):keynumber=2;break;//10110000
case(0x70):keynumber=3;break;//01110000
}
P3=0x0f;
switch(P3)
{
case(0x0e):keynumber=keynumber;break; //switch case后面是冒号
case(0x0d):keynumber=keynumber+4;break;
case(0x0b):keynumber=keynumber+8;break;
case(0x07):keynumber=keynumber+12;break;
}
while ((a<50)&&(P3!=0x0f))
{
delay(10);
a++ ;
}
}
}
}
void display(uchar num)
{
P0=table[num];
duan=1;
duan=0;
P0=0xc0;//11000000
wei=1;
wei=0;
}
void main()
{
duan=0;
wei=0;
while(1)
{
keyscan();
display(keynumber);
}
}
运行结果
无法一一展示,这里只展示一部分。
好啦,今天矩阵按键模块的学习就到这里啦。你学废了吗?有问题的话,欢迎共同交流。最近在准备研究生复试,内容比较粗糙,但个人比较喜欢有输出的学习。以后有机会的话,会继续更新完善的!!!