欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 家装 > ESP-ADF外设子系统深度解析:esp_peripherals组件架构与核心设计(显示输出类外设之LED)

ESP-ADF外设子系统深度解析:esp_peripherals组件架构与核心设计(显示输出类外设之LED)

2025/4/27 16:46:37 来源:https://blog.csdn.net/qq_35762024/article/details/147344723  浏览:    关键词:ESP-ADF外设子系统深度解析:esp_peripherals组件架构与核心设计(显示输出类外设之LED)

目录

  • ESP-ADF外设子系统深度解析:esp_peripherals组件架构与核心设计(显示输出类外设之LED)
    • 简介
    • 模块概述
      • 功能定义
      • 架构位置
      • 核心特性
    • LED外设分析
      • LED外设概述
        • LED外设功能特点
        • 常见应用场景
        • LED外设架构图
      • LED外设API和数据结构
        • 公共API
        • 事件类型
        • 配置结构体
        • 内部数据结构
      • LED外设配置选项
      • LED外设初始化流程
        • 外设层初始化过程(periph_led.c)
        • LED外设完整初始化时序图
      • LED外设销毁流程
        • 销毁流程分析
        • 销毁流程时序图
      • LED外设事件处理机制
        • 事件处理函数特点
        • LED闪烁控制流程
        • LED定时器处理函数
        • LED闪烁控制流程图
        • 事件类型
        • 事件触发机制
        • 事件处理特点
        • 事件处理流程图
      • LED外设典型使用示例

ESP-ADF外设子系统深度解析:esp_peripherals组件架构与核心设计(显示输出类外设之LED)

版本信息: ESP-ADF v2.7-65-gcf908721

简介

本文档详细分析ESP-ADF中的显示/输出类外设实现机制,包括LCD、LED、WS2812、IS31FL3216和AW2013等外设的设计模式、接口规范、初始化流程和事件处理机制。ESP-ADF显示/输出类外设基于统一的外设框架设计,通过事件驱动模型实现显示和指示功能,为音频应用提供了丰富的视觉反馈能力和用户界面支持。

模块概述

功能定义

ESP-ADF显示/输出类外设主要负责提供视觉反馈和用户界面显示功能,将应用程序的状态和数据以可视化方式呈现给用户。主要功能包括:

  • 状态指示(LED指示灯、状态灯等)
  • 用户界面显示(LCD屏幕显示文本、图形等)
  • 视觉效果(WS2812彩色灯带、IS31FL3216和AW2013 LED矩阵等)
  • 音频可视化(音频频谱显示、节奏灯光效果等)

架构位置

显示/输出类外设是ESP-ADF外设子系统的重要组成部分,位于硬件驱动层和应用层之间:

应用程序
ESP外设子系统
显示/输出类外设
LCD外设
LED外设
WS2812外设
IS31FL3216外设
AW2013外设
SPI/I2C驱动
GPIO驱动
RMT驱动
I2C驱动
I2C驱动

核心特性

  • 多种显示设备支持:支持LCD、LED、WS2812、IS31FL3216和AW2013等多种显示和指示设备
  • 统一控制接口:所有显示/输出外设使用统一的初始化和控制接口
  • 丰富的显示效果:支持开关控制、亮度调节、颜色变化、动画效果等多种显示功能
  • 与音频处理集成:可与音频处理模块协同工作,实现音频可视化效果
  • 低功耗设计:支持设备休眠和唤醒管理,优化功耗表现
  • 事件驱动模型:通过事件机制实现显示状态变化的通知和处理

LED外设分析

LED外设概述

LED外设是ESP-ADF框架中用于控制LED灯的外设组件,基于ESP32的LEDC(LED控制器)硬件模块实现。该外设提供了简单易用的API接口,支持PWM控制、闪烁效果、渐变效果等功能,并能在闪烁完成时发送事件通知应用程序。

LED外设主要由以下文件实现:

  • 头文件:components/esp_peripherals/include/periph_led.h
  • 实现文件:components/esp_peripherals/periph_led.c
LED外设功能特点
  1. PWM控制:利用ESP32的LEDC模块,通过PWM(脉冲宽度调制)信号控制LED亮度
  2. 闪烁效果:支持设置LED的开启时间和关闭时间,实现闪烁效果
  3. 渐变效果:支持LED亮度的渐变变化,实现平滑的明暗过渡
  4. 多通道支持:最多支持8个LED通道同时控制
  5. 事件通知:当LED闪烁完成时,会发送事件通知应用程序
常见应用场景
  • 状态指示:显示系统运行状态,如电源状态、网络连接状态等
  • 警告提示:通过闪烁或特定模式的亮灭来提示用户注意
  • 用户界面反馈:对用户操作提供视觉反馈
  • 氛围照明:通过控制LED的亮度和颜色创造特定的氛围
  • 调试辅助:在开发过程中用作调试指示器
LED外设架构图
ESP-ADF外设层 periph_led.c
调用
调用
调用
调用
设置
设置
设置
调用
启动
发送
通知
调用
调用
调用
_led_init
periph_led_init
_led_run
_led_destroy
_find_led_channel
periph_led_blink
led_timer_handler
ESP-ADF应用
periph_led_stop
esp_periph_create
ESP-ADF事件系统
ESP-IDF LEDC API

LED外设API和数据结构

公共API
// LED外设初始化函数
esp_periph_handle_t periph_led_init(periph_led_cfg_t* config);// LED闪烁控制函数
esp_err_t periph_led_blink(esp_periph_handle_t periph, int gpio_num, int time_on_ms, int time_off_ms, bool fade, int loop, periph_led_idle_level_t level);// LED停止闪烁函数
esp_err_t periph_led_stop(esp_periph_handle_t periph, int gpio_num);
事件类型
// LED事件类型
typedef enum {PERIPH_LED_UNCHANGE = 0,     // 无事件PERIPH_LED_BLINK_FINISH,     // LED闪烁完成时
} periph_led_event_id_t;// LED空闲电平类型
typedef enum {PERIPH_LED_IDLE_LEVEL_LOW,   // 低电平输出PERIPH_LED_IDLE_LEVEL_HIGH   // 高电平输出
} periph_led_idle_level_t;
配置结构体
// LED配置结构体
typedef struct {ledc_mode_t      led_speed_mode;        // LEDC速度模式,高速模式或低速模式ledc_timer_bit_t led_duty_resolution;   // LEDC通道占空比分辨率ledc_timer_t     led_timer_num;         // 选择通道的定时器源(0-3)uint32_t         led_freq_hz;           // LEDC定时器频率(Hz)int              gpio_num;              // 可选,<0表示无效的GPIO编号
} periph_led_cfg_t;
内部数据结构
// LED通道结构体(内部实现)
typedef struct {int index;             // 通道索引int pin;               // GPIO引脚编号int high_level_ms;     // 高电平持续时间(毫秒)int low_level_ms;      // 低电平持续时间(毫秒)long long tick;        // 时间戳int loop;              // 循环次数bool is_high_level;    // 当前是否为高电平bool fade;             // 是否启用渐变效果bool stop;             // 是否停止int level;             // 空闲电平
} periph_led_channel_t;// LED外设主结构体(内部实现)
typedef struct periph_led {ledc_mode_t      led_speed_mode;       // LEDC速度模式ledc_timer_bit_t led_duty_resolution;  // 占空比分辨率ledc_timer_t     led_timer_num;        // 定时器编号uint32_t         led_freq_hz;          // 频率(Hz)QueueHandle_t    led_mutex;            // 互斥锁periph_led_channel_t channels[MAX_LED_CHANNEL]; // LED通道数组
} periph_led_t;

LED外设配置选项

LED外设提供了以下配置选项,通过periph_led_cfg_t结构体设置:

  • led_speed_mode: LEDC速度模式,可选LEDC_HIGH_SPEED_MODELEDC_LOW_SPEED_MODE
  • led_duty_resolution: LEDC占空比分辨率,如LEDC_TIMER_10_BIT表示10位分辨率(0-1023)
  • led_timer_num: LEDC定时器编号,可选LEDC_TIMER_0LEDC_TIMER_3
  • led_freq_hz: LEDC定时器频率,单位Hz,默认为5000Hz
  • gpio_num: 可选参数,指定默认的GPIO引脚,<0表示无效

在调用periph_led_blink函数时,还可以设置以下参数:

  • gpio_num: 指定要控制的GPIO引脚
  • time_on_ms: LED亮的时间,单位毫秒
  • time_off_ms: LED灭的时间,单位毫秒
  • fade: 是否启用渐变效果
  • loop: 闪烁循环次数,<0表示无限循环
  • level: 空闲电平,可选PERIPH_LED_IDLE_LEVEL_LOWPERIPH_LED_IDLE_LEVEL_HIGH

LED外设初始化流程

LED外设的初始化流程主要通过periph_led_init_led_init函数实现。下面详细介绍这个初始化过程。

外设层初始化过程(periph_led.c)

外设层初始化主要通过periph_led_init函数(位于periph_led.c)完成,主要包括以下步骤:

  1. 创建外设句柄:调用esp_periph_create函数创建LED外设句柄
  2. 分配内部数据结构:分配periph_led_t结构体内存
  3. 设置配置参数:设置LED速度模式、占空比分辨率、定时器编号和频率
  4. 创建互斥锁:创建用于保护LED通道访问的互斥锁
  5. 初始化通道数组:将所有通道的引脚设置为-1(无效)
  6. 注册回调函数:设置初始化、运行和销毁回调函数
// 文件:components/esp_peripherals/periph_led.c
esp_periph_handle_t periph_led_init(periph_led_cfg_t *config)
{// 1. 创建外设句柄esp_periph_handle_t periph = esp_periph_create(PERIPH_ID_LED, "periph_led");//check periph// 2. 分配内部数据结构periph_led_t *periph_led = audio_calloc(1, sizeof(periph_led_t));//check periph_led// 3. 设置配置参数periph_led->led_speed_mode      = config->led_speed_mode;periph_led->led_duty_resolution = config->led_duty_resolution;periph_led->led_timer_num       = config->led_timer_num;periph_led->led_freq_hz         = config->led_freq_hz;// 4. 创建互斥锁periph_led->led_mutex           = mutex_create();// 设置默认频率(如果未指定)if (periph_led->led_freq_hz == 0) {periph_led->led_freq_hz = 5000;}// 5. 初始化通道数组memset(&periph_led->channels, -1, sizeof(periph_led->channels));// 6. 注册回调函数esp_periph_set_data(periph, periph_led);esp_periph_set_function(periph, _led_init, _led_run, _led_destroy);return periph;
}

当LED外设被添加到外设集合并启动时,会调用_led_init函数(位于periph_led.c),该函数负责初始化LEDC定时器和渐变功能:

// 文件:components/esp_peripherals/periph_led.c
static esp_err_t _led_init(esp_periph_handle_t self)
{// 验证LED外设VALIDATE_LED(self, ESP_FAIL);// 获取LED外设数据periph_led_t *periph_led = esp_periph_get_data(self);// 配置LEDC定时器ledc_timer_config_t ledc_timer = {.duty_resolution = periph_led->led_duty_resolution, // PWM占空比分辨率.freq_hz = periph_led->led_freq_hz,                 // PWM信号频率.speed_mode = periph_led->led_speed_mode,           // 定时器模式.timer_num = periph_led->led_timer_num              // 定时器索引};// 设置高速通道的定时器0配置ledc_timer_config(&ledc_timer);// 安装LEDC渐变功能ledc_fade_func_install(0);return ESP_OK;
}
LED外设完整初始化时序图

下图展示了LED外设初始化的流程:

应用程序 periph_led_init (periph_led.c) esp_periph库 _led_init (periph_led.c) ESP-IDF LEDC API periph_led_init(config) esp_periph_create(PERIPH_ID_LED, "periph_led") periph 分配 periph_led_t 结构体 设置 LED配置参数 创建互斥锁 初始化通道数组 esp_periph_set_data(periph, periph_led) esp_periph_set_function(periph, _led_init, _led_run, _led_destroy) periph 当外设被添加到外设集合并启动时 esp_periph_start(periph) _led_init(self) esp_periph_get_data(self) periph_led 准备ledc_timer_config_t配置 ledc_timer_config(&ledc_timer) ESP_OK ledc_fade_func_install(0) ESP_OK ESP_OK ESP_OK 应用程序 periph_led_init (periph_led.c) esp_periph库 _led_init (periph_led.c) ESP-IDF LEDC API

LED外设销毁流程

LED外设的销毁流程主要通过_led_destroy函数实现,该函数在外设被停止时由ESP外设框架调用。下面详细介绍销毁过程。

销毁流程分析

LED外设销毁主要通过_led_destroy函数(位于periph_led.c)完成,主要包括以下步骤:

  1. 停止所有LED通道:遍历所有通道,对有效通道调用ledc_stop函数停止输出
  2. 停止定时器:调用esp_periph_stop_timer函数停止LED闪烁定时器
  3. 卸载渐变功能:调用ledc_fade_func_uninstall函数卸载LEDC渐变功能
  4. 销毁互斥锁:释放用于保护LED通道访问的互斥锁
  5. 释放内存:释放periph_led_t结构体占用的内存
// 文件:components/esp_peripherals/periph_led.c
static esp_err_t _led_destroy(esp_periph_handle_t self)
{// 获取LED外设数据periph_led_t *periph_led = esp_periph_get_data(self);// 1. 停止所有LED通道for (int i = 0; i < MAX_LED_CHANNEL; i++) {periph_led_channel_t *ch = &periph_led->channels[i];if (ch->index > 0 && ch->pin > 0) {ledc_stop(periph_led->led_speed_mode, ch->index, ch->level);}}// 2. 停止定时器esp_periph_stop_timer(self);// 3. 卸载渐变功能ledc_fade_func_uninstall();// 4. 销毁互斥锁mutex_destroy(periph_led->led_mutex);// 5. 释放内存audio_free(periph_led);return ESP_OK;
}
销毁流程时序图

下图展示了LED外设销毁的完整流程:

应用程序 esp_periph库 _led_destroy (periph_led.c) ESP-IDF LEDC API esp_periph_stop(set, led_handle) _led_destroy(self) 遍历所有LED通道 ledc_stop(led_speed_mode, ch->>index, ch->>level) ESP_OK loop [每个有效通道] esp_periph_stop_timer(self) ESP_OK ledc_fade_func_uninstall() ESP_OK mutex_destroy(periph_led->>led_mutex) audio_free(periph_led) ESP_OK ESP_OK 应用程序 esp_periph库 _led_destroy (periph_led.c) ESP-IDF LEDC API

LED外设事件处理机制

LED外设的事件处理机制相对简单,主要包括以下几个方面:

事件处理函数特点

LED外设的_led_run函数实现非常简单,仅返回ESP_OK,不处理任何事件。这表明LED外设本身不会对接收到的事件进行处理:

// 文件:components/esp_peripherals/periph_led.c
static esp_err_t _led_run(esp_periph_handle_t self, audio_event_iface_msg_t *msg)
{return ESP_OK;
}
LED闪烁控制流程

当调用periph_led_blink函数控制LED闪烁时,会进行以下初始化步骤:

  1. 查找可用通道:调用_find_led_channel函数查找指定GPIO对应的通道或可用通道
  2. 配置LEDC通道:设置通道、占空比、GPIO引脚等参数
  3. 设置闪烁参数:设置高电平时间、低电平时间、循环次数等参数
  4. 启动定时器:启动定时器处理LED状态变化
// 文件:components/esp_peripherals/periph_led.c
esp_err_t periph_led_blink(esp_periph_handle_t periph, int gpio_num, int time_on_ms, int time_off_ms, bool fade, int loop, periph_led_idle_level_t level)
{// 获取LED外设数据periph_led_t *periph_led = esp_periph_get_data(periph);// 1. 查找可用通道periph_led_channel_t *ch = _find_led_channel(periph_led, gpio_num);if (ch == NULL) {return ESP_FAIL;}// 2. 配置LEDC通道ledc_channel_config_t ledc_channel_cfg = {.channel    = ch->index,.duty       = 0,.gpio_num   = gpio_num,.speed_mode = periph_led->led_speed_mode,.timer_sel  = periph_led->led_timer_num,};ledc_channel_config(&ledc_channel_cfg);// 3. 设置闪烁参数ch->pin = gpio_num;ch->tick = audio_sys_get_time_ms();ch->loop = loop;ch->fade = fade;// 根据空闲电平设置高低电平时间if (level == PERIPH_LED_IDLE_LEVEL_LOW) {ch->is_high_level = false;ch->high_level_ms = time_on_ms;ch->low_level_ms = time_off_ms;} else {ch->is_high_level = true;ch->high_level_ms = time_off_ms;ch->low_level_ms = time_on_ms;}ch->stop = false;ch->level = level;// 4. 启动定时器esp_periph_start_timer(periph, portTICK_RATE_MS, led_timer_handler);return ESP_OK;
}
LED定时器处理函数

LED闪烁的核心是通过定时器处理函数led_timer_handler实现的,该函数会定期检查每个LED通道的状态并根据配置进行切换:

// 文件:components/esp_peripherals/periph_led.c
static void led_timer_handler(xTimerHandle tmr)
{// 获取外设句柄和数据esp_periph_handle_t periph = (esp_periph_handle_t) pvTimerGetTimerID(tmr);periph_led_t *periph_led = esp_periph_get_data(periph);// 加锁保护通道访问mutex_lock(periph_led->led_mutex);// 遍历所有LED通道for (int i = 0; i < MAX_LED_CHANNEL; i++) {periph_led_channel_t *ch = &periph_led->channels[i];// 跳过无效或已停止的通道if (ch->pin < 0 || ch->stop == true) {continue;}// 检查是否完成所有循环if (ch->loop == 0) {// 停止LED并发送完成事件ledc_stop(periph_led->led_speed_mode, ch->index, ch->level);esp_periph_send_event(periph, PERIPH_LED_BLINK_FINISH, (void *)ch->pin, 0);ch->stop = true;continue;}// 处理低电平到高电平的切换if (!ch->is_high_level && audio_sys_get_time_ms() - ch->tick > ch->low_level_ms) {// 减少循环计数(如果需要)if (ch->loop > 0) {ch->loop--;}// 切换到高电平if (ch->fade) {// 带渐变效果ledc_set_fade_with_time(periph_led->led_speed_mode, ch->index, pow(2, periph_led->led_duty_resolution) - 1, ch->high_level_ms);ledc_fade_start(periph_led->led_speed_mode, ch->index, LEDC_FADE_NO_WAIT);} else {// 无渐变效果ledc_set_duty(periph_led->led_speed_mode, ch->index, pow(2, periph_led->led_duty_resolution) - 1);ledc_update_duty(periph_led->led_speed_mode, ch->index);}// 更新状态和时间戳if (ch->low_level_ms > 0) {ch->is_high_level = true;}ch->tick = audio_sys_get_time_ms();} // 处理高电平到低电平的切换else if (ch->is_high_level && audio_sys_get_time_ms() - ch->tick > ch->high_level_ms) {// 减少循环计数(如果需要)if (ch->loop > 0) {ch->loop--;}// 切换到低电平if (ch->fade) {// 带渐变效果ledc_set_fade_with_time(periph_led->led_speed_mode, ch->index, 0, ch->low_level_ms);ledc_fade_start(periph_led->led_speed_mode, ch->index, LEDC_FADE_NO_WAIT);} else {// 无渐变效果ledc_set_duty(periph_led->led_speed_mode, ch->index, 0);ledc_update_duty(periph_led->led_speed_mode, ch->index);}// 更新状态和时间戳if (ch->high_level_ms > 0) {ch->is_high_level = false;}ch->tick = audio_sys_get_time_ms();}}// 解锁mutex_unlock(periph_led->led_mutex);
}
LED闪烁控制流程图

下图展示了应用程序控制LED闪烁的流程,包括闪烁启动和定时器处理过程:

应用程序 periph_led_blink (periph_led.c) 定时器 (led_timer_handler) ESP-IDF LEDC API periph_led_blink(periph, gpio_num, time_on_ms, time_off_ms, fade, loop, level) _find_led_channel(periph_led, gpio_num) ledc_channel_config(&ledc_channel_cfg) ESP_OK 设置通道参数 esp_periph_start_timer(periph, portTICK_RATE_MS, led_timer_handler) ESP_OK 定时器周期性执行 检查所有通道状态 ledc_stop(...) 发送PERIPH_LED_BLINK_FINISH事件 设置新的占空比/渐变 ESP_OK 更新通道状态 alt [循环次数为0] [需要切换状态] loop [每个定时器周期] 应用程序 periph_led_blink (periph_led.c) 定时器 (led_timer_handler) ESP-IDF LEDC API
事件类型

LED外设定义了两种事件类型:

  1. PERIPH_LED_UNCHANGE:LED状态未改变事件
  2. PERIPH_LED_BLINK_FINISH:LED闪烁完成事件

这些事件定义在periph_led.h文件中:

// 文件:components/esp_peripherals/include/periph_led.h
typedef enum {PERIPH_LED_UNCHANGE = 0,PERIPH_LED_BLINK_FINISH,
} periph_led_event_id_t;
事件触发机制

LED外设主要在以下情况下触发事件:

  1. 闪烁完成:当LED完成指定循环次数的闪烁后,在led_timer_handler函数中触发PERIPH_LED_BLINK_FINISH事件:
// 文件:components/esp_peripherals/periph_led.c (led_timer_handler函数片段)
if (ch->loop == 0) {// 停止LED并发送完成事件ledc_stop(periph_led->led_speed_mode, ch->index, ch->level);esp_periph_send_event(periph, PERIPH_LED_BLINK_FINISH, (void *)ch->pin, 0);ch->stop = true;continue;
}
事件处理特点
  1. 被动触发:LED外设事件是被动触发的,只有在特定条件满足时(如闪烁完成)才会发送事件
  2. 单向通信:LED外设只发送事件到应用程序,不接收和处理来自应用程序的事件
  3. GPIO信息传递:事件触发时会将对应的GPIO引脚号作为参数传递,便于应用程序识别是哪个LED触发了事件
事件处理流程图

下图展示了LED外设事件的触发和处理流程:

定时器 (led_timer_handler) esp_periph库 应用程序 检测到闪烁完成(loop=0) esp_periph_send_event(periph, PERIPH_LED_BLINK_FINISH, (void *)ch->>pin, 0) 事件回调(PERIPH_LED_BLINK_FINISH, gpio_num) 应用程序处理事件 可以根据gpio_num 识别是哪个LED触发了事件 定时器 (led_timer_handler) esp_periph库 应用程序

LED外设典型使用示例

下面是一个简单的LED外设使用示例,展示了基本的初始化和控制流程:

#include "esp_log.h"
#include "esp_peripherals.h"
#include "periph_led.h"static const char *TAG = "LED_EXAMPLE";void app_led_simple_example(void)
{// 1. 初始化外设管理器esp_periph_config_t periph_cfg = DEFAULT_ESP_PERIPH_SET_CONFIG();esp_periph_set_handle_t set = esp_periph_set_init(&periph_cfg);// 2. 配置LED外设periph_led_cfg_t led_cfg = {.led_speed_mode = LEDC_HIGH_SPEED_MODE,.led_duty_resolution = LEDC_TIMER_10_BIT,.led_timer_num = LEDC_TIMER_0,.led_freq_hz = 5000,};// 3. 初始化LED外设esp_periph_handle_t led_handle = periph_led_init(&led_cfg);// 4. 启动LED外设esp_periph_start(set, led_handle);// 5. 控制LED闪烁 - GPIO 22闪烁5次// 参数: 外设句柄, GPIO引脚, 亮时间(ms), 灭时间(ms), 渐变效果, 循环次数, 空闲电平periph_led_blink(led_handle, 22, 300, 700, true, 5, PERIPH_LED_IDLE_LEVEL_LOW);// 等待LED闪烁完成vTaskDelay(5000 / portTICK_PERIOD_MS);// 6. 清理资源esp_periph_stop(set, led_handle);esp_periph_set_destroy(set);
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词