STM32--KEY

STM32按键控制详解

一、按键原理图

其中一种按键按下低电平,不按高电平

按下高电平

二、代码实操

1、单个按键控制

C
/**
  * @brief  按键检测函数
  * @note   检测PA0引脚的电平变化,实现按键消抖
  * @retval 返回按键状态:1-按键按下,0-无按键按下
  */
uint8_t key(void)
{
    // 第一次检测PA0引脚是否为高电平(按键可能被按下)
    if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 1)
    {
        delay_ms(20);              // 延时20ms进行消抖,消除机械抖动
        
        // 再次检测确认按键是否真的被按下
        if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 1)
        {
            // 等待按键释放(保持高电平直到变为低电平)
            while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 1);
            
            return 1;              // 返回按键按下的状态
        }
    }
    return 0;                      // 无按键按下
}

/**
  * @brief  主函数
  */
int main(void)
{
    // 系统初始化
    HAL_Init();                                    // 初始化HAL库
    sys_stm32_clock_init(RCC_PLL_MUL9);           // 设置系统时钟为72MHz
    delay_init(72);                               // 初始化延时函数(基于72MHz时钟)
    usart_init(115200);                           // 初始化串口,波特率115200
    
    // 使能GPIOA时钟
    __HAL_RCC_GPIOA_CLK_ENABLE();
    
    // GPIO初始化结构体
    GPIO_InitTypeDef GPIO_InitStruct;
    
    // 配置PA8为推挽输出模式(用于控制LED等外设)
    GPIO_InitStruct.Mode  = GPIO_MODE_OUTPUT_PP;  // 推挽输出模式
    GPIO_InitStruct.Pull  = GPIO_NOPULL;          // 无上拉下拉
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速模式
    GPIO_InitStruct.Pin = GPIO_PIN_8;             // PA8引脚
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);       // 初始化PA8
    
    // 配置PA0为输入模式(用于按键检测)
    GPIO_InitStruct.Mode  = GPIO_MODE_INPUT;      // 输入模式
    GPIO_InitStruct.Pull  = GPIO_PULLDOWN;        // 下拉电阻(按键按下时为高电平)
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速模式
    GPIO_InitStruct.Pin = GPIO_PIN_0;             // PA0引脚
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);       // 初始化PA0
    
    // 主循环
    while(1)
    {
        // 检测按键是否按下
        if(key() == 1)
        {
            // 按键按下时,翻转PA8引脚电平(LED状态取反)
            HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_8);
        }
    }
}

代码注释由AI编写

注释:这里记得加上分号,否则按键控制不稳定

        while循环后面的分号非常重要,它表示一个空语句,也就是循环体本身为空。

2、多个按键控制

2.1代码解析

1.这里使用 do { ... } while(0) 可以:

  • 确保宏在语法上是一个完整的语句

  • 在需要分号的地方可以正常使用分号

2. 避免if-else语句的悬挂else问题

如果没有do while包裹:

2. 避免if-else语句的悬挂else问题
如果没有do while包裹:

c
#define MACRO() func1(); func2()

if (condition)
    MACRO();
else
    // 其他代码
展开后:

c
if (condition)
    func1(); func2();  // func2()不在if作用域内!
else
    // 编译错误:else没有对应的if
2. 避免if-else语句的悬挂else问题
如果没有do while包裹:

c
#define MACRO() func1(); func2()

if (condition)
    MACRO();
else
    // 其他代码
展开后:

c
if (condition)
    func1(); func2();  // func2()不在if作用域内!
else
    // 编译错误:else没有对应的if

do { ... } while(0) 是C语言宏定义的最佳实践之一,它提供了语法上的安全性,同时保持了代码的灵活性。

程序部分代码

#include "./stm32f1xx_it.h"
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"

#include "./BSP/LED/led.h"
#include "./BSP/KEY/key.h"


int main(void)
{
    // 系统初始化
	  uint8_t  key;
    HAL_Init();                                    // 初始化HAL库
    sys_stm32_clock_init(RCC_PLL_MUL9);           // 设置系统时钟为72MHz
    delay_init(72);                               // 初始化延时函数(基于72MHz时钟)
    usart_init(115200);                           // 初始化串口,波特率115200
	  led_init();                                   //LED引脚初始化
    key_init();                                   // 按键引脚初始化
		
    while(1)
    {

	    key = key_scan(0);                //调用key_scan函数,将返回值给key
			if(key)
			{
				   switch(key)
					 {
						 case KEY0_PRES:             //KEY0按下     
							 HAL_GPIO_TogglePin(LED0_GPIO_PORT, LED0_GPIO_PIN);   // LED0翻转
						   break;                           //切记一定要加
						 case KEY1_PRES:                         
							 HAL_GPIO_TogglePin(LED1_GPIO_PORT, LED1_GPIO_PIN);
						   break;
					 }
				
			}
			
			
			
		}

}

uint8_t key_scan(uint8_t mode)
{
    static uint8_t key_up = 1;  /* 按键按松开标志 */
    uint8_t keyval = 0;

    if (mode) key_up = 1;       /* 支持连按 */

    if (key_up && (KEY0 == 0 || KEY1 == 0 || WK_UP == 1))  /* 按键松开标志为1, 且有任意一个按键按下了 */
    {
        delay_ms(10);           /* 去抖动 */
        key_up = 0;

        if (KEY0 == 0)  keyval = KEY0_PRES;

        if (KEY1 == 0)  keyval = KEY1_PRES;

        if (WK_UP == 1) keyval = WKUP_PRES;
    }
    else if (KEY0 == 1 && KEY1 == 1 && WK_UP == 0) /* 没有任何按键按下, 标记按键松开 */
    {
        key_up = 1;
    }

    return keyval;              /* 返回键值 */
}

2.2长按亮灯

				if(key_scan(1))  // 检测按键1是否被按下(假设返回1表示按下)
				{
						count++;  // 如果按键被按下,计数器加1
				}
				else  // 重点:如果按键没有被按下
				{
						count = 0;  // 计数器清零
				}

				if(count == 200)  // 当计数器达到200时
				{
						HAL_GPIO_TogglePin(LED1_GPIO_PORT, LED1_GPIO_PIN);  // 翻转LED1的状态
				}
			}

}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值