MSP430单片机实例12-4X4矩阵键盘键值显示
[复制链接]
任务要求
将4X4矩阵式键盘编号,如果其中一个按键闭合,则在LED数码管上显示相应的按键编号。
分析说明
4X4矩阵键盘只需要占用一个8位的I/O端口,硬件电路的设计较为简单,重点在于如何在程序中判断矩阵键盘的按键位置。
选取MSP430F247单片机的P4端口连接数码管,用以显示按键编号,P5端口8个引脚分别和矩阵式键盘的行线和列线连接,硬件电路如下图所示。
选取MSP430F247单片机的P4端口连接数码管,用以显示按键编号,P5端口8个引脚分别和矩阵式键盘的行线和列线连接,硬件电路如下图所示。
电路图中,列线P5.4~P5.7通过上拉电阻连接电源,处于输入状态;行线P5.0~P5.3为输出状态。键盘上没有按键闭合时,所有列线P5.4~P5.7的输入全部为高电平。当键盘上某个按键闭合时,则对应的行线和列线短接。
在检测是否有键闭合时,先使4条行线全部输出低电平,然后读取4条列线的状态,如果全部为高电平则表示没有任何按键闭合,如果有任一键闭合,由于列线上是上拉电阻,则行线上读到的将是一个非全“1”的值。
确定矩阵式键盘上那个按键闭合通常采用行扫描法,又称为逐行(或列)扫描查询法,其软件主要基于扫描完成。
关于键盘扫描查询法的程序大致可以分为以下几个步骤:
1、检测当前是否有键闭合
首先看输入的列线,假设4条行线都输出低电平,4条列线上都是上拉电阻,在没有任何键闭合时,4条列线输入都为1,但当与某一条行线相连的4个键中的任何一个闭合时,这条列线将输入低电平,即当某条列线输入低电平时,必定是连接在这条裂线上的某个键闭合了。
2、去除按键抖动当检测到有按键闭合后,延长一段时间再做下一步的检测判断。
3、若有键闭合,检测出是哪一个键闭合
逐行扫描方式:在4条行线上分别输出0信号。第一次,在第一条行线上输出低电平,其它行线上输出高电平,第二次,在第二条行线上输出低电平,其它行线上输出高电平,,第三次,在第三条行线上输出低电平,其它行线上输出高电平,,第四次,在第四条行线上输出低电平,其它行线上输出高电平,当某一行线上输出低电平时,此时如果此行上有键被按下,那么相应键的列线上就会读到0,于是可以唯一的确定是那个那键被按下。
//main.c
#include "msp430f247.h"
#include "stdlib.h"
#include "string.h"
/*****************************************软件延时,主频1M*******************/
#define CPU_F1 ((double)1000000)
#define delay_us1M(x) __delay_cycles((long)(CPU_F1*(double)x/1000000.0))
#define delay_ms1M(x) __delay_cycles((long)(CPU_F1*(double)x/1000.0))
/****************************************************************************/
//共阳极数码管段码表
unsigned char const Led_Tab1[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,
0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
//共阴极数码管段码表
unsigned char const Led_Tab2[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,
0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
static unsigned char key;
unsigned char KeyScan(void);//
unsigned char GetKeyValue(unsigned char keycode);//
/************************************************
函数名称:主函数
函数功能:矩阵键盘编号显示
入口参数:无
出口参数:无
************************************************/
main()
{
unsigned char key;
WDTCTL = WDTPW + WDTHOLD;//关看门狗
P4DIR=0xff;//端口初始化
P4OUT=0x00;//端口初始化
//行线P5.0~P5.3为输出状态。列线P5.4~P5.7为输入
P5DIR=0x0f;//
while(1)
{
key=GetKeyValue(KeyScan());//显示扫描
if(key != 255)
{
P4OUT=Led_Tab2[key];
}
}
}
unsigned char KeyScan(void)
{
unsigned char ScCode,ReCode;
P5OUT=0x00;
if((P5IN & 0xf0) != 0xf0)//判断是否有键闭合
{
delay_ms1M(40);
if((P5IN & 0xf0) != 0xf0)//延时后再次判断是否有按键闭合,
{
ScCode=0xfe;//逐行扫描初值,先扫描第一行
while((ScCode&0x0f) != 0x0f)//行扫描完成
{
P5OUT=ScCode;//输出行扫描码
if((P5IN & 0xf0) != 0xf0)//当前行有键闭合
{
ReCode=(P5IN & 0xf0) | 0x0f;//读取高4位列值,低4位置1
key=(ScCode & ReCode);//行和列组合得到键盘编码
return key;
}
else//所扫描行没有按键闭合,则扫描下一行
{
ScCode=(ScCode<<1)|0x01;//行扫描码左移一位
}
}
}
return 0xff;//无键按下
}
return 0xff;//无键按下
}
unsigned char GetKeyValue(unsigned char keycode)
{
unsigned char keyval;
switch(keycode)
{
case 0x77:
keyval=0;
break;
case 0x7b:
keyval=1;
break;
case 0x7d:
keyval=2;
break;
case 0x7e:
keyval=3;
break;
case 0xb7:
keyval=4;
break;
case 0xbb:
keyval=5;
break;
case 0xbd:
keyval=6;
break;
case 0xbe:
keyval=7;
break;
case 0xd7:
keyval=8;
break;
case 0xdb:
keyval=9;
break;
case 0xdd:
keyval=10;
break;
case 0xde:
keyval=11;
break;
case 0xe7:
keyval=12;
break;
case 0xeb:
keyval=13;
break;
case 0xed:
keyval=14;
break;
case 0xee:
keyval=15;
break;
default:
keyval=255;
}
return keyval;
}
程序说明
主程序通过调用键盘扫描程序获取键值,并通过数码管显示出键盘编号。键盘扫描首先通过读取列线输入,如果不全是1,则延迟一定时间后再次判断列线是否全为1,如果依旧不全为1,则可以确定有稳定的按键动作,通过逐行扫描的方式得到按键的位置。
从程序上看还存在两个问题,一是按键扫描中延迟去抖需要一定的时间,浪费了单片机的运算资源;二是在扫描得到按键后如果按键闭合不动,主程序会得到多个相同的键值,即重复按键,这种情况可以通过判断按键弹起的动作来解决
|