ESP32-S3学习笔记<2>:GPIO的应用

  • 1. 头文件包含
  • 2. GPIO的配置
    • 2.1 pin_bit_mask
    • 2.2 mode
    • 2.3 pull_up_en和pull_down_en
    • 2.4 intr_type
  • 3. 设置GPIO输出/获取GPIO输入
  • 4. 中断的使用
    • 4.1 gpio_install_isr_service
    • 4.2 gpio_isr_handler_add
    • 4.3 gpio_intr_enable
    • 4.4 中断服务函数
  • 5. 示例

1. 头文件包含

需要包含以下头文件:

#include "esp_attr.h"
#include "driver/gpio.h"
#include "hal/gpio_types.h"

2. GPIO的配置

使用如下函数配置GPIO:

esp_err_t gpio_config(const gpio_config_t *pGPIOConfig);

配置信息结构体 gpio_config_t 的定义为:

typedef struct {uint64_t pin_bit_mask;          /*!< GPIO pin: set with bit mask, each bit maps to a GPIO */gpio_mode_t mode;               /*!< GPIO mode: set input/output mode                     */gpio_pullup_t pull_up_en;       /*!< GPIO pull-up                                         */gpio_pulldown_t pull_down_en;   /*!< GPIO pull-down                                       */gpio_int_type_t intr_type;      /*!< GPIO interrupt type                                  */
#if SOC_GPIO_SUPPORT_PIN_HYS_FILTERgpio_hys_ctrl_mode_t hys_ctrl_mode;       /*!< GPIO hysteresis: hysteresis filter on slope input    */
#endif
} gpio_config_t;

其中:

2.1 pin_bit_mask

指定要配置的GPIO。需要按位指定GPIO。由于 ESP32-S3 引脚数超过32位,所以用一个64位数表达。正确写法是:

pin_bit_mask = 1ull << GPIO_NUM_1 ;

特别需要注意写法 1ull,指定是 unsigned long long 类型。否则位宽不够,左移32位后就溢出了。

2.2 mode

mode为一枚举类型,定义为:

typedef enum {GPIO_MODE_DISABLE = GPIO_MODE_DEF_DISABLE,  GPIO_MODE_INPUT = GPIO_MODE_DEF_INPUT,     GPIO_MODE_OUTPUT = GPIO_MODE_DEF_OUTPUT,   GPIO_MODE_OUTPUT_OD = ((GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)), GPIO_MODE_INPUT_OUTPUT_OD = ((GPIO_MODE_DEF_INPUT) | (GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)),GPIO_MODE_INPUT_OUTPUT = ((GPIO_MODE_DEF_INPUT) | (GPIO_MODE_DEF_OUTPUT)),   
} gpio_mode_t;

主要选项有:仅输入、仅输出、仅开漏输出、输入输出、带有开漏的输入输出。
需要注意的是,如果配置为仅输出,是没有办法通过后续的 gpio_get_level 函数来获取到GPIO当前的输出值的。某些应用可能需要读取当前输出值(例如翻转一个GPIO,如LED亮/灭切换等),这时就要配置GPIO为输入输出。

2.3 pull_up_en和pull_down_en

指定GPIO的上拉和下拉。可用的选项有:

typedef enum {GPIO_PULLUP_DISABLE = 0x0,     /*!< Disable GPIO pull-up resistor */GPIO_PULLUP_ENABLE = 0x1,      /*!< Enable GPIO pull-up resistor */
} gpio_pullup_t;typedef enum {GPIO_PULLDOWN_DISABLE = 0x0,   /*!< Disable GPIO pull-down resistor */GPIO_PULLDOWN_ENABLE = 0x1,    /*!< Enable GPIO pull-down resistor  */
} gpio_pulldown_t;

2.4 intr_type

中断指定。仅代码控制输入输出的话,可以指定禁用中断。选项有:

typedef enum {GPIO_INTR_DISABLE = 0,     /*!< Disable GPIO interrupt                             */GPIO_INTR_POSEDGE = 1,     /*!< GPIO interrupt type : rising edge                  */GPIO_INTR_NEGEDGE = 2,     /*!< GPIO interrupt type : falling edge                 */GPIO_INTR_ANYEDGE = 3,     /*!< GPIO interrupt type : both rising and falling edge */GPIO_INTR_LOW_LEVEL = 4,   /*!< GPIO interrupt type : input low level trigger      */GPIO_INTR_HIGH_LEVEL = 5,  /*!< GPIO interrupt type : input high level trigger     */GPIO_INTR_MAX,
} gpio_int_type_t;

可用的中断选项有:禁用中断、上升沿中断、下降沿中断、任意边沿中断(上升沿或下降沿)、低电平中断、高电平中断。

3. 设置GPIO输出/获取GPIO输入

以下2个函数,用于设置GPIO输出,或者读取GPIO的输入。

/* 设置输出 */
esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level);/* 获取输入 */
int gpio_get_level(gpio_num_t gpio_num)

这里 gpio_num 不需要像 gpio_config 那样按位设置,直接填写GPIO即可,例如 GPIO_NUM_4level 可以是0或1,表示设置低电平或高电平输出。

4. 中断的使用

使用GPIO的中断,除了在GPIO配置中设置中断类型(上升沿、下降沿、高低电平中断)外,还需要几个步骤:

  1. gpio_install_isr_service ,安装isr服务。这个函数是逐引脚触发中断用的,即后续需要为特定的引脚绑定中断服务函数。此外还有一个函数 gpio_isr_register ,用来为所有的GPIO绑定中断服务函数。也就是说,使用后者时,任意GPIO触发了中断,都会使用同一个通断服务函数。感觉还是前者更常用一些。
  2. gpio_isr_handler_add , 为指定的GPIO添加一个中断服务函数。同时还可以设置一些属性。
  3. gpio_intr_enable ,使能中断。这个函数实测不是必需的。前两个函数应用之后,中断默认使能了(在 gpio_isr_handler_add 函数中)。

4.1 gpio_install_isr_service

此函数安装isr服务。函数本身不指定GPIO。所以即使有多个GPIO需要配置中断,此函数也只调用一次。如果多次调用,运行会报错。

esp_err_t gpio_install_isr_service(int intr_alloc_flags) ;

参数 intr_alloc_flags 有如下这些选项:

#define ESP_INTR_FLAG_LEVEL1        (1<<1)  ///< Accept a Level 1 interrupt vector (lowest priority)
#define ESP_INTR_FLAG_LEVEL2        (1<<2)  ///< Accept a Level 2 interrupt vector
#define ESP_INTR_FLAG_LEVEL3        (1<<3)  ///< Accept a Level 3 interrupt vector
#define ESP_INTR_FLAG_LEVEL4        (1<<4)  ///< Accept a Level 4 interrupt vector
#define ESP_INTR_FLAG_LEVEL5        (1<<5)  ///< Accept a Level 5 interrupt vector
#define ESP_INTR_FLAG_LEVEL6        (1<<6)  ///< Accept a Level 6 interrupt vector
#define ESP_INTR_FLAG_NMI           (1<<7)  ///< Accept a Level 7 interrupt vector (highest priority)
#define ESP_INTR_FLAG_SHARED        (1<<8)  ///< Interrupt can be shared between ISRs
#define ESP_INTR_FLAG_EDGE          (1<<9)  ///< Edge-triggered interrupt
#define ESP_INTR_FLAG_IRAM          (1<<10) ///< ISR can be called if cache is disabled
#define ESP_INTR_FLAG_INTRDISABLED  (1<<11) ///< Return with this interrupt disabled#define ESP_INTR_FLAG_LOWMED    (ESP_INTR_FLAG_LEVEL1|ESP_INTR_FLAG_LEVEL2|ESP_INTR_FLAG_LEVEL3) ///< Low and medium prio interrupts. These can be handled in C.
#define ESP_INTR_FLAG_HIGH      (ESP_INTR_FLAG_LEVEL4|ESP_INTR_FLAG_LEVEL5|ESP_INTR_FLAG_LEVEL6|ESP_INTR_FLAG_NMI) ///< High level interrupts. Need to be handled in assembly.

主要设置中断优先级、边沿中断、是否放在内部指令RAM中等。
需要注意,按照网站上的说法,如果 intr_alloc_flags 中设置了标记 ESP_INTR_FLAG_IRAM,则中断服务函数需要设置属性 IRAM_ATTR 。该属性将中断服务函数放在内部指令RAM中,以提高性能。建议加上。

4.2 gpio_isr_handler_add

此函数为特定的GPIO绑定中断服务函数。

esp_err_t gpio_isr_handler_add(gpio_num_t gpio_num, gpio_isr_t isr_handler, void *args);

第一个参数用来指定GPIO。
第二个参数指定中断服务函数。
第三个参数指定传递给中断服务函数的参数。可以为 NULL

4.3 gpio_intr_enable

此函数使能中断。

esp_err_t gpio_intr_enable(gpio_num_t gpio_num);

实际上,gpio_isr_handler_add 函数中已经有使能代码。实测这个函数也不是必需的。

4.4 中断服务函数

中断服务函数形如:

void IRAM_ATTR __TEST_GPIO_InterruptHandler(void *pvArg)
{__TEST_GPIO_ToggleLED() ;return ;
}

属性 IRAM_ATTR 用于将服务函数放在内部IRAM中,提高性能。

5. 示例

以下例子,配置2个输入GPIO(不带中断的A和带中断的B)和一个输出GPIO。输出GPIO驱动一个LED。输入GPIO,一个配置为单输入,一个配置为中断输入,中断由下降沿触发。
中断触发时,翻转LED的显示状态。
主循环轮询A的输入,如果是低电平,每隔一段时间翻转一次LED。

文件 test_gpio.h

#define TEST_GPIO_LED_GPIO             (GPIO_NUM_1)   /* led control pin                      */
#define TEST_GPIO_INPUT_WITHOUT_INT    (GPIO_NUM_4)   /* input pin with no interrupt          */
#define TEST_GPIO_INPUT_WITH_INT       (GPIO_NUM_0)   /* input pin with interrupt             */void TEST_GPIO_Init(void) ;
void TEST_GPIO_ToggleLED(void) ;
int TEST_GPIO_GetInputGPIOWithoutInt(void) ;

文件 test_gpio.c

#include "esp_attr.h"
#include "driver/gpio.h"
#include "hal/gpio_types.h"#include "test_gpio.h"void __TEST_GPIO_INIT_InitLEDGPIO(void)
{esp_err_t           iRetVal ;const gpio_config_t stGPIOConfig = {.pin_bit_mask = 1ull << TEST_GPIO_LED_GPIO ,.mode         = GPIO_MODE_INPUT_OUTPUT ,.pull_up_en   = GPIO_PULLUP_DISABLE ,.pull_down_en = GPIO_PULLDOWN_DISABLE ,.intr_type    = GPIO_INTR_DISABLE } ;iRetVal = gpio_config(&stGPIOConfig) ;if(ESP_OK != iRetVal){printf("Config LED GPIO error! Return value is %d\n", iRetVal) ;}return ;
}void __TEST_GPIO_ToggleLED(void)
{int iGPIOInputVal ;iGPIOInputVal = gpio_get_level(TEST_GPIO_LED_GPIO) ;if(0 == iGPIOInputVal){gpio_set_level(TEST_GPIO_LED_GPIO, 1) ;}else {gpio_set_level(TEST_GPIO_LED_GPIO, 0) ;}return ;
}void __TEST_GPIO_INIT_InitInputWithNoInt(void)
{esp_err_t           iRetVal ;const gpio_config_t stGPIOConfig = {.pin_bit_mask = 1ull << TEST_GPIO_INPUT_WITHOUT_INT ,.mode         = GPIO_MODE_INPUT ,.pull_up_en   = GPIO_PULLUP_ENABLE ,.pull_down_en = GPIO_PULLDOWN_DISABLE ,.intr_type    = GPIO_INTR_DISABLE } ;iRetVal = gpio_config(&stGPIOConfig) ;if(ESP_OK != iRetVal){printf("Config input GPIO without interrupt error! Return value is %d\n", iRetVal) ;}return ;
}void IRAM_ATTR __TEST_GPIO_InterruptHandler(void *pvArg)
{__TEST_GPIO_ToggleLED() ;return ;
}void __TEST_GPIO_INIT_InitInputWithInt(void)
{esp_err_t           iRetVal ;const gpio_config_t stGPIOConfig = {.pin_bit_mask = 1ull << TEST_GPIO_INPUT_WITH_INT ,.mode         = GPIO_MODE_INPUT ,.pull_up_en   = GPIO_PULLUP_ENABLE ,.pull_down_en = GPIO_PULLDOWN_DISABLE ,.intr_type    = GPIO_INTR_NEGEDGE } ;iRetVal = gpio_config(&stGPIOConfig) ;if(ESP_OK != iRetVal){printf("Config input GPIO with interrupt error! Return value is %d\n", iRetVal) ;}/* GPIO interrupt*/iRetVal = gpio_install_isr_service(ESP_INTR_FLAG_LEVEL1 | ESP_INTR_FLAG_EDGE) ;if(ESP_OK != iRetVal){printf("Install GPIO isr service error! Return value is %d\n", iRetVal) ;}/* add interrupt handler */gpio_isr_handler_add(TEST_GPIO_INPUT_WITH_INT, __TEST_GPIO_InterruptHandler, NULL);/* enable interrupt *///gpio_intr_enable(TEST_GPIO_INPUT_WITH_INT) ;return ;
}void TEST_GPIO_Init(void)
{/* config all GPIOs */__TEST_GPIO_INIT_InitLEDGPIO() ;__TEST_GPIO_INIT_InitInputWithNoInt() ;__TEST_GPIO_INIT_InitInputWithInt() ;
}void TEST_GPIO_ToggleLED(void)
{__TEST_GPIO_ToggleLED() ;
}int TEST_GPIO_GetInputGPIOWithoutInt(void)
{return gpio_get_level(TEST_GPIO_INPUT_WITHOUT_INT) ;
}

文件 main.c

#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"#include "test_gpio.h"void app_main(void)
{int iGPIOInputVal ;TEST_GPIO_Init() ;while (true){iGPIOInputVal = TEST_GPIO_GetInputGPIOWithoutInt() ;if(0 == iGPIOInputVal){TEST_GPIO_ToggleLED() ;}vTaskDelay(500) ;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/915604.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/915604.shtml
英文地址,请注明出处:http://en.pswp.cn/news/915604.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

得物视觉算法面试30问全景精解

得物视觉算法面试30问全景精解 ——潮流电商 商品鉴别 视觉智能&#xff1a;得物视觉算法面试核心考点全览 前言 得物App作为中国领先的潮流电商与鉴别平台&#xff0c;持续推动商品识别、真假鉴别、图像搜索、内容审核、智能推荐等视觉AI技术的创新与落地。得物视觉算法岗位…

[Linux入门] Linux 账号和权限管理入门:从基础到实践

一、Linux 用户账号&#xff1a;谁能访问系统&#xff1f; 1️⃣超级用户&#xff08;root&#xff09; 2️⃣普通用户 3️⃣程序用户 二、组账号&#xff1a;让用户管理更高效 1️⃣组的类型 2️⃣特殊组 三、用户与组的 “身份证”&#xff1a;UID 和 GID 四、配置文…

阿里云ssl证书自动安装及续订(acme)

目录 一、shell命令安装 二、docker run安装 三、docker compose安装 一、shell命令安装 # 安装acme curl https://get.acme.sh | sh -s emailfloxxx5163.com# 注册zerossl .acme.sh/acme.sh --register-account -m flowxxx25163.com --server zerossl# 获取证书 export Al…

@fullcalendar/vue 日历组件

功能&#xff1a;日程安排&#xff0c;展示日历&#xff0c;可以用来做会议日历&#xff0c;可以跨日期显示日程。 Fullcalendarvue3 日历组件 参考文档&#xff1a;【vue2】一个完整的日历组件 fullcalendar&#xff0c;会议预约功能 中文说明文档&#xff1a;https://www.he…

Dijkstra 算法求解多种操作

一、问题背景与核心需求 需要找到从a到b的最优操作序列&#xff0c;使得总花费最小。三种操作的规则为&#xff1a; 操作 1&#xff1a;x → x1&#xff0c;花费c1&#xff1b;操作 2&#xff1a;x → x-1&#xff0c;花费c2&#xff1b;操作 3&#xff1a;x → x*2&#xff0…

本地项目提交到git教程

创建远程仓库 登录 GitHub&#xff0c;点击右上角 New repository。 填写仓库名称&#xff08;如 my-project&#xff09;、描述&#xff0c;选择公开 / 私有。 不要初始化 README、.gitignore 或 LICENSE&#xff08;保持空仓库&#xff09;&#xff0c;点击 Create repositor…

Linux 密码生成利器:pwgen 命令详解

往期好文&#xff1a;统信 UOS 运行 Windows 应用新利器&#xff01;彩虹虚拟化软件 V3.2 全新上线&#xff0c;限时30天免费体验 在日常运维、安全测试、用户管理等场景中&#xff0c;随机密码的生成是一项常见需求。为了避免人工设置密码带来的重复性弱密码问题&#xff0c;…

Qt 应用程序入口代码分析

Qt 应用程序入口代码分析 这段代码是 Qt GUI 应用程序的标准入口点&#xff0c;相当于 Qt 程序的"心脏"。让我详细解释每一部分的作用&#xff1a; int main(int argc, char *argv[]) {// 1. 创建 Qt 应用程序对象QApplication a(argc, argv);// 2. 创建主窗口对象Wi…

基于springboot+mysql的中小型医院网站(源码+论文+开题报告)

一、开发环境 Java技术 描述&#xff1a;Java是一种非常常用的编程语言&#xff0c;在全球编程语言排行榜上总是前三。Java的跨平台能力十分强大&#xff0c;只需一次编译&#xff0c;任何地方都可以运行。除此之外&#xff0c;它还拥有简单的语法和实用的类库&#xff0c;让…

【Docker基础】Docker-compose常用命令实践(三):镜像与配置管理

目录 前言 1 镜像与配置管理概述 1.1 核心概念解析 2 镜像构建命令详解 2.1 构建镜像&#xff08;build命令&#xff09; 2.2 基本语法 2.3 常用选项 2.4 构建过程流程 2.5 实际应用案例 3 配置验证命令详解 3.1 验证配置&#xff08;config命令&#xff09; 3.2 基…

Android 实例 - 分页器封装实现(上一页按钮、下一页按钮、当前页码 / 总页数、每页条数、总记录数)

一、需求分页器需要包含&#xff1a;【上一页按钮】、【下一页按钮】、【当前页码 / 总页数】、【每页条数】、【总记录数】点击【上一页按钮】&#xff0c;渲染上一页的数据&#xff0c;如果当前页码为第一页&#xff0c;则禁用【上一页按钮】点击【下一页按钮】&#xff0c;渲…

从代码学习深度强化学习 - SAC PyTorch版

文章目录 前言 SAC处理连续动作空间问题 (Pendulum-v1) 核心代码实现 **工具函数与环境初始化** **ReplayBuffer、网络结构与SAC算法** **训练与结果** SAC处理离散动作空间问题 (CartPole-v1) 核心代码实现 **工具函数与环境初始化** **ReplayBuffer、网络结构与SAC算法 (离散…

物联网安装调试-温湿度传感器

以下为温湿度传感器在物联网安装调试中的全流程技术指南,涵盖选型、安装、调试及故障排查,结合工业/农业/家居三大场景实操要点: 一、传感器选型核心参数表 参数 工业场景 农业大棚 智能家居 选型建议 精度 0.5℃/1.5%RH 1℃/3%RH 1℃/5%RH 工业级首选Sensirion SHT3x系列 防…

MySQL 核心知识点梳理(1)

目录 1.什么是数据库? 关系型数据库 非关系型数据库 2.Mysql出现性能差的原因? 3.MySQL的内联,左外联,右外连接的区别 4.为什么要有三大范式 建表需要考虑的问题? char和varchar的区别 blob和text的区别? DATETIME和TIMESTAMP的区别 in和exists的区别 null值陷 …

Word快速文本对齐程序开发经验:从需求分析到实现部署

在日常办公中&#xff0c;文档排版是一项常见但耗时的工作&#xff0c;尤其是当需要处理大量文本并保持格式一致时。Microsoft Word作为最流行的文档处理软件之一&#xff0c;虽然提供了丰富的排版功能&#xff0c;但在处理复杂的文本对齐需求时&#xff0c;往往需要重复执行多…

力扣面试150(34/150)

7.20 242. 有效的字母异位词 给定两个字符串 s 和 t &#xff0c;编写一个函数来判断 t 是否是 s 的 字母异位词 我的思路&#xff1a; 遍历s到一个sMap&#xff0c;字母次数的方式遍历t&#xff0c;判断t中的char是否在sMap当中&#xff0c;如果在的话次数-1&#xff0c;判…

软件工程:可行性分析的任务及报告

简介 本博客围绕软件工程中的第一关——“可行性分析的任务及报告”展开&#xff0c;详细解析了可行性分析的基本概念、分析任务、四类可行性&#xff08;技术、经济、操作、社会&#xff09;以及可行性分析报告的结构与撰写要点。通过丰富的理论基础与图示支持&#xff0c;帮…

STM32与树莓派通信

STM32 与树莓派&#xff08;Raspberry Pi&#xff09;的通信常见方案及实现步骤&#xff1a;1. UART 串口通信&#xff08;最简单&#xff09;适用场景&#xff1a;短距离、低速数据交换&#xff08;如传感器数据、调试信息&#xff09;。 硬件连接&#xff1a;STM32引脚树莓派…

【NLP舆情分析】基于python微博舆情分析可视化系统(flask+pandas+echarts) 视频教程 - 数据持久化到Mysql

大家好&#xff0c;我是java1234_小锋老师&#xff0c;最近写了一套【NLP舆情分析】基于python微博舆情分析可视化系统(flaskpandasecharts)视频教程&#xff0c;持续更新中&#xff0c;计划月底更新完&#xff0c;感谢支持。今天讲解数据持久化到Mysql 视频在线地址&#xff…

【Java EE】多线程-初阶-Thread 类及常见方法

多线程-初阶2. Thread 类及常⻅⽅法2.1 Thread 的常⻅构造⽅法2.2 Thread 的⼏个常⻅属性2.3 启动⼀个线程 - start()2.4 中断⼀个线程2.5 等待⼀个线程 - join()2.6 获取当前线程引⽤2.7 休眠当前线程本节⽬标• 认识多线程• 掌握多线程程序的编写• 掌握多线程的状态• 掌握…