4×4矩阵按键扫描,不知哪里出错?

lzh280 2011-12-01 09:36:50
4×4 矩阵按键扫描(行线接 P1.0~P1.4; 列线接P1.5~P1.7;列线(P1.5~P1.7)通过接上拉电阻拉电源),无法返回按键值,不知哪里出错?
接线图:

源码:

// 键盘扫描函数,无按键返回 16,有键按下返回键值.
uchar keyscan(void)
{
// row: 行号 Column: 列号 num: 按键号
// row_data: 行状态 Column_data: 列状态
uchar row, Column, num, row_data, Column_data;

P1 = 0xf0; // 将行线(P1.0 ~ P1.3)拉低

if((P1 & 0xf0) != 0xf0) // 有键按下
{
delay(); // 消抖
}

if((P1 & 0xf0) != 0xf0) // 消抖后还是有键按下,则查找键值
{
row_data = 0xfe; // 首行扫描字送变量 row_data
row = 0; // 首行号送 row

while(1)
{
P1 = row_data; // 行扫描字送 P1 口
Column_data = P1; // 读入 P1 口的列状态

if((Column_data & 0x10) == 0)
{
Column = 0; // 第 0 列有键按下,第 0 列首号送 Column
break;
}
else if((Column_data & 0x20) == 0)
{
Column = 1; // 第 1 列有键按下,第 1 列首号送 Column
break;
}
else if((Column_data & 0x40) == 0)
{
Column = 2; // 第 2 列有键按下,第 2 列首号送 Column
break;
}
else if(Column_data & 0x80 == 0)
{
Column = 3; // 第 3 列有键按下,第 3 列首号送 Column
break;
}

row += 4; // 扫描行号加 4 (第2行从 4 开始排列:0 4 8 12)
row_data <<= 1; // 扫描下一行
//_crol_(row_data, 1);
}

num = row + Column; // 将行号与列号相加,求键号

do
{
P1 = 0xf0;
delay();
}while((P1 & 0xf0) != 0xf0); // 等待释放按键

return num;
}

return 16;
}
...全文
235 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
UnTit1E 2011-12-03
  • 打赏
  • 举报
回复
MARK 你按第一行也没反应么?
lzh280 2011-12-03
  • 打赏
  • 举报
回复
经过多次分析仿真,原来是这句少了括号 else if(Column_data & 0x80 == 0)
应为else if((Column_data & 0x80) == 0)
lzh280 2011-12-03
  • 打赏
  • 举报
回复
按最后一列的按键没有反应,按照上面的修改了,但还是有的键无法返回按键值。在网上查了下,按下函数写,可正确返回按键值。

uchar keyscan(void)
{
uchar scode, rcode, keycode, keyno;

P1 = 0xf0; //发全0行扫描码,列输入

if((P1 & 0xf0) != 0xf0) //若有键按下
{
delay10(); //消抖
if((P1 & 0xf0) != 0xf0) //重测
{
scode = 0xfe; //逐行扫描初值

while((scode & 0x10) != 0) //确保只扫描4行
{
P1 = scode; //输出行扫描码

if((P1 & 0xf0) != 0xf0) //若本行有键按下
{
rcode = (P1 & 0xf0) | 0x0f;
//while((P1 & 0xf0) != 0xf0); //松手检测(视情况也可去掉这句)
keycode = ((~scode) + (~rcode));
break;
}
else
{
scode = (scode << 1) | 0x01; //此行无键按下、行扫描码左移一位
}
}

switch(keycode) //键值比较/选择
{
case 0x11: keyno = 1; break; // 0
case 0x21: keyno = 2; break; // 1
case 0x41: keyno = 3; break; // 2
case 0x81: keyno = 4; break; // 3
case 0x12: keyno = 5; break; // 4
case 0x22: keyno = 6; break; // 5
case 0x42: keyno = 7; break; // 6
case 0x82: keyno = 8; break; // 7
case 0x14: keyno = 9; break; // 8
case 0x24: keyno = 10; break; // 9
case 0x44: keyno = 11; break; // A
case 0x84: keyno = 12; break; // B
case 0x18: keyno = 13; break; // C
case 0x28: keyno = 14; break; // D
case 0x48: keyno = 15; break; // E
case 0x88: keyno = 16; break; // F
default: keyno = 17; break;
}
return keyno;
}
}
return 0; //无键按下、则返回值为0
}
didijiji 2011-12-02
  • 打赏
  • 举报
回复
keil软件里面有一个自带的_rol_函数的啊,就是用来循环左移用的。
bjtea 2011-12-02
  • 打赏
  • 举报
回复
1)row_data <<= 1; 实现的是左移(不是循环左移),
可以改成row_data = (row_data<<1)| 0x01;
2)另外if((P1 & 0xf0) != 0xf0) // 有键按下
{ delay(); } // 消抖
应该改成:
if((P1 & 0xf0) == 0xf0)
return 16; //无键按下
delay(); // 消抖


27,515

社区成员

发帖
与我相关
我的任务
社区描述
硬件/嵌入开发 单片机/工控
社区管理员
  • 单片机/工控社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧