【ESP32-IDF+VScode】开发笔记(二):按键输入——按键控制LED状态


前言

按键输入是各类MCU的GPIO输入开发学习的常用例程。本文将通过【ESP32按键控制LED(非中断实现)】这个例程来学习使用ESP32的GPIO输入,了解GPIO输入功能配置、操作的相关函数。


目标

  • 熟悉ESP-IDF+VScode开发环境
  • 了解按键消抖原理
  • 学习ESP32 GPIO输入相关配置方法、函数
  • 创建一个按键的工程,并编程实现按键控制LED亮灭

一、按键消抖

按键消抖通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动。

按键触发时其理想工作波形和实际工作波形如下图所示,在按键闭合和断开时(即区域①和区域③)会出现抖动,使得输入GPIO时无法检测其有效电平,因此需要进行消抖,使得输入GPIO的电平为有效电平(区域②)。对于按键消抖的方法,主要有软件法硬件法两类,在已经设计好的电路中,常采用软件法进行消抖,即通过软件编程,添加一个延时,在检测GPIO电平时,将区域①或区域②延时过去,仅保留有效电平,本文采用的就是软件消抖的方式。

图1

二、ESP-IDF GPIO输入相关配置

1.GPIO输入初始化配置

官方配置内容如下

struct gpio_config_t	//GPIO参数初始化配置结构体
	//结构体成员
	uint64_t pin_bit_mask			//GPIO引脚配置
	gpio_mode_t mode				//GPIO模式配置:有输入和输出两种,若配置输出模式,设置:GPIO_MODE_INPUT
	gpio_pullup_t pull_up_en		//GPIO上拉输入配置,根据需求设置,若使能,设置:GPIO_PULLUP_ENABLE
	gpio_pulldown_t pull_down_en	//GPIO下拉输入配置,根据此需求设置,若使能,设置:GPIO_PULLDOWN_ENABLE
--------------------------------------------------------------------------------------------------------------
esp_err_t gpio_config(const gpio_config_t *pGPIOConfig)
//GPIO初始化函数,初始化上述结构体

2.GPIO输入操作函数

官方提供的相关操作函数如下:

int gpio_get_level(gpio_num_t gpio_num)
//读取GPIO电平
/*
参数:	gpio_num -- GPIO number. If you want to get the logic level of e.g. pin GPIO16,
		gpio_num should be GPIO_NUM_16 (16);
返回:	0 the GPIO input level is 0
		1 the GPIO input level is 1
*/

对于GPIO的相关配置和操作常用的就是上述介绍的,更详细的内容可参考官方ESP-IDF文档(v5.3版本)自行学习,若有疑惑可在评论区探讨。

三、按键KEY初始化配置

根据前文对GPIO输入相关配置介绍,配置按键GPIO如下

//按键初始化配置
void key_init(void)
{
    gpio_config_t key_pin_config;	//定义按键初始化结构体
    key_pin_config.pin_bit_mask = 1ULL << KEY_IO;	//配置按键引脚,本文按键链接的是GPIO0,以宏定义的形式赋值给KEY_IO
    key_pin_config.mode = GPIO_MODE_INPUT;	//配置GPIO为输入模式
    key_pin_config.pull_up_en = GPIO_PULLUP_ENABLE;	  //使能上拉输入,根据需求设置即可
    key_pin_config.pull_down_en = GPIO_PULLDOWN_DISABLE;	//失能下拉输入,根据需求设置即可
    gpio_config(&key_pin_config);	//初始化按键配置结构体
    printf("key init\n");	//输出按键初始化状态
}

四、工程实战——按键控制点灯

功能:通过检测按键动作来控制LED。每按一次按键,LED的状态发生翻转,即按一次亮,再按一次灭。
注意:本工程并非采用中断形式来控制LED的亮灭,若想通过外部中断形式实现此功能,可自行学习ESP外部中断相关操作,或者继续关注此系列教程后续更新。

1、新建空白工程

参考【ESP32-IDF+VScode】开发笔记(一):从点灯开始——点亮LED

2、相关配置、代码

【配置CMakeLists】
首先配置自定义组件key的CMake文件:components->key->CMakeLists.txt完整配置内容如下:

file(TO_CMAKE_PATH "$ENV{IDF_PATH}" IDF_PATH)

idf_component_register(SRCS "key.c"
                    INCLUDE_DIRS "include"
                    "${IDF_PATH}/components/driver/gpio/include"
                    )

然后配置自定义组件led的CMake文件:components->led->CMakeLists.txt完整配置内容如下:

file(TO_CMAKE_PATH "$ENV{IDF_PATH}" IDF_PATH)

idf_component_register(SRCS "led.c"
                    INCLUDE_DIRS "include"
                    "${IDF_PATH}/components/driver/gpio/include"
                    )

【配置自定义组件头文件】
components->key->include->key.h

#ifndef __KEY_H__
#define __KEY_H__

#include "driver/gpio.h"

void key_init(void);
uint8_t key_scan(void);

#endif

components->led->include->led.h

#ifndef __LED_H
#define __LED_H
 
#include "driver/gpio.h"

void led_init(void);
void led_on(void);
void led_off(void);

#endif

【编写自定义组件驱动】
components->key->key.c

#include <stdio.h>
#include "key.h"
#include "freertos/FreeRTOS.h"
#include "FreeRTOS/task.h"

#define KEY_IO 0

void key_init(void)
{
    gpio_config_t key_pin_config;
    key_pin_config.pin_bit_mask = 1ULL << KEY_IO;
    key_pin_config.mode = GPIO_MODE_INPUT;
    key_pin_config.pull_up_en = GPIO_PULLUP_ENABLE;
    key_pin_config.pull_down_en = GPIO_PULLDOWN_DISABLE;
    gpio_config(&key_pin_config);
    printf("key init\n");

}

uint8_t key_scan(void)
{
    static uint8_t key_up = 1;
    if (key_up && (gpio_get_level(KEY_IO) == 0))
    {
        vTaskDelay(10);
        key_up = 0;
        return 1;
    }
    else if (gpio_get_level(KEY_IO) == 1)
    {
        key_up = 1;
    }
    return 0;
}

components->led->led.c

#include <stdio.h>
#include "led.h"


#define LED_PIN 2

void led_init(void)
{
    gpio_config_t led_pin_config;
    led_pin_config.pin_bit_mask = 1<<LED_PIN;
    led_pin_config.mode = GPIO_MODE_OUTPUT;
    led_pin_config.pull_up_en = GPIO_PULLUP_DISABLE;
    led_pin_config.pull_down_en = GPIO_PULLDOWN_DISABLE;
    gpio_config(&led_pin_config);
}

void led_on(void)
{    
    gpio_set_level(LED_PIN, 1);
}

void led_off(void)
{
    gpio_set_level(LED_PIN, 0);
}

【编写主函数】
main->main.c,这里注意头文件的包含。

#include <stdio.h>
#include "led.h"
#include "key.h"
#include "FreeRTOS/freertos.h"
#include "FreeRTOS/task.h"


void app_main(void)
{
    uint8_t led_status = true;  //定义LED电平状态
    led_init(); //初始化LED
    key_init(); //初始化按键
    while(1)
    {
        if(gpio_get_level(0) == 0)
        {
            vTaskDelay(20);   //通过延时进行按键消抖
            if(gpio_get_level(0) == 0)
            {
                printf("key down\n");   //按键按下状态输出
                led_status = !led_status;  //翻转LED电平状态
            }
        }
        gpio_set_level(2, led_status);  //设置LED电平

    }
}

3、烧录前准备和烧录

参考【ESP32-IDF+VScode】开发笔记(一):从点灯开始——点亮LED

4、Wokwi 在线仿真

【仿真链接】

https://wokwi.com/projects/405574590798517249

【仿真说明】
在wokwi里仿真,自定义函数都要写在main.c,不能像在VScode中那样将外设驱动单独列出,否则仿真会出错。

【仿真视频】

【ESP32-Wokwi仿真】:KEY CTRL LED

【Wokwi仿真代码示例】

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"

#define KEY_IO 0
#define LED_GPIO 2

void key_init(void)
{
    gpio_config_t key_pin_config;
    key_pin_config.pin_bit_mask = 1ULL << KEY_IO;
    key_pin_config.mode = GPIO_MODE_INPUT;
    key_pin_config.pull_up_en = GPIO_PULLUP_ENABLE;
    key_pin_config.pull_down_en = GPIO_PULLDOWN_DISABLE;
    gpio_config(&key_pin_config);
    printf("key init\n");

}

void led_init(void)
{
    gpio_config_t led_pin_config;
    led_pin_config.pin_bit_mask = 1 << LED_GPIO;
    led_pin_config.mode = GPIO_MODE_OUTPUT;
    led_pin_config.pull_up_en = GPIO_PULLUP_DISABLE;
    led_pin_config.pull_down_en = GPIO_PULLDOWN_DISABLE;
    gpio_config(&led_pin_config);
}

void app_main(void)
{
    uint8_t led_status = true;  //定义LED电平状态
    led_init(); //初始化LED
    key_init(); //初始化按键
    while(1)
    {
        if(gpio_get_level(0) == 0)
        {
            vTaskDelay(20);   //通过延时进行按键消抖
            if(gpio_get_level(0) == 0)
            {
                printf("key down\n");   //按键按下状态输出
                led_status = !led_status;  //翻转LED电平状态
            }
        }
        gpio_set_level(2, led_status);  //设置LED电平

    }
}


五、常见问题及解决方案

待发现

总结

本文章主要讲解ESP-IDF配置ESP32GPIO输入相关操作,实现按键控制LED亮灭的功能,后续还会按照学习流程,更新用ESP-IDF开发ESP32的每一步教程,如果有兴趣的话,就点赞收藏关注不迷路!!!

  • 20
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乔乔同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值