ESP32-S3學習筆記<2>:GPIO的應用

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 休眠當前線程本節?標? 認識多線程? 掌握多線程程序的編寫? 掌握多線程的狀態? 掌握…