ESP32-S3學習筆記<8>:LEDC的應用
- 1. 頭文件包含
- 2. LEDC的配置
- 2.1 配置定時器
- 2.1.1 speed_mode/設置速度模式
- 2.1.2 duty_resolution/設置占空比分辨率
- 2.1.3 timer_num/選擇定時器
- 2.1.4 freq_hz/設定PWM頻率
- 2.1.5 clk_cfg/選擇LEDC的外設時鐘源
- 2.1.6 deconfigure/撤銷定時器配置
- 2.2 配置通道
- 2.2.1 gpio_num/設置PWM輸出的GPIO
- 2.2.2 speed_mode/速度模式
- 2.2.3 channel/選擇通道
- 2.2.4 intr_type/是否使能中斷
- 2.2.5 timer_sel/選擇通道綁定定時器
- 2.2.6 duty/占空比選擇
- 2.2.7 hpoint/設置高電平切換點
- 2.2.8 output_invert/指定輸出是否需要反相
- 3. 軟件控制PWM占空比
- 4. 示例
1. 頭文件包含
#include "driver/ledc.h"
2. LEDC的配置
配置LEDC生成PWM波,主要分為2個步驟完成:
- 配置LEDC的定時器。定時器決定了PWM的一些基礎特性,例如頻率。
- 配置LEDC的通道,并將通道綁定到定時器。通道可以配置和控制PWM占空比。
2.1 配置定時器
使用如下代碼配置定時器。LEDC外設內一共有4個定時器,8個通道。通道可以綁定在任意一個定時器上。定時器決定了PWM的頻率,因此綁定在一個定時器上的所有通道都具有相同的PWM頻率。
esp_err_t ledc_timer_config(const ledc_timer_config_t *timer_conf);
參數 timer_conf 的定義為:
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;
2.1.1 speed_mode/設置速度模式
定義如下。ESP32-S3僅支持 LEDC_LOW_SPEED_MODE 。
typedef enum {
#if SOC_LEDC_SUPPORT_HS_MODELEDC_HIGH_SPEED_MODE = 0, /*!< LEDC high speed speed_mode */
#endifLEDC_LOW_SPEED_MODE, /*!< LEDC low speed speed_mode */LEDC_SPEED_MODE_MAX, /*!< LEDC speed limit */
} ledc_mode_t;
2.1.2 duty_resolution/設置占空比分辨率
所謂分辨率,就是PWM波的一個完整周期中,定時器計數多少次。在給定的輸入時鐘情況下。對于不同的 freq_hz(PWM頻率),有不同的分辨率范圍可選。可以認為,最大的duty_resolution(2的duty_resolution次方) 乘以 freq_hz,接近于輸入時鐘頻率(但不相等)。下表羅列了不同時鐘源情況下,不同的PWM頻率可選的最大分辨率和最小分辨率。分辨率越大,輸出PWM的占空比調節越精細。
2.1.3 timer_num/選擇定時器
以下選項選擇LEDC中的定時器:
typedef enum {LEDC_TIMER_0 = 0, /*!< LEDC timer 0 */LEDC_TIMER_1, /*!< LEDC timer 1 */LEDC_TIMER_2, /*!< LEDC timer 2 */LEDC_TIMER_3, /*!< LEDC timer 3 */LEDC_TIMER_MAX,
} ledc_timer_t;
2.1.4 freq_hz/設定PWM頻率
設定PWM波的頻率。
2.1.5 clk_cfg/選擇LEDC的外設時鐘源
可用的選項有:
typedef enum {LEDC_AUTO_CLK = 0, /*!< LEDC source clock will be automatically selected based on the giving resolution and duty parameter when init the timer*/LEDC_USE_APB_CLK = SOC_MOD_CLK_APB, /*!< Select APB as the source clock */LEDC_USE_RC_FAST_CLK = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */LEDC_USE_XTAL_CLK = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */LEDC_USE_RTC8M_CLK __attribute__((deprecated("please use 'LEDC_USE_RC_FAST_CLK' instead"))) = LEDC_USE_RC_FAST_CLK, /*!< Alias of 'LEDC_USE_RC_FAST_CLK' */
} soc_periph_ledc_clk_src_legacy_t;
2.1.6 deconfigure/撤銷定時器配置
如果選項 deconfigure,設置為了1,則函數僅取消對定時器的配置,不會使用上面的參數對定時器配置。
2.2 配置通道
定時器配置完成,則可以使用如下函數配置PWM通道。
esp_err_t ledc_channel_config(const ledc_channel_config_t *ledc_conf);
參數 ledc_conf 的定義如下:
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] */struct {unsigned int output_invert: 1;/*!< Enable (1) or disable (0) gpio output invert */} flags; /*!< LEDC flags */} ledc_channel_config_t;
2.2.1 gpio_num/設置PWM輸出的GPIO
2.2.2 speed_mode/速度模式
對于ESP32-S3而言僅選擇 LEDC_LOW_SPEED_MODE 。
2.2.3 channel/選擇通道
參數 channel 選擇一個通道進行配置。可用選項有:
typedef enum {LEDC_CHANNEL_0 = 0, /*!< LEDC channel 0 */LEDC_CHANNEL_1, /*!< LEDC channel 1 */LEDC_CHANNEL_2, /*!< LEDC channel 2 */LEDC_CHANNEL_3, /*!< LEDC channel 3 */LEDC_CHANNEL_4, /*!< LEDC channel 4 */LEDC_CHANNEL_5, /*!< LEDC channel 5 */
#if SOC_LEDC_CHANNEL_NUM > 6LEDC_CHANNEL_6, /*!< LEDC channel 6 */LEDC_CHANNEL_7, /*!< LEDC channel 7 */
#endifLEDC_CHANNEL_MAX,
} ledc_channel_t;
2.2.4 intr_type/是否使能中斷
LEDC外設支持硬件自動調節PWM占空比(用來調節LED燈的漸亮漸暗、呼吸效果之類的)。如果使用這項功能,可在此處選擇是否使用中斷。如果是軟件控制占空比,則不必使能中斷。
typedef enum {LEDC_INTR_DISABLE = 0, /*!< Disable LEDC interrupt */LEDC_INTR_FADE_END, /*!< Enable LEDC interrupt */LEDC_INTR_MAX,
} ledc_intr_type_t;
2.2.5 timer_sel/選擇通道綁定定時器
定時器一共有4個,這里選擇將通道綁定到哪個定時器。
2.2.6 duty/占空比選擇
設置占空比。這里是配置時設置的,相當于默認占空比。后續運行時也有其他API可以修改占空比。其可設定的最小值為0,最大值為 2的duty_resolution次方。
假設前面設置定時器時 duty_resolution 是10位,則最大值為1024。當 duty 設置為512時,輸出信號高電平占空比為50%。設置為256時,輸出高電平占空比為25%。
2.2.7 hpoint/設置高電平切換點
通道內部有2個參數,hpoint 和 lpoint。前者確定輸出PWM信號從低電平到高電平切換的計數器的值。后者則決定信號從高電平到低電平切換的計數器的值。前者在此處設置。一旦 hpoint 和 duty 是確定的,則 lpoint 也是確定的。所以 lpoint 不需要用戶設置,驅動代碼會根據前兩個參數去算。
hpoint的值最小為0,最大為2的duty_resolution次方-1。
2.2.8 output_invert/指定輸出是否需要反相
PWM輸出信號默認是低電平的。設置此位,則反相輸出。
3. 軟件控制PWM占空比
使用如下函數設置PWM輸出的占空比:
esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty) ;
esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel) ;
前一個函數設置占空比門限。調用此函數不會立即生效。調用后一個函數來使得設定生效。
4. 示例
以下示例程序,先配置一個LEDC定時器,然后設置定時器的一個通道。默認情況下,輸出占空比50%。在主函數中,將占空比改為25%。
test_ledc.h文件:
#define TEST_LEDC_TIMER_SELECT (LEDC_TIMER_0 )
#define TEST_LEDC_TIMER_RESOLUTION (LEDC_TIMER_10_BIT )
#define TEST_LEDC_TIMER_FREQ (5000 )#define TEST_LEDC_CHANNEL_GPIO (GPIO_NUM_4 )
#define TEST_LEDC_CHANNEL_SELECT (LEDC_CHANNEL_0 )
#define TEST_LEDC_CHANNEL_DUTY (512 )
#define TEST_LEDC_CHANNEL_HPOINT (1 )void TEST_LEDC_LEDCConfig(void) ;
void TEST_LEDC_SoftUpdateDuty(void) ;
test_ledc.c文件:
#include "driver/ledc.h"
#include "esp_log.h"#include "test_ledc.h"void TEST_LEDC_LEDCConfig(void)
{esp_err_t iErrCode ;const ledc_timer_config_t stLEDCConfigInfo ={.speed_mode = LEDC_LOW_SPEED_MODE ,.duty_resolution = TEST_LEDC_TIMER_RESOLUTION ,.timer_num = TEST_LEDC_TIMER_SELECT ,.freq_hz = TEST_LEDC_TIMER_FREQ ,.clk_cfg = LEDC_USE_XTAL_CLK ,.deconfigure = 0} ;const ledc_channel_config_t stChannelConfigInfo = {.gpio_num = TEST_LEDC_CHANNEL_GPIO ,.speed_mode = LEDC_LOW_SPEED_MODE ,.channel = TEST_LEDC_CHANNEL_SELECT ,.intr_type = LEDC_INTR_DISABLE ,.timer_sel = TEST_LEDC_TIMER_SELECT ,.duty = TEST_LEDC_CHANNEL_DUTY ,.hpoint = TEST_LEDC_CHANNEL_HPOINT ,.flags.output_invert = 0} ;iErrCode = ledc_timer_config(&stLEDCConfigInfo) ;if(ESP_OK != iErrCode){ESP_LOGE("test_ledc", "Config LEDC timer error! Return value is %d\n", iErrCode) ;}iErrCode = ledc_channel_config(&stChannelConfigInfo) ;if(ESP_OK != iErrCode){ESP_LOGE("test_ledc", "Config LEDC channel error! Return value is %d\n", iErrCode) ;}return ;
}void TEST_LEDC_SoftUpdateDuty(void)
{esp_err_t iErrCode ;iErrCode = ledc_set_duty(LEDC_LOW_SPEED_MODE, TEST_LEDC_CHANNEL_SELECT, 256) ;if(ESP_OK != iErrCode){ESP_LOGE("test_ledc", "Set duty error! Return value is %d\n", iErrCode) ;}iErrCode = ledc_update_duty(LEDC_LOW_SPEED_MODE, TEST_LEDC_CHANNEL_SELECT) ;if(ESP_OK != iErrCode){ESP_LOGE("test_ledc", "Update duty error! Return value is %d\n", iErrCode) ;}return ;
}
main.c文件:
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"#include "test_ledc.h"void app_main(void)
{TEST_LEDC_LEDCConfig() ;while (true){vTaskDelay(1000) ;TEST_LEDC_SoftUpdateDuty() ;}
}