长短按键的检测是国赛题里面遇到的,省赛没出过有两种实方法
定时器配置:
定时器的话要比delay准确,其中tim7定时器的准度最高
定时器预分配配置32 - 1,计数周期是10000 - 1这样做那么32MHZ/32也就是一秒钟记录10^6的数,计数周期配置10 ^ 4也就是说一个周期花费10 ^ 4/10 ^6秒也就是10ms
c
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){ // 10ms
// OLED_ShowString(0, "KEY)");
COUNTNUMBER ++;
}
1、普通按键实现:
普通按键我用的是矩阵按键模块的B1按键测试的
ROW1与ROW2配置为输入模式上拉,COLUMN1配置输出模式
c
void Function_KeyCheck(){
HAL_GPIO_WritePin(COLUMN1_GPIO_Port, COLUMN1_Pin, GPIO_PIN_RESET);
if(HAL_GPIO_ReadPin(ROW1_GPIO_Port, ROW1_Pin) == 0){ // 按键按下
HAL_TIM_Base_Start_IT(&htim7);
while(HAL_GPIO_ReadPin(ROW1_GPIO_Port, ROW1_Pin) == 0); // 等待定时器关闭
HAL_TIM_Base_Stop_IT(&htim7);
if(COUNTNUMBER <= 100) KEYTIMEFLAG = 0;
else KEYTIMEFLAG = 1;
PRESSTIME = (float) COUNTNUMBER * 1.0 / 100;
COUNTNUMBER = 0;
}
HAL_GPIO_WritePin(COLUMN1_GPIO_Port, COLUMN1_Pin, GPIO_PIN_SET);
}
2、中断按键实现:
中断按键设置成上升沿和下降沿都会触发的模式,这样人按下按键就是下降沿这时候开定时器,松开就是上升沿,关定时器
c
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){ // 中断按键
if(!HAL_GPIO_ReadPin(USER_Key_GPIO_Port, USER_Key_Pin)){ // 下降电平开启定时器
HAL_TIM_Base_Start_IT(&htim7);
}else{ // 上升电平关闭定时器并检测时间
if(COUNTNUMBER <= 100) KEYTIMEFLAG = 0;
else KEYTIMEFLAG = 1;
PRESSTIME = (float) COUNTNUMBER * 1.0 / 100;
COUNTNUMBER = 0;
HAL_TIM_Base_Stop_IT(&htim7);
}
}
完整代码:
Function.c
c
#include "Function.h"
#include "main.h"
#include "oled.h"
#include "i2c.h"
#include <stdio.h>
#include "tim.h"
unsigned char KEYFLAG = 0;
unsigned char ARRAY[20];
char* LONGKEY = "long key press";
char* SHORTKEY = "short key press";
unsigned char KEYTIMEFLAG = 2;
float PRESSTIME = 0;
uint32_t COUNTNUMBER = 0; // 记录时间,这个区间必须要足够大
void OLED_Write(unsigned char type, unsigned char data){
unsigned char WriteData[2];
WriteData[0] = type;
WriteData[1] = data;
HAL_I2C_Master_Transmit(&hi2c3, 0x78, WriteData, 2, 0xff);
}
void Function_OledInit(unsigned char ms){
HAL_GPIO_WritePin(OLED_Power_GPIO_Port, OLED_Power_Pin, GPIO_PIN_RESET);
HAL_Delay(ms);
OLED_Init();
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){ // 10ms
// OLED_ShowString(0, "KEY)");
COUNTNUMBER ++;
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){ // 中断按键
if(!HAL_GPIO_ReadPin(USER_Key_GPIO_Port, USER_Key_Pin)){ // 下降电平开启定时器
HAL_TIM_Base_Start_IT(&htim7);
}else{ // 上升电平关闭定时器并检测时间
if(COUNTNUMBER <= 100) KEYTIMEFLAG = 0;
else KEYTIMEFLAG = 1;
PRESSTIME = (float) COUNTNUMBER * 1.0 / 100;
COUNTNUMBER = 0;
HAL_TIM_Base_Stop_IT(&htim7);
}
}
void Function_KeyCheck(){
HAL_GPIO_WritePin(COLUMN1_GPIO_Port, COLUMN1_Pin, GPIO_PIN_RESET);
if(HAL_GPIO_ReadPin(ROW1_GPIO_Port, ROW1_Pin) == 0){ // 按键按下
HAL_TIM_Base_Start_IT(&htim7);
while(HAL_GPIO_ReadPin(ROW1_GPIO_Port, ROW1_Pin) == 0); // 等待定时器关闭
HAL_TIM_Base_Stop_IT(&htim7);
if(COUNTNUMBER <= 100) KEYTIMEFLAG = 0;
else KEYTIMEFLAG = 1;
PRESSTIME = (float) COUNTNUMBER * 1.0 / 100;
COUNTNUMBER = 0;
}
HAL_GPIO_WritePin(COLUMN1_GPIO_Port, COLUMN1_Pin, GPIO_PIN_SET);
}
void Function_MyMain(){
Function_KeyCheck();
if(KEYTIMEFLAG != 2){
sprintf((char* )ARRAY, "%.2f s", PRESSTIME);
if(KEYTIMEFLAG == 0){
OLED_ShowString(0, (unsigned char* )SHORTKEY);
}else if(KEYTIMEFLAG == 1){
OLED_ShowString(0, (unsigned char* )LONGKEY);
}
OLED_ShowString(2, ARRAY);
KEYTIMEFLAG = 2;
}
}
Function.h
c
#ifndef __FUNCTION_H__
#define __FUNCTION_H__
#include "main.h"
void OLED_Write(unsigned char type, unsigned char data);
void Function_OledInit(unsigned char ms);
void Function_MyMain();
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);
#endif
效果: