在 Arduino环境下,我们如何优雅的输出频率可变的PWM波?
支持ADC功能的引脚请查看:引脚定义
这里我们就要借助 esp32-hal-ledc.c 和 esp32-hal-ledc.h 两个文件来完成 esp32-hal库 内置的 PWM 功能
1.在esp32-hal-ledc.c这个文件中,我们可以看到每个通道的和组、定时器的关系,共0~15个通道:
** LEDC Chan to Group/Channel/Timer Mapping
** ledc: 0 => Group: 0, Channel: 0, Timer: 0
** ledc: 1 => Group: 0, Channel: 1, Timer: 0
** ledc: 2 => Group: 0, Channel: 2, Timer: 1
** ledc: 3 => Group: 0, Channel: 3, Timer: 1
** ledc: 4 => Group: 0, Channel: 4, Timer: 2
** ledc: 5 => Group: 0, Channel: 5, Timer: 2
** ledc: 6 => Group: 0, Channel: 6, Timer: 3
** ledc: 7 => Group: 0, Channel: 7, Timer: 3
** ledc: 8 => Group: 1, Channel: 0, Timer: 0
** ledc: 9 => Group: 1, Channel: 1, Timer: 0
** ledc: 10 => Group: 1, Channel: 2, Timer: 1
** ledc: 11 => Group: 1, Channel: 3, Timer: 1
** ledc: 12 => Group: 1, Channel: 4, Timer: 2
** ledc: 13 => Group: 1, Channel: 5, Timer: 2
** ledc: 14 => Group: 1, Channel: 6, Timer: 3
** ledc: 15 => Group: 1, Channel: 7, Timer: 3
2. 在esp32-hal-ledc.h中,我们可以看到PWM相关的一些函数:
#ifndef _ESP32_HAL_LEDC_H_
#define _ESP32_HAL_LEDC_H_
#ifdef __cplusplus
extern "C" {
#endif
#include
#include
typedef enum {
NOTE_C, NOTE_Cs, NOTE_D, NOTE_Eb, NOTE_E, NOTE_F, NOTE_Fs, NOTE_G, NOTE_Gs, NOTE_A, NOTE_Bb, NOTE_B, NOTE_MAX
} note_t;
//channel 0-15 resolution 1-16bits freq limits depend on resolution
double ledcSetup(uint8_t channel, double freq, uint8_t resolution_bits);//设置通道频率和分辨率
void ledcWrite(uint8_t channel, uint32_t duty);//设置通道占空比
double ledcWriteTone(uint8_t channel, double freq);//设置通道频率
double ledcWriteNote(uint8_t channel, note_t note, uint8_t octave);//输出需要的音阶
uint32_t ledcRead(uint8_t channel);//读取某个通道的占空比
double ledcReadFreq(uint8_t channel);//读取通道频率
void ledcAttachPin(uint8_t pin, uint8_t channel);//将通道与引脚绑定
void ledcDetachPin(uint8_t pin);//解绑引脚与通道的关系
#ifdef __cplusplus
}
#endif
#endif /* _ESP32_HAL_LEDC_H_ */
3.其中ledcWriteNote函数为输出一些音阶,可以接上蜂鸣器发出一些简单的音频, 函数如下:
double ledcWriteNote(uint8_t chan, note_t note, uint8_t octave){
const uint16_t noteFrequencyBase[12] = {
// C C# D Eb E F F# G G# A Bb B
4186, 4435, 4699, 4978, 5274, 5588, 5920, 6272, 6645, 7040, 7459, 7902
};
if(octave > 8 || note >= NOTE_MAX){
return 0;
}
double noteFreq = (double)noteFrequencyBase[note] / (double)(1 << (8-octave));
return ledcWriteTone(chan, noteFreq);
}
例子代码功能:在Arduino环境下输出频率可变的PWM波
/*
@功能:输出两路PWM,可调占空比
@时间:2020/3/5
@作者:刘泽文
@QQ:2822604962
*/
#include
#define LED1 19
#define LED2 22
#define LED1_OFF digitalWrite(LED1, HIGH)//关灯1
#define LED1_ON digitalWrite(LED1, LOW)//开灯1
#define LED1_PWM digitalWrite(LED1, !digitalRead(LED1))//灯1闪烁
#define LED2_OFF digitalWrite(LED2, HIGH)//关灯2
#define LED2_ON digitalWrite(LED2, LOW)//开灯2
#define LED2_PWM digitalWrite(LED2, !digitalRead(LED2))//灯2闪烁
int freq1 = 2000; // 频率
int channel1 = 0; // 通道0,共16个通道,0~15
int resolution1 = 10; // 分辨率,取值0~20,duty最大取值为2^resolution-1
int freq2 = 2000; // 频率
int channel2 = 1; // 通道1,共16个通道,0~15
int resolution2 = 10; // 分辨率,取值0~20,duty最大取值为2^resolution-1
void setup()
{
ledcSetup(channel1, freq1, resolution1); // 设置通道0
ledcSetup(channel2, freq2, resolution2); // 设置通道1
ledcAttachPin(LED1, channel1); // 将通道0与引脚19连接
ledcAttachPin(LED2, channel2); // 将通道1与引脚22连接
}
void loop()
{
// 逐渐变亮
for (int dutyCycle = 0; dutyCycle <= 1023; dutyCycle = dutyCycle + 5)
{
ledcWrite(channel1, dutyCycle); // 输出PWM
ledcWrite(channel2, 1023 - dutyCycle); // 输出PWM
delay(5);
}
// 逐渐变暗
for (int dutyCycle = 1023; dutyCycle >= 0; dutyCycle = dutyCycle - 5)
{
ledcWrite(channel1, dutyCycle); // 输出PWM
ledcWrite(channel2, 1023 - dutyCycle); // 输出PWM
delay(5);
}
}
将代码上传到你的ESP32板卡上
实验效果:LED1 与 LED2 为呼吸灯状态,且亮度互补~