0%

[ESP32]PWM的输出

一、PWM信号简介

  • PWM:脉冲宽度调制,简称脉宽调制
  • 频率(f):一秒钟PWM有多少个周期(单位Hz)
  • 周期(T):一个周期的时间
  • 占空比(duty):在一个脉冲周期内,高电平的时间与整个周期时间的比例
  • 脉宽时间:一个周期内高电平时间
  • 占空比越大,输出的有效电压越高。

    二、ESP32中的LEDC(PWM控制器)

  • LEDC:指LED PWM控制器,即PWM信号产生器。
  • LED_PWM有16路通道(0~15)
  • 8路高速通道(0~7),由80MHz时钟驱动
  • 8路低速通道(8~15),由8MHz时钟驱动

    三、产生PWM信号的流程

    使用Arduino 通过PWM调光LED必须遵循的步骤:
  1. 首先,选择一个PWM通道,从0到15共有16个通道。

  2. 然后,设置PWM信号频率。对于LED来说,使用5000 Hz的频率是合适的。

  3. 设置信号的占空比分辨率,分辨率从1到16位。此处将使用8位分辨率,可以使用0到255的值来控制LED亮度(2的8次方)。

    1
    ledcSetup(0, 30000, 8); // pwm通道, 频率, 精度
  4. 指定信号将出现在哪个或哪些GPIO上。为此,将使用以下函数:

    1
    ledcAttachPin(GPIO, channel)       //输出信号的GPIO,产生信号的通道。
  5. 使用PWM控制LED亮度,可以使用以下函数:
    1
    ledcWrite(channel, dutycycle);       // PWM信号的通道和占空比

3.1 LEDC频率与分辨率的关系

7c78c8eb42d29ae93a68e224c7485da1.jpeg

4aac65a593fa35e71173d9b1387a519e.jpeg

3.2 LEDC频率与最大分辨率表

1dc9b31603e691d22537e849a1cd084b.jpeg

3.3 使用LEDC输出PWM的示例程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <Arduino.h>

int pwmA = 12;
int pwmB = 13;
int pwmC = 14;

void setup()
{
// 建立LEDC通道
ledcSetup(0, 30000, 8); // pwm频道, 频率, 精度
ledcSetup(1, 30000, 8); // pwm频道, 频率, 精度
ledcSetup(2, 30000, 8); // pwm频道, 频率, 精度

// 将GPIO与LEDC通道绑定
ledcAttachPin(pwmA, 0);
ledcAttachPin(pwmB, 1);
ledcAttachPin(pwmC, 2);

// 输出PWM
ledcWrite(0, 255);
ledcWrite(1, 255);
ledcWrite(2, 255);
}

void loop()
{
}

虽然之前在STM32的博文里面的其中一篇讲PWM的博文已经讲过了,但在这里再讲一遍,我们手里的舵机模块基本都是靠时基脉冲中的占空比调节来控制的,那再具体再说的通俗一点呢?就是比如我的时基为20ms , 要求舵机转到0度的所要求的的占空比为0.5ms,那么我们就需要以20ms为一个周期,每个周期内的高电平时间为0.5ms(这就是占空比),然后其余时间为低电平即可,而具体到我手上的这个360度舵机呢,说实话不建议大家使用360度舵机,因为360度舵机失去了舵机最大的优势就是角度调节,我可以控制比如180度的舵机能够精确转动到哪一个位置,但是360度舵机不行,我们只能控制他正反转以及正反转速度,但是控制方法是一模一样的,下边是示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <Arduino.h>

// 舵机通道
int channel_PWM = 3;
// 舵机频率,那么周期也就是1/50,也就是20ms ,PWM一共有16个通道,0-7位高速通道由80Mhz时钟驱动,后面8个为低速通道由1Mhz时钟驱动
int freq_PWM = 50;
// PWM分辨率,取值为 0-20 之间 ,这里填写为10,那么后面的ledcWrite 这个里面填写的pwm值就在 0 - 2的10次方 之间 也就是 0-1024 ,如果是要求不高的东西你可以直接拿1000去算了
int resolution_PWM = 10;
// 绑定的IO,在下面的绑定函数里面会用到,绑定之后这个IO就会变成我们PWM的输出口
const int PWM_Pin = 4; //指定pwm绑定到这个io上输出

void setup() {
Serial.begin(115200);
ledcSetup(channel_PWM, freq_PWM, resolution_PWM); // 设置舵机通道
ledcAttachPin(PWM_Pin, channel_PWM); //将 LEDC 通道绑定到指定 IO 口上以实现输出
}

void get_pwm_info()
{
Serial.println("*******************************************************************");
Serial.print("读取指定通道占空比的值为:");
Serial.println(ledcRead(channel_PWM)); //读取指定通道占空比的值
Serial.print("读取指定通道频率的值为:");
Serial.println(ledcReadFreq(channel_PWM)); //返回指定通道当前频率(如果当前占空比为0 则该方法返回0)
}

void loop() {
ledcWrite(channel_PWM, 52); //20ms高电平为1ms左右 ,也就是1/20*1024,此时360度舵机正传最快
get_pwm_info(); //打印信息,点击IDE右上角的串口查看器就可以看到打印的内容了
delay(5000);
ledcWrite(channel_PWM, 77); //20ms高电平为1.5ms左右 ,也就是1.5/20*1024,此时360度舵机几乎停转
get_pwm_info();
delay(5000);
ledcWrite(channel_PWM, 102); //20ms高电平为2ms左右 ,也就是2/20*1024,此时360度舵机反转最快
get_pwm_info();
delay(5000);
//ledcDetachPin(PWM_Pin); //这个是解除IO口的pwm输出功能模式
}

一些需要注意的地方
1.注意PWM的最重要双要素
也就是频率与占空比,这上面我设置的频率为50,那么一个周期就是1/50那就是20ms,刚好就是我们的时基的长度,而占空比呢,上面有一个选项是设置这个PWM通道的分辨率,我这里设置10,那么占空比取值就是 0-2的10次方 , 也就是 0-1024 ,也就是在20ms这个时长内被分成1024份,我们需要20ms中1.5ms为高电平,那么就需要这1024份的前1.5/20这个比例的部分为高电平。

2.注意PWM的通道以及绑定的IO
我们要先制定好我们使用的是哪个通道,一共有16个通道,然后我们还要指定IO去绑定上我们就可以使用这个io输出我们的PWM 了

再来一个呼吸灯示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// the number of the LED pin
const int ledPin = 15; // 15 corresponds to GPIO16

// setting PWM properties
const int freq = 5000;
const int ledChannel = 0;
const int resolution = 8;

void setup(){
// configure LED PWM functionalitites
ledcSetup(ledChannel, freq, resolution);

// attach the channel to the GPIO to be controlled
ledcAttachPin(ledPin, ledChannel);
}

void loop(){
// increase the LED brightness
for(int dutyCycle = 0; dutyCycle <= 255; dutyCycle++){
// changing the LED brightness with PWM
ledcWrite(ledChannel, dutyCycle);
delay(15);
}

// decrease the LED brightness
for(int dutyCycle = 255; dutyCycle >= 0; dutyCycle--){
// changing the LED brightness with PWM
ledcWrite(ledChannel, dutyCycle);
delay(15);
}
}

参考文章:
https://blog.csdn.net/ailta/article/details/106537037
https://blog.csdn.net/qq_45355603/article/details/132654343