相關宏和變量
#define LED_PIN GPIO_NUM_3
#define LEDC_CHANNEL LEDC_CHANNEL_0
#define LEDC_TIMER LEDC_TIMER_0
#define LEDC_MODE LEDC_LOW_SPEED_MODE
#define LEDC_DUTY_RES LEDC_TIMER_13_BIT // 2^13 = 8192級亮度
#define LEDC_FREQUENCY 5000 // 5kHz頻率//呼吸燈效果
int direction = 1; // 1: 漸亮, -1: 漸暗
int duty = 0;
1.通過ledc_timer_config_t配置PWM參數
下面是結構體源碼
/*** @brief Configuration parameters of LEDC timer for ledc_timer_config function*/
typedef struct {ledc_mode_t speed_mode; /*!< LEDC speed speed_mode, high-speed mode (only exists on esp32) or low-speed mode */ledc_timer_bit_t duty_resolution; /*!< LEDC channel duty resolution */ledc_timer_t timer_num; /*!< The timer source of channel (0 - LEDC_TIMER_MAX-1) */uint32_t freq_hz; /*!< LEDC timer frequency (Hz) */ledc_clk_cfg_t clk_cfg; /*!< Configure LEDC source clock from ledc_clk_cfg_t.Note that LEDC_USE_RC_FAST_CLK and LEDC_USE_XTAL_CLK arenon-timer-specific clock sources. You can not have one LEDC timer usesRC_FAST_CLK as the clock source and have another LEDC timer uses XTAL_CLKas its clock source. All chips except esp32 and esp32s2 do not havetimer-specific clock sources, which means clock source for all timersmust be the same one. */bool deconfigure; /*!< Set this field to de-configure a LEDC timer which has been configured beforeNote that it will not check whether the timer wants to be de-configuredis binded to any channel. Also, the timer has to be paused first beforeit can be de-configured.When this field is set, duty_resolution, freq_hz, clk_cfg fields are ignored. */
} ledc_timer_config_t;
下面是配置
// 定義 LEDC 定時器配置結構體,用于設置 PWM 信號的“時間基準”(頻率、精度等)ledc_timer_config_t ledc_timer = {.speed_mode = LEDC_MODE, // LEDC 工作模式(如 LEDC_LOW_SPEED_MODE/LEDC_HIGH_SPEED_MODE)// 低速模式適合普通 GPIO,高速模式需配合特定引腳,由宏定義指定.duty_resolution = LEDC_DUTY_RES, // PWM 占空比分辨率(單位:bit)// 例:若設為 13bit,占空比范圍是 0~2^13-1=8191(數值越大精度越高).timer_num = LEDC_TIMER, // 選擇 LEDC 定時器編號(如 LEDC_TIMER_0 ~ LEDC_TIMER_3)// 每個定時器可對應多個通道,實現多路 PWM 輸出.freq_hz = LEDC_FREQUENCY, // PWM 信號的頻率(單位:Hz)// 例:設為 500Hz,即 PWM 周期為 2ms,人眼無閃爍感.clk_cfg = LEDC_AUTO_CLK, // LEDC 時鐘源選擇(LEDC_AUTO_CLK 表示自動選擇最優時鐘源)// 也可手動指定(如 LEDC_USE_APB_CLK),自動模式更便捷};// 調用 API 將配置參數寫入 LEDC 定時器硬件寄存器,完成定時器初始化ledc_timer_config(&ledc_timer);
2.通過ledc_channel_config_t配置PWM通道
結構體源碼
/*** @brief Configuration parameters of LEDC channel for ledc_channel_config function*/
typedef struct {int gpio_num; /*!< the LEDC output gpio_num, if you want to use gpio16, gpio_num = 16 */ledc_mode_t speed_mode; /*!< LEDC speed speed_mode, high-speed mode (only exists on esp32) or low-speed mode */ledc_channel_t channel; /*!< LEDC channel (0 - LEDC_CHANNEL_MAX-1) */ledc_intr_type_t intr_type; /*!< configure interrupt, Fade interrupt enable or Fade interrupt disable */ledc_timer_t timer_sel; /*!< Select the timer source of channel (0 - LEDC_TIMER_MAX-1) */uint32_t duty; /*!< LEDC channel duty, the range of duty setting is [0, (2**duty_resolution)] */int hpoint; /*!< LEDC channel hpoint value, the range is [0, (2**duty_resolution)-1] */ledc_sleep_mode_t sleep_mode; /*!< choose the desired behavior for the LEDC channel in Light-sleep */struct {unsigned int output_invert: 1;/*!< Enable (1) or disable (0) gpio output invert */} flags; /*!< LEDC flags */} ledc_channel_config_t;
配置
// 定義 LEDC 通道配置結構體,用于將“定時器生成的時鐘”與“具體 GPIO 引腳”綁定,輸出 PWM 信號ledc_channel_config_t ledc_channel = {.speed_mode = LEDC_MODE, // 必須與定時器的工作模式一致(低速/高速模式需匹配).channel = LEDC_CHANNEL, // 選擇 LEDC 通道編號(如 LEDC_CHANNEL_0 ~ LEDC_CHANNEL_7)// 一個定時器可對應多個通道,實現“同一頻率、不同占空比”的多路 PWM.timer_sel = LEDC_TIMER, // 綁定的定時器編號(需與上方配置的 LEDC_TIMER 一致)// 表示該通道使用此定時器生成的 PWM 基準時鐘.intr_type = LEDC_INTR_DISABLE, // 中斷使能配置(LEDC_INTR_DISABLE 表示禁用中斷)// 若需占空比更新完成后觸發中斷,可設為 LEDC_INTR_ENABLE.gpio_num = LED_PIN, // 輸出 PWM 信號的 GPIO 引腳(如 GPIO_NUM_2)// 需確保該引腳支持 LEDC 功能(參考芯片手冊的引腳功能表).duty = 0, // 初始占空比(需與定時器分辨率匹配,此處初始為 0,LED 熄滅)// 例:分辨率 13bit 時,0 表示占空比 0%(全滅),8191 表示 100%(全亮).hpoint = 0 // PWM 高電平起始點(單位:定時器計數周期)// 默認為 0,即定時器計數從 0 開始時輸出高電平,無需特殊調整};// 調用 API 將配置參數寫入 LEDC 通道硬件寄存器,完成通道初始化(此時 GPIO 已開始輸出 PWM)ledc_channel_config(&ledc_channel);
實現
while (1) { ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, duty);ledc_update_duty(LEDC_MODE, LEDC_CHANNEL);duty += direction * 100;if (duty >= 8191) { duty = 8191; direction = -1; }else if (duty <= 0) { duty = 0; direction = 1; }vTaskDelay(10 / portTICK_PERIOD_MS);}
流程
一:先配置目標PWM的參數
二:然后配置定時器的PWM輸出到哪個引腳
三:編寫呼吸燈的漸變
四:實現
#include <stdio.h>
#include "driver/ledc.h"
#include "esp_log.h"// 硬件配置定義
#define LED_PIN GPIO_NUM_3
#define LEDC_CHANNEL LEDC_CHANNEL_0
#define LEDC_TIMER LEDC_TIMER_0
#define LEDC_MODE LEDC_LOW_SPEED_MODE
#define LEDC_DUTY_RES LEDC_TIMER_13_BIT // 2^13 = 8192級亮度
#define LEDC_FREQUENCY 5000 // 5kHz頻率static const char *TAG = "BREATHE_LED";/*** @brief 應用程序入口*/
void app_main(void)
{printf("ESP32 Breathe LED Demo Started!\n");printf("LED Pin: GPIO %d\n", LED_PIN);printf("PWM Frequency: %d Hz\n", LEDC_FREQUENCY);printf("PWM Resolution: 13-bit (0-8191)\n");// -------------------------- 1. 配置 LEDC 定時器 ---------------------------ledc_timer_config_t ledc_timer = {.speed_mode = LEDC_MODE,.duty_resolution = LEDC_DUTY_RES,.timer_num = LEDC_TIMER,.freq_hz = LEDC_FREQUENCY,.clk_cfg = LEDC_AUTO_CLK,};ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));// -------------------------- 2. 配置 LEDC 通道 ---------------------------ledc_channel_config_t ledc_channel = {.speed_mode = LEDC_MODE,.channel = LEDC_CHANNEL,.timer_sel = LEDC_TIMER,.intr_type = LEDC_INTR_DISABLE,.gpio_num = LED_PIN,.duty = 0,.hpoint = 0};ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));ESP_LOGI(TAG, "Breathe LED initialized on GPIO %d", LED_PIN);// 呼吸燈變量int direction = 1; // 1: 漸亮, -1: 漸暗int duty = 0;// -------------------------- 3. 呼吸燈主循環 ---------------------------while (1) {// 設置占空比并立即生效(推薦使用這個函數)ESP_ERROR_CHECK(ledc_set_duty_and_update(LEDC_MODE, LEDC_CHANNEL, duty, 0));// 調整占空比duty += direction * 100;// 邊界檢查if (duty >= 8191) {duty = 8191;direction = -1;printf("Reached maximum brightness, starting to fade out...\n");} else if (duty <= 0) {duty = 0;direction = 1;printf("Reached minimum brightness, starting to fade in...\n");}// 簡單的延時(使用空循環實現,不依賴FreeRTOS)// 注意:這種方法會阻塞CPU,在實際應用中建議使用vTaskDelayfor (volatile int i = 0; i < 10000; i++) {// 空循環延時}}
}
說明
esp32的ledc庫專門負責PWM信號的生成