深圳市建设主管部门门户网站,合肥做兼职网站,购物网站建设要多少钱,德州网站建设教程STM32框架之按键扫描新思路 引入代码展示思路分析 我们学习了定时器实现毫秒级/秒级任务框架#xff0c;这期我们基于任务框架学习按键扫描新思路。 引入
在按键扫描的过程中#xff0c;最重要的一步就是按键消抖#xff0c;解决的方法最简单粗暴的就是先扫描一次按键状态这期我们基于任务框架学习按键扫描新思路。 引入
在按键扫描的过程中最重要的一步就是按键消抖解决的方法最简单粗暴的就是先扫描一次按键状态判断按键按下后延时再次判断按键状态。就像这样
if(1-HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)) //判断按键0是否按下{HAL_Delay(20); //延时消抖 if(1-HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)) //再次判断按键0是否按下 {while(1-HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)) //等待按键0松开{}Key_Num 1; //赋值按键值}} 这是最笨的方法当然还可以 多次调用按键扫描函数当按键按下的时候开始计数/计时。当数字/时间到达一定值时判断按键按下当有一次扫描到按键为按下时计数/计时清零代码如下
int Key_Scan(void)
{int Key_Num 0; //定义按键值int temp 0; //定义临时变量static int Key0_Count0,Key1_Count0,Key2_Count0,WKUP_Count0 ; //定义不同按键的按键值if(1-HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)) temp 1; //当某一个按键按下是临时变量值为对应的按键值加一if(1-HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)) temp 2; //加一是因为temp为0时无法进入switch中所以案件之都加一if(1-HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)) temp 3; //if(HAL_GPIO_ReadPin(WKUP_GPIO_Port,WKUP_Pin)) temp 4;switch(temp){case 1: Key0_Count; Key1_Count0;Key2_Count0;WKUP_Count0 ; //通过temp变量的值将对应按键计数值加一break; //同时将其他按键计数值清零case 2: Key1_Count; Key0_Count0;Key2_Count0;WKUP_Count0 ; break;case 3: Key2_Count; Key0_Count0;Key1_Count0;WKUP_Count0 ;break;case 4: WKUP_Count; Key0_Count0;Key1_Count0;Key2_Count0 ;break;default: Key0_Count0; Key1_Count0;Key2_Count0;WKUP_Count0 ;break;}if(Key0_Count 500) //当temp到达一定值时则可判断按键按下{Key_Num 1; //按键按下将所有的按键计数值清零Key0_Count0; Key1_Count0;Key2_Count0;WKUP_Count0 ;}if(Key1_Count 500){Key_Num 2;Key0_Count0; Key1_Count0;Key2_Count0;WKUP_Count0 ;}if(Key2_Count 500){Key_Num 3;Key0_Count0; Key1_Count0;Key2_Count0;WKUP_Count0 ;}if(WKUP_Count 500){Key_Num 4;Key0_Count0; Key1_Count0;Key2_Count0;WKUP_Count0 ;}return Key_Num; //返回按键值当没有按键按下或者存在抖动时返回值为0 这种方法相对于第一种逻辑上更严谨但是不好控制计数值。并且多次进入函数占用大量CPU资源所以我们引入第三种方法规定时间间隔进行扫描通过数组判断结果。代码如下 代码展示
main.c
/* USER CODE BEGIN PFP */
void Proc2msTask(void) //2ms任务
{static uint8_t i0;if(Get_2ms_Flag() 1) //获取2ms标志位{Clear_2ms_Flag(); //清除2ms标志位//2mstask codei;if(i4) //1s扫描一处按键状态{i0;Key_One_Scan(Key_Name_Key0,Key0_Up_Task,Key0_Down_Task); //扫描Key0状态Key_One_Scan(Key_Name_Key1,Key1_Up_Task,Key1_Down_Task); //扫描Key1状态Key_One_Scan(Key_Name_Key2,Key2_Up_Task,Key2_Down_Task); //扫描Key2状态Key_One_Scan(Key_Name_WKUP,WWKUP_Up_Task,WKUP_Down_Task); //扫描WKUP状态}}
}void Proc1sTask(void) //1s任务
{if(Get_1s_Flag() 1) //获取1s标志位{Clear_1s_Flag(); //清除1s标志位//1stask code
// HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);}
}
/* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 *//* USER CODE END 0 *//*** brief The application entry point.* retval int*/
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_TIM10_Init();/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(htim10);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){Proc2msTask(); //调用2ms任务Proc1sTask(); //调用1s任务/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}Key.c
/* USER CODE BEGIN 2 */
void Key0_Down_Task(void)
{HAL_GPIO_WritePin(LED0_GPIO_Port,LED0_Pin,GPIO_PIN_RESET); //按下亮灯
}
void Key0_Up_Task(void)
{HAL_GPIO_WritePin(LED0_GPIO_Port,LED0_Pin,GPIO_PIN_SET); //松开关闭
}
void Key1_Down_Task(void)
{HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_RESET); //按下亮灯
}
void Key1_Up_Task(void)
{HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_SET); //松开关闭
}
void Key2_Down_Task(void)
{HAL_GPIO_WritePin(LED2_GPIO_Port,LED2_Pin,GPIO_PIN_RESET); //按下亮灯
}
void Key2_Up_Task(void)
{HAL_GPIO_WritePin(LED2_GPIO_Port,LED2_Pin,GPIO_PIN_SET); //松开关闭
}
void WKUP_Down_Task(void)
{HAL_GPIO_WritePin(LED3_GPIO_Port,LED3_Pin,GPIO_PIN_RESET); //按下亮灯
}
void WWKUP_Up_Task(void)
{HAL_GPIO_WritePin(LED3_GPIO_Port,LED3_Pin,GPIO_PIN_SET); //松开关闭
}void Key_One_Scan(uint8_t KeyName ,void(*OnKeyOneUp)(void), void(*OnKeyOneDown)(void))
{static uint8_t Key_Val[Key_Name_Max]; //按键值的存放位置static uint8_t Key_Flag[Key_Name_Max]; //KEY0~2为0时表示按下为1表示松开WKUP反之Key_Val[KeyName] Key_Val[KeyName] 1; //每次扫描完将上一次扫描的结果左移保存switch(KeyName){case Key_Name_Key0: Key_Val[KeyName] Key_Val[KeyName] | (HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin)); //读取Key0按键值break;case Key_Name_Key1: Key_Val[KeyName] Key_Val[KeyName] | (HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin)); //读取Key1按键值break;case Key_Name_Key2: Key_Val[KeyName] Key_Val[KeyName] | (HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin)); //读取Key2按键值break;case Key_Name_WKUP: Key_Val[KeyName] Key_Val[KeyName] | (HAL_GPIO_ReadPin(WKUP_GPIO_Port, WKUP_Pin)); //读取WKUP按键值break; default:break;}if(KeyName Key_Name_WKUP) //WKUP的电路图与其他按键不同所以需要特殊处理{//WKUP特殊情况//当按键标志为1(松开)是判断是否按下WKUP按下时为0xffif(Key_Val[KeyName] 0xff Key_Flag[KeyName] 1){(*OnKeyOneDown)();Key_Flag[KeyName] 0;}//当按键标志位为0按下判断按键是否松开,WKUP松开时为0x00if(Key_Val[KeyName] 0x00 Key_Flag[KeyName] 0){(*OnKeyOneUp)();Key_Flag[KeyName] 1;} }else //Key0~2按键逻辑判断{//Key0~2常规判断//当按键标志为1(松开)是判断是否按下if(Key_Val[KeyName] 0x00 Key_Flag[KeyName] 1){(*OnKeyOneDown)();Key_Flag[KeyName] 0;}//当按键标志位为0按下判断按键是否松开if(Key_Val[KeyName] 0xff Key_Flag[KeyName] 0){(*OnKeyOneUp)();Key_Flag[KeyName] 1;} }}
/* USER CODE END 2 */Key.h
/* Includes ------------------------------------------------------------------*/
#include main.h/* USER CODE BEGIN Includes *//* USER CODE END Includes *//* USER CODE BEGIN Private defines */
typedef enum{Key_Name_Key0 0,Key_Name_Key1,Key_Name_Key2,Key_Name_WKUP,Key_Name_Max}EnumKeyOneName;/* USER CODE END Private defines */void MX_GPIO_Init(void);/* USER CODE BEGIN Prototypes */
void Key0_Down_Task(void);void Key0_Up_Task(void);void Key1_Down_Task(void);void Key1_Up_Task(void);void Key2_Down_Task(void);void Key2_Up_Task(void);void WKUP_Down_Task(void);void WWKUP_Up_Task(void);void Key_One_Scan(uint8_t KeyName ,void(*OnKeyOneUp)(void), void(*OnKeyOneDown)(void));
/* USER CODE END Prototypes */#ifdef __cplusplus
}
#endif
#endif /*__ GPIO_H__ */思路分析
按键按下的过程中难免会有抖动但是抖动的时间通常在10~20ms之间而按键按下的过程往往会持续100ms以上所以我们可以每10ms扫描一次按键状态如果连续八次都是按下则认为按键已经按下想要的执行认为即可。反之如果八次都是松开则认为按键松开了也可以执行按键松开的相关任务。
具体细节大家看代码吧这个只是大体思路代码还有很多精彩的地方。