单片机Key模版笔记

单片机key模块是一种用于输入控制信号的模块,通常由按键或开关组成。其作用是接收用户的输入操作,并将操作信号传递给单片机进行相应的处理。

单片机key模块在嵌入式系统中广泛应用,常见的应用场景包括:

  1. 人机交互:通过按键或开关,用户可以与系统进行交互,如控制设备的开关、调整参数等。
  2. 系统配置:通过按键或开关,用户可以对系统进行配置和设置,如修改系统的工作模式、切换功能等。
  3. 响应触发:通过按键或开关,用户可以触发系统的某些功能或操作,如启动/停止设备、切换显示内容等。
  4. 事件处理:通过按键或开关,用户可以处理系统中的事件,如确认、取消、选择等。

单片机key模块的工作原理通常是通过检测按键的状态变化来实现的。在按键未按下时,输入引脚通常处于高电平状态;而当按键按下时,输入引脚会被拉低。单片机通过对输入引脚状态的检测来判断按键是否被按下,并相应地进行处理。

单片机key模块的设计需要考虑按键的数量、类型、布局等因素,以及按键的可靠性和抗干扰能力。同时,还需要根据系统的需求进行处理,如消抖、长按识别、组合按键等功能的设计。

总之,单片机key模块是嵌入式系统中输入控制的重要组成部分,能够实现用户与系统的交互,为系统的功能和操作提供便捷的操作方式。


本文使用STC15F2K60S2

首先新建工程,建立Key.c文件 Key.h文件

Key.c

使用矩阵按键前,需把跳线帽切换至矩阵键盘

对于如图所示矩阵按键,我们可以采用

逐行扫描法

通过逐列扫描的方式,我们首先对某一行施加低电平信号,然后检测指定列是否同样处于低电平状态。如果检测到该指定列确实为低电平,那么我们可以确定,与该行列交叉点对应的按键已被按下。

先让第一行按键的公共引脚为低电平,第二到四行公共引脚为高电平,去检测第一到四列公共引脚的电平(引脚由于接了上拉电阻,不输出即是高电平)检测到哪个列引脚为低电平,则可确定行列交叉点对应的按键被按下。然后依次检测第二,第三,第四行即可。

特点:原理简单但代码冗余

unsigned char read_keyboard(void)
{
   unsigned char key_value=0xff;
		
	  P3=0xff;
		P32 = 0;     
  
		if(P42==0) //有按键按下
		{ Delay1ms(10);
			if(P42==0)
			key_value=0x0a;
			while(P42==0);
		}
		if(P44==0) //有按键按下
		{ Delay1ms(10);
			if(P44== 0)
			key_value=0x0b;
			while(P44==0);
		}	
		
		
		P3=0xff;
		P33 = 0;     

		if(P42==0) //有按键按下
		{ Delay1ms(10);
			if(P42==0)
			key_value=0x0e;
			while(P42==0);
		}
		if(P44==0) //有按键按下
		{ Delay1ms(10);
			if(P44== 0)
			key_value=0x0f;
			while(P44==0);
		}
  return key_value;	

}

行列扫描法(坐标法)


先确定列数n
再确定行数m
对应的键盘就是第一行:n+4*(m-1)
第一行n+0,第二行n+4,第三行+8,第四行n+12

先让按键的列公共引脚电平都为高电平,行公共引脚都为低电平,去判断哪个列引脚为低电平可以确定那一列被按下,记下列号

再让列公共引脚为低电平,行公共引脚为高电平,判断哪个行引脚为低电平,去判断哪一行被按下,对应的按键键值就是

第一行:列号
第二行:列号+4
第三行:列号+8
第四行:列号+12

由此可得,若使用delay消抖

unsigned char key_scan()//行列扫描法
{
	unsigned char key=0;
	P44=P42=P35=P34=1;
	P30=P31=P32=P34=0;
    //列公共引脚电平都为高电平,行公共引脚都为低电平
	if(key_up==1&&(P44==0||P42==0||P35==0||P34==0))
	{
		key_up=0;//检测到按键被按下
		Delay1ms(20);
		if(P44==0)key=1;
			else if(P42==0)key=2;
				else if(P35==0)key=3;
					else if(P34==0)key=4;
	

    P44=P42=P35=P34=0;
	P30=P31=P32=P34=1;
    //行公共引脚电平都为高电平,列公共引脚都为低电平
	if(P30==0||P31==0||P32==0||P33==0)
	{
		if(P30==0) key=key+0;
		else if(P31==0) key=key+4;
		else if(P32==0) key=key+8;
		else if(P33==0) key=key+12;
	}
	return key;
	}
	else if(P44==1&&P42==1&&P35==1&&P34==1)
	{
		key_up=1;//按键未被按下
	}
	return 0;
}

若不使用delay消抖,仅为获取键值

#include "key.h"
/**
  * @brief  矩阵键盘 - 获取键值
  * @param  None
  * @retval key: 当前按键的键值,实际的按键标号
  */
unsigned char Key_Read()
{
	unsigned char key = 0;
    
    ET1=0

	P3=0xf0;P4=0xff;	//列扫描
	if(P44==0) key=4;
	if(P42==0) key=8;
	if(P35==0) key=12;
	if(P34==0) key=16;

	P3=0x0f;P4=0x00;	//行扫描
	if(P33==0) key=key + 0;
	if(P32==0) key=key + 1;
	if(P31==0) key=key + 2;
	if(P30==0) key=key + 3;

    P3=0xff;
    ET1=1;
	
	return key;
}

特别注意:

1.key值一定要注意初始化为0

2.在进行串口发送时,需要注意一个关键问题:串口通信会占用P30和P31端口,这可能导致与键盘扫描功能的硬件冲突。为了避免这种冲突,在进入键盘扫描函数之前,我们需要暂时关闭用于定时调度各函数的轮询定时器(在本例中为定时器1)。具体做法是,在进入扫描函数时,通过设置ET1=0来关闭定时器1,以确保在扫描过程中不会触发与串口通信相关的中断。扫描完成后,我们需恢复P3端口的状态,并通过设置ET1=1重新开启定时器1,以恢复系统的正常轮询调度。这样,我们就能在确保无硬件冲突的情况下,顺利进行键盘扫描操作。

ET1 = 0;
......
省略主体
......
P3 = 0xff;
ET1 = 1;


Key.h

注意声明函数格式即可

#include <STC15F2K60S2.H>
unsigned char Key_Read();


消抖

由于单片机按键抖动是由于‌机械开关在闭合和断开时产生的抖动现象。当机械触点断开、闭合时,由于机械触点的弹性作用,开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开,因此在闭合及断开的瞬间均伴随有一连串的抖动。这种抖动时间一般为5ms~10ms,不同的开关抖动时间可能有所不同。

所以在使用时我们需进行“消抖”操作。

状态机法

‌单片机按键消抖状态机法‌是一种通过状态机的概念来实现按键消抖的方法,这种方法通过定义按键的不同状态(如未按下、按下、抖动、释放等),并利用定时器来周期性地检查这些状态的变化,从而实现对按键信号的稳定读取。状态机消抖方法不仅能够有效减少按键抖动带来的影响,还能提高程序的可靠性和用户体验。

实现步骤:

1.状态定义:首先,需要定义按键的各种状态,如初始状态、按下抖动状态、稳定按下状态、释放抖动状态和稳定释放状态等。
2.状态切换:当检测到按键信号发生变化时,根据当前状态和信号变化类型,决定下一个状态。例如,当从初始状态检测到按键按下时,会进入按下抖动状态;在按下抖动状态下,如果持续检测到按键按下信号,则会切换到稳定按下状态。
3.消抖处理:在状态切换过程中,通过设定一定的延时或计数阈值来消除抖动。例如,在按下抖动状态下,可以设定一个计数阈值,只有当连续多次检测到按键按下信号时,才认为按键真正被按下,从而切换到稳定按下状态。

/**
  * @brief  独立按键 - 状态机法
  * @param  None
  * @retval key_retrun: 按键的键值,单次触发
  */
#define KEY_NO   0  //无按键状态,用于判断是否按下
#define KEY_DOWN 1  //有按键按下状态,判断是否为抖动
#define KEY_UP   2  //等待松手状态,判断是否弹起
unsigned char Key_Proc() 				//每10ms执行一次
{ 
	static unsigned char key_state = 0; 	   //定义静态变量,保存每次按键的状态
	unsigned char key_io = 0, key_retrun = 0; //key_io:读取的IO状态; key_retrun:返回的键值;
	
	key_io = P3 & 0x0f; 		//对P3读回来的高4位IO清零,屏蔽此处不关心的IO状态
	switch(key_state) 
	{ 	
		case KEY_NO:     								//无按键状态,用于判断是否按下
			if(key_io!=0x0f) key_state = KEY_DOWN; 
		break; 

		case KEY_DOWN:    								//有按键按下状态,判断是否为抖动
			if(key_io!=0x0f)
			{ 
				key_state = KEY_UP; 
				
				if(key_io==0x0e) key_retrun = 7;  	//S7
				if(key_io==0x0d) key_retrun = 6;  	//S6
				if(key_io==0x0b) key_retrun = 5;  	//S5
				if(key_io==0x07) key_retrun = 4;  	//S4
			} 
			else 
				key_state = KEY_NO;  
		break;  
		
		case KEY_UP: 									//等待松手状态,判断是否弹起
			if(key_io==0x0f) key_state = KEY_NO; 
		break; 
	} 
	return key_retrun; 
} 

优点:状态机消抖法具有较高的可靠性和稳定性,能够有效地避免误操作。同时,它还可以根据具体需求进行灵活配置和调整。
适用性:这种方法适用于各种需要按键输入的单片机应用场景,特别是在对按键稳定性要求较高的场合中表现尤为出色。


  • 三行按键法

原理:瞬时值获取-> 获取按下的值,获取抬起的值->更新⼀下值

实现步骤:

1.定义四个静态变量:Key_Val(按键输入信号),Key_Down(按键按下信号),Key_Up(按键释放信号),Key_Old(上一次按键输入信号)  Down和Up都是瞬时值,Old比Val延后10ms,基于这个特性我们可以进行书写代码

2.读取按键输入信号并赋值给Key_Val变量。

3.利用位运算进行按键消抖处理:

  • Key_Up = ~Key_Val & (Key_Old ^ Key_Val):通过将Key_Old与Key_Val异或,得到按键释放时的电平变化,然后取反(~Key_Val)再与Key_Old异或,得到按键释放信号。
  • Key_Down = Key_Val & (Key_Old ^ Key_Val):通过将Key_Old与Key_Val异或,得到按键按下时的电平变化,然后与Key_Val进行与操作,得到按键按下信号。

4.更新Key_Old的值,将Key_Val赋值给Key_Old,以备下一次按键处理。

读取按键值:

Key_Val = Key_Read();

这行代码通过调用Key_Read()函数来从按键输入端口读取当前的按键状态,并将其值存储在Key_Val变量中。这是按键检测的基础步骤。

检测按键按下:

Key_Down = Key_Val & (Key_Old ^ Key_Val);

这里使用位运算来检测是否有按键被按下。Key_Old ^ Key_Val计算了当前按键值和上一次按键值之间的异或,结果表示了发生变化的位。通过与运算&结合当前的按键值Key_Val,可以确定哪些按键是新按下的。

检测按键释放:

Key_Up = ~Key_Val & (Key_Old ^ Key_Val);

与检测按键按下类似,这行代码用于检测按键的释放。通过取反当前的按键值~Key_Val,并与变化位进行与运算,可以确定哪些按键是从按下状态变为了释放状态。

更新旧按键值:

Key_Old = Key_Val;


最后,将当前的按键值Key_Val赋值给Key_Old,以便在下一次调用Key_Proc()函数时能够使用这个旧值与新读取的按键值进行比较,从而持续跟踪按键状态的变化。

综上所述

void Key_Proc() {
  static unsigned char Key_Val, Key_Down, Key_Up, Key_Old;
  
  Key_Val = Key_Read();
  Key_Down = Key_Val & (Key_Old ^ Key_Val);
  Key_Up = ~Key_Val & (Key_Old ^ Key_Val);
  Key_Old = Key_Val;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值