Proteus中以中断方式实现矩阵键盘的扫描

前言

最近做单片机的课程设计用到矩阵键盘,在此做个记录。

1 矩阵键盘的扫描方式

使用矩阵键盘时,首先要判断是否有按键按下,这个过程称为矩阵键盘的全局扫描。单片机对于键盘按下的响应方式一般有三种:(1)定时扫描:利用定时器每间隔一段时间扫描一次键盘(2)程序扫描:在程序运行的过程中,当有必要了解是否有按键按下时,调用键盘扫描函数进行扫描(3)中断扫描:当有按键按下时,触发外部中断。
网络上关于矩阵键盘的扫描方式的介绍多局限于(1)和(2)两种方式,这两种方式在单一的矩阵键盘的实验中是可行的,但对于一个复杂的系统来说,单片机要处理的任务较多,宜采用中断扫描的方式,仅在有按键按下时触发中断,以节约CPU资源,本文介绍第(3)种方式

2 获取按下的按键的键值的方法

上面提到的全局扫描只能了解是否有按键按下,具体是哪一个按键按下,需要进一步扫描确定,在这个过程中完成按键的键值(编号)的获取。获取键值主要有线反转法和逐行逐列扫描法,本文介绍逐行逐列扫描法,线反转法的效率更高,但本文不作介绍。

3 逐行逐列扫描法

Proteus中以中断方式实现矩阵键盘的扫描_第1张图片
对于上图所示的矩阵键盘,键盘全局扫描(判断是否有按键按下)的一般原理如下:首先使列线所连接的I/O引脚P14至P16输出低电平,行线所连接的I/O引脚P10-P13输出高电平。当没有按键按下时,四条行线R1-R4所连接的I/O引脚读取到的将全部是高电平;而当有按键按下时,由于该行线与列线接通,将被下拉到低电平。此时读取行线所连接的引脚,将不再全是高电平,由此可以判断出有按键按下。

获取按下的按键键值的方法与之类似,逐条拉低每一条列线(其他列线为高电平),读取行线的状态,如果某一条行线被拉至低电平,则该行线就是被按下的按键所在行,而此时我们所拉低的那条列线,就是按下的按键所在的列,由此唯一确定按下的按键。

4 中断的触发电路

根据上面的逐行逐列扫描法,如果将行线置为高电平,而列线置为低电平,一旦有按键按下,将会有行线被下拉至低电平。因此只要有一条行线为低电平,就应该输出一个低电平,向单片机请求中断。可以用一个四输入与门(74LS21)来实现这种逻辑功能。这就是基于中断的全局扫描法

有了这个中断触发电路,我们就只需要通过中断就能了解到是否有按键按下
Proteus中以中断方式实现矩阵键盘的扫描_第2张图片
可以将外部中断0设置为下降沿触发方式。有按键按下时将触发中断。但是要注意上面的逐行逐列扫描的过程中可能会误触发中断,为避免误触发,在扫描键值的函数退出前应该把中断标志位EX0清除,这样就不会因为逐行逐列的扫描方式而误触发中断。下面给出逐行逐列扫描的程序。其实扫描键盘还可以采用线反法,效率更高,有兴趣的可以自行了解一下。

//keycode是全局变量,用于返回按键键值,对于上图的键盘,按键键值从左到右、从上到下依次为1-12
//使用前需包含 intrins.h
void int0() interrupt 0  //在中断服务函数中进行键盘扫描
{
	unsigned char row_scan_code=0x01; //行扫描码
	unsigned char col_scan_code=0xEF;//列扫描码
	unsigned char i,x,j;
	
	for(i=0;i<3;i++)//逐列扫描,将列线逐列拉低
	{
		keycode=i+1;
		keyboard=col_scan_code;
		x=keyboard; //读取行线状态
		for(j=0;j<4;j++)//逐行扫描
		{
			if(!(x&row_scan_code))//说明对应行的按键按下,使行线被拉低
			{
				keycode+=3*j;
				//如果按键还未释放,则行线仍被拉至低电平,与门输出0
				while(!P32);//等待按键释放 P32为外部中断0输入引脚
				P1=0x0F;     //恢复原状态,为下次按键做准备
				IE0=0;       //清除因扫描而误触发的中断标志
				return;     //已检测到按键键码,返回
			}
			else
				row_scan_code=_crol_(row_scan_code,1);
		}
		col_scan_code=_crol_(col_scan_code,1);//左移一位,将下一列线拉低
		row_scan_code=0x01;//重置行扫描码,为下一行扫描作准备
	}
	IE0=0;       //清除因扫描而误触发的中断标志
	keycode=0;//没有按键按下,键值记为0
}

你可能感兴趣的:(单片机)