# 8. PWM

### 1. BiBoard（ESP32）PWM功能简介

BiBoard使用的ESP32和UNO用的328P有所不同。ESP32的PWM因为使用了矩阵总线的缘故，可以使用在非特定的引脚上。

ESP32的PWM被称作LED控制器（LEDC），LED PWM 控制器主要用于控制 LED，也可产生 PWM 信号用于其他设备的控制。该控制器有 8个定时器，对应8个高速通道和8个低速通道，合计16通道。

![Key Settings of LED PWM Controller's API](/files/-MX3fg-6riNXMr2TBGIa)

相比UNO直接使用“analogWrite()” 输入0-255之间任意的占空比。BiBoard上ESP32的PWM控制要略麻烦一些。需要控制的参数如下：

1. 人工选择PWM通道（0-15），也提高了引脚的使用灵活性
2. PWM波形的位数，决定了PWM波形占空比的分辨率，位数越高精度越高。
3. PWM波形的频率，决定了PWM波形的速度，频率越高速度越快。

PWM波形的频率和位数是相对的，位数越高频率越低。以下例子引用自ESP32编程手册：

比如，PWM 频率为 5 kHz 时，占空比分辨率最大可为 13 位。这意味着占空比可为 0 至 100% 之间的任意值，分辨率为 \~0.012%（2 \*\* 13 = 8192 LED 亮度的离散电平）。

LED PWM 控制器可用于生成频率较高的信号，足以为数码相机模组等其他设备计时。此时，最大频率可为 40 MHz，占空比分辨率为 1 位。也就是说，占空比固定为 50%，无法调整。

LED PWM 控制器 API 可在设定的频率和占空比分辨率超过 LED PWM 控制器硬件范围时报错。例如，试图将频率设置为 20 MHz、占空比分辨率设置为 3 位时，串行端口监视器上会报错。

### 2. Arduino配置BiBoard频率

如上文所示，我们需要配置通道、频率和位数，同时选择输出引脚。

第一步：配置PWM控制器

```
const int freq = 5000; // PWM frequency
const int ledcChannel = 0; // ledc channel, 0-15
const int resolution = 8; // resolution of PWM，8bit（0～255）
ledcSetup(ledcChannel, freq, resolution);
```

第二步：配置PWM输出引脚

```
ledcAttachPin(ledPin, ledcChannel);
```

第三步：输出PWM波形

```
ledcWrite(ledcChannel, dutyCycle);
```

例程中我们选择IO2作为输出引脚，连接IO2至一个LED，可以观察到LED呼吸灯的效果。

### 3. 完整的代码：

```
/* In this demo, we show how to use PWM in BiBoard(ESP32)
* It's different from the Arduino UNO based on the ATMega328P
*/

// define the PWM pin
const int ledPin = 2;  // 16 corresponds to GPIO16

// setting PWM properties
const int freq = 5000;          // PWM frequency
const int ledcChannel = 0;      // ledc channel, in ESP32 there're 16 ledc(PWM) channels
const int resolution = 8;       // resolution of PWM
 
void setup(){
  // configure ledc functionalitites
  // channels 0-15, resolution 1-16 bits, freq limits depend on resolution
  // ledcSetup(uint8_t channel, uint32_t freq, uint8_t resolution_bits);
  ledcSetup(ledcChannel, freq, resolution);     
  
  // attach the channel to the GPIO to be controlled
  ledcAttachPin(ledPin, ledcChannel);
}
 
void loop(){
  // increase the LED brightness
  for(int dutyCycle = 0; dutyCycle <= 255; dutyCycle++){   
    // changing the LED brightness with PWM
    ledcWrite(ledcChannel, dutyCycle);
    delay(15);
  }

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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.petoi.com/chinese/biboard/li-cheng/8.-pwm.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
