当前位置: 首页 > news >正文

ESP32-S3 入门学习笔记(四):LED实验

ESP32-S3 入门学习笔记(四):LED实验

开发板:正点原子ESP32S3
B站学习链接:link

1. GPIO&LED 简介

1.1 GPIO 简介

GPIO 是负责控制或采集外部器件信息的外设,主要负责输入输出功能。以下是ATK-MWS3S 模组的 GPIO 分布图。
在这里插入图片描述
从上面的图示中可见,黄色区域的管脚均可作为普通的 IO 端口使用。因此,在控制 LED灯时,我们可以自由选择任意一个管脚进行操作。但请注意,部分 IO 端口可能与 Flash 或PSRAM 等元件的管脚相关联,这就需要开发者在操作过程中参考相关技术手册,以避免潜在的问题。在正点原子ESP32S3 开发板中,模组的 IO1 被用来连接 LED 的负极,因此在本章的实验中,我们将主要对 IO1 进行操作。

1.2 LED 简介

LED,即发光二极管,其发光原理基于半导体的特性。在半导体中,有两类重要的载流子:电子,主要存在于 n 型半导体中;而空穴,则主要存在于 p型半导体中。当 n 型半导体与 p型半导体材料接触时,它们的交界处会形成一个特殊的层结。当对这个层结施加适当的电压时,层结中的空穴与电子会发生重组,并释放出能量。这些能量会以光子的形式被释放出来,从而产生可见光。这就是 LED 发光的基本原理。

1.2.1 LED 灯驱动原理

LED 驱动是指通过稳定的电源为 LED 提供适宜的电流和电压,确保其正常发光。 LED 驱动方式主要有恒流和恒压两种,其中,恒流驱动因其能限定电流而备受青睐。由于 LED 灯对电流变化极为敏感,一旦电流超过其额定值,可能导致损坏。因此,恒流驱动通过确保电流的稳定性,进而保障 LED 的安全运行。

1.2.2 LED 灯驱动方式

下面,我们来看一下 LED 两种驱动方式。
1) 灌入电流接法。指的是 LED 的供电电流是由外部提供电流,将电流灌入我们的 MCU;风险是当外部电源出现变化时,会导致 MCU 的引脚烧坏。其接法如下图所示。
在这里插入图片描述
(2) 输出电流接法。指的是由 MCU 提供电压电流,将电流输出给 LED;如果使用 MCU的 GPIO 直接驱动 LED,则驱动能力较弱,可能无法提供足够的电流驱动 LED。其接法如下图所示。
在这里插入图片描述
正点原子ESP32S3 开发板上的 LED 采用灌入电流接法,这种方式避免了 MCU 直接提供电压电流来驱动 LED,从而有效减轻了 MCU 的负载。这使得 MCU 能够更加专注于执行其他核心任务,进而提升了整体系统的性能和稳定性。

2. 硬件设计

2.1 例程功能

实验现象: LED 灯以 500ms 的频率交替闪烁。

2.2 硬件资源

1.LED:LED-IO1

2.3 原理图

本章用到的硬件有 LED 灯。电路在开发板上已经连接好,所以在硬件上不需要动任何东西,直接下载代码就可以测试使用。其连接原理图如下图所示:
在这里插入图片描述
从上图可知,若 IO1 输出低电平时,则 LED 亮起,反之,熄灭。

3. 程序设计

3.1 程序流程图

程序流程图能帮助我们更好的理解一个工程的功能和实现的过程,对学习和设计工程有很好的主导作用。下面看看本实验的程序流程图:
在这里插入图片描述

3.2 GPIO 函数解析

ESP-IDF 提供了丰富的 GPIO 操作函数,开发者可以在 esp-idf-v5.3.1\components\driver\gpio路径下找到相关的 gpio.c 和 gpio.h 文件。在 gpio.h 头文件中,你可以找到 ESP32-S3 的所有 GPIO 函数定义。接下来,作者将介绍一些常用的 GPIO 函数,这些函数的描述及其作用如下:

  1. GPIO 配置函数
    该函数用来配置 GPIO 的模式、上下拉等功能,其函数原型如下所示:
esp_err_t gpio_config(const gpio_config_t *pGPIOConfig)

该函数的形参描述如下表所示:
在这里插入图片描述
返回值: ESP_OK 表示配置成功, ESP_FAIL 表示配置失败。
pGPIOConfig 为 GPIO 配置结构体指针,下面来看一下 gpio_config_t 结构体中的变量。

/* GPIO 配置参数 */
typedef struct {
uint64_t pin_bit_mask; /* 配置引脚位 */
gpio_mode_t mode; /* 设置引脚模式 */
gpio_pullup_t pull_up_en; /* 设置上拉 */
gpio_pulldown_t pull_down_en; /* 设置下拉 */
gpio_int_type_t intr_type; /* 中断配置 */
} gpio_config_t;

关于各个参数有哪一些看下表说明:
在这里插入图片描述
在上表中,可填参数均可在 gpio_types.h 文件中找到。这些参数通常是通过枚举类型(enum)定义的,它们为特定的 GPIO 模式或配置提供了预定义的数值。当我们需要为结构体变量(如 gpio_mode_t)设置参数时,我们可以查阅 gpio_types.h 文件,找到对应的枚举类型,并从中选择适当的数值。这样,我们可以确保为GPIO接口设置的模式或配置是准确和有效的。
2. 设置管脚输出电平
该函数用于配置某个管脚输出电平,该函数原型如下所示:

esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level);

该函数的形参描述如下表所示:
在这里插入图片描述
返回值: ESP_OK 表示设置成功, ESP_FAIL 表示设置失败。
3. 获取管脚电平
该函数用于获取某个管脚的电平,该函数原型如下所示:

esp_err_t gpio_get_level(gpio_num_t gpio_num);

该函数的形参描述如下表所示:
在这里插入图片描述
返回值: ESP_OK 表示获取成功, ESP_FAIL 表示获取失败。
上述函数,便是本实验所需的核心 GPIO 函数。

3.3 LED 驱动解析

在项目\components路径下新增一个 LED文件夹,用于存放 led.c 和 led.h 这两个文件。其中 led.h 文件负责声明 LED 相关的函数和变量,而 led.c文件则实现 LED 的驱动代码。下面,我们将详细解析这两个文件的实现内容。正点原子官方代码运行时存在问题,于是重写了相关代码,运行测试后没有问题

  1. led.h 文件
#ifndef __LED_H_
#define __LED_H_#include "driver/gpio.h"/* 引脚定义 */
#define LED_GPIO_PIN GPIO_NUM_1 /* LED 连接的 GPIO 端口 */
/* 引脚的输出的电平状态 */
enum GPIO_OUTPUT_STATE
{PIN_RESET,PIN_SET
};/* 函数声明*/
void led_init(void); /* 初始化 LED */
void led(int stat);
void led_toggle(void);#endif
  1. led.c 文件
#include "led.h"/**
* @brief 初始化 LED
* @param 无
* @retval 无
*/
void led_init(void)
{gpio_config_t gpio_init_struct = {0};gpio_init_struct.intr_type = GPIO_INTR_DISABLE; /* 失能引脚中断 */gpio_init_struct.mode = GPIO_MODE_INPUT_OUTPUT; /* 输入输出模式 */gpio_init_struct.pull_up_en = GPIO_PULLUP_ENABLE; /* 使能上拉 */gpio_init_struct.pull_down_en = GPIO_PULLDOWN_DISABLE; /* 失能下拉 */gpio_init_struct.pin_bit_mask = 1ull << LED_GPIO_PIN; /* 设置的引脚的位掩码*/gpio_config(&gpio_init_struct); /* 配置 GPIO */led(1);
}void led(int stat){gpio_set_level(LED_GPIO_PIN, stat);
}void led_toggle(){gpio_set_level(LED_GPIO_PIN, !(gpio_get_level(LED_GPIO_PIN)));
}

在.c 文件中,首先对 gpio_init_struct 结构体变量进行了参数配置。接着,调用gpio_config 函数,利用该配置变量完成了 GPIO 的初始化工作。

3.4 CMakeLists.txt 文件

具体原理请参考博文:link
/component/LED下的CMakeLists.txt 文件

idf_component_register(SRCS "led.c" INCLUDE_DIRS "."REQUIRES "driver")

整个项目下的CMakeLists.txt 文件

cmake_minimum_required(VERSION 3.16)include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(EXTRA_COMPONENT_DIRS "./component")      //加入组件
project(project-name)

3.5 实验应用代码

打开 main/main.c 文件,该文件定义了工程入口函数,名为 app_main。该函数代码如下。

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "nvs_flash.h"
#include "led.h"/**
* @brief 程序入口
* @param 无
* @retval 无
*/
void app_main(void)
{esp_err_t ret;ret = nvs_flash_init(); /* 初始化 NVS */if (ret == ESP_ERR_NVS_NO_FREE_PAGES|| ret == ESP_ERR_NVS_NEW_VERSION_FOUND){ESP_ERROR_CHECK(nvs_flash_erase());ret = nvs_flash_init();} led_init(); /* 初始化 LED */while(1){led_toggle();vTaskDelay(500); /* 延时 500ms */}}

上述应用代码中,首先通过调用 nvs_flash_init 函数来初始化 NVS。若初始化时遇到没有足够空闲页面或检测到新版本的情况,代码会先擦除整个 NVS 分区,并随后重新进行初始化。这种处理方式旨在确保 NVS 在特定错误条件下能够被重置并重新使用。紧接着,代码调用led_init 函数来初始化 LED。在随后的 while 循环中,利用 led_toggle()来定期翻转LED 的电平状态,每次翻转间隔为 500 毫秒,从而实现了 LED 的闪烁效果。

4. 下载验证

下载完之后,可以看到 LED 以每次 500ms 闪烁。

相关文章:

  • 数据库查询艺术:从单表操作到多表联查的全面指南
  • C语言(3)—分支和循环
  • Java基础高频面试
  • Neowise Labs Contest 1 (Codeforces Round 1018, Div. 1 + Div. 2)
  • 前端权限管理
  • C语言学习之结构体
  • 《代码整洁之道》第9章 单元测试 - 笔记
  • 《代码整洁之道》第5章 格式 - 笔记
  • MRI学习笔记-conjunction analysis
  • docker(3) -- 图形界面
  • 驱动开发硬核特训 · Day 22(下篇): # 深入理解 Power-domain 框架:概念、功能与完整代码剖析
  • 《操作系统真象还原》第十章(1)——输入输出系统
  • 加密算法 AES、RSA、MD5、SM2 的对比分析与案例(AI)
  • 「Docker已死?」:基于Wasm容器的新型交付体系如何颠覆十二因素应用宣言
  • 2025.4.21-2025.4.26学习周报
  • 泰迪杯实战案例超深度解析:基于YOLOv5的农田害虫图像识别系统设计
  • 「Mac畅玩AIGC与多模态04」开发篇01 - 创建第一个 LLM 对话应用
  • 迷你世界UGC3.0脚本Wiki组件事件管理
  • 显存在哪里看 分享查看及优化方法
  • 分布式一致性算法起源思考与应用
  • 新任海南琼海市委副书记陈明已主持市政府党组全面工作
  • 在县中,我看到“走出去”的渴望与“留下来”的惯性
  • 苏迪曼杯即将在厦门打响,国羽向创纪录的14冠进军
  • 四川省人大常委会原党组成员、副主任宋朝华接受审查调查
  • 《不眠之夜》上演8年推出特别版,多业态联动形成戏剧经济带
  • 中国驻英国大使郑泽光:中国反制美国关税是为了维护国际公平正义和多边贸易体制