ESP32开发之LED闪烁和呼吸的实现

article/2025/6/8 13:10:15
  • 硬件电路介绍
  • GPIO输出模式
  • GPIO配置过程
  • 闪烁灯的源码
  • LED PWM的控制器(LEDC)概述
  • LEDC配置过程及现象
  • 整体流程

硬件电路介绍

电路图如下:

在这里插入图片描述

只要有硬件基础的应该都知道上图中,当GPIO4的输出电平为高时,LED灯亮,反之则熄灭。如果每间隔一段时间进行一次电平的反转,则将使LED产生闪烁的效果。

GPIO模式

在进行GPIO控制之前,需要熟悉一下ESP32的GPIO几种模式:

GPIO模式模式宏定义说明
输入模式GPIO_MODE_INPUT可以通过配置项pull_up_en或pull_down_en配置上拉或者下拉
推挽输出模式GPIO_MODE_OUTPUT高低电平输出
开漏输出模式GPIO_MODE_OUTPUT_OD通常用于I2C
中断可通过intr_type配置项配置触发方式:上升沿/下降沿/双沿/电平触发等
禁用GPIO_MODE_DISABLE禁用GPIO,不作为输入也不作为输出
输入输出模式GPIO_MODE_INPUT_OUTPUT
输入及开漏输出GPIO_MODE_INPUT_OUTPUT_OD

注意:

  • 使用中断时,将GPIO模式设置为输入模式
  • 如果GPIO用于I2C的SDA,设置模式为GPIO_MODE_INPUT_OUTPUT_OD,且需要配置上拉,也可在芯片相关引脚增加上拉电路

GPIO配置过程

  • 配置GPIO

    使用结构体gpio_config_t对GPIO相关参数进行配置

  • 注册GPIO

​ 通过函数gpio_config函数将以上配置注册进系统

  • 通过GPIO相关API函数对GPIO进行控制

​ 比如此次实验是控制LED闪烁,那么则是使用gpio_set_level函数进行输出电平控制

闪烁灯的源码

/*** Copyright (C) 2024-2034 HalfMoon2.* All rights reserved.* * @file 	 Filename without the absolute path* @brief 	 Brief description* @author 	 HalfMoon2* @date 	 2025-05-20* @version	 v0.1* * @revision history:* 	 2025-05-20 - Initial version.*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_log.h"#define LED_GPIO GPIO_NUM_4 //根据实际的连接方式更改void ledCtlTask(void *pvParam)
{while(1){gpio_set_level(LED_GPIO, 1);  // 设置为高电平(点亮 LED)vTaskDelay(pdMS_TO_TICKS(500));  // 延时 0.5 秒gpio_set_level(LED_GPIO, 0);  // 设置为低电平(熄灭 LED)vTaskDelay(pdMS_TO_TICKS(500));  // 延时 0.5 秒}
}void app_main(void)
{// 配置 GPIOgpio_config_t io_conf = {.pin_bit_mask = (1ULL << LED_GPIO),    // 选择 GPIO.mode = GPIO_MODE_OUTPUT,              // 设置为输出模式.pull_up_en = GPIO_PULLUP_DISABLE,     // 不启用上拉.pull_down_en = GPIO_PULLDOWN_DISABLE, // 不启用下拉.intr_type = GPIO_INTR_DISABLE         // 不启用中断};gpio_config(&io_conf);xTaskCreatePinnedToCore(ledCtlTask,"ledCtlTask",2048,NULL,3,NULL,1);
}

LED PWM的控制器(LEDC)概述

从以上案例可以看出,对于通用GPIO的控制要么是高电平,要么是低电平。所以只能控制LED的闪烁现象。而对于ESP32-S3却有专用控制LED的控制器,称之LED PWM。它有8路低速通道。专用于控制LED。当然也可以产生PWM控制电机等。ESP32有两组LED PWM控制器,一组为8路高速通道,另一组为8路低速通道。

LED PWM 控制器可在无需 CPU 干预的情况下自动改变占空比,实现亮度渐变,如果是RGB LED,还能实现颜色的渐变。

LEDC的配置过程及现象

  1. 定时器的配置过程
  • 创建定时器配置结构体

    typedef struct {ledc_mode_t speed_mode;                /* LEDC速度模式, high-speed mode (only exists on esp32) or low-speed mode */ledc_timer_bit_t duty_resolution;      /* LEDC占空比分辨率 */ledc_timer_t  timer_num;                  /* The timer source of channel (0 - LEDC_TIMER_MAX-1) */uint32_t freq_hz;                               /* LEDC 的时钟频率 */ledc_clk_cfg_t clk_cfg;                       /*配置LEDC的时钟源. */bool deconfigure;                             /*是否取消此配置之前的配置,取消之前先要关闭定时器 */
    } ledc_timer_config_t
    
  • 使用相关函数将结构体完成配置

esp_err_t ledc_timer_config(const ledc_timer_config_t *timer_conf);//参数为以上定义的结构体
/*返回值:
* ESP_OK  成功
* ESP_ERR_INVALID_ARG 参数错误
* ESP_FAIL   无法根据给定频率和当前占空比分辨率找到合适的预分频器编号
*ESP_ERR_INVALID_STATE  定时器未配置或未暂停
*/
  1. 配置通道以及指定GPIO
  • 创建配置通道结构体
typedef struct {int gpio_num;                   /* LEDC的输出GPIO*/ledc_mode_t speed_mode;         /* LEDC 速度模式,ESP32S3只能配置为低速 */ledc_channel_t channel;         /*LED PWM的控制器(LEDC) LEDC的通道 */ledc_intr_type_t intr_type;     /*是否开启渐变中断 */ledc_timer_t timer_sel;         /*选择定时器l (0 - LEDC_TIMER_MAX-1) */uint32_t duty;                  /*!< LEDC 通道占空比*/int hpoint;                     /*!< LEDC channel hpoint value, the range is [0, (2**duty_resolution)-1] */struct {unsigned int output_invert: 1;/*!< Enable (1) or disable (0) gpio output invert */} flags;                        /*!< LEDC 标志 */} ledc_channel_config_t;
  • 使用函数完成配置
esp_err_t ledc_channel_config(const ledc_channel_config_t *ledc_conf);
  1. 配置占空比改变PWM信号
  • 使能硬件PWM
//参数intr_alloc_flags为分配的中断优先级
esp_err_t ledc_fade_func_install(int intr_alloc_flags)
  • 配置渐变参数
/*
参数:speed_mode:LEDC的速度模式,只有ESP32有高速模式channel:通道,0-7target_duty:占空比,取值范围 [0, (2**duty_resolution)]max_fade_time_ms:最大的渐变时间
*/
esp_err_t ledc_set_fade_with_time(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t target_duty, int max_fade_time_ms)
  • 开启渐变
/*
参数:speed_mode:LEDC的速度模式channel:通道,0-7
fade_mode:是否阻塞直到渐变完成,如果设置成LEDC_FADE_WAIT_DONE模式,则不渐变到预定值则不返回
*/
esp_err_t ledc_fade_start(ledc_mode_t speed_mode, ledc_channel_t channel, ledc_fade_mode_t fade_mode)
  1. 第一阶段实例:实现LED缓慢亮灯
/*** Copyright (C) 2024-2034 HalfMoon2.* All rights reserved.* * @file 	 Filename without the absolute path* @brief 	 Brief description* @author 	 HalfMoon2* @date 	 2025-05-27* @version	 v0.1* * @revision history:* 	 2025-05-27 - Initial version.*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include <driver/ledc.h>#define LEDC_MODE 		LEDC_LOW_SPEED_MODE
#define LEDC_DUTY_RES 	LEDC_TIMER_13_BIT
#define LEDC_TIMER_NUM 	LEDC_TIMER_0
#define LEDC_FREQ 		5000
#define LEDC_CHANNEL 	LEDC_CHANNEL_0
#define LEDC_GPIO		GPIO_NUM_4
#define LEDC_DUTY		4095    //2^13-1void ledc_init(void)
{ledc_timer_config_t timer_config={.speed_mode= LEDC_MODE,.duty_resolution= LEDC_DUTY_RES,.timer_num= LEDC_TIMER_NUM,.clk_cfg=LEDC_AUTO_CLK,.freq_hz=LEDC_FREQ};ledc_timer_config(&timer_config);ledc_channel_config_t ledc_channel={.speed_mode = 	LEDC_MODE,.channel 	=	LEDC_CHANNEL,.gpio_num	=	LEDC_GPIO,.intr_type	= 	LEDC_INTR_DISABLE,.duty		=	0,.hpoint		=	0};ledc_channel_config(&ledc_channel);
}void app_main(void)
{ledc_init();ledc_fade_func_install(0);ledc_set_fade_with_time(LEDC_MODE,LEDC_CHANNEL,4095,10000);ledc_fade_start(LEDC_MODE,LEDC_CHANNEL,LEDC_FADE_NO_WAIT);
}

在这里插入图片描述

波形说明:可以明显的看到PWM的占空比的变化,LED也缓慢的亮起。

那么接下来就是实现从亮起再缓慢的熄灭,以此循环则实现了LED呼吸的效果。

  1. 渐变回调函数

LEDC控制器在使能渐变后,每个通道都可以有一个回调函数,通过ledc_cb_register()进行注册

esp_err_t ledc_cb_register(ledc_mode_t speed_mode, ledc_channel_t channel, ledc_cbs_t *cbs, void *user_arg)/*参数:speed_mode:速度模式,只有ESP32有高速模式channel: LEDC通道,低速模式有8个通道cbs:回调函数原型定义在 ledc_cbs_t 结构体中user_arg:用户注册时的数据,用于给回调函数传参 */
  1. 通过事件组的方式将此时LED的状态发送出去,即设置事件值

在中断中避免处理复杂的内容,所以在渐变回调函数中只使用事件组方式发送相关事件。不了解这块的知识可以参考我之前的文章

《ESP32开发之freeRTOS的事件组》

bool IRAM_ATTR ledc_fade_cb(const ledc_cb_param_t *param, void *user_arg)
{BaseType_t  pxHigherPriorityTaskWoken;//如果当前LEDC占空比最大,说明此时LED为开灯状态,反之为关灯状态if(param->duty){xEventGroupSetBitsFromISR(s_ledc_ev,LED_ON_EV,&pxHigherPriorityTaskWoken);}else{xEventGroupSetBitsFromISR(s_ledc_ev,LED_OFF_EV,&pxHigherPriorityTaskWoken);}return pxHigherPriorityTaskWoken;
}
  1. 创建一个任务来接收事件并做渐变过程的改变
void ledc_fade_task(void* param)
{EventBits_t ev;while(1){ev=xEventGroupWaitBits(s_ledc_ev,LED_OFF_EV|LED_ON_EV,pdTRUE,pdFALSE,portMAX_DELAY);if(ev){if(ev&LED_OFF_EV){ledc_set_fade_with_time(LEDC_MODE,LEDC_CHANNEL,LEDC_DUTY,1000);ledc_fade_start(LEDC_MODE,LEDC_CHANNEL,LEDC_FADE_NO_WAIT);}if(ev&LED_ON_EV){ledc_set_fade_with_time(LEDC_MODE,LEDC_CHANNEL,0,1000);ledc_fade_start(LEDC_MODE,LEDC_CHANNEL,LEDC_FADE_NO_WAIT);}}//处理完成需要再次注册回调函数,产生循环ledc_cbs_t cbs={.fade_cb=ledc_fade_cb};ledc_cb_register(LEDC_MODE,LEDC_CHANNEL,&cbs,NULL);}
}
  1. 第二阶段实例:完整实现渐变的循环
/*** Copyright (C) 2024-2034 HalfMoon2.* All rights reserved.* * @file 	 Filename without the absolute path* @brief 	 Brief description* @author 	 HalfMoon2* @date 	 2025-05-27* @version	 v0.1* * @revision history:* 	 2025-05-27 - Initial version.*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include <driver/ledc.h>#define LEDC_MODE 		LEDC_LOW_SPEED_MODE
#define LEDC_DUTY_RES 	LEDC_TIMER_13_BIT
#define LEDC_TIMER_NUM 	LEDC_TIMER_0
#define LEDC_FREQ 		5000
#define LEDC_CHANNEL 	LEDC_CHANNEL_0
#define LEDC_GPIO		GPIO_NUM_4
#define LEDC_DUTY		4095    //2^13-1//通知渐变完成
static EventGroupHandle_t   s_ledc_ev = NULL;//此时为关灯状态
#define LED_OFF_EV (1<<0)//事件组bit0设置为关灯事件//此时为开灯状态
#define LED_ON_EV (1<<1)//事件组bit1设置为开灯事件/*** @brief 	 渐变结束回调函数* @param 	 *param:LEDC callback parameter* @param 	 *user_arg:User registered data* @return 	 返回是否唤醒高优先级任务* @note	 此函数为中断服务函数,所以不应处理过多的操作,那么在此函数中通过发送事件的方式,由渐变任务函数处理事件*/
bool IRAM_ATTR ledc_fade_cb(const ledc_cb_param_t *param, void *user_arg)
{BaseType_t  pxHigherPriorityTaskWoken;//如果当前LEDC占空比最大,说明此时LED为开灯状态,反之为关灯状态if(param->duty){xEventGroupSetBitsFromISR(s_ledc_ev,LED_ON_EV,&pxHigherPriorityTaskWoken);}else{xEventGroupSetBitsFromISR(s_ledc_ev,LED_OFF_EV,&pxHigherPriorityTaskWoken);}return pxHigherPriorityTaskWoken;
}/*** @brief 	 led渐变任务* @param 	 任务参数* @note	 接收事件并做LED操作*/
void ledc_fade_task(void* param)
{EventBits_t ev;while(1){ev=xEventGroupWaitBits(s_ledc_ev,LED_OFF_EV|LED_ON_EV,pdTRUE,pdFALSE,portMAX_DELAY);if(ev){if(ev&LED_OFF_EV){ledc_set_fade_with_time(LEDC_MODE,LEDC_CHANNEL,LEDC_DUTY,1000);ledc_fade_start(LEDC_MODE,LEDC_CHANNEL,LEDC_FADE_NO_WAIT);}if(ev&LED_ON_EV){ledc_set_fade_with_time(LEDC_MODE,LEDC_CHANNEL,0,1000);ledc_fade_start(LEDC_MODE,LEDC_CHANNEL,LEDC_FADE_NO_WAIT);}}//处理完成需要再次注册回调函数,产生循环ledc_cbs_t cbs={.fade_cb=ledc_fade_cb};ledc_cb_register(LEDC_MODE,LEDC_CHANNEL,&cbs,NULL);}
}void ledc_init(void)
{ledc_timer_config_t timer_config={.speed_mode= LEDC_MODE,.duty_resolution= LEDC_DUTY_RES,.timer_num= LEDC_TIMER_NUM,.clk_cfg=LEDC_AUTO_CLK,.freq_hz=LEDC_FREQ};ledc_timer_config(&timer_config);ledc_channel_config_t ledc_channel={.speed_mode = 	LEDC_MODE,.channel 	=	LEDC_CHANNEL,.gpio_num	=	LEDC_GPIO,.intr_type	= 	LEDC_INTR_DISABLE,.duty		=	0,.hpoint		=	0};ledc_channel_config(&ledc_channel);//创建事件组,用于接收和发送渐变事件s_ledc_ev = xEventGroupCreate();//开启硬件PWMledc_fade_func_install(0);//设置渐变参数ledc_set_fade_with_time(LEDC_MODE,LEDC_CHANNEL,LEDC_DUTY,1000);//启动渐变ledc_fade_start(LEDC_MODE,LEDC_CHANNEL,LEDC_FADE_NO_WAIT);//注册渐变回调函数ledc_cbs_t cbs={.fade_cb=ledc_fade_cb,};ledc_cb_register(LEDC_MODE,LEDC_CHANNEL,&cbs,NULL);xTaskCreatePinnedToCore(ledc_fade_task,"ledc_fade_task",2048,NULL,3,NULL,1);
}void app_main(void)
{ledc_init();
}

在这里插入图片描述

整体流程

在这里插入图片描述


http://www.hkcw.cn/article/ipYndwgrlq.shtml

相关文章

【办公类-48-04】202506每月电子屏台账汇总成docx-5(问卷星下载5月范围内容,自动获取excel文件名,并转移处理)

背景需求&#xff1a; 1-4月电子屏表格&#xff0c;都是用这个代码将EXCEL数据整理成分类成3个WORD表格。 【办公类-48-04】20250118每月电子屏台账汇总成docx-4&#xff08;提取EXCLE里面1月份的内容&#xff0c;自制月份文件夹&#xff09;-CSDN博客文章浏览阅读1.2k次&…

25年宁德时代新能源科技SHL 测评语言理解数字推理Verify题库

宁德时代新能源科技的SHL测评中&#xff0c;语言理解部分主要考察阅读理解、逻辑填空和语句排序等题型&#xff0c;要求应聘者在17分钟内完成30题。阅读理解需要快速捕捉文章主旨和理解细节信息&#xff1b;逻辑填空则要根据语句逻辑填入最合适的词汇&#xff1b;语句排序是将打…

Windows下WSL(Ubuntu)安装1Panel

1Panel 1Panel 提供了一个直观的 Web 界面和 MCP Server&#xff0c;帮助用户轻松管理 Linux 服务器中的网站、文件、容器、数据库以及大型语言模型&#xff08;LLMs&#xff09;。 官网地址&#xff1a;1Panel - 现代化、开源的 Linux 服务器运维管理面板 - 官网 前置条件 …

virtualbox安装扩展工具以支持共享文件夹

1.下载扩展镜像 https://download.virtualbox.org/virtualbox/7.0.16/ 2.加载扩展镜像并安装 3. 配置共享文件夹

实现仿中国婚博会微信小程序

主要功能&#xff1a; 1、完成底部标签导航设计、首页海报轮播效果设计和宫格导航设计&#xff0c;如图1所示 2、在首页里&#xff0c;单击全部分类宫格导航的时候&#xff0c;会进入到全部分类导航界面&#xff0c;把婚博会相关内容的导航集成到一个界面里&#xff0c;如图2…

Meta ASC广告:智能电商营销利器解析

Meta推出的ASC广告&#xff08;全称Advantage Shopping Campaign&#xff09;是专为电商卖家打造的智能营销利器。作为新一代自动化购物广告解决方案&#xff0c;它通过AI技术重塑了传统广告投放模式&#xff0c;为商家带来更高效的转化路径。 五大核心优势解析&#xff1a; 全…

1.1Nodejs和浏览器中的二进制处理

Buffer 在 Node.js 中&#xff0c;Buffer 类用于处理二进制数据。由于 JavaScript 在浏览器环境中主要用于处理字符串和数字等类型的数据&#xff0c;对二进制数据的处理能力较弱&#xff0c;因此 Node.js 引入了 Buffer 类来弥补这一不足&#xff0c;特别是在处理文件系统操作…

redis的哨兵模式和Redis cluster

目录 一. redis的主从复制 二. 哨兵模式 2.1 定义 2.2 作用 2.3 配置实例 三. Redis cluster 3.1 定义 3.2 作用 3.3 配置实例 1. 新建集群文件目录 2. 准备可执行文件到每个文件夹 3. 开启群集功能 4. 启动redis节点 5. 查看是否启动成功 6. 启动集群 7. 测试…

[Java 基础]打印金字塔

实现一个 Java 程序&#xff0c;让用户输入金字塔的层数&#xff0c;打印出对应层数的金字塔。 比如&#xff0c;如果用户指定金字塔的层数是 5&#xff0c;那么将会打印如下的金字塔&#xff1a; 0000* 000*** 00***** 0******* 假如 i 代表的是行&#xff0c;i 从 1 开始…

ollama的安装及加速下载技巧

下载ollama ollama的安装可以从官网下载&#xff0c;地址&#xff1a; https://ollama.com 但是下载会很慢&#xff0c;我是去的这里下载&#xff1a;https://www.gy328.com/app/ollama/ 和官网一样。 下载好了&#xff0c;点击安装&#xff0c;安装好了&#xff…

Qiskit:量子计算模拟器

参考文献&#xff1a; IBM Qiskit 官网Qiskit DocumentationQiskit Benchpress packageQiskit Algorithms package量子计算&#xff1a;基本概念常见的几类矩阵&#xff08;正交矩阵、酉矩阵、正规矩阵等&#xff09;Qiskit 安装指南-博客园使用Python实现量子电路模拟&#x…

05 APP 自动化- Appium 单点触控 多点触控

文章目录 一、单点触控查看指针的指针位置实现手势密码&#xff1a; 二、多点触控 一、单点触控 查看指针的指针位置 方便查看手势密码-九宫格每个点的坐标 实现手势密码&#xff1a; 执行手势操作&#xff1a; 按压起点 -> 移动到下一点 -> 依次移动 -> 释放&am…

aardio 图像识别

今天终于学会了编程中的 OCR 技术&#xff01;原来计算机真的能识别图片里的文字&#xff0c;这种让程序 "看懂" 图像的能力太神奇了&#xff0c;赶紧把学习过程记录下来。 一、初识OCR&#xff1a;让程序读懂图片文字 &#xff08;一&#xff09;简单识别实验 OC…

【北邮 操作系统】第十二章 文件系统实现

一、文件的物理结构 1.1 文件块、磁盘块 类似于内存分页&#xff0c;磁盘中的存储单元也会被分为一个个“块/磁盘块/物理块”。很多操作系统中&#xff0c;磁盘块的大小与内存块、页面的大小相同 内存与磁盘之间的数据交换(即读/写操作、磁盘I/0)都是以“块”为单位进行的。即…

VS2022下C++ Boost库安装与使用使用

一.Boost概述 1.简介 Boost 是一个广泛使用的 C 库集合&#xff0c;提供了许多高质量、可移植、高效的工具和组件&#xff0c;被视为 C 标准库的延伸。自 1998 年成立以来&#xff0c;Boost 已成为 C 社区的核心资源&#xff0c;许多 Boost 库通过实践验证后被纳入 C 标准&am…

Unity-UI组件详解

今天我们来学习Unity的UI的详解&#xff0c;这部分的内容相对较少&#xff0c;对于程序员来说主要的工作是负责将各种格式的图片呈现在显示器上并允许操作这些图片。 本篇帖子的理论依据依然是官方开源的UGUI代码&#xff0c;网址为&#xff1a;GitHub - Unity-Technologies/u…

化工厂爆炸事件看制造业AI转型

一、事件警示&#xff1a;化工制造安全风险不容忽视 近日&#xff0c;某化学有限公司发生事故。涉事工厂主体工程建设有2座硝化装置区&#xff0c;1座加氢装置区&#xff0c;均属于危险工艺生产装置。硝化反应通常属于强放热反应&#xff0c;原料及产物具有爆炸危险性&#xf…

Ubuntu系统安装与配置NTP时间同步服务

Ubuntu系统安装与配置NTP时间同步服务 一、NTP服务介绍NTP服务简介工作原理系统环境准备检查当前时间状态二、方案选择:systemd-timesyncd vs ntpd三、使用systemd-timesyncd时间同步1. 方案介绍2. 配置优化3. 应用配置4. 验证状态5. 检查当前时间状态6. 查看当前实践四、使用…

【小红书】API接口,获取笔记核心数据

小红书笔记核心数据API接口详解 - 深圳小于科技提供专业数据服务 深圳小于科技&#xff08;官网&#xff1a;https://www.szlessthan.com&#xff09;推出的小红书笔记核心数据API接口&#xff0c;为开发者提供精准的笔记互动数据分析能力&#xff0c;助力内容运营与商业决策。…

ElasticStack技术之logstash介绍

一、什么是Logstash Logstash 是 Elastic Stack&#xff08;ELK Stack&#xff09;中的一个开源数据处理管道工具&#xff0c;主要用于收集、解析、过滤和传输数据。它支持多种输入源&#xff0c;如文件、网络、数据库等&#xff0c;能够灵活地对数据进行处理&#xff0c;比如…