STM32–固件库使用–按键输入

简介

1.硬件
STM32F103C8T6 独立按键
2.软件
keil软件

硬件部分

1.按键分类与输入原理

按键按照结构原理科分为两类,一类是触点式开关按键,如机械式开关、导电橡胶式开关灯;另一类是无触点式开关按键,如电气式按键,磁感应按键等。前者造价低,后者寿命长。目前,微机系统中最常见的是触点式开关按键。

在单片机应用系统中,除了复位按键有专门的复位电路及专一的复位功能外,其他按键都是以开关状态来设置控制功能或输入数据的。当所设置的功能键或数字键按下时,计算机应用系统应完成该按键所设定的功能,键信息输入时与软件结构密切相关的过程。

对于一组键或一个键盘,总有一个接口电路与CPU相连。CPU可以采用查询或中断方式了解有无将按键输入,并检查是哪一个按键按下,将该键号送人累加器,然后通过跳转指令转入执行该键的功能程序,执行完成后再返回主程序。

2.按键结构与特点

微机键盘通常使用机械触点式按键开关,其主要功能式把机械上的通断转换为电气上的逻辑关系。也就是说,它能提供标准的TTL逻辑电平,以便于通用数字系统的逻辑电平相容。机械式按键再按下或释放时,由于机械弹性作用的影响,通常伴随有一定的时间触点机械抖动,然后其触点才稳定下来。其抖动过程如下图1所示,抖动时间的长短与开关的机械特性有关,一般为5-10ms。在触点抖动期间检测按键的通与断,可能导致判断出错,即按键一次按下或释放错误的被认为是多次操作,这种情况是不允许出现的。为了克服你、按键触点机械抖动所致的检测误判,必须采取消抖措施。按键较少时,可采用硬件消抖;按键较多式,采用软件消抖。


按键编码

一组按键或键盘都要通过I/O口线查询按键的开关状态。根据键盘结构的不同,采用不同的编码。无论有无编码,以及采用什么编码,最后都要转换成为与累加器中数值相对应的键值,以实现按键功能程序的跳转。

(2)键盘程序

一个完整的键盘控制程序应具备以下功能:

a.检测有无按键按下,并采取硬件或软件措施消抖。

b.有可靠的逻辑处理办法。每次只处理一个按键,期间对任何按键的操作对系统不产生影响,且无论一次按键 时间有多长,系统仅执行一次按键功能程序。

c.准确输出按键值(或键号),以满足跳转指令要求。

3.独立按键

(1)独立按键

单片机控制系统中,如果只需要几个功能键,此时,可采用独立式按键结构。

独立按键式直接用I/O口线构成的单个按键电路,其特点式每个按键单独占用一根I/O口线,每个按键的工作不会影响其他I/O口线的状态。独立按键的典型应用如图所示。独立式按键电路配置灵活,软件结构简单,但每个按键必须占用一个I/O口线,因此,在按键较多时,I/O口线浪费较大,不宜采用。

独立按键的软件常采用查询式结构。先逐位查询没跟I/O口线的输入状态,如某一根I/O口线输入为低电平,则可确认该I/O口线所对应的按键已按下,然后,再转向该键的功能处理程序。

软件部分

key.c


#include"key.h"
void KEY_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;         //定义结构体指针变量
	RCC_APB2PeriphClockCmd(KEY1_GPIO_CLK|KEY2_GPIO_CLK,ENABLE);  
 //开启按键端口的时钟
	/*按键输入控制GPIO端口的步骤*/
	/* { 1.选择按键的引脚 2.设置按键的引脚为浮空输入 3.使用结构体初始化按键 } */
  //key1
	GPIO_InitStructure.GPIO_Pin = KEY1_GPIO_PIN; 
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; 
	GPIO_Init(KEY1_GPIO_PORT, &GPIO_InitStructure);
	//key2
	GPIO_InitStructure.GPIO_Pin = KEY2_GPIO_PIN; 
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; 
	GPIO_Init(KEY2_GPIO_PORT, &GPIO_InitStructure);	
	
}
 /* * 函数名:Key_Scan * 描述 :检测是否有按键按下 * 输入 :GPIOx:x 可以是 A,B,C,D或者 E * GPIO_Pin:待读取的端口位 * 输出 :KEY_OFF(没按下按键)、KEY_ON(按下按键) */
uint8_t Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
{	/*检测是否有按键按下 */
	if(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON )  
	{	 /*等待按键释放 *///松手检测
		while(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON);   	
		return 	KEY_ON;	 
	}
	else
		return KEY_OFF;
}

key.h


#ifndef __KEY_H
#define __KEY_H

#include "stm32f10x.h"
/* 注意:该引脚定义是根据野火STM32F103霸道开发板的原理图定义的,如果需要自行的设计需要重新更改宏定义选择不同的GPIO端口 STM32F103ZET6芯片共有144个引脚 其中:GPIOA,GPIOB,GPIOC,GPIOD,GPIOE */

// 引脚定义
#define KEY1_GPIO_CLK RCC_APB2Periph_GPIOA
#define KEY1_GPIO_PORT GPIOA 
#define KEY1_GPIO_PIN GPIO_Pin_0

#define KEY2_GPIO_CLK RCC_APB2Periph_GPIOC
#define KEY2_GPIO_PORT GPIOC 
#define KEY2_GPIO_PIN GPIO_Pin_13


 /** 按键按下标置宏 * 按键按下为高电平,设置 KEY_ON=1, KEY_OFF=0 * 若按键按下为低电平,把宏设置成KEY_ON=0 ,KEY_OFF=1 即可 */
#define KEY_ON 1
#define KEY_OFF 0

void KEY_GPIO_Config(void);
uint8_t Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);

#endif


main.c

#include "stm32f10x.h" 
#include "key.h"

int main(void)
{
	
	  LED_GPIO_Config();
	  KEY_GPIO_Config();
		while(1)                            
	{	   
		if( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON  )
		{
			GPIO_ResetBits(LED1_GPIO_PORT , LED1_GPIO_PIN);//开
			GPIO_SetBits(LED2_GPIO_PORT   , LED2_GPIO_PIN);//关
			GPIO_SetBits(LED3_GPIO_PORT   , LED3_GPIO_PIN);//关
		}  

		if( Key_Scan(KEY2_GPIO_PORT,KEY2_GPIO_PIN) == KEY_ON  )
		{
		    GPIO_SetBits(LED1_GPIO_PORT , LED1_GPIO_PIN);//关
			GPIO_SetBits(LED2_GPIO_PORT , LED2_GPIO_PIN);//关
			GPIO_SetBits(LED3_GPIO_PORT , LED3_GPIO_PIN);//关
			 
		}		
	}
}

案例(51单片机 独立按键)

#include"reg51.h"

/*引脚端口定义*/
sbit key1=P1^0;
sbit key2=P1^1;
sbit key3=P1^2; 
sbit key4=P1^3;

sbit led1=P2^1;
sbit led2=P2^2;

/* 声明定义*/
#define uchar unsigned char
#define uint unsigned int
void DELAY_nMS(unsigned int time);	
void key_scan(void);

/*函数主体部分*/
void DELAY_nMS(unsigned int time)//DELAY_nMS(1)//延迟一毫秒
{
  unsigned int  i,j;             
  for(i=0;i<time;i++)    
     for(j=0;j<939;j++); 
}	
/*独立按键扫描函数*/
void key_scan(void)
{
	if(key1==0)		  //检测按键K1是否按下
	{	
		DELAY_nMS(10);   //消除抖动 一般大约10ms
		if(key1==0)	 //再次判断按键是否按下
		{
			led1=~led1;	  //led状态取反
		}
		while(!key1);	 //检测按键是否松开
	}	
	if(key2==0)		  //检测按键K1是否按下
	{	
		DELAY_nMS(10);   //消除抖动 一般大约10ms
		if(key2==0)	 //再次判断按键是否按下
		{
			led2=~led2;	  //led状态取反
		}
		while(!key2);	 //检测按键是否松开
	}	

}

void keyscan(void)
{
  if(key1==0)		  //检测按键K1是否按下
	{	
		DELAY_nMS(10);   //消除抖动 一般大约10ms
		if(key1==0)	 //再次判断按键是否按下
		{
				          //执行需要完成的操作
		}
		while(!key1);	 //检测按键是否松开
	}	
}


/*主函数部分*/
void main(void)
{
	while(1)
	{
		key_scan();
	}
}

参考资料

1.野火STM32视频学习https://space.bilibili.com/356820657/
2.野火STM32论坛http://www.firebbs.cn/forum.php
3.野火STM32开源资料http://products.embedfire.com/zh_CN/latest/
4.知乎链接https://zhuanlan.zhihu.com/p/103575964