STC15单片机-按键检测单击或长按(外部中断)
按键检测(外部中断)
STC15外部中断说明
程序
文件结构
main.c -> 主函数文件,包含 main 函数等,当用外部中断翻转指示灯时 ,则不用调用函数,否则调用按键扫描函数翻转指示灯;
Public.c -> 公共函数文件,包含 Delay 延时函数等;
Sys_init -> 系统初始化函数,包含 GPIO 初始化函数等;
LED.c -> LED 外设函数,包含 LED 打开、关闭函数等;
Timer0.c -> 定时器函数,包含定时器初始化,中断函数等;
KEY.c -> 按键函数,包含按键检测,中断函数等。
外部中断0配置
在LED闪烁(定时器)的工程中加上 KEY.c 和 KEY.h 文件,在Sys_Init.c文件中初始化外部中断0,在KEY.c中定义外部中断0中断处理函数,按键检测也是在KEY.c文件中实现
配置方法跟STC89C52一样
/*
* @name IE_Init
* @brief 中断初始化
* @param None
* @retval None
*/
static void IE_Init()
{
IT0 = 1; //外部中断0选择下降沿触发
EX0 = 1; //打开外部中断0
EA = 1; //打开总中断
}
外部中断0中断处理函数
/*
* @name INT0_isr
* @brief 外部中断0处理函数
* @param None
* @retval None
*/
void INT0_isr() interrupt 0
{
KEY.KEY_Flag = 1;
//Run_LED.Run_LED_Flip(); //运行指示灯翻转
}
使用外部中断就可实现按键按下运行指示灯翻转的效果
然后再实现按键检测,实现单击和长按的不同效果
KEY.c:
/* Includes ------------------------------------------------------------------*/
#include <main.h>
/* Private define-------------------------------------------------------------*/
/* Private variables----------------------------------------------------------*/
static void KEY_Detect();
/* Public variables-----------------------------------------------------------*/
KEY_t KEY1 = {FALSE,FALSE,FALSE,FALSE,KEY_Detect};
/* Private function prototypes------------------------------------------------*/
/*
* @name KEY_Detect
* @brief 按键检测
* @param None
* @retval None
*/
static void KEY_Detect()
{
uint8_t i;
//单击检测
if(KEY1.KEY_Flag == TRUE) //外部中断改变标志位的值,说明按键被按下
{
KEY1.KEY_Flag = FALSE; //标志位重新置0,为下次按键准备
EX0 = 0; //关闭中断
if(KEY1_State == 0)
{
Public.Delay_ms(5); //虽然硬件已经有消抖功能,软件再做一次
if(KEY1_State == 0)
{
KEY1.Click = TRUE; //单击标志位置1
}
}
}
//长按检测
if(KEY1.Click == TRUE)
{
KEY1.Press = TRUE; //如果有按键按下,默认会进行长按
for(i = 0;i<200;i++) //每次循环延时10ms,即延时2秒
{
Public.Delay_ms(10);
if(KEY1_State == 1) //如果这期间按键松开了,则达不到长按的条件
{
KEY1.Press = FALSE; //长按标志位清0
break; //提前结束延时
}
}
}
//按键功能
//单击 -> 运行指示灯翻转
//长按 -> 运行指示灯闪一下
if(KEY1.Press == TRUE)
{
Run_LED.Run_LED_Flip();
Public.Delay_ms(100);
Run_LED.Run_LED_Flip();
}
else
{
if(KEY1.Click == TRUE)
{
Run_LED.Run_LED_Flip();
}
}
KEY1.Click = FALSE;
KEY1.Press = FALSE;
EX0 = 1; //打开中断
}
/*
* @name INT0_isr
* @brief 外部中断0中断处理函数
* @param None
* @retval None
*/
void INT0_isr() interrupt 0
{
KEY1.KEY_Flag = TRUE;
//Run_LED.Run_LED_Flip();
}
/********************************************************
End Of File
********************************************************/
为什么在标志位清0后要关闭外部中断?
因为在标志位清0时外部中断可能还会被触发,这可能是按键抖动引起的,标志位会重新被置1,在按键检测时会被重复判断
KEY.h:
头文件主要是按键引脚定义,结构体变量定义
#ifndef __KEY_H_
#define __KEY_H_
//定义按键引脚
#define KEY1_State P32
//定义结构体类型
typedef struct
{
uint8_t volatile KEY_Flag; //按键标志位
uint8_t Click; //单击
uint8_t Double_Click; //双击
uint8_t Press; //长按
void (*KEY_Detect)();
}KEY_t;
/* extern variables-----------------------------------------------------------*/
extern KEY_t KEY1;
/* extern function prototypes-------------------------------------------------*/
#endif
/********************************************************
End Of File
********************************************************/
main.c:
主函数中调用KEY_Detect函数一直检测按键
/******************************************************************************
* @file main.c
* @author
* @version V1.0
* @date 2022-xx-xx
* @Conpany
* @project STC15实战项目
*******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <main.h>
/* Private define-------------------------------------------------------------*/
/* Private variables----------------------------------------------------------*/
/* Public variables-----------------------------------------------------------*/
/* Private function prototypes------------------------------------------------*/
/*
* @name main
* @brief 主函数
* @param void
* @retval int
*/
int main(void)
{
//系统初始化
Hradware.Sys_Init();
//系统主循环
while(1)
{
//按键检测
KEY1.KEY_Detect();
}
}
/********************************************************
End Of File
********************************************************/