从0学起的esp-idf之旅——外设篇gpio

本文通过分析ESP-IDF官方的GPIO中断例程,讲解了如何配置GPIO、设置中断以及使用FreeRTOS任务处理中断事件。在示例中,GPIO18和19作为输出,4和5作为上拉输入,利用中断服务函数和消息队列实现中断处理。博主强调了在嵌入式系统中,结合中断服务和任务处理能提高实时性,避免了中断服务函数处理时间过长导致的问题。最后,提供了官方GPIO API和FreeRTOS的相关链接。
摘要由CSDN通过智能技术生成

前言

闲来无事,再开一坑,说是说从零学起,实际上就是分析官方例子。顺便帮助大家总结一波,在此分析一下,不要拿我的博文作为自己的学习esp-idf的”教参“。

官方例程详细注释

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

/**
 * 摘要:
 * 此代码展示了如何配置 gpio 以及如何使用 gpio 中断。
 *
 * GPIO 状态:
 * GPIO18: 推挽输出
 * GPIO19: 推挽输出
 * GPIO4:  上拉输入, 上升沿和下降沿中断
 * GPIO5:  上拉输入, 下降沿中断
 *
 * 实验操作:
 * GPIO18 连接到 GPIO4
 * GPIO19 连接到 GPIO5
 * 利用GPIO18/19产生信号,触发GPIO4/5上的中断
 *
 */

#define GPIO_OUTPUT_IO_0    18
#define GPIO_OUTPUT_IO_1    19
#define GPIO_OUTPUT_PIN_SEL  ((1ULL<<GPIO_OUTPUT_IO_0) | (1ULL<<GPIO_OUTPUT_IO_1))
#define GPIO_INPUT_IO_0     4
#define GPIO_INPUT_IO_1     5
#define GPIO_INPUT_PIN_SEL  ((1ULL<<GPIO_INPUT_IO_0) | (1ULL<<GPIO_INPUT_IO_1))
#define ESP_INTR_FLAG_DEFAULT 0

static xQueueHandle gpio_evt_queue = NULL; // 设置消息队列,用于传递中断的信息

// 真正的中断服务函数,这里只干一件事,通过队列把中断信息打包发送出去
static void IRAM_ATTR gpio_isr_handler(void* arg) 
{
    uint32_t gpio_num = (uint32_t) arg;
    xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL); // 中断专属发送信息给队列的函数
}

// 实际起作用的gpio中断处理函数,一直等待中断发送信息然后到这里处理信息
static void gpio_task_example(void* arg)
{
    uint32_t io_num;
    for(;;) 
    {
        if(xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) // 堵塞等待中断给信息
        {
        	// 打印信息,中断实际上的处理在这里进行
            printf("GPIO[%d] intr, val: %d\n", io_num, gpio_get_level(io_num));
        }
    }
}

void app_main(void)
{
    gpio_config_t io_conf1 = {
    	.intr_type = GPIO_INTR_DISABLE, //不启用gpio中断
    	.mode = GPIO_MODE_OUTPUT,//推挽输出模式
    	.pin_bit_mask = GPIO_OUTPUT_PIN_SEL,//设置goio,可以同时设置多个
    	.pull_down_en = 0,// 不下拉
    	.pull_up_en = 0,// 不上拉
    };
    gpio_config(&io_conf1);
	
	gpio_config_t io_conf2 = {
    	.intr_type = GPIO_INTR_POSEDGE, //启用上升沿中断
    	.mode = GPIO_MODE_INPUT,//输入模式
    	.pin_bit_mask = GPIO_INPUT_PIN_SEL,//设置goio,可以同时设置多个
    	.pull_down_en = 0,// 不下拉
    	.pull_up_en = 1,// 上拉
    };
    gpio_config(&io_conf2);

    //改变gpio中断模式为任意边沿中断(上升沿和下降沿中断)
    gpio_set_intr_type(GPIO_INPUT_IO_0, GPIO_INTR_ANYEDGE);

    //创建用于传递中断信息的消息队列
    gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));
    //开始gpio中断处理线程
    xTaskCreate(gpio_task_example, "gpio_task_example", 2048, NULL, 10, NULL);

    //安装gpio中断驱动(参数为优先级)
    gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
    //给指定的gpio绑定中断服务函数
    gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0);
    gpio_isr_handler_add(GPIO_INPUT_IO_1, gpio_isr_handler, (void*) GPIO_INPUT_IO_1);
    
    // 打印内存使用情况
    printf("Minimum free heap size: %d bytes\n", esp_get_minimum_free_heap_size());

    int cnt = 0;
    while(1) {
        printf("cnt: %d\n", cnt++);
        vTaskDelay(1000 / portTICK_RATE_MS);
        gpio_set_level(GPIO_OUTPUT_IO_0, cnt % 2); // 设置gpio电平
        gpio_set_level(GPIO_OUTPUT_IO_1, cnt % 2);
    }
}

吐槽

本例程总的来说还不错,只不过官方为了尽可能的展示自己的api在绑定好gpio的中断服务函数后,多此一举的remove掉了,然后再次绑定。
官方源码迷惑行为
这里我删掉了这个迷惑行为。还有就是为了大家看起来简洁,我直接使用结构体声明的时候赋值。其余的部分均参照官方例子

解析官方例子

实际上,这个最简单的代码,在没有接触过嵌入式系统的人来说会有点迷惑。我们如果玩裸机编程玩惯了,下意识的情况会选择去直接写中断服务函数。实际上,中断服务函数的作用是再外界的信号来的时候,打断你手头做的事情,去执行它的服务函数,如果该函数的时间很长,则会导致整个程序的其它东西被耽搁。而我们通过全局变量将变量保存后,丢个主循环去处理,则会导致处理的不够及时,整个系统的实时性会变得很差。于是乎,上了嵌入式系统后,我们就结合二者的情况,专门创建一个线程去做。当我们的中断来临的时候,把中断信息打包好,然后交给中断处理的线程去处理这个信息。由于线程之间的并发性,所以不会去耽搁别的线程,这个是不同于裸机的中断编程思维。

总结

gpio总结脑图

相关官方资料链接

gpio例程:https://github.com/espressif/esp-idf/tree/master/examples/peripherals/gpio/generic_gpio
gpio相关api:https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/api-reference/peripherals/gpio.html
freertos相关链接:https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/api-reference/system/freertos.html

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
esp32-freertos-sdk 工具包 See the Getting Started guide links above for a detailed setup guide. This is a quick reference for common commands when working with ESP-IDF projects: Setup Build Environment (See Getting Started guide for a full list of required steps with details.) Install host build dependencies mentioned in Getting Started guide. Add tools/ directory to the PATH Run python -m pip install -r requirements.txt to install Python dependencies Configuring the Project idf.py menuconfig Opens a text-based configuration menu for the project. Use up & down arrow keys to navigate the menu. Use Enter key to go into a submenu, Escape key to go out or to exit. Type ? to see a help screen. Enter key exits the help screen. Use Space key, or Y and N keys to enable (Yes) and disable (No) configuration items with checkboxes "[*]" Pressing ? while highlighting a configuration item displays help about that item. Type / to search the configuration items. Once done configuring, press Escape multiple times to exit and say "Yes" to save the new configuration when prompted. Compiling the Project idf.py build ... will compile app, bootloader and generate a partition table based on the config. Flashing the Project When the build finishes, it will print a command line to use esptool.py to flash the chip. However you can also do this automatically by running: idf.py -p PORT flash Replace PORT with the name of your serial port (like COM3 on Windows, /dev/ttyUSB0 on Linux, or /dev/cu.usbserial-X on MacOS. If the -p option is left out, idf.py flash will try to flash the first available serial port. This will flash the entire project (app, bootloader and partition table) to a new chip. The settings for serial port flashing can be configured with idf.py menuconfig. You don't need to run idf.py build before running idf.py flash, idf.py flash will automatically rebuild anything which needs it. Viewing Serial Output The idf.py monitor target uses the idf_monitor tool to display se
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值