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