PWM
LEDC
LED 控制器 (LEDC) 主要用于控制 LED,也可产生 PWM 信号用于其他设备的控制。该控制器有 8 路通道,可以产生独立的波形,驱动 RGB LED 等设备。
LEDC 通道共有两组,分别为 8 路高速通道和 8 路低速通道。高速通道模式在硬件中实现,可以自动且无干扰地改变 PWM 占空比。低速通道模式下,PWM 占空比需要由软件中的驱动器改变。每组通道都可以使用不同的时钟源。
LED PWM 控制器可在无需 CPU 干预的情况下自动改变占空比,实现亮度和颜色渐变。
设置 LEDC 通道在 高速模式或低速模式 下运行,需要进行如下配置:
-
定时器配置 指定 PWM 信号的频率和占空比分辨率。
-
通道配置 绑定定时器和输出 PWM 信号的 GPIO。
-
改变 PWM 信号 输出 PWM 信号来驱动 LED。可通过软件控制或使用硬件渐变功能来改变 LED 的亮度。
要设置定时器,可调用函数 ledc_timer_config(),并将包括如下配置参数的数据结构 ledc_timer_config_t 传递给该函数:
-
速度模式 ledc_mode_t
-
定时器索引 ledc_timer_t
-
PWM 信号频率(Hz)
-
PWM 占空比分辨率
-
时钟源 ledc_clk_cfg_t
频率和占空比分辨率相互关联。PWM 频率越高,占空比分辨率越低,反之亦然。如果 API 不是用来改变 LED 亮度,而是用于其它目的,这种相互关系可能会很重要。更多信息详见 频率和占空比分辨率支持范围 一节。
时钟源同样可以限制 PWM 频率。选择的时钟源频率越高,可以配置的 PWM 频率上限就越高。
如果不知道用什么时钟源,可以选择:LEDC_AUTO_CLK
自动选择时钟源
LEDC 驱动提供了一个辅助函数 ledc_find_suitable_duty_resolution()。传入时钟源频率及期望的 PWM 信号频率,这个函数可以直接找到最大可配的占空比分辨率值。
当一个定时器不再被任何通道所需要时,可以通过调用相同的函数 ledc_timer_config() 来重置这个定时器。此时,函数入参的配置结构体需要指定:
-
ledc_timer_config_t::speed_mode 重置定时器的所属速度模式 (ledc_mode_t)
-
ledc_timer_config_t::timer_num 重置定时器的索引 (ledc_timer_t)
-
ledc_timer_config_t::deconfigure 将指定定时器重置必须配置此项为 true
代码驱动Sg90
main.c
/*
* @Author: i want to 舞动乾坤
* @Date: 2024-07-23 18:30:30
* @LastEditors: i want to 舞动乾坤
* @LastEditTime: 2024-07-23 18:50:35
* @FilePath: \pwm_sg90\main\main.c
* @Description:
*
* Copyright (c) 2024 by ${i want to 舞动乾坤}, All Rights Reserved.
*/
#include <stdio.h>
#include "sg90.h"
#include "freeRtos/FreeRTOS.h"
#include "freertos/task.h"
void app_main(void)
{
sg90_init();
sg90_SetAngle(0);//归0
vTaskDelay(1000/portTICK_PERIOD_MS);
sg90_SetAngle(60);//旋转60度
vTaskDelay(1000/portTICK_PERIOD_MS);
sg90_SetAngle(0);//旋转到0
vTaskDelay(1000/portTICK_PERIOD_MS);
sg90_SetAngle(180);//旋转到180度
while (1)
{
/* code */
}
}
sg90.c
/*
* @Author: i want to 舞动乾坤
* @Date: 2024-07-23 18:30:26
* @LastEditors: i want to 舞动乾坤
* @LastEditTime: 2024-07-23 18:53:13
* @FilePath: \pwm_sg90\main\sg90.c
* @Description: sg90舵机驱动代码
*
* Copyright (c) 2024 by i want to 舞动乾坤, All Rights Reserved.
*/
#include <freeRtos/FreeRTOS.h>
#include <driver/ledc.h>
#include <driver/gpio.h>
#include <freeRtos/task.h>
#define sg90_pin GPIO_NUM_23//信号线的引脚
#define sg90_freq_hz (50)//sg90频率
#define sg90_timer0 LEDC_TIMER_0//定时器0
#define sg90_timer_channel LEDC_CHANNEL_0 //通道0
#define sg90_speedMode LEDC_LOW_SPEED_MODE//低速模式
//为了符合 0.5ms~2.5ms的脉宽 将500~2500 映射到 0度~180度
#define sg90_min_pulse_width_us 500 //映射到500 的最小脉冲宽度
#define sg90_max_pulse_width_us 2500//映射到2500的最大脉冲宽度
/**
* @description: sg90初始化
* @param 无
* @return {*}
*/
void sg90_init()
{
ledc_timer_config_t ledc_timer_InitStructure=
{
.clk_cfg = LEDC_AUTO_CLK, //自动选择时钟
.duty_resolution=LEDC_TIMER_13_BIT,//13bit位分辨率
.freq_hz=sg90_freq_hz,//50hz T=1/50 =0.02s =20ms 周期
.speed_mode=sg90_speedMode,//模式位低速模式
.timer_num=sg90_timer0//使用定时器0
};
ledc_timer_config(&ledc_timer_InitStructure);
ledc_channel_config_t ledc_channel_InitStructure=
{
.channel=sg90_timer_channel,//通道0
.duty=0,//占空比 后面可以再设置 范围:0~ 2^13 -1
.gpio_num=sg90_pin,
.hpoint=0,
.intr_type=LEDC_INTR_DISABLE,//中断使能关闭
.speed_mode=sg90_speedMode,//低速模式
.timer_sel=sg90_timer0//定时器 0
};
ledc_channel_config(&ledc_channel_InitStructure);
}
/**
* @description: 设置sg90占空比
* @param: duty 设置的占空比 范围:0~(2^13) -1
* @return {*}
*/
void sg90_SetDuty(uint32_t duty)
{
ledc_set_duty(sg90_speedMode,sg90_timer_channel,duty);
ledc_update_duty(sg90_speedMode,sg90_timer_channel);
}
/**
* @description: 设置sg90转动的角度
* @param: angle 角度 范围:0~180
* @return {*}
*/
void sg90_SetAngle(float angle)
{
uint16_t pulse_width_us=0;
uint32_t duty;
if(angle>180){angle=180;}
else if(angle<0){angle=0;}
//计算过程:0度 对应 500us 180度 对应 2500us 即线性关系 y=kx+b ,代入 (x=0,y=500)以及(x=180,y=2500) 求解k 和 b ,由传来的参数angle得到最终映射的带宽us数
pulse_width_us=(sg90_min_pulse_width_us+(sg90_max_pulse_width_us-sg90_min_pulse_width_us)*(angle /180));//将0度和180度映射到 500~2500的脉冲上,返回的结果为高电平持续的时间:单位us
//占空比= 高电平持续时间 (ps:单位转换为s 1s=10^6us) / 一个周期的时间(1/sg90_freq_hz) (ps单位:秒)
//高电平持续时间 =pulse_width_us ,一个周期的时间 (1/sg90_freq_hz) pulse_width_us*10^-6/(1/sg90_freq_hz) *=pulse_width_us *sg90_freq_hz /10^6(1e6)
//为什么要乘以 1<<13 -1 即 8192呢,因为13位的分辨率 需要将计算得到的占空比值缩放至 0 到 (1<<13) - 1 的范围内。
duty=pulse_width_us *sg90_freq_hz *((1<<13)-1)/ 1e6;
sg90_SetDuty(duty);//设置占空比
}
sg90.h
#ifndef _SG90__H
#define _SG90__H
void sg90_init();
void sg90_SetAngle(float angle);
#endif
目录结构
完结撒花————————————————————————————