【蓝桥杯】嵌入式编程_KEY模块

目录

认识按键原理图

按键代码配置

模块KEY代码参考

主程序设计

uwTick小练习

异或逻辑练习

按键的长按和短按练习


认识按键原理图

05d7e873f2be4c108d1247adff74ce6b.png

此图来源:CT117E-M4产品手册.pdf

PB0 PB1 PB2 PA0 分别对应按键B1 B2 B3 B4 当按键被按下时 GPIO口是检测高低电平的 不需要输出

因此我们选择输入模式 按键没有被按下GPIO口是一直被检测高电平 按键按下GPIO口是检测到了低电平 所以我们选择浮空输入模式(没有上拉也没有下拉)

模块设置不准备使用中断

思考如何才能检测到按键被按下?

使用下降沿还是上降沿?

按键代码配置

2b5b8c61291e43b593826890c5caa8b4.png

 (注 此MX配置不在上一个led模块基础上配置)

b987048605744b65bbe73cff3d463843.png

模块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);
}	

猜你喜欢

转载自blog.csdn.net/shelter1234567/article/details/129116002