先来让我们了解一下GPIO是什么吧,它在单片机中也有很重要的作用,接下来我们来看看吧。
esp32C3是QFN32封装(一种集成电路(IC)封装类型),GPIO引脚一共有22个,从GPIO-0到GPIO-21。从理论上来说,所有的IO引脚都可以复用为任何外设功能,但有些引脚用作连接芯片内部FLASH或者外部FLASH功能时,官方不建议用作其它用途。
esp32c3的GPIO,可以用作输入、输出,可以配置内部上拉、下拉,可以配置为中断引脚。这里我们将BOOT按键的IO-9引脚连接,设置为GPIO中断,用来接收BOOT按键请求。
1.首先,咱们需要复制esp-idf-v5.1.3\examples\get-started\sample_project这个工程到咱们的项目实操文件夹,然后把这个文件夹的名称修改为gpio_key,之后看的时候容易理解,修改后的工程路径为D:\esp32c3\gpio_key。
2.接着打开VScode软件,并打开gpio_key这个文件夹,打开工程一级目录下的CMakeLists.txt文件(不是main目录下的),继续我们把工程名字修改为gpio_key,保存后关闭。
3.接着继续打开VSCode软件,然后打开esp-idf-v5.1.3整个工程文件夹,然后我们依次找到examples\peripherals\gpio\generic_gpio这个工程作为参考,注意不能修改这个工程中的内容和配置,只是作为参考。我们点击gpio_example_main.c打开这个文件,找到app_main函数。复制它的第80~93行代码到我们自己的gpio_key工程中。复制过来以后,我们按照原理图进行了如下的修改
cpp
#include <stdio.h>
void app_main(void)
{
//zero-initialize the config structure.
gpio_config_t io_conf = {};//定义了一个gpio_config_t结构体变量
//falling edge interrupt
io_conf.intr_type = GPIO_INTR_DISABLE; //定义引脚中断类型
//set as input mode
io_conf.mode = GPIO_MODE_OUTPUT; //配置模式
//bit mask of the pins GPIO-9
io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL; //配置选择哪个引脚
//disable pull-down mode
io_conf.pull_down_en = 0;//第五六句配置是否打开上下拉电阻,0是关闭,1是打开,我们把上拉打开
//disable pull-up mode
io_conf.pull_up_en = 0;
//configure GPIO with the given settings
gpio_config(&io_conf);
}
在这顺便对上图代码的注释解释进行补充:
p2:开发板上的按键没有按下的时候是高电平,按下去以后是低电平,我们定义成下降沿中断,这里原来是GPIO_INTR_DISABLE,表示中断关闭,这里我们修改为GPIO_INTR_NEGEDGE,即下降沿中断。这些宏定义在gpio_types.h文件中被定义,我们在gpio_example_main.c文件中的GPIO_INTR_DISABLE上单击右键,然后选择"转到定义",就可以找到这几个宏定义
p3:之前的模式是GPIO_MODE_OUTPUT,我们现在修改为GPIO_MODE_INPUT输入模式
p4:把之前的GPIO_OUTPUT_PIN_SEL修改为1<<GPIO_NUM_9,因为BOOT按键连接到了GPIO-9
接下来,咱们再复制gpio_example_main.c文件中的第108~116行代码到main.c文件中,然后我们进行了修改,下面代码是进行修改后的代码
cpp
void app_main(void)
{
gpio_config_t io_conf = {
.intr_type = GPIO_INTR_NEGEDGE, //falling edge interrupt
.mode = GPIO_MODE_INPUT, //set as input mode
.pin_bit_mask = 1<<GPIO_NUM_9, //bit mask of the pins GPIO9
.pull_down_en = 0, //disable pull-down mode
.pull_up_en = 1 //enable pull-up mode
};
//configure GPIO with the given settings
gpio_config(&io_conf);
//create a queue to handle gpio event from isr
gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));
//start gpio task
xTaskCreate(gpio_task_example, "gpio_task_example", 2048, NULL, 10, NULL);
//install gpio isr service
gpio_install_isr_service(0);
//hook isr handler for specific gpio pin
gpio_isr_handler_add(GPIO_NUM_9, gpio_isr_handler, (void*) GPIO_NUM_9);
}
ps:
第一条创建了一个队列,队列消息数量为10,gpio_evt_queue是队列句柄,一会儿需要我们在main函数外面定义
第二条创建了一个任务,任务名称为gpio_task_example
第三条代码,启动GPIO中断服务,其中ESP_INTR_FLAG_DEFAULT的值是0,这个宏定义是在gpio_example_main.c文件中定义的,我们可以直接把这里改成0,也可以把这个宏定义复制到我们的main.c文件中
第四条代码,添加某个GPIO的中断,这里我们添加GPIO9,第1个和第3个参数,都修改为GPIO_NUM_9
接下来,我们在app_main函数的上方添加队列、中断等相关的代码,复制gpio_example_main.c中的第60~76行到我们的main.c文件中,放到app_main函数的上方
cpp
static QueueHandle_t gpio_evt_queue = NULL; //定义了一个队列句柄,用来处理gpio队列消息
static void IRAM_ATTR gpio_isr_handler(void* arg) //定义了两个函数,第一个函数是gpio中断服务函数,当GPIO产生中断的时候呢,会进入这个函数,xQueueSendFromISR函数将参数GPIO_NUM_9添加到队列消息。
第二个函数是gpio的任务函数,在任务函数中,接收队列消息,当接收到一个队列消息时,打印字符串。PRIu32 是C语言中用于格式化输出的宏,用于打印32位无符号整数。它是由C99标准引入的,位于inttypes.h头文件中。在使用该宏时,需要包含inttypes.h头文件。gpio_get_level函数用于获取引脚的电平
{
uint32_t gpio_num = (uint32_t) arg;
xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
}
static void gpio_task_example(void* arg)
{
uint32_t io_num;
for(;;) {
if(xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {
printf("GPIO[%"PRIu32"] intr, val: %d\n", io_num, gpio_get_level(io_num));
}
}
}
我们再把需要的头文件添加到我们的main.c文件就可以了
cpp
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
使用printf函数,需要添加stdio.h头文件。string.h和stdlib.h我们这里用不着,可以去掉。接下来是3个freeRTOS的头文件,最后一个头文件是用于gpio的配置,接着进行编译就行了。