标题: 在书上看到的程序,总感觉它中断里面的扫描缓存有问题,有兴趣的可以看一下 [打印本页]
作者: 星际漫游者 时间: 2017-7-14 15:00
标题: 在书上看到的程序,总感觉它中断里面的扫描缓存有问题,有兴趣的可以看一下
#include <reg52.h>
sbit KEY_IN_1 = P2^4; //矩阵按键的扫描输入引脚1
sbit KEY_IN_2 = P2^5; //矩阵按键的扫描输入引脚2
sbit KEY_IN_3 = P2^6; //矩阵按键的扫描输入引脚3
sbit KEY_IN_4 = P2^7; //矩阵按键的扫描输入引脚4
sbit KEY_OUT_1 = P2^3; //矩阵按键的扫描输出引脚1
sbit KEY_OUT_2 = P2^2; //矩阵按键的扫描输出引脚2
sbit KEY_OUT_3 = P2^1; //矩阵按键的扫描输出引脚3
sbit KEY_OUT_4 = P2^0; //矩阵按键的扫描输出引脚4
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
unsigned char code LedChar[] = {
0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,
0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8e
}; //数码管真值表
unsigned char KeySta[4][4] = { //全部矩阵按键的当前状态,默认都未按下
{1, 1, 1, 1}, //bit类型不能定义数组,因此定义成unsigned char
{1, 1, 1, 1},
{1, 1, 1, 1},
{1, 1, 1, 1}
};
void main(void)
{
unsigned char i, j;
unsigned char backup[4][4] = { //按键值备份,保存前一次的值
{1, 1, 1, 1},
{1, 1, 1, 1},
{1, 1, 1, 1},
{1, 1, 1, 1}
};
//选择最右边的数码管进行显示
P0 = 0xFF;
ADDR0 = 0;
ADDR1 = 0;
ADDR2 = 0;
ADDR3 = 1;
ENLED = 0;
//配置T0工作在模式1,定时1ms
TMOD = 0x01;
TH0 = 0xFC;
TL0 = 0x67;
TR0 = 1;
ET0 = 1;
EA = 1;
while(1)
{
//检索按键状态的变化
for (i=0; i<4; i++) //i作为行循环变量
{
for (j=0; j<4; j++) //j作为列循环变量
{
if (backup[j] != KeySta[j]) //判断按键动作
{
if (backup[j] == 0) //判断按键弹起
{
P0 = LedChar[i*4+j]; //执行按键动作
}
backup[j] = KeySta[j]; //更新前一次的值
}
}
}
}
}
void InterruptTimer0() interrupt 1
{
unsigned char i;
static unsigned char keyout = 0; //矩阵按键扫描输出计数器
static unsigned char keybuf[4][4] = { //按键扫描缓冲区,保存一段时间内的扫描值
{0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF}
};
TH0 = 0xFC; //溢出后进入中断重新赋值
TL0 = 0x67; 按照我们的键盘扫描程序应该是中断1ms键值赋值一次并赋值
左移4次则keyout加1转下一列重新扫描16ms扫描完成。而此
程序我发现中断1ms虽然会有键值输入缓存但他会输入一次
keyout就增加一次达不到我们所涉及的效果吗。或许我分析的
不对,就请各位看一下
//将一行的4个按键值移入缓冲区
keybuf[keyout][0] = (keybuf[keyout][0] << 1) | KEY_IN_1;
keybuf[keyout][1] = (keybuf[keyout][1] << 1) | KEY_IN_2;
keybuf[keyout][2] = (keybuf[keyout][2] << 1) | KEY_IN_3;
keybuf[keyout][3] = (keybuf[keyout][3] << 1) | KEY_IN_4;
//消抖后更新按键状态
for (i=0; i<4; i++) //每行4个按键,所以循环4次
{
if ((keybuf[keyout] & 0x0F) == 0x00)
{ //连续4次扫描值为0,即16ms(4*4ms)内都只检测到按下状态时,可认为按键已按下
KeySta[keyout] = 0;
}
else if ((keybuf[keyout] & 0x0F) == 0x0F)
{ //连续4次扫描值为1,即16ms(4*4ms)内都只检测到弹起状态时,可认为按键已弹起
KeySta[keyout] = 1;
}
}
//执行下一次的扫描输出
keyout++;
keyout &= 0x03; //用跟0x03做“与”的方式,实现加到4即归零,是不是很巧妙,学会它吧
switch (keyout)
{
case 0:
KEY_OUT_4 = 1;
KEY_OUT_1 = 0;
break;
case 1:
KEY_OUT_1 = 1;
KEY_OUT_2 = 0;
break;
case 2:
KEY_OUT_2 = 1;
KEY_OUT_3 = 0;
break;
case 3:
KEY_OUT_3 = 1;
KEY_OUT_4 = 0;
break;
default:
break;
}
}
作者: wulin 时间: 2017-7-14 17:08
这是哪本误人子弟的书,这个例程不值得研究,给你推荐一个例程,程序很简单,一眼看明白:
#include <reg52.h> //头文件
#define uchar unsigned char //宏定义
#define uint unsigned int //宏定义
uchar key=0; //键值变量
void key_scan() //矩阵键盘扫描函数
{
uchar temp1,temp2,temp3; //临时变量
static bit sign=0; //按键自锁标志
static uchar count=0; //消抖计数变量
P3=0xf0; //先给P3赋一个初值
if(P3!=0xf0) //判断P3不等于所赋初值,说明有健按下
{
if(sign==0) //如果按键自锁标志为0
{
count++; //消抖计数
if(count>=100) //消抖计数自>=100,估算主循环周期调整
{ //摒弃Delay延时方式,
count=100; //防止溢出
sign=1; //按键自锁标志置1,键不抬起,按其他键无效
temp1=P3; //temp1保存高4位变化
P3=0x0f; //再给P3赋值0x0f
temp2=P3; //temp2保存低4位变化
temp3=temp2|temp1; //temp3=高4位+低4位
key=temp3; //保存键值
}
}
}
else //按键抬起
{
sign=0; //按键自锁标志清0
count=0; //消抖计数清0
}
}
void main()
{
while(1)
{
key_scan(); //键盘扫描
P1=key; //LED低电平亮显示键值
}
}
作者: #include51.h 时间: 2019-2-7 15:21
同感,最不喜欢将那些变量名定的又臭又长的
欢迎光临 (http://www.51hei.com/bbs/) |
Powered by Discuz! X3.1 |