单片机系统中实用的按键驱动(STM32、51都适用)_按键驱动代码,物联网嵌入式开发开发面试书籍推荐

51 阅读4分钟

2019/5/21 按键程序移植成功,以后可以使用此按键,需要研究一下 和以前单片机项目按钮方式类似 by qzh 2019/8/30 确定了第三行,第一个必须是7,才能按下到时间自动触发 by qzh */ #include "mod_button.h"

//GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin) void io_getDigital(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin,uint8 *pu8Value) { *pu8Value = HAL_GPIO_ReadPin(GPIOx,GPIO_Pin); }

void time_setTimerCount(TIMER_TYPE *pu8timer,uint32 u32timeToCount)
{ // __HAL_TIM_SET_COUNTER HAL_TIM_Base_Start_IT(&htim21); // HAL_TIM_Base_Stop_IT // TIM_Cmd(TIM4, ENABLE); if(pu8timer->on == 0) pu8timer->on = 1; if(pu8timer->on == 1) //IntNum = 0; pu8timer->timeInit = Timer4_count; //pu8timer->timeInit = IntNum; pu8timer->timeOut = 0; pu8timer->timeToCount = u32timeToCount; }

RETURN_TYPE time_getTimeOut(TIMER_TYPE *pu8timer) { uint32 Temp_Val; if(Timer4_count > pu8timer->timeInit) Temp_Val = Timer4_count - pu8timer->timeInit; else Temp_Val = (0xFFFFFFFF-pu8timer->timeInit)+Timer4_count; if(Temp_Val >= pu8timer->timeToCount) { pu8timer->timeOut = 1; pu8timer->on = 0; pu8timer->timeToCount = 0; pu8timer->timeInit = 0; } else pu8timer->timeOut = 0; return (pu8timer->timeOut == 1)?TIME_OUT:OK; }

BTN_STATE btn_getState(BTN_STRUCT *pBtn) { const uint8 transition_table[8][4]={ 0, 1, 0, 1, 5, 2, 5, 1, 7, 2, 5, 3, 5, 4, 5, 4, 5, 4, 5, 4, 6, 1, 0, 1, 6, 1, 7, 1, 0, 1, 0, 1 };

//register uint8 u8Input;
uint8 u8Input;
// Get button state
io\_getDigital(pBtn->u8Pin,pBtn->GPIO_Pin ,&u8Input);
u8Input = (u8Input == pBtn->u8ActiveState)?1:0;

// Get timeout state
u8Input |= ((time\_getTimeOut(&(pBtn->tTimer))==TIME_OUT)?2:0);

// Get new state
pBtn->u8State = transition_table[pBtn->u8State][u8Input]; // we want only the state, not action

// Perform action 
switch (pBtn->u8State)
{
	case 1:
		time\_setTimerCount(&(pBtn->tTimer), pBtn->u16TimeOutON);
		break;
	case 5:
		time\_setTimerCount(&(pBtn->tTimer), pBtn->u16TimeOutOFF);
		break;
}
// return pBtn->u8State;
//待测试
return (BTN_STATE)pBtn->u8State;	

}

//下面是mod_button.h

#ifndef _MOD_BUTTON_H_INCLUDED #define _MOD_BUTTON_H_INCLUDED

#include "main.h" #include "Datadef.h" #include "tim.h" /* Timeout ON _______|_____ P | | Timeout OFF R ___________| |________|____ ^ ^ ^ ^ ^ ^ ^ ^ S 0 1 2 3 4 5 6 7

P - pressed, R - released, S - BTN_STATE */

/* °´Å¥Ïà¹Ø KEY1 learn PB5 KEY2 CLEAR PB6 */ #define BTN_ACTIVE 0 //when pressed, switch to GND

typedef struct { // Public //uint8 u8Pin; // e.g. ADIO0 //uint16 u8Pin; // e.g. ADIO0 GPIO_TypeDef * u8Pin; uint16_t GPIO_Pin; uint8 u8ActiveState; // button is pressed if (io_getDigital(u8Button)==bActiveState) uint16 u16TimeOutON; // time the button has to be pressed to be recognized as pressed uint16 u16TimeOutOFF; // time the button has to be pressed to be recognized as released

// Private
TIMER_TYPE	tTimer;
uint8		u8State;

} BTN_STRUCT;

typedef enum { BTN_IDLE = 0, BTN_EDGE1, BTN_TRIGGERED, BTN_PRESSED, //< most important BTN_PRESS_HOLD, BTN_EDGE2, BTN_RELEASE_HOLD, BTN_RELEASED } BTN_STATE;

extern u16 Timer4_count;

BTN_STATE btn_getState(BTN_STRUCT *pBtn); void time_setTimerCount(TIMER_TYPE *pu8timer,uint32 u32timeToCount); void io_getDigital(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin,uint8 *pu8Value); RETURN_TYPE time_getTimeOut(TIMER_TYPE *pu8timer);

#endif //_MOD_BUTTON_H_INCLUDED


### 1.2 使用方法



//先定义一个按键的结构体类型, BTN_STRUCT K1_BUTTON_150mS ={K1_GPIO_Port, K1_Pin, BTN_ACTIVE, // Active state 150, // Time the button has to be in 'Active state' to be recognized as pressed 100 }; BTN_STRUCT K1_BUTTON_2S = { K1_GPIO_Port, K1_Pin, BTN_ACTIVE, // Active state 2000, // Time the button has to be in 'Active state' to be recognized as pressed 100 } ;

//然后在主函数循环中调用不同的状态 if(btn_getState(&K1_BUTTON_150mS) == BTN_EDGE2){...}//BTN_EDGE2按住松开 if(btn_getState(&K1_BUTTON_2S) == BTN_PRESSED){...} //BTN_PRESSED为按住不松开状态 //注意使用的时候,如果长时间的按钮操作需要状态为 BTN_EDGE2 ,即长按松开 才会执行,在执行完语句最后需要包含比此次短的 BTN_EDGE2 操作:

if((btn_getState(&CLEAR_BUTTON_2S)==BTN_EDGE2){ ... while(btn_getState(&CLEAR_BUTTON_150mS));// 防止长时间按住松开会触发短时间的松开操作 }


一般的情况下,上面代码中用到的按键事件足够应付,所以 BTN\_STATE 中其他的按键状态我也没有花太多事件去测试,如果有谁能够把其他状态测试说清楚,还希望能够告知一声,


此按键程序最初原型是国外一家公司提供的SDK包里面的 Demo,然后经过自己的多次测试与修改才变成自己的最常用的驱动,当然他还可以更加的优化,希望大家多多指导。



## 2、另一种按键驱动


当初在做按键的时候,想着除了上面的是否有其他简单的通俗易懂的按键驱动,然后自己在网上各种寻找,反正不可能按键直接检测IO,然后防抖做一个短延时,最终这种还是逃不过得开定时器,然后还是做了一个测试可用的:



### 2.1 驱动源码



//开启按键IO的外部中断,为上升下降沿都能触发,这样是检测按下,弹起之间的时间差

EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; /* 有一个问题,就是按下以后,长按需要下一次进入外部中断才能执行 */ void EXTI9_5_IRQHandler(void) {

if( EXTI\_GetITStatus(EXTI_Line7)!= RESET)
{
	if( KEY == 0 )
	{				
		Timer4_count = 0;
		readkey1 =0;
	}
	else readkey1=1;
	}
EXTI\_ClearITPendingBit(EXTI_Line7);	

}

//外部中断实施按键操作 KEY_TIME Press_Key1(void) { KEY_TIME i; if( readkey1 == 1 ) { if( Timer4_count < 20 ) { Timer4_count = 0; readkey1 = 0; i = NOT;

收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。 img img

如果你需要这些资料,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!