ESP32——基于idf框架开发GPIO设备
文章目录
- 一、sourceinsight使用smaba访问esp-idf工程
- 二、编译烧写led闪灯示例
- 三、GPIO硬件原理
- 3.1 什么是GPIO
- 3.2 GPIO 用途
- 四、GPIO控制器
- 4.1 什么是控制器
- 4.2 ESP32-C3 GPIO硬件特性
- 4.3 获取开发板GPIO设备对应引脚编号
- 4.3.1 查看开发板底板获取都有那些GPIO设备
- 4.3.2 查看ESP32-C3-DevKit核心板确定引脚编
- 4.3.3 查看CPU芯片手册确定引脚编号
- 五、基于ESP-IDF进行GPIO开发
- 5.1 ESP-IDF的常用GPIO函数
- 5.1.1 IOMUX功能配置等函数
- 5.1.2 GPIO操作的相关函数
- 5.2 操作一个GPIO设备
- 5.2.1 配置为输出模式
- 5.2.2 配置为输入模式
- 5.2.3 配置为中断模式
- 5.3 使用gpio config配置GPIO
- 5.3.1 配置输出模式
- 5.3.2 配置输入模式
- 5.3.3 配置为中断模式
- 5.4 扩展示例
- 5.4.1 使用GPIO控制直流电机风扇旋转
- 5.4.2 使用GPIO控制三盏LED灯实现流水灯效果
- 5.4.3 使用GPIO按键控制GPIO LED灯亮灭
- 5.4.4 使用FreeRTOS实现按键中断
- 5.4.5 按键控制风扇转动以及灯亮灭
一、sourceinsight使用smaba访问esp-idf工程
我这里使用的是sourceinsight4.0版本,我们首先需要在电脑上映射一个unubtu的网络磁盘:
- 查看ubuntu的ip地址
- 在此电脑处添加网络驱动器
- 我这里是之前已经创建好的,可以进去查看文件目录,跟ubuntu一致
- 新建一个sourceinsight工程
- 代码源地址选择创建好的网络磁盘
后面选中需要的文件和文件夹即可,同时去同步解析源码间的调用关系,工程完成创建:
二、编译烧写led闪灯示例
找到我们事先写好的 blink
文件夹,将其放到 esp
目录下:
打印一下 blink.c
查看里面的其他要求:(提示了要去 idf.py menuconfig
图形界面下配置某些引脚)
对芯片进行配置:
输入 idf.py menuconfig
进入配置,输入 /
出现跳转选项,输入 blink
即可找到引脚配置,将其设置为8:
输入 idf.py build
编译工程:
输入 esptool.py -p /dev/ttyUSB0 -b 460800 --before default_reset --after hard_reset --chip esp32c3 write_flash --flash_mode dio --flash_size detect --flash_freq 80m 0x0 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/blink.bin
将程序烧录到开发板上:
烧录完之后LED常亮。
三、GPIO硬件原理
3.1 什么是GPIO
通用输入/输出(GPIO) 是一个数字信号管脚的集成电路,其可被用作输入或输出,GPIO 没有预定义用途。如果使用,GPIO 的用途和行为由电路的设计者定义和实现。
3.2 GPIO 用途
GPIO 用于各种应用,限于 GPIO 接口的电气和时序规范以及软件与 GPIO 及时交互的能力的限制。
GPIO 通常采用标准逻辑电平,不能为输出负载提供大量电流。当后面跟适当的大电流输出缓冲器(或机械或固态继电器)时,GPIO才可用于控制大功率设备,例如灯、螺线管、加热器和电机(如风扇和鼓风机)。类似地,输入缓冲器、继电器或光隔离器通常用于将不兼容的信号(例如,高电压)转换为 GPIO 所需的逻辑电平。
四、GPIO控制器
4.1 什么是控制器
控制器(controller)是依据传感器信号,调整发送至状况的装置。举例来说,屋内的空调系统是一个驱动器的输出信号,用以改变受控体(plant)温度控制器,她可以依据温度计测量的气温,来调整冷气机强度,以达到一个舒适的环境温度。
4.2 ESP32-C3 GPIO硬件特性
ESP32-C3 系列共有22个GPIO管脚,通过配置对应的寄存器,可以为这些管脚分配不同的功能。除作为数字信号管脚外,部分GPIO管脚也可配置为模拟功能管脚,比如ADC等管脚。
所有GPIO都可选择内部上拉/下拉,或设置为高阻。GPIO配置为输入管脚时,可通过读取寄存器获取其输入值。输入管脚也可经设置产生边缘触发或电平触发的CPU中断。数字IO管脚都是双向、非反相和三态的,包括带有三态控制的输入和输出缓冲器。这些管脚可以复用作其他功能,例如UART、SPI等。当芯片低功耗运行时,GPIO可设定为保持状态。
IOMUX和GPIO交换矩阵用于将信号从外设传输至GPIO管脚。两者共同组成了芯片的IO控制。利用GPIO交换矩阵,可配置外设模块的输入信号来源于任何的IO管脚,并且外设模块的输出信号也可连接到任意IO管脚。下图列出了所有GPIO管脚的IOMUX功能。
每个管脚复位后的默认配置:
- 0-输入关闭,高阻(IE=0)
- 1-输入使能,高阻(IE=1)
- 2-输入使能,下拉电阻使能(IE=1,WPD=1)
- 3-输入使能,上拉电阻使能(IE=1,WPU=1)
- 4-输出使能,上拉电阻使能(OE=1,WPU=1)
- 0*-输入关闭,上拉电阻使能(IE=0,WPU=0,USB_WPU=1),具体见说明
- 1*-eFuse的EFUSE_DIS_PAD_JTAG位为0时(初始默认值),管脚复位后输入使能,上拉电阻使能(IE=1,WPU=1)1 时,管脚复位后输入使能,高阻(IE=1)
建议对处于高阻态的管脚配置上拉或下拉,以避免不必要的耗电。
4.3 获取开发板GPIO设备对应引脚编号
4.3.1 查看开发板底板获取都有那些GPIO设备
查看 ESP32_Extend_V2.pdf 百问网独家底板原理图文件,可以看到如下图所示红框内的这几个引脚标号 都是GPIO设备。
通过搜索可以看到这些引脚都连接到了 ESP32连接排座 ,其中ESP32连接排座又连接至了核心板的两排接口处,可以参考下表对应一下。
4.3.2 查看ESP32-C3-DevKit核心板确定引脚编
获取信息页面:https://docs.espressif.com/projects/esp-dev-kits/zh_CN/latest/esp32c3/esp32-c3-devkitc-02/index.html#id21
也可以打开 SCH_ESP32-C3-DEVKITC-02_V1_1_20210126A.pdf 原理图文件,来确认那几个GPIO引脚连接到了模组那些引脚上。
继续阅读模组手册 esp32-c3-wroom-02_datasheet_cn.pdf 来确认接到了CPU上具体引脚。
4.3.3 查看CPU芯片手册确定引脚编号
参考 esp32-c3_datasheet_cn.pdf 手册具体名称为 ESP32-C3 系列芯片技术规格书V1.0
五、基于ESP-IDF进行GPIO开发
5.1 ESP-IDF的常用GPIO函数
参考网址:https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32c3/api-reference/peripherals/gpio.html
5.1.1 IOMUX功能配置等函数
参考文件 esp-idf\components\esp_rom\include\esp32c3\rom\gpio.h
/*** @brief 配置某个引脚为GPIO功能** @param uint32_t gpio_num : gpio number, 0~0x27** @return None*/
void gpio_pad_select_gpio(uint8_t gpio_num);
5.1.2 GPIO操作的相关函数
参考文件 esp-idf\components\driver\include\driver\gpio.h
/*** @brief 配置 GPIO 通用参数** 配置 GPIO 的工作模式、上拉/下拉电阻以及中断触发类型** @param pGPIOConfig 指向 GPIO 配置结构体的指针** @return* - ESP_OK 配置成功* - ESP_ERR_INVALID_ARG 参数错误*/
esp_err_t gpio_config(const gpio_config_t *pGPIOConfig);/*** @brief 将 GPIO 重置为默认状态(选择 GPIO 功能,启用上拉,禁用输入和输出)** @param gpio_num GPIO 编号** @note 此函数还会将该引脚的 IOMUX 配置为 GPIO 功能,* 并断开通过 GPIO 矩阵配置的任何其他外设输出** @return 始终返回 ESP_OK*/
esp_err_t gpio_reset_pin(gpio_num_t gpio_num);/*** @brief 设置 GPIO 中断触发类型** @param gpio_num GPIO 编号。例如,若要设置 GPIO16 的触发类型,* 则 gpio_num 应为 GPIO_NUM_16 (16)* @param intr_type 中断触发类型,从 gpio_int_type_t 中选择** @return* - ESP_OK 成功* - ESP_ERR_INVALID_ARG 参数错误*/
esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type);/*** @brief 设置 GPIO 输出电平** @param gpio_num GPIO 编号。例如,若要设置 GPIO16 的输出电平,* 则 gpio_num 应为 GPIO_NUM_16 (16)* @param level 输出电平。0: 低电平; 1: 高电平** @return* - ESP_OK 成功* - ESP_ERR_INVALID_ARG GPIO 编号错误*/
esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level);/*** @brief 获取 GPIO 输入电平** @warning 如果该引脚未配置为输入(或输入输出)模式,返回值始终为 0** @param gpio_num GPIO 编号。例如,若要获取 GPIO16 的逻辑电平,* 则 gpio_num 应为 GPIO_NUM_16 (16)** @return* - 0 GPIO 输入电平为 0* - 1 GPIO 输入电平为 1*/
int gpio_get_level(gpio_num_t gpio_num);/*** @brief 设置 GPIO 方向** 配置 GPIO 的方向,如仅输出、仅输入、输入输出双向** @param gpio_num 配置的 GPIO 引脚编号。例如,若要设置 GPIO16 的方向,* 则 gpio_num 应为 GPIO_NUM_16 (16)* @param mode GPIO 方向模式** @return* - ESP_OK 成功* - ESP_ERR_INVALID_ARG GPIO 错误*/
esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode);/*** @brief 启用 GPIO 上拉电阻** @param gpio_num GPIO 编号** @return* - ESP_OK 成功* - ESP_ERR_INVALID_ARG 参数错误*/
esp_err_t gpio_pullup_en(gpio_num_t gpio_num);/*** @brief 禁用 GPIO 上拉电阻** @param gpio_num GPIO 编号** @return* - ESP_OK 成功* - ESP_ERR_INVALID_ARG 参数错误*/
esp_err_t gpio_pullup_dis(gpio_num_t gpio_num);/*** @brief 启用 GPIO 下拉电阻** @param gpio_num GPIO 编号** @return* - ESP_OK 成功* - ESP_ERR_INVALID_ARG 参数错误*/
esp_err_t gpio_pulldown_en(gpio_num_t gpio_num);/*** @brief 禁用 GPIO 下拉电阻** @param gpio_num GPIO 编号** @return* - ESP_OK 成功* - ESP_ERR_INVALID_ARG 参数错误*/
esp_err_t gpio_pulldown_dis(gpio_num_t gpio_num);/*** @brief 安装驱动的 GPIO 中断服务程序,支持为每个引脚设置独立的中断处理函数** 此函数与 gpio_isr_register() 不兼容 - 如果使用了 gpio_isr_register(),* 则为所有 GPIO 中断注册一个全局中断处理函数;如果使用此函数,* 中断服务程序会提供一个全局 GPIO 中断处理函数,* 并通过 gpio_isr_handler_add() 函数注册各个引脚的处理函数** @param intr_alloc_flags 用于分配中断的标志。可以是一个或多个标志的按位或** @return* - ESP_OK 成功* - ESP_ERR_NO_MEM 没有足够内存安装此服务* - ESP_ERR_INVALID_STATE 中断服务已安装* - ESP_ERR_NOT_FOUND 未找到符合指定标志的空闲中断* - ESP_ERR_INVALID_ARG GPIO 错误*/
esp_err_t gpio_install_isr_service(int intr_alloc_flags);/*** @brief 卸载驱动的 GPIO 中断服务程序,释放相关资源*/
void gpio_uninstall_isr_service(void);/*** @brief 为相应的 GPIO 引脚添加中断处理函数** 在使用 gpio_install_isr_service() 安装驱动的 GPIO 中断服务程序后调用此函数** 引脚中断处理函数不再需要声明为 IRAM_ATTR,* 除非在 gpio_install_isr_service() 分配中断时传递了 ESP_INTR_FLAG_IRAM 标志** 此中断处理函数将从中断服务程序中调用,因此存在堆栈大小限制* (可在 menuconfig 中配置为 "ISR 堆栈大小")* 由于额外的间接调用层级,此限制比全局 GPIO 中断处理函数的限制更小** @param gpio_num GPIO 编号* @param isr_handler 对应 GPIO 编号的中断处理函数* @param args 传递给中断处理函数的参数** @return* - ESP_OK 成功* - ESP_ERR_INVALID_STATE 状态错误,中断服务未初始化* - ESP_ERR_INVALID_ARG 参数错误*/
esp_err_t gpio_isr_handler_add(gpio_num_t gpio_num, gpio_isr_t isr_handler, void *args);/*** @brief 移除相应 GPIO 引脚的中断处理函数** @param gpio_num GPIO 编号** @return* - ESP_OK 成功* - ESP_ERR_INVALID_STATE 状态错误,中断服务未初始化* - ESP_ERR_INVALID_ARG 参数错误*/
esp_err_t gpio_isr_handler_remove(gpio_num_t gpio_num);
5.2 操作一个GPIO设备
- 硬件&手册资源准备
- 准备好开发板硬件以及GPIO模块 并连接成功
- 提前下载好GPIO模块配套的原理图芯片手册等资料
- 提前准备好CPU开发板配套的原理图 芯片手册等资料
- 基础知识
- 了解GPIO硬件通信原理
- 清楚GPIO模块与CPU引脚连接编号
- 熟悉ESP-IDF GPIO SDK开发介绍
5.2.1 配置为输出模式
GPIO配置输出模式流程图
点亮白色LED灯:
#include <stdio.h>#include <unistd.h>
#include "driver/gpio.h"#define WHITE_LED 5 //LED灯引脚为5void app_main(void)
{gpio_reset_pin(WHITE_LED); // 复位引脚gpio_pad_select_gpio(WHITE_LED); // 设置引脚为GPIO功能gpio_set_direction(WHITE_LED, GPIO_MODE_OUTPUT); // 设置该引脚为输出模式int on = 0;while (1){on = !on;gpio_set_level(WHITE_LED, on); //设置引脚电平sleep(1);}
}
设置环境变量:
get_idf
设置芯片为 esp32c3:
idf.py set-target esp32c3
编译命令:
idf.py build
烧写(两种方法):
esptool.py -p /dev/ttyUSB0 -b 460800 --before default_reset --after hard_reset --chip esp32c3 write_flash --flash_mode dio -- flash_size detect --flash_freq 80m 0x0 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/blink.bin
idf.py -p /dev/ttyUSB0 flash
此时板子上白色LED开始闪烁。
监控:
idf.py -p /dev/ttyUSB0 monitor
5.2.2 配置为输入模式
对于输入模式,我们需要设置为上拉模式或者下拉模式:
- PULLUP&PULLDOWN针对输入模式,比如我们一个单片机的I / O脚接一个按键的左端,按键的右端接正电源,那么我们就要设置I / O脚为下拉模式,因为这样才能使得按键按下去的时候,能把I / O脚拉高,不然设置上拉模式的话,即按键的功能等于摆设。同理,如果按键另一端接地,我们就要设置为上拉模式了。
- 按键默认情况下是低电平,那么如何区分按键按下或者松开 ? 此时需要高低电平的变化 也就是需要GPIO内部作为输入时 需要有一个上拉电阻 来区分按键按下与松开,当按键按下时,是由高变低也就是低电平;松开时,由低变高也就是高电平。
#include <stdio.h>
#include <unistd.h>
#include "driver/gpio.h"#define KEY1_BUTTON 18 // 开发板Key1为GPIO19void app_main()
{gpio_pad_select_gpio(KEY1_BUTTON); // 设置引脚为GPIO功能gpio_set_direction(KEY1_BUTTON, GPIO_MODE_INPUT); //设置KEY1引脚为输入功能//gpio_pulldown_en(KEY1_BUTTON);//启用下拉电阻gpio_pullup_en(KEY1_BUTTON); // 启用上拉电阻(默认高电平)//gpio_pullup_dis(KEY1_BUTTON); // 禁用上拉电阻gpio_pulldown_dis(KEY1_BUTTON); // 禁用下拉电阻while (true){// 读取GPIO电平状态(0=低电平,1=高电平)int level = gpio_get_level(KEY1_BUTTON);printf("Key1 status %d\n\r",level);sleep(1);}
}
设置环境变量:
get_idf
设置芯片为 esp32c3:
idf.py set-target esp32c3
编译命令:
idf.py build
烧写(两种方法):
esptool.py -p /dev/ttyUSB0 -b 460800 --before default_reset --after hard_reset --chip esp32c3 write_flash --flash_mode dio -- flash_size detect --flash_freq 80m 0x0 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/blink.bin
idf.py -p /dev/ttyUSB0 flash
监控:
idf.py -p /dev/ttyUSB0 monitor
按键按下时,key1 status=0,松开后key1 status=1。
5.2.3 配置为中断模式
中断讲解:
- 取个场景解释中断。假设有个大房间里面有小房间,婴儿正在睡觉,他的妈妈在外面看书。
- 问:这个母亲怎么才能知道这个小孩醒?
- 方法1:过一会打开一次房门,看婴儿是否睡醒,让后接着看书
- 方法2: 一直等到婴儿发出声音以后再过去查看,期间都在读书
第一种 叫做查询方式:
- 优点:简单 缺点: 累
程序中会这样体现:
while(1)
{1 read book(读书)2 open door(开门)if(睡)return(read book)else照顾小孩
}
第二种叫中断方式:
- 优点:不累 缺点:复杂
程序中应该这样体现:
中断服务程序()
{照顾小孩....
}main()
{register_irq(中断服务程序);while (1){read book; // 读书过程中被哭声打断,就去照顾小孩}
}
GPIO中断操作流程
配置按键中断为双边沿出发方式来打印按键值:
#include <stdio.h>
#include "driver/gpio.h"
#include "esp_rom_sys.h"#define KEY1_BUTTON 18 // 定义按键连接的GPIO引脚号// 定义GPIO中断服务函数的参数结构体
typedef struct {int gpio_num; // GPIO引脚编号int isr_cnt; // 中断触发计数器
} gpio_isr_param_t;static void gpio_isr_handler(void* arg)
{// 将参数转换为结构体指针gpio_isr_param_t *param = (gpio_isr_param_t *)arg;// 打印触发中断的GPIO引脚号及其当前电平esp_rom_printf("GPIO[%d] intr, val: %d\n", param->gpio_num, gpio_get_level(param->gpio_num));// 中断计数器递增param->isr_cnt++;
}void app_main()
{static gpio_isr_param_t io18_param = {.gpio_num = KEY1_BUTTON, // 配置为KEY1_BUTTON对应的引脚.isr_cnt = 0, // 初始化中断计数为0};gpio_pad_select_gpio(KEY1_BUTTON); // 选择GPIO引脚gpio_set_direction(KEY1_BUTTON, GPIO_MODE_INPUT); // 设置为输入模式gpio_pulldown_dis(KEY1_BUTTON); // 禁用下拉电阻gpio_pullup_en(KEY1_BUTTON); // 启用上拉电阻gpio_set_intr_type(KEY1_BUTTON, GPIO_INTR_ANYEDGE); // 配置中断触发方式为任意边沿触发(上升沿+下降沿)// 安装GPIO中断服务// 注意:ESP32中必须先调用此函数才能注册具体引脚的中断处理函数gpio_install_isr_service(0);// 为指定GPIO引脚添加中断处理函数gpio_isr_handler_add(KEY1_BUTTON, gpio_isr_handler, (void *)&io18_param);
}
设置环境变量:
get_idf
设置芯片为 esp32c3:
idf.py set-target esp32c3
编译命令:
idf.py build
烧写(两种方法):
esptool.py -p /dev/ttyUSB0 -b 460800 --before default_reset --after hard_reset --chip esp32c3 write_flash --flash_mode dio -- flash_size detect --flash_freq 80m 0x0 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/blink.bin
idf.py -p /dev/ttyUSB0 flash
监控:
idf.py -p /dev/ttyUSB0 monitor
5.3 使用gpio config配置GPIO
5.3.1 配置输出模式
点亮 白色LED1:
#include <stdio.h>
#include <unistd.h>
#include "driver/gpio.h"// 定义白色LED连接的GPIO引脚
#define WHITE_LED 5void app_main(void)
{// 定义GPIO配置结构体gpio_config_t io_conf;// 配置项1:禁用GPIO中断(不使用中断,仅通过轮询控制)io_conf.intr_type = GPIO_INTR_DISABLE;// 配置项2:设置GPIO为输出模式io_conf.mode = GPIO_MODE_OUTPUT;// 配置项3:设置要配置的GPIO引脚位掩码(使用位移操作指定引脚)io_conf.pin_bit_mask = (1ULL << WHITE_LED);// 配置项4:禁用下拉电阻(确保无下拉影响)io_conf.pull_down_en = 0;// 配置项5:禁用上拉电阻(输出模式通常不需要上拉/下拉)io_conf.pull_up_en = 0;// 将上述配置应用到GPIO控制器gpio_config(&io_conf);// LED状态变量(0=灭,1=亮)int on = 0;// 无限循环:实现LED闪烁效果while (1){// 切换LED状态(亮→灭 或 灭→亮)on = !on;// 设置GPIO输出电平gpio_set_level(WHITE_LED, on);// 延时1秒(注意:此处使用标准库sleep,在ESP32中建议使用vTaskDelay)sleep(1);}
}
设置环境变量:
get_idf
设置芯片为 esp32c3:
idf.py set-target esp32c3
编译命令:
idf.py build
烧写(两种方法):
esptool.py -p /dev/ttyUSB0 -b 460800 --before default_reset --after hard_reset --chip esp32c3 write_flash --flash_mode dio -- flash_size detect --flash_freq 80m 0x0 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/blink.bin
idf.py -p /dev/ttyUSB0 flash
烧写后白色LED灯不断闪烁。
监控:
idf.py -p /dev/ttyUSB0 monitor
5.3.2 配置输入模式
配置为输入模式 设置为双边沿触发 并打印按键状态。
#include <stdio.h>
#include <unistd.h>
#include "driver/gpio.h"// 定义按键连接的GPIO引脚号
#define KEY1_BUTTON 18void app_main(void)
{// 定义GPIO配置结构体gpio_config_t io_conf;// 配置项1:禁用GPIO中断(使用轮询方式检测按键)io_conf.intr_type = GPIO_INTR_DISABLE;// 配置项2:设置GPIO模式为输入模式io_conf.mode = GPIO_MODE_INPUT;// 配置项3:设置要配置的GPIO引脚位掩码(使用位移操作指定引脚)io_conf.pin_bit_mask = (1ULL << KEY1_BUTTON);// 配置项4:禁用下拉电阻(确保无下拉影响)io_conf.pull_down_en = 0;// 配置项5:启用上拉电阻(使引脚在无输入时保持高电平)io_conf.pull_up_en = 1;// 将上述配置应用到GPIO控制器gpio_config(&io_conf);// 无限循环:持续检测并打印按键状态while (1){// 读取当前GPIO引脚电平(0=低电平,1=高电平)int level = gpio_get_level(KEY1_BUTTON);// 打印按键状态(\n\r组合确保在不同终端上正确换行)printf("Key1 status %d\n\r", level);// 延时1秒(注意:此处使用标准库sleep,在ESP32中建议使用vTaskDelay)sleep(1);}
}
设置环境变量:
get_idf
设置芯片为 esp32c3:
idf.py set-target esp32c3
编译命令:
idf.py build
烧写(两种方法):
esptool.py -p /dev/ttyUSB0 -b 460800 --before default_reset --after hard_reset --chip esp32c3 write_flash --flash_mode dio -- flash_size detect --flash_freq 80m 0x0 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/blink.bin
idf.py -p /dev/ttyUSB0 flash
监控:
idf.py -p /dev/ttyUSB0 monitor
5.3.3 配置为中断模式
#include <stdio.h>
#include "driver/gpio.h"
#include "esp_rom_sys.h"// 定义按键连接的GPIO引脚号
#define KEY1_BUTTON 18// 定义GPIO中断服务函数的参数结构体
typedef struct {int gpio_num; // GPIO引脚编号int isr_cnt; // 中断触发计数器
} gpio_isr_param_t;static void gpio_isr_handler(void* arg)
{// 将参数转换为结构体指针gpio_isr_param_t *param = (gpio_isr_param_t *)arg;// 打印触发中断的GPIO引脚号及其当前电平esp_rom_printf("GPIO[%d] intr, val: %d\n", param->gpio_num, gpio_get_level(param->gpio_num));// 中断计数器递增param->isr_cnt++;
}/*** 应用程序主入口函数*/
void app_main()
{// 静态初始化GPIO参数结构体static gpio_isr_param_t io18_param = {.gpio_num = KEY1_BUTTON, // 配置为KEY1_BUTTON对应的引脚.isr_cnt = 0, // 初始化中断计数为0};// 定义GPIO配置结构体gpio_config_t config;// 配置中断触发类型为双边沿触发(上升沿和下降沿都触发)config.intr_type = GPIO_INTR_ANYEDGE;// 配置GPIO为输入模式config.mode = GPIO_MODE_INPUT;// 禁用下拉电阻(确保无下拉影响)config.pull_down_en = false;// 启用上拉电阻(使引脚在无输入时保持高电平)config.pull_up_en = true;// 设置要配置的GPIO引脚位掩码(使用位移操作指定引脚)config.pin_bit_mask = (1ULL<<KEY1_BUTTON);// 将上述配置应用到GPIO控制器gpio_config(&config);// 安装GPIO中断服务(必须先调用此函数才能注册具体引脚的中断处理函数)// 参数0表示使用默认配置gpio_install_isr_service(0);// 为指定GPIO引脚添加中断处理函数// 参数1:GPIO引脚号// 参数2:中断处理函数指针// 参数3:传递给中断处理函数的参数gpio_isr_handler_add(KEY1_BUTTON, gpio_isr_handler, (void *)&io18_param);// 主函数执行完毕后,系统进入后台运行,中断服务函数会在触发时自动执行
}
设置环境变量:
get_idf
设置芯片为 esp32c3:
idf.py set-target esp32c3
编译命令:
idf.py build
烧写(两种方法):
esptool.py -p /dev/ttyUSB0 -b 460800 --before default_reset --after hard_reset --chip esp32c3 write_flash --flash_mode dio -- flash_size detect --flash_freq 80m 0x0 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/blink.bin
idf.py -p /dev/ttyUSB0 flash
监控:
idf.py -p /dev/ttyUSB0 monitor
5.4 扩展示例
5.4.1 使用GPIO控制直流电机风扇旋转
- 功能特点:
- 产品尺寸:50x27x13mm
- 螺旋桨直径:75mm
- 工作电压:5V
- L9110驱动,可控制正反转配有安装孔,兼容舵机舵盘控制优质螺旋桨,效率高。可轻松吹灭20cm外的打火机火焰可用于救火机器人的制作,机器人设计开发必备
- 模块的VCC接5V, GND接GND,INA接数字接口GPIO1,INB接数字接口GPIO0 其中控制风扇转动方式请参考下述表格。
注意: 一定要先断开电源再接 风扇模块 否则会导致 开发板芯片损坏。
#include <stdio.h>
#include <unistd.h>
#include "driver/gpio.h"// 定义电机控制引脚
#define MOTOR_INA 1 // 电机方向控制引脚A
#define MOTOR_INB 0 // 电机方向控制引脚Bvoid app_main(void)
{// 选择GPIO引脚作为输出功能gpio_pad_select_gpio(MOTOR_INA);gpio_pad_select_gpio(MOTOR_INB);// 配置GPIO方向为输出模式gpio_set_direction(MOTOR_INA, GPIO_MODE_OUTPUT);gpio_set_direction(MOTOR_INB, GPIO_MODE_OUTPUT);// 无限循环:持续控制电机运行while (1){/* 正转控制 */// INA=0, INB=1: 电机正转gpio_set_level(MOTOR_INA, 0);gpio_set_level(MOTOR_INB, 1);sleep(3); // 保持正转3秒/* 反转控制 */// INA=1, INB=0: 电机反转gpio_set_level(MOTOR_INA, 1);gpio_set_level(MOTOR_INB, 0);sleep(3); // 保持反转3秒/* 停止控制 */// INA=1, INB=1: 电机停止(根据H桥驱动特性)gpio_set_level(MOTOR_INA, 1);gpio_set_level(MOTOR_INB, 1);sleep(3); // 保持停止3秒}
}
设置环境变量:
get_idf
设置芯片为 esp32c3:
idf.py set-target esp32c3
编译命令:
idf.py build
烧写(两种方法):
esptool.py -p /dev/ttyUSB0 -b 460800 --before default_reset --after hard_reset --chip esp32c3 write_flash --flash_mode dio -- flash_size detect --flash_freq 80m 0x0 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/blink.bin
idf.py -p /dev/ttyUSB0 flash
监控:
idf.py -p /dev/ttyUSB0 monitor
5.4.2 使用GPIO控制三盏LED灯实现流水灯效果
#include <stdio.h>
#include <unistd.h>
#include "driver/gpio.h"// 定义三个LED连接的GPIO引脚
#define WHITE_LED 5 // 白色LED连接到GPIO5
#define BLUE_LED 8 // 蓝色LED连接到GPIO8
#define GREEN_LED 10 // 绿色LED连接到GPIO10void app_main(void)
{// 选择并配置GPIO引脚为输出模式gpio_pad_select_gpio(WHITE_LED);gpio_pad_select_gpio(BLUE_LED);gpio_pad_select_gpio(GREEN_LED);gpio_set_direction(WHITE_LED, GPIO_MODE_OUTPUT);gpio_set_direction(BLUE_LED, GPIO_MODE_OUTPUT);gpio_set_direction(GREEN_LED, GPIO_MODE_OUTPUT);int on = 0; // LED状态变量(0=灭,1=亮)// 无限循环:实现LED流水灯效果while (1){on = !on; // 切换LED状态(亮→灭 或 灭→亮)// 控制白色LEDgpio_set_level(WHITE_LED, on);usleep(200000); // 延时200毫秒// 控制蓝色LEDgpio_set_level(BLUE_LED, on);usleep(200000); // 延时200毫秒// 控制绿色LEDgpio_set_level(GREEN_LED, on);usleep(200000); // 延时200毫秒}
}
设置环境变量:
get_idf
设置芯片为 esp32c3:
idf.py set-target esp32c3
编译命令:
idf.py build
烧写(两种方法):
esptool.py -p /dev/ttyUSB0 -b 460800 --before default_reset --after hard_reset --chip esp32c3 write_flash --flash_mode dio -- flash_size detect --flash_freq 80m 0x0 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/blink.bin
idf.py -p /dev/ttyUSB0 flash
监控:
idf.py -p /dev/ttyUSB0 monitor
5.4.3 使用GPIO按键控制GPIO LED灯亮灭
使用KEY1按键来控制WIHTE LED的亮灭 其中按下按键灯亮 松开按键灯灭。
#include <stdio.h>
#include <unistd.h>
#include "driver/gpio.h"// 定义按键和LED连接的GPIO引脚
#define KEY1_BUTTON 18 // 按键连接到GPIO18
#define WHITE_LED 5 // 白色LED连接到GPIO5void app_main()
{// 配置LED引脚为输出模式gpio_pad_select_gpio(WHITE_LED);gpio_set_direction(WHITE_LED, GPIO_MODE_OUTPUT);// 配置按键引脚为输入模式gpio_pad_select_gpio(KEY1_BUTTON);gpio_set_direction(KEY1_BUTTON, GPIO_MODE_INPUT);gpio_pullup_en(KEY1_BUTTON); // 启用上拉电阻gpio_pulldown_dis(KEY1_BUTTON); // 禁用下拉电阻// 无限循环:持续检测按键状态并控制LEDwhile (true){// 读取按键引脚电平(0=按下,1=释放)int level = gpio_get_level(KEY1_BUTTON);// 将按键状态直接映射到LED(按下点亮,释放熄灭)gpio_set_level(WHITE_LED, level);// 延时1秒(降低CPU使用率,但会影响响应速度)sleep(1);}
}
设置环境变量:
get_idf
设置芯片为 esp32c3:
idf.py set-target esp32c3
编译命令:
idf.py build
烧写(两种方法):
esptool.py -p /dev/ttyUSB0 -b 460800 --before default_reset --after hard_reset --chip esp32c3 write_flash --flash_mode dio -- flash_size detect --flash_freq 80m 0x0 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/blink.bin
idf.py -p /dev/ttyUSB0 flash
监控:
idf.py -p /dev/ttyUSB0 monitor
5.4.4 使用FreeRTOS实现按键中断
基于freertos来实现一个中断处理函数处理按键消息队列。
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"#define KEY1_BUTTON 18 // 定义按键连接的GPIO引脚
#define WHITE_LED 5 // 定义LED连接的GPIO引脚(代码中缺少此定义)xQueueHandle interputQueue; // 定义中断消息队列句柄static void IRAM_ATTR gpio_isr_handler(void *args)
{int pinNumber = (int)args;// 将触发中断的引脚号发送到队列中xQueueSendFromISR(interputQueue, &pinNumber, NULL);
}void buttonPushedTask(void *params)
{int pinNumber, count = 0; // 引脚号和按下计数while (true){// 阻塞等待队列消息(portMAX_DELAY表示永久等待)if (xQueueReceive(interputQueue, &pinNumber, portMAX_DELAY)){// 点亮LEDgpio_set_level(WHITE_LED, 1);// 打印按键信息(包括引脚号、按下次数和当前引脚电平)printf("GPIO %d was pressed %d times. The state is %d\n", pinNumber, count++, gpio_get_level(KEY1_BUTTON));}}
}void app_main()
{// 配置按键引脚gpio_pad_select_gpio(KEY1_BUTTON);gpio_set_direction(KEY1_BUTTON, GPIO_MODE_INPUT);gpio_pullup_en(KEY1_BUTTON); // 启用上拉电阻gpio_pulldown_dis(KEY1_BUTTON); // 禁用下拉电阻// 设置中断触发类型为双边沿(上升沿+下降沿)gpio_set_intr_type(KEY1_BUTTON, GPIO_INTR_ANYEDGE);// 创建消息队列(最多存储10个int类型数据)interputQueue = xQueueCreate(10, sizeof(int));// 创建按键处理任务xTaskCreate(buttonPushedTask, "buttonPushedTask", 2048, NULL, 1, NULL);// 安装GPIO中断服务(必须先调用此函数才能注册具体引脚的中断处理函数)gpio_install_isr_service(0);// 为指定GPIO引脚添加中断处理函数gpio_isr_handler_add(KEY1_BUTTON, gpio_isr_handler, (void *)KEY1_BUTTON);
}
设置环境变量:
get_idf
设置芯片为 esp32c3:
idf.py set-target esp32c3
编译命令:
idf.py build
烧写(两种方法):
esptool.py -p /dev/ttyUSB0 -b 460800 --before default_reset --after hard_reset --chip esp32c3 write_flash --flash_mode dio -- flash_size detect --flash_freq 80m 0x0 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/blink.bin
idf.py -p /dev/ttyUSB0 flash
监控:
idf.py -p /dev/ttyUSB0 monitor
5.4.5 按键控制风扇转动以及灯亮灭
#include <stdio.h>
#include <unistd.h>
#include "driver/gpio.h"// 定义电机控制引脚
#define MOTOR_INA 1 // 电机方向控制引脚A
#define MOTOR_INB 0 // 电机方向控制引脚B
#define BLUE_LED 8 // 蓝色LED连接到GPIO8
#define GREEN_LED 10 // 绿色LED连接到GPIO10
#define KEY1_BUTTON 18 // 按键连接到GPIO18
#define KEY2_BUTTON 19 // 按键连接到GPIO19void app_main(void)
{// 选择GPIO引脚作为输出功能gpio_pad_select_gpio(MOTOR_INA);gpio_pad_select_gpio(MOTOR_INB);gpio_pad_select_gpio(BLUE_LED);gpio_pad_select_gpio(GREEN_LED);// 配置GPIO方向为输出模式gpio_set_direction(MOTOR_INA, GPIO_MODE_OUTPUT);gpio_set_direction(MOTOR_INB, GPIO_MODE_OUTPUT);gpio_set_direction(BLUE_LED, GPIO_MODE_OUTPUT);gpio_set_direction(GREEN_LED, GPIO_MODE_OUTPUT);// 配置按键引脚为输入模式gpio_pad_select_gpio(KEY2_BUTTON);gpio_set_direction(KEY2_BUTTON, GPIO_MODE_INPUT);gpio_pullup_en(KEY2_BUTTON); // 启用上拉电阻gpio_pulldown_dis(KEY2_BUTTON); // 禁用下拉电阻// 配置按键引脚为输入模式gpio_pad_select_gpio(KEY1_BUTTON);gpio_set_direction(KEY1_BUTTON, GPIO_MODE_INPUT);gpio_pullup_en(KEY1_BUTTON); // 启用上拉电阻gpio_pulldown_dis(KEY1_BUTTON); // 禁用下拉电阻 // 初始化状态:风扇不转(INA=1, INB=1),蓝灯灭(LED=1),绿灯灭(LED=1)gpio_set_level(MOTOR_INA, 1);gpio_set_level(MOTOR_INB, 1);gpio_set_level(BLUE_LED, 1);gpio_set_level(GREEN_LED, 1);while (true){// 读取按键状态(0=按下,1=未按下)int level1 = gpio_get_level(KEY1_BUTTON);int level2 = gpio_get_level(KEY2_BUTTON);// 按键2按下if (level2 == 0) {// 电机正转,蓝灯亮gpio_set_level(MOTOR_INA, 0);gpio_set_level(MOTOR_INB, 1);gpio_set_level(BLUE_LED, 0);}else if (level1 == 0){// 电机反转,绿灯亮gpio_set_level(MOTOR_INA, 1);gpio_set_level(MOTOR_INB, 0);gpio_set_level(GREEN_LED, 0); }else{// 无按键按下:风扇停止,蓝灯灭,绿灯灭gpio_set_level(MOTOR_INA, 1);gpio_set_level(MOTOR_INB, 1);gpio_set_level(BLUE_LED, 1); gpio_set_level(GREEN_LED, 1);}}
}
设置环境变量:
get_idf
设置芯片为 esp32c3:
idf.py set-target esp32c3
编译命令:
idf.py build
烧写(两种方法):
esptool.py -p /dev/ttyUSB0 -b 460800 --before default_reset --after hard_reset --chip esp32c3 write_flash --flash_mode dio -- flash_size detect --flash_freq 80m 0x0 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/blink.bin
idf.py -p /dev/ttyUSB0 flash
监控:
idf.py -p /dev/ttyUSB0 monitor
按下按键1,电机反转并且绿灯亮;按下按键2,电机正转并且蓝灯亮。