28335学习笔记4——F28335之3*3按键控制(包含按键消抖和按键检测方法介绍)

1.按键消抖

通常的按键所用开关为机械弹性开关,当机械触点断开、 闭合时, 电压信号如下图所示
在这里插入图片描述
由于机械点的弹性作用,按键开关在闭合时不会马上稳定的接通,在断开时也不会一下子断开。在闭合和断开的瞬间均伴随着一连串的抖动。抖动时间的长短由按键的机械特性决定的, 一般为 5ms 到 10ms。 按键稳定闭合时间的长短则由操作人员的按键动作决定的, 一般为零点几秒至数秒。 按键抖动会引起按键被误读多次。 为了确保 CPU 对按键的一次闭合仅作一次处理, 必须进行消抖。
按键消抖有两种方式, 一种是硬件消抖(在按键管脚上串联RC电路,通过延时相当于把抖动的波滤除掉), 另一种是软件消抖。 为了使电路更加简单, 通常采用软件消抖。一个简单的按键消抖就是先读取按键的状态, 如果得到按键按下之后, 延时 10ms, 再次读取按键的状态, 如果按键还是按下状态, 那么说明按键已经按下。其中延时10ms 就是软件消抖处理。

2.矩阵键盘工作原理及检测

3X3 矩阵键盘将 9 个按键排成 3行 3 列, 第一行将每个按键的一端连接在一起构成行线, 第一列将每个按键的另一端连接在一起构成列线, 这样便一共有 3 行 3 列共 6 根线, 我们将这 6
根线连接到6 个 I/O 口上, 通过程序扫描键盘就可检测 9 个键。 用这种方法我们也可实现 4 行 4 列 16 个键、 5 行 5 列 25 个键、 6 行 6 列36 个键甚至更多。
矩阵键盘两端都与 I/O 口相连, 因此在检测时需编程通过一侧的 I/O 口送出低电平。 检测方法有多种,最常用的是行列扫描线翻转法
行列扫描法检测时, 先送一列为低电平, 其余几列全为高电平(此时我们确定了列数), 然后立即轮流检测一次各行是否有低电平, 若检测到某一行为低电平(这时我们又确定了行数),则我们便可确认当前被按下的键是哪一行哪一列的, 用同样方法轮流送各列一次低电平,再轮流检测一次各行是否变为低电平,这样即可检测完所有的按键, 当有键被按下时便可判断出按下的键是哪一个键。当然我们也可以将行线置低电平, 扫描列是否有低电平。 从而达到整个键盘的检测。
线翻转法, 就是使所有行线为低电平时, 检测所有列线是否有低电平, 如果有, 就记录列线值; 然后再翻转, 使所有列线都为低电平, 检测所有行线的值,由于有按键按下, 行线的值也会有变化, 记录行线的值。 从而就可以检测到全部按键。

3.程序

按键驱动程序源文件

#include "key.h"

//按键初始化函数
void KEY_Init(void)
{
    
    
	EALLOW;
	SysCtrlRegs.PCLKCR3.bit.GPIOINENCLK=1;//开启GPIO时钟

	//KEY端口配置
	GpioCtrlRegs.GPAMUX1.bit.GPIO12=0;//设置为普通IO口
	GpioCtrlRegs.GPADIR.bit.GPIO12=0;//设置为输入
	GpioCtrlRegs.GPAPUD.bit.GPIO12=0;//默认上拉

	GpioCtrlRegs.GPAMUX1.bit.GPIO13=0;//设置为普通IO口
	GpioCtrlRegs.GPADIR.bit.GPIO13=0;//设置为输入
	GpioCtrlRegs.GPAPUD.bit.GPIO13=0;//默认上拉

	GpioCtrlRegs.GPAMUX1.bit.GPIO14=0;//设置为普通IO口
	GpioCtrlRegs.GPADIR.bit.GPIO14=0;//设置为输入
	GpioCtrlRegs.GPAPUD.bit.GPIO14=0;//默认上拉

	GpioCtrlRegs.GPBMUX2.bit.GPIO48=0;//设置为普通IO口
	GpioCtrlRegs.GPBDIR.bit.GPIO48=1;//设置为输出
	GpioCtrlRegs.GPBPUD.bit.GPIO48=0;//默认上拉

	GpioCtrlRegs.GPBMUX2.bit.GPIO49=0;//设置为普通IO口
	GpioCtrlRegs.GPBDIR.bit.GPIO49=1;//设置为输出
	GpioCtrlRegs.GPBPUD.bit.GPIO49=0;//默认上拉

	GpioCtrlRegs.GPBMUX2.bit.GPIO50=0;//设置为普通IO口
	GpioCtrlRegs.GPBDIR.bit.GPIO50=1;//设置为输出
	GpioCtrlRegs.GPBPUD.bit.GPIO50=0;//默认上拉

	EDIS;

	GpioDataRegs.GPBSET.bit.GPIO48=1;//设置输出高电平
	GpioDataRegs.GPBSET.bit.GPIO49=1;//设置输出高电平
	GpioDataRegs.GPBSET.bit.GPIO50=1;//设置输出高电平
	//即使按键按下也不影响判断
}

//按键检测函数
char KEY_Scan(char mode)
{
    
    
	static char keyl1=1;//三个静态变量(如不是静态变量,在执行过程中,每次进入该函数变量值为1.
	static char keyl2=1;
	static char keyl3=1;

	//第一列扫描
	KEY_L1_SetL;//第一列为低电平,其他为高电平
	KEY_L2_SetH;//
	KEY_L3_SetH;//
	if(keyl1==1&&(KEY_H1==0||KEY_H2==0||KEY_H3==0))//有一个为0即按键按下
	{
    
    
		DELAY_US(10000);//软件消抖
		keyl1=0;//如该列有按键按下,则变为0。方便下一次再判断(按键松开后,可能还有抖动,有了这个松开按键后不会再执行。其实是松开按键的消抖
		if(KEY_H1==0)
		{
    
    
			return KEY1_PRESS;
		}
		else if(KEY_H2==0)
		{
    
    
			return KEY4_PRESS;
		}
		else if(KEY_H3==0)
		{
    
    
			return KEY7_PRESS;
		}
	}
	else if(KEY_H1==1&&KEY_H2==1&&KEY_H3==1)
	{
    
    
		keyl1=1;//松开后按键要为1,为下次判断做准备
	}
	if(mode)//mode为0相当于按键按一下执行一下不能连续按。但当mode为1(连续扫描)时则可以连续按,像音量加减那样
		keyl1=1;//始终

	//第2列扫描
	KEY_L1_SetH;//第2列为低电平,其他为高电平
	KEY_L2_SetL;//
	KEY_L3_SetH;//
	if(keyl2==1&&(KEY_H1==0||KEY_H2==0||KEY_H3==0))//有一个为0即按键按下
	{
    
    
		DELAY_US(10000);//软件消抖
		keyl2=0;
		if(KEY_H1==0)
		{
    
    
			return KEY2_PRESS;
		}
		else if(KEY_H2==0)
		{
    
    
			return KEY5_PRESS;
		}
		else if(KEY_H3==0)
		{
    
    
			return KEY8_PRESS;
		}
	}
	else if(KEY_H1==1&&KEY_H2==1&&KEY_H3==1)
	{
    
    
		keyl2=1;
	}
	if(mode)
		keyl2=1;

	//第三列扫描
	KEY_L1_SetH;//第3列为低电平,其他为高电平
	KEY_L2_SetH;//
	KEY_L3_SetL;//
	if(keyl3==1&&(KEY_H1==0||KEY_H2==0||KEY_H3==0))//有一个为0即按键按下
	{
    
    
		DELAY_US(10000);//软件消抖
		keyl3=0;
		if(KEY_H1==0)
		{
    
    
			return KEY3_PRESS;
		}
		else if(KEY_H2==0)
		{
    
    
			return KEY6_PRESS;
		}
		else if(KEY_H3==0)
		{
    
    
			return KEY9_PRESS;
		}
	}
	else if(KEY_H1==1&&KEY_H2==1&&KEY_H3==1)
	{
    
    
		keyl3=1;
	}
	if(mode)
		keyl3=1;

	return KEY_UNPRESS;
}

按键驱动程序头文件

#ifndef KEY_H_
#define KEY_H_

#include "DSP2833x_Device.h"//包含所有的头文件,常用的宏定义 、F2833x 内核、 外设驱动的源文件对应的头文件
#include "DSP2833x_Examples.h"// 包含F2833x 通用文件的头文件。 比如中断、全局变量及函数声明、 IQmath 库等

#define KEY_L1_SetL     (GpioDataRegs.GPBCLEAR.bit.GPIO48=1)
#define KEY_L2_SetL     (GpioDataRegs.GPBCLEAR.bit.GPIO49=1)
#define KEY_L3_SetL     (GpioDataRegs.GPBCLEAR.bit.GPIO50=1)

#define KEY_L1_SetH     (GpioDataRegs.GPBSET.bit.GPIO48=1)
#define KEY_L2_SetH     (GpioDataRegs.GPBSET.bit.GPIO49=1)
#define KEY_L3_SetH     (GpioDataRegs.GPBSET.bit.GPIO50=1)

#define KEY_H1          (GpioDataRegs.GPADAT.bit.GPIO12)
#define KEY_H2          (GpioDataRegs.GPADAT.bit.GPIO13)
#define KEY_H3          (GpioDataRegs.GPADAT.bit.GPIO14)

#define KEY1_PRESS         1
#define KEY2_PRESS         2
#define KEY3_PRESS         3
#define KEY4_PRESS         4
#define KEY5_PRESS         5
#define KEY6_PRESS         6
#define KEY7_PRESS         7
#define KEY8_PRESS         8
#define KEY9_PRESS         9
#define KEY_UNPRESS        0

void KEY_Init(void);
char KEY_Scan(char mode);

#endif /* KEY_H_ */

主程序

#include "DSP2833x_Device.h"//包含所有的头文件,常用的宏定义 、F2833x 内核、 外设驱动的源文件对应的头文件
#include "DSP2833x_Examples.h"// 包含F2833x 通用文件的头文件。 比如中断、全局变量及函数声明、 IQmath 库等
#include "leds.h"
#include "key.h"


void main()
{
    
    
	int i=0;
	char key=0;

	InitSysCtrl();//系统时钟初始化

	LED_Init();
	KEY_Init();


	while(1)//不断的检测按键扫描
	{
    
    
		key=KEY_Scan(0);
		switch(key)
		{
    
    
		case KEY1_PRESS: LED2_TOGGLE;break;
		case KEY2_PRESS: LED3_TOGGLE;break;
		case KEY3_PRESS: LED4_TOGGLE;break;
		case KEY4_PRESS: LED5_TOGGLE;break;
		case KEY5_PRESS: LED6_TOGGLE;break;
		case KEY6_PRESS: LED7_TOGGLE;break;
		}
		i++;
		if(i%2000==0)
		{
    
    
			LED1_TOGGLE;//设置GPIO输出翻转信号
			i=0;
		}
		DELAY_US(100);
	}
}

猜你喜欢

转载自blog.csdn.net/qq_39529052/article/details/106177185