目录
认识按键原理图
此图来源:CT117E-M4产品手册.pdf
PB0 PB1 PB2 PA0 分别对应按键B1 B2 B3 B4 当按键被按下时 GPIO口是检测高低电平的 不需要输出
因此我们选择输入模式 按键没有被按下GPIO口是一直被检测高电平 按键按下GPIO口是检测到了低电平 所以我们选择浮空输入模式(没有上拉也没有下拉)
模块设置不准备使用中断
思考如何才能检测到按键被按下?
使用下降沿还是上降沿?
按键代码配置
(注 此MX配置不在上一个led模块基础上配置)
模块KEY代码参考
因为不在上一个led mx上配置所以函数MX_GPIO_Init 增加key.c会有重名函数 我们需要改一下名 主函数在调用配置函数 不用担心会与模块ledGPIO配置冲突!
文件key.c
#include "key.h"
unsigned char key_val;
unsigned char key_old;
unsigned char key_down;
void MX_GPIO_key_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin : PA0 */
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pins : PB0 PB1 PB2 */
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
unsigned char key_can(void)
{
//思路不断做if判断引脚电平 低电平代表该键按下
if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == 0)
return B1;
else if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == 0)
return B2;
else if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == 0)
return B3;
else if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 0)
return B4;
else
return (unsigned char)0;//没有按键被按下
}
//检测下降沿函数
unsigned char key_down_fun(void)
{
//新值异或旧值再与新值得到下降沿
key_val=key_can();
key_down=(key_val^key_old)&key_val;
key_old=key_val;
return key_down;
}
文件key.h
#ifndef __KEY_H__
#define __KEY_H__
#include "main.h"
#define B1 (unsigned char)1
#define B2 (unsigned char)2
#define B3 (unsigned char)3
#define B4 (unsigned char)4
void MX_GPIO_key_Init(void);
unsigned char key_can(void);
unsigned char key_down_fun(void);
#endif
主程序设计
//设置周期的变量
#include "key.h"
__IO uint32_t uwTick_key;
void key_proc(void);
int main(void)
{
MX_GPIO_key_Init();
HAL_Init();
SystemClock_Config();
MX_GPIO_key_Init();
while (1)
{
key_proc();
}
}
void key_proc(void)
{
if((uwTick-uwTick_key)<100) return;
uwTick_key = uwTick;
//设置扫描周期
unsigned char key_down = key_down_fun();
if(key_down == B1)//按键被按下
Led_Input_Disp(0XFF);
if(key_down == B2)
Led_Input_Disp(0X00);
if(key_down == B3)
Led_Input_Disp(0X88);
if(key_down == B4)
Led_Input_Disp(0Xaa);
}
介绍下新成员uwTick
程序运行后这个值会一直自增加 类似计数器 单位时间的固定的 因此称为定时器
uwTick小练习
现在利用uwTick 实现 B1按下指示灯LED全亮 5秒后熄灭
void key_proc(void)
{
if((uwTick-uwTick_key)<100) return;
uwTick_key = uwTick;
static unsigned char B1down_Do_Time;
static __IO uint32_t uwTick_key_delay;
unsigned char key_down = key_down_fun();
if(key_down == B1){
Led_Input_Disp(0XFF);
B1down_Do_Time = 1;
uwTick_key_delay = uwTick;
}
if(((uwTick-uwTick_key_delay)>= 5000)&&(B1down_Do_Time == 1))
Led_Input_Disp(0X00);
}
大家看懂上面的逻辑了吗!巧妙地利用uwTick 实现了延迟 但程序还存在一定的问题....B1down_Do_Time没有重置为0 让程序再次发生同样的效果。
异或逻辑练习
现在利用uwTick 实现 B1按下指示灯LED闪烁 5秒后熄灭
void key_proc(void)
{
if((uwTick-uwTick_key)<100) return;//准备这段时间是led的闪烁间隔 有扫描函数的存在也不宜过大
uwTick_key = uwTick;
static unsigned char B1down_Do_Time;
static __IO uint32_t uwTick_key_delay;
static unsigned char ucLed;
unsigned char key_down = key_down_fun();
if(key_down == B1){
B1down_Do_Time = 1;
uwTick_key_delay = uwTick;
}
if(B1down_Do_Time == 1){
ucLed ^= 0xff; //异或操作 不同为1 相同为零 实现进行闪烁操作
}
if(((uwTick-uwTick_key_delay)>= 5000)&&(B1down_Do_Time == 1)){
// if(((uwTick_key_delay+5000) <= uwTick)...
// Led_Input_Disp(0X00);
B1down_Do_Time = 0;
ucLed &= (~0xff); //与操作就是清零操作
}
Led_Input_Disp(ucLed);
}
按键的长按和短按练习
现 实现 短按B1(<800ms)led1 切换闪烁灯状态 长按B1 led1实现闪烁灯效果(间隔为500ms)
void key1_fun(void)
{
static unsigned char uled;
static __IO uint32_t uwTick_key_up_time;
static __IO uint32_t uwTick_key1;
static __IO uint32_t uwTick_key_delay1;
key_new=key_scan();
key_down = (key_new^key_old)&key_new;
key_up=(key_new^key_old)&~key_new;
key_old=key_new;
if(key_down)
{
uwTick_key_up_time = uwTick;
uwTick_key_delay1 = uwTick;
}
if((uwTick - uwTick_key_up_time) <= 800)//短按识别
{
if(key_up == B1)
{
uled ^= 0x01;
}
}else //长按
{
if(key_new == B1&& uwTick-uwTick_key_delay1>500)
{
uled ^= 0x01;
uwTick_key_delay1 = uwTick;
}
}
inputchar_led_display(uled);
}