ESP32开发之路(3)--- 点亮第一个LED灯及按键输入

ESP32 专栏收录该内容
16 篇文章 62 订阅

ESP32开发之路(3)— 点亮第一个LED灯及按键输入

本次开发是在Ubuntu下的,使用的模块是GOOUUU-ESP32,使用VSCode编辑项目。基于工程:ESP32开发之路(2)— HelloWorld工程分析和优化

一、点亮第一个LED灯

复制hello_world文件并命名为led_key,修改hello_world_main.c为app_main.c;
在这里插入图片描述
然后将工作区保存在led_key文件夹下:
在这里插入图片描述
通过硬件原理图查询可得,LED连在GPIO2上;所以首先宏定义LED的引脚编号:

#define GPIO_LED_NUM 2 

然后定义一个gpio配置结构体

	/* 定义一个gpio配置结构体 */
	gpio_config_t gpio_config_structure;

对该结构体进行初始化,配置并使能

    /* 初始化gpio配置结构体*/
    gpio_config_structure.pin_bit_mask = (1ULL << GPIO_LED_NUM);/* 选择gpio2 */
    gpio_config_structure.mode = GPIO_MODE_OUTPUT;              /* 输出模式 */
    gpio_config_structure.pull_up_en = 0;                       /* 不上拉 */
    gpio_config_structure.pull_down_en = 0;                     /* 不下拉 */
    gpio_config_structure.intr_type = GPIO_PIN_INTR_DISABLE;    /* 禁止中断 */ 

    /* 根据设定参数初始化并使能 */  
	gpio_config(&gpio_config_structure);

然后将其设为高电平,点亮该LED灯:

	/* 输出高电平,点亮LED*/
    gpio_set_level(GPIO_LED_NUM, 1);

然后我们可以看到开发板上的蓝色LED已经亮起来了:
在这里插入图片描述

二、LED闪烁

我们编写一个while循环,让LED一秒闪烁一次

    while(1)
    {
        gpio_set_level(GPIO_LED_NUM, 0);        /* 熄灭 */
        vTaskDelay(500 / portTICK_PERIOD_MS);   /* 延时500ms*/
        gpio_set_level(GPIO_LED_NUM, 1);        /* 点亮 */
        vTaskDelay(500 / portTICK_PERIOD_MS);   /* 延时500ms*/
    }

烧录,运行结果:
在这里插入图片描述

三、按键电平检测

查看硬件原理图,BOOT按键连在GPIO0上,并且已经上拉;所以首先宏定义BOOT按键的引脚编号

#define GPIO_KEY_NUM 0

然后对gpio配置结构体进行初始化,配置并使能

    /* 初始化gpio配置结构体*/
    gpio_config_structure.pin_bit_mask = (1ULL << GPIO_KEY_NUM);/* 选择gpio0 */
    gpio_config_structure.mode = GPIO_MODE_INPUT;               /* 输入模式 */
    gpio_config_structure.pull_up_en = 0;                       /* 不上拉 */
    gpio_config_structure.pull_down_en = 0;                     /* 不下拉 */
    gpio_config_structure.intr_type = GPIO_PIN_INTR_DISABLE;    /* 禁止中断 */ 

    /* 根据设定参数初始化并使能 */  
	gpio_config(&gpio_config_structure);

然后我们1s查询一次按键电平,并打印出来

    while(1)
    {
        printf("Boot_key Level is : %d \n",gpio_get_level(GPIO_KEY_NUM));   /* 获取BOOT按键电平并打印 */
        vTaskDelay(1000 / portTICK_PERIOD_MS);                              /* 延时1000ms*/
    }

运行结果,检测成功
在这里插入图片描述

四、循环检测按键是否按下

我们创建一个按键检测任务检测是否有按键按下,在主任务里执行LED的闪烁
首先我们查看一下这个freeRTOS的优先级可选范围,查询得知configMAX_PRIORITIES=25,所以任务优先级可选范围为0~24,且数字越大,优先级越高!

/* 定义按键检测任务的任务句柄*/
TaskHandle_t Key_Task_Handler;
/* 声明按键检测任务函数 */
void key_task(void *pvParameters);

然后在主任务里创建按键检测任务,

	/* 创建按键检测任务 */
    xTaskCreatePinnedToCore((TaskFunction_t )key_task,          /* 任务函数 */
                            (const char*    )"key task",        /* 任务名称*/          
                            (uint16_t       )2048,				/* 任务堆栈大小,单位为字节*/        
                            (void*          )NULL,              /* 传递给任务函数的参数*/
                            (UBaseType_t    )20,                /* 任务优先级,最高优先级为24 */
                            (TaskHandle_t*  )&Key_Task_Handler, /* 任务句柄*/ 
                            (const BaseType_t)tskNO_AFFINITY);  /* 指定运行任务的CPU,使用这个宏表示不会固定到任何核上*/ 

然后我们实现按键检测任务函数,注意,portTICK_PERIOD_MS的值为10,即RTOS的一个时间片为10ms,则使用vTaskDelay()函数进行延时,不能小于10ms

/* 按键检测任务函数 */
void key_task(void *pvParameters)
{
    static int key_up = 1;   /* 按键松开标志 */
    while (1)
    {
        /* 检测按键是否按下 */
        if (key_up && (gpio_get_level(GPIO_KEY_NUM) == 0) )
        {
            vTaskDelay(50 / portTICK_PERIOD_MS);   /* 延时50ms消抖*/
            key_up = 0;
            if (gpio_get_level(GPIO_KEY_NUM) == 0)
            {
                /* 按键BOOT按下,按键按下处理*/
                printf("BOOT Key pressed!\n");
            }
        }
        else if(gpio_get_level(GPIO_KEY_NUM) == 1 )
        {
            key_up = 1;     /* 按键已松开 */
        }
        vTaskDelay(100 / portTICK_PERIOD_MS);
    }
}

烧录后的实现效果如下,同时LED正常闪烁
在这里插入图片描述

五、补充

说一下任务创建函数,因为我之前看的freeRTOS,任务创建函数是xTaskCreate,然后我特意找了一下idf里的xTaskCreate函数,发现是调用了xTaskCreatePinnedToCore()函数,
在这里插入图片描述
所以以后创建任务在不需要指定哪个内核运行的时候,可以使用xTaskCreate()函数

    /* 创建按键检测任务 */
    xTaskCreate((TaskFunction_t )key_task,      /* 任务函数 */
                (const char*    )"key task",    /* 任务名称*/          
                (uint16_t       )2048,          /* 任务堆栈大小,单位为字节*/        
                (void*          )NULL,          /* 传递给任务函数的参数*/
                (UBaseType_t    )20,            /* 任务优先级,最高优先级为24 */
                (TaskHandle_t*  )NULL);         /* 任务句柄,在不需要使用任务句柄时,可以填入NULL*/ 

六、代码

最后贴上整个app_main.c的代码

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

#define GPIO_LED_NUM 2 
#define GPIO_KEY_NUM 0

/* 定义按键检测任务的任务句柄*/
TaskHandle_t Key_Task_Handler;
/* 声明按键检测任务函数 */
void key_task(void *pvParameters);

void app_main(void)
{
    /* 打印Hello world! */
    printf("Hello world!\n");

    /* 定义一个gpio配置结构体 */
    gpio_config_t gpio_config_structure;

    /* 初始化gpio配置结构体*/
    gpio_config_structure.pin_bit_mask = (1ULL << GPIO_LED_NUM);/* 选择gpio2 */
    gpio_config_structure.mode = GPIO_MODE_OUTPUT;              /* 输出模式 */
    gpio_config_structure.pull_up_en = 0;                       /* 不上拉 */
    gpio_config_structure.pull_down_en = 0;                     /* 不下拉 */
    gpio_config_structure.intr_type = GPIO_PIN_INTR_DISABLE;    /* 禁止中断 */ 

    /* 根据设定参数初始化并使能 */  
	gpio_config(&gpio_config_structure);

    /* 初始化gpio配置结构体*/
    gpio_config_structure.pin_bit_mask = (1ULL << GPIO_KEY_NUM);/* 选择gpio0 */
    gpio_config_structure.mode = GPIO_MODE_INPUT;               /* 输入模式 */
    gpio_config_structure.pull_up_en = 0;                       /* 不上拉 */
    gpio_config_structure.pull_down_en = 0;                     /* 不下拉 */
    gpio_config_structure.intr_type = GPIO_PIN_INTR_DISABLE;    /* 禁止中断 */ 

    /* 根据设定参数初始化并使能 */  
	gpio_config(&gpio_config_structure);

    /* 输出高电平,点亮LED*/
    gpio_set_level(GPIO_LED_NUM, 1);
#if 1
    /* 创建按键检测任务 */
    xTaskCreate((TaskFunction_t )key_task,      /* 任务函数 */
                (const char*    )"key task",    /* 任务名称*/          
                (uint16_t       )2048,          /* 任务堆栈大小,单位为字节*/        
                (void*          )NULL,          /* 传递给任务函数的参数*/
                (UBaseType_t    )20,            /* 任务优先级,最高优先级为24 */
                (TaskHandle_t*  )NULL);         /* 任务句柄,在不需要使用任务句柄时,可以填入NULL*/ 
#else
    /* 创建按键检测任务 */
    xTaskCreatePinnedToCore((TaskFunction_t )key_task,          /* 任务函数 */
                            (const char*    )"key task",        /* 任务名称*/          
                            (uint16_t       )2048,              /* 任务堆栈大小,单位为字节*/        
                            (void*          )NULL,              /* 传递给任务函数的参数*/
                            (UBaseType_t    )20,                /* 任务优先级,最高优先级为24 */
                            (TaskHandle_t*  )&Key_Task_Handler, /* 任务句柄*/ 
                            (const BaseType_t)tskNO_AFFINITY);  /* 指定运行任务的CPU,使用这个宏表示不会固定到任何核上*/          
#endif
    while(1)
    {
        gpio_set_level(GPIO_LED_NUM, 0);        /* 熄灭 */
        vTaskDelay(500 / portTICK_PERIOD_MS);   /* 延时500ms*/
        gpio_set_level(GPIO_LED_NUM, 1);        /* 点亮 */
        vTaskDelay(500 / portTICK_PERIOD_MS);   /* 延时500ms*/
    }

    while(1)
    {
        printf("Boot_key Level is : %d \n",gpio_get_level(GPIO_KEY_NUM));   /* 获取BOOT按键电平并打印 */
        vTaskDelay(1000 / portTICK_PERIOD_MS);                              /* 延时1000ms*/
        gpio_set_level(GPIO_LED_NUM, 0);        /* 熄灭 */
    }
    
           
}

/* 按键检测任务函数 */
void key_task(void *pvParameters)
{
    static int key_up = 1;   /* 按键松开标志 */
    while (1)
    {
        /* 检测按键是否按下 */
        if (key_up && (gpio_get_level(GPIO_KEY_NUM) == 0) )
        {
            vTaskDelay(50 / portTICK_PERIOD_MS);   /* 延时50ms消抖*/
            key_up = 0;
            if (gpio_get_level(GPIO_KEY_NUM) == 0)
            {
                /* 按键BOOT按下,按键按下处理*/
                printf("BOOT Key pressed!\n");
            }
        }
        else if(gpio_get_level(GPIO_KEY_NUM) == 1 )
        {
            key_up = 1;     /* 按键已松开 */
        }
        vTaskDelay(100 / portTICK_PERIOD_MS);
    }
}
  • 8
    点赞
  • 1
    评论
  • 43
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

Willliam_william

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

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值