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

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);
}

相关文章:

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

目录 ESP-ADF外设子系统深度解析&#xff1a;esp_peripherals组件架构与核心设计&#xff08;显示输出类外设之LED&#xff09;简介模块概述功能定义架构位置核心特性 LED外设分析LED外设概述LED外设功能特点常见应用场景LED外设架构图 LED外设API和数据结构公共API事件类型配置…...

[特殊字符] Kotlin与C的类型别名终极对决:typealias vs typedef,如何让代码脱胎换骨?

在 Kotlin 中&#xff0c;typealias 是一个非常实用的关键字&#xff0c;它可以为已有的类型定义一个新的名称&#xff0c;起到简化代码和提升可读性的作用。比如&#xff1a; // 定义一个复杂函数类型的别名 typealias ClickListener (View, Int) -> Unitfun setOnClickL…...

第9期:文本条件生成(CLIP + Diffusion)详解

“让我们用一句话&#xff0c;让模型画出一幅画。” 在前几期中我们学习了 Denoising Diffusion Probabilistic Models&#xff08;DDPM&#xff09;如何在无条件情况下生成图像。而在本期&#xff0c;我们将跨入更具挑战性但也更酷的领域 —— 文本条件图像生成&#xff08;Te…...

8 编程笔记全攻略:Markdown 语法精讲、Typora 编辑器全指南(含安装激活、基础配置、快捷键详解、使用技巧)

1 妙笔在手&#xff0c;编程无忧&#xff01; 1.1 编程为啥要做笔记&#xff1f;这答案绝了&#xff01; 嘿&#xff0c;各位键盘魔法师&#xff01;学编程不记笔记&#xff0c;就像吃火锅不配冰可乐 —— 爽到一半直接噎住&#xff01;你以为自己脑子是顶配 SSD&#xff0c;结…...

C#测试linq中的左连接的基本用法

使用linq联表或者连接两个对象集合查询时一般使用的是join关键字&#xff0c;返回结果中包含两个表或两个对象集合中连接字段相等的数据记录&#xff0c;如果要实现sql语句中的左连接效果&#xff0c;并没有现成的left join关键字&#xff0c;此时可以使用DefaultIfEmpty 实现左…...

【Android面试八股文】Android系统架构【一】

Android系统架构图 1.1 安卓系统启动 1.设备加电后执行第一段代码&#xff1a;Bootloader 系统引导分三种模式&#xff1a;fastboot&#xff0c;recovery&#xff0c;normal&#xff1a; fastboot模式&#xff1a;用于工厂模式的刷机。在关机状态下&#xff0c;按返回开机 键进…...

什么是 Stream

Stream 是对集合对象功能的增强&#xff0c;它不是集合&#xff0c;也不存储数据&#xff0c;而是从集合中抽象出一条数据通道&#xff0c;让你可以用链式方式一步步处理数据。 &#x1f527; 常见操作分类 类型方法举例创建stream(), Stream.of(), Arrays.stream()中间操作fi…...

网络编程 - 4 ( TCP )

目录 TCP 流套接字编程 API 介绍 SeverSocket Socket 用 TCP 实现一个回显服务器 服务端 客户端 运行调试 第一个问题&#xff1a;PrintWriter 内置的缓冲区 - flush 刷新解决 第二个问题&#xff1a;上述代码中&#xff0c;需要进行 close 操作吗&#xff1f; 第三…...

在STM32的定时器外设中,选择使用哪个外部时钟配置函数

在STM32的定时器外设中&#xff0c;选择使用哪个外部时钟配置函数主要取决于以下几个因素&#xff1a; 时钟源类型&#xff1a; TIM_ITRxExternalClockConfig&#xff1a;使用内部触发输入(ITRx)&#xff0c;即来自其他定时器的时钟信号 TIM_TIxExternalClockConfig&#xff1…...

【Tauri2】026——Tauri+Webassembly

前言 不多废话 直言的说&#xff0c;笔者看到这篇文章大佬的文章 【04】Tauri 入门篇 - 集成 WebAssembly - 知乎https://zhuanlan.zhihu.com/p/533025312尝试集成一下WebAssembly&#xff0c;直接开始 正文 准备工作 新建一个项目 安装 vite的rsw插件和rsw pnpm instal…...

jenkins尾随命令

在访问jenkins的网址后面可以追加命令&#xff0c;比如访问地址是 http://10.20.0.124:8080/&#xff0c;常用的有以下几种方式&#xff1a; 1.关闭Jenkins 只要浏览器输入http://10.20.0.124:8080/exit即可退出&#xff0c;或者http://localhost:8080/exit 2.重启Jenkins …...

基于机器学习 LSTM 算法的豆瓣评论情感分析系统

基于机器学习 LSTM 算法的豆瓣评论情感分析系统 博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f44…...

腾讯云对象存储m3u8文件使用腾讯播放器播放

参考腾讯云官方文档&#xff1a; 播放器 SDK Demo 体验_腾讯云 重要的一步来了&#xff1a; 登录腾讯云控制台&#xff0c;找到对象存储的存储桶。 此时&#xff0c;再去刷新刚才创建的播放器html文件&#xff0c;即可看到播放画面了。...

基于chatgpt和deepseek解答显卡的回答

当然可以&#xff01;了解显卡特别是英伟达&#xff08;NVIDIA&#xff09;的系列&#xff0c;对于选购、升级或者了解游戏和创作性能都很重要。下面我帮你系统整理一下 NVIDIA 显卡的各个系列&#xff0c;并加点选购建议&#xff0c;方便你快速上手。 chatgpt &#x1f9e0; …...

2025年渗透测试面试题总结-拷打题库06(题目+回答)

网络安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 1. Sleep被禁用后的SQL注入 2. XSS属性控制利用 3. CSRF防护 4. 危险请求头 5. XXE高发场景 6. Ja…...

【一起学Rust】使用Thunk工具链实现Rust应用对Windows XP/7的兼容性适配实战

前言 在Rust语言快速发展的今天&#xff0c;开发者经常面临将现代语言特性与遗留系统兼容的挑战。特别是在工业控制、嵌入式设备等场景中&#xff0c;Windows XP/7等经典操作系统仍占据重要地位。本文深入解析如何通过Thunk工具链突破Rust编译器对旧版Windows系统的兼容性限制…...

leetcode 674. Longest Continuous Increasing Subsequence

目录 题目描述 第一步&#xff0c;明确并理解dp数组及下标的含义 第二步&#xff0c;分析明确并理解递推公式 第三步&#xff0c;理解dp数组如何初始化 第四步&#xff0c;理解遍历顺序 代码 题目描述 这是动态规划解决子序列问题的例子。与第300题的唯一区别就是&#…...

在VMware Workstation 17 Pro上实现Windows与UOS虚拟机之间复制粘贴文本及文件

在VMware Workstation 17 Pro上实现Windows与UOS虚拟机之间复制粘贴文本及文件 在本教程中&#xff0c;我们将介绍如何在VMware Workstation 17 Pro中安装UOS虚拟机&#xff0c;并通过安装open-vm-tools-desktop软件来实现Windows和UOS系统之间的文本和文件复制粘贴功能。 1.…...

十一、数据库day03--SQL语句02

文章目录 一、查询语句1. 基本查询2. 条件查询2.1 ⽐较运算符&逻辑运算符2.2 模糊查询2.3 范围查询2.4 判断空 3. 其他复杂查询3.1 排序3.2 聚合函数3.3 分组3.4 分页查询 二、回顾1. 使⽤ Navicat ⼯具中的命令列2.命令⾏基本操作步骤 提示&#xff1a;以下是本篇文章正文…...

第6章 类文件结构《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)》

第6章 类文件结构 代码编译的结果从本地机器码转变为字节码&#xff0c;是存储格式发展的一小步&#xff0c;却是编程语言发展的一大步。 6.1 概述 老师说过&#xff0c;计算机只认识0和1&#xff0c;所以我们写的程序需要被编译器翻译成由0和1构成的二进制格式才能被计算机…...

【Vue】模板语法与指令

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Vue 文章目录 1. Vue 模板语法基础1.1 文本插值1.2 原始 HTML1.3 属性绑定 2. Vue 指令系统2.1 条件渲染2.2 列表渲染2.3 事件处理2.4 表单输入绑定 3. 计算属性与侦听器3.1 计算属性3.2 侦听器 4. 类与样式绑定4.1 绑定 HTML 类…...

Python语法系列博客 · 第5期[特殊字符] 模块与包的导入:构建更大的程序结构

上一期小练习解答&#xff08;第4期回顾&#xff09; ✅ 练习1&#xff1a;判断偶数函数 def is_even(num):return num % 2 0print(is_even(4)) # True print(is_even(5)) # False✅ 练习2&#xff1a;求平均值 def avg(*scores):return sum(scores) / len(scores)print(…...

HashMap 初步理解 put 操作流程 HashMap 的线程安全问题

一、HashMap 核心原理 HashMap 是 Java 中最常用的哈希表实现&#xff0c;基于 数组 链表/红黑树 的复合结构&#xff0c;核心特性如下&#xff1a; 哈希函数 键的哈希值通过 hashCode() 计算&#xff0c;并通过扰动函数优化分布&#xff1a;static final int hash(Object ke…...

服务治理-服务发现和负载均衡

第一步&#xff1a;引入依赖 第二步&#xff1a;配置地址 改写购物车服务的代码 负载均衡成功实现。 假如有一个服务挂了&#xff0c;比如说8081&#xff0c;cart-service能不能正常访问&#xff0c;感知到。 再重新启动8081端口。 不管服务宕机也好&#xff0c;还是服务刚启动…...

GNU,GDB,GCC,G++是什么?与其他编译器又有什么关系?

文章目录 前言1. GNU和他的工具1.1 gcc与g1.2 gdb 2.Windows的Mingw/MSVC3.LLVM的clang/clang4.Make/CMake 前言 在开始之前我们先放一段Hello World&#xff1a;hello.c #include <stdio.h>int main() {printf("Hello World");return 0; }然后就是一段老生常…...

定制一款国密浏览器(9):SM4 对称加密算法

上一章介绍了 SM3 算法的移植要点,本章介绍对称加密算法 SM4 的移植要点。 SM4 算法相对 SM3 算法来说复杂一些,但还是比较简单的算法,详细算法说明参考《GMT 0002-2012 SM4分组密码算法》这份文档。铜锁开源项目的实现代码在 sm4.c 文件中,直接拿过来编译就可以。 但需要…...

kafka集群认证

1、安装Kerberos(10.10.10.168) yum install krb5-server krb5-workstation krb5-libs -y ​ 查看版本 klist -V ​ Kerberos 5 version 1.20.1 ​ 编辑/etc/hosts 10.10.10.168 ms1 10.10.10.150 ms2 10.10.10.110 ms3 vim /etc/krb5.conf # Configuration snippets ma…...

Mermaid 是什么,为什么适合AI模型和markdown

什么是 Mermaid&#xff1f; Mermaid 是一个基于 JavaScript 的开源绘图和图表工具&#xff0c;允许用户通过简单的文本语法创建图表。它支持生成流程图、时序图、类图、甘特图等多种类型的可视化内容&#xff0c;并直接从类似 Markdown 的代码中渲染。Mermaid 因其与 Markdow…...

为什么信号完整性对于高速连接器设计至关重要?

外部连接器通过在各种电子元件和系统之间可靠地传输数据而不损失保真度来保持信号完整性。在本文中&#xff0c;我们将讨论信号完整性的重要性&#xff0c;回顾高速部署挑战&#xff0c;并重点介绍各种连接器设计策略&#xff0c;以防止失真和降级。 了解连接器信号完整性挑战…...

【FFmpeg从入门到精通】第三章-FFmpeg转封装

1 音视频文件转MP4格式 在互联网常见的格式中&#xff0c;跨平台最好的应该是MP4文件&#xff0c;因为MP4文件既可以在PC平台的 Flashplayer 中播放&#xff0c;又可以在移动平台的 Android、ios 等平台中进行播放&#xff0c;而且使用系统默认的播放器即可播放&#xff0c;因…...

PG数据库推进医疗AI向量搜索优化路径研究(2025年3月修订版)

PG数据库推进医疗AI向量搜索优化路径研究 一、医疗 AI 向量搜索的发展现状与挑战 1.1 医疗数据特征与检索需求 医疗数据作为推动医疗领域进步与创新的关键要素,具有鲜明且复杂的特征。从多模态角度看,医疗数据涵盖了结构化数据,如患者基本信息、检验检查报告中的数值结果;…...

Android 下拉栏中的禁用摄像头和麦克风隐藏

Android 下拉栏中的禁用摄像头和麦克风隐藏 文章目录 Android 下拉栏中的禁用摄像头和麦克风隐藏一、前言二、下拉框中的禁用摄像头和麦克风隐藏实现1、设置支持属性为false2、修改代码 三、其他1、下拉栏中的禁用摄像头和麦克风隐藏小结2、 Android SensorPrivacyService ps&a…...

阿里云Clickhouse 冷热数据分层存储 实战记录

一、 背景 某业务Clickhouse库月数据增长超过2.5T&#xff0c;云上Clickhouse容量并不是无限的&#xff0c;单节点有32T上限&#xff0c;而业务已使用一半以上&#xff0c;依此速度&#xff0c;半年内就将达到上限。 与业务讨论&#xff0c;大致有以下几种解决思路&#xff1a;…...

ARINC818-实现

1.编码和解码&#xff1b;分隔符插入和删除&#xff1b;空闲idle字符插入 2.视频TX和RX接口&#xff1a;可以设计为流传输和帧同步传输 3.传输媒介&#xff1a;光纤或者铜缆 4.链路支持fc 1x,2x,3x,5x,6x,8x 上图中N有限制&#xff0c;N不能允许ADVB帧负载和填充长度不超过2112…...

OpenStack Yoga版安装笔记(23)Swift安装

一、官方文档 Object Storage Install Guide — Swift 2.29.3.dev5 documentation 二、环境准备 之前的实验&#xff0c;已经有controller, compute1, block1节点&#xff0c;并已经完成Keystone、Glance、Nova、Neutron、Cinder等主要OpenStack Service的安装。 此处新增…...

MySql 三大日志(redolog、undolog、binlog)详解

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/aa730ab3f84049638f6c9a785e6e51e9.png 1. redo log&#xff1a;“你他妈别丢数据啊&#xff01;” 干啥的&#xff1f; 这货是InnoDB的“紧急备忘录”。比如你改了一条数据&#xff0c;MySQL怕自己突然断电嗝屁了&am…...

算法题(128):费解的开关

审题&#xff1a; 本题需要我们将多组测试用例中拉灯数小于等于6的最小拉灯数输出&#xff0c;若拉灯数最小值仍大于6&#xff0c;则输出-1 思路&#xff1a; 方法一&#xff1a;二进制枚举 首先我们先分析一下基本特性&#xff1a; 1.所有的灯不可能重复拉&#xff1a;若拉的数…...

2025.04.19-阿里淘天春招算法岗笔试-第三题

📌 点击直达笔试专栏 👉《大厂笔试突围》 💻 春秋招笔试突围在线OJ 👉 笔试突围OJ 03. 数值平衡之道 问题描述 LYA 是一位精通树形数据结构的数学家,她有一棵包含 n n n...

单片机毕业设计选题物联网计算机电气电子类

题目一&#xff1a;基于单片机的PM2.5空气质量检测仪器 选 1.用到ADC0832模数转换芯片&#xff0c;数据更加精准。 2.使用夏普传感器的GP2Y1010AUOF粉尘传感器实时检测空气中的PM2.5值并通过1602显示出来&#xff0c;检测准确。 3.LCD1602液晶第一行 前面显示测到的PM2.5…...

TDOA解算——牛顿迭代法|以4个基站的三维空间下TDOA定位为背景,使用牛顿迭代法解算。附完整代码,订阅专栏后可复制粘贴

本问所介绍的代码通过TDOA(到达时间差)方法,结合牛顿迭代算法,实现了三维空间内目标位置的定位。系统包含1个主锚点和3个副锚点,通过测量信号到达各基站的时间差计算距离差,最终迭代求解目标坐标。订阅专栏后可以获得完整的MATLAB代码,粘贴到空脚本中即可运行 文章目录 …...

海量聊天数据处理:基于Spring Boot与SharingJDBC的分库分表策略及ClickHouse冷热数据分离

引言 随着互联网应用的快速发展&#xff0c;每天产生的聊天记录数量级已经达到了惊人的程度。以2000万条/天为例&#xff0c;一年下来就是大约7.3亿条记录。如此庞大的数据量给数据库的设计和管理带来了前所未有的挑战。本文将探讨如何使用SharingJDBC整合Spring Boot技术来实…...

网络开发基础(游戏)之 Socket API

Socket简介 Socket (套接字)是网络编程的基础&#xff0c;在 C# 中通过 System.Net.Sockets 命名空间提供了一套完整的 API 来实现网络通信。 网络上的两个程序通过一个双向的通信连接实现数据交换&#xff0c; 这个连接的一端称为一个Socket。 一个Socket包含了进行网络通信必…...

在 Amazon Graviton 上运行大语言模型:CPU 推理性能实测与调优指南

引言 在生成式 AI 浪潮中&#xff0c;GPU 常被视为大模型推理的唯一选择。然而&#xff0c;随着 ARM 架构的崛起和量化技术的成熟&#xff0c;CPU 推理的性价比逐渐凸显。本文基于 Amazon Graviton 系列实例与 llama.cpp 工具链&#xff0c;实测了 Llama 3、DeepSeek 等模型的…...

基于尚硅谷FreeRTOS视频笔记——15—系统配制文件说明与数据规范

目录 配置函数 INCLUDE函数 config函数 数据类型 命名规范 函数与宏 配置函数 官网上可以查找 最核心的就是 config和INCLUDE INCLUDE函数 这些就是裁剪的函数 它们使用一个ifndef。如果定义了&#xff0c;就如果定义了这个宏定义&#xff0c;那么代码就生效。 通过ifn…...

Nacos 使用了什么日志框架?如何配置和查看日志?

Nacos 使用的日志框架 Nacos 主要使用 SLF4j (Simple Logging Facade for Java) 作为日志门面&#xff08;API&#xff09;&#xff0c;并选择 Logback 作为其底层的日志实现。 SLF4j: 这是一个日志抽象层&#xff0c;允许开发者在代码中使用统一的接口进行日志记录&#xff…...

【基于Fluent+Python耦合的热管理数字孪生系统开发:新能源产品开发的硬核技术实践】

引言&#xff1a;热管理数字孪生的技术革命 在新能源领域&#xff08;如动力电池、储能系统、光伏逆变器等&#xff09;&#xff0c;热管理是决定产品性能与安全的核心问题。传统热设计依赖实验与仿真割裂的流程&#xff0c;而数字孪生技术通过实时数据驱动与动态建模&#xf…...

【工具变量】A股上市公司信息披露质量KV指数测算数据集(含do代码 1991-2024年)

KV指数&#xff08;Key Value Index&#xff09;作为评估信息披露质量的关键指标&#xff0c;在证券市场&#xff0c;尤其是A股市场上市公司信息披露监管与评估中占据重要地位。该指数通过系统化、定量化的方法&#xff0c;对企业发布的信息进行全面剖析与打分&#xff0c;精准…...

【ELF2学习板】利用OpenMP采用多核并行技术提升FFTW的性能

目录 引言 OpenMP简介 编译OpenMP支持的FFTW库 部署与测试 测试程序 程序部署 测试结果 结语 引言 在前面已经介绍了在ELF2开发板上运行FFTW计算FFT。今天尝试利用RK3588的多核运算能力来加速FFT运算。FFTW利用多核能力可以考虑使用多线程或者OpenMP。今天介绍一下Ope…...

打靶日记 zico2: 1

一、探测靶机IP&#xff08;进行信息收集&#xff09; 主机发现 arp-scan -lnmap -sS -sV -T5 -p- 192.168.10.20 -A二、进行目录枚举 发现dbadmin目录下有个test_db.php 进入后发现是一个登录界面&#xff0c;尝试弱口令&#xff0c;结果是admin&#xff0c;一试就出 得到加…...

【技术派后端篇】 Redis 实现用户活跃度排行榜

在各类互联网应用中&#xff0c;排行榜是一个常见的功能需求&#xff0c;它能够直观地展示用户的表现或贡献情况&#xff0c;提升用户的参与感和竞争意识。在技术派项目中&#xff0c;也引入了用户活跃度排行榜&#xff0c;该排行榜主要基于 Redis 的 ZSET 数据结构来实现。接下…...