ESP32のPWMとDACを使ってみる ~ おまけ:LCDのバックライトを調光

Arduino/ESP32DAC,ESP32,LCD,PWM,バックライト

サクサクと動かす事が出来た1.3インチLCDですが、今回はバックライトを調光しようと思います。

小さい画面ですからたいして眩しく無いんですけれど、ESP32はArduinoの様なAnalogWrite関数が無いらしいですね。

代わりにLED制御用の関数 ledc というのがあるらしく、これがESP32ではPWM出力用として使われる様です。

はて、確かESP32はDACも持ってなかったっけ・・・?

というわけで調べたら25、26番ピンがアナログ波形を出力できるみたいですね。

dacWriteというメソッドで実行できる様子。

ひとまずいきなりLCDのバックライトを操作するのは怖いですので、LEDで試みてみます。

ESP32 PWM(ledc)によるLEDの調光制御

EspressifのArduino core for the ESP32ライブラリを使ってみます。

検索をかけてみると、それらしきものがありました。

毎度の事ながらヘッダーしか見ませんが・・・

一部抜粋

//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);

https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-ledc.h

これを見ると0~15の合計16チャンネルを持つ事が出来て、各チャンネルに登録されたGPIOに対して制御できる様な造りになっている様子。

PWM的なものって出すだけかと思ってましたが、なかledcRead系のものもある様で。

PWMを読み取れるって事なんでしょうか。

モールス信号的な?

よく判らないのでRead系はとりあえずスルーしておいて、、

ledcの使い方

1.ledcSetup でチャンネルと周波数、ビット幅を決める
2.ledcAttachPin でPWMを出力するGPIOピンとチャンネルを関連づける
3.ledcWrite でチャンネルに対してデューティー比を指定して出力する

こんな感じかな。

わりと簡潔に出来ている様です。

コードはこんな感じでしょうか。

#include <Arduino.h>

// PWM出力 ledc変数
uint8_t ledcGPIO = 27;      // PWM GPIO
uint8_t ledcCH = 0;         // ledcチャンネル
double ledcFreq = 5000;     // PWM周波数
uint8_t ledcBitWidth = 8;   // 8bit 0-255(13bit default)
uint32_t ledcDuty = ( pow(2, ledcBitWidth) / 2 ) - 1;   // デューティ比初期値設定 1/2 (127)

uint16_t timeWait = 2;      // 調光ウェイト ms

void setup() {
    Serial.begin(115200);

    // 1.ledc設定
    ledcSetup(ledcCH, ledcFreq, ledcBitWidth);

    // 2.GPIOピンをチャンネルに所属させる
    ledcAttachPin(ledcGPIO, ledcCH);

    // 3.対象チャンネルに対してデューティ値(ビット幅分の値)でPWM開始
    ledcWrite(ledcCH, ledcDuty);

    // 比較用LED 常灯
    pinMode(14, OUTPUT);
    digitalWrite(14, HIGH);

}

// デューティー比増減
void volumeDuty(void *param) {

    Serial.println("volumeDuty Start.");

    for(uint8_t cnt = 0; cnt < 5; cnt++) {
        for(long i=0; i <= pow(2, ledcBitWidth)-1; i++) {
            ledcWrite(ledcCH, i);
            delay(timeWait);
            Serial.print("LEDC Duty : ");
            Serial.println(i);
        }
        for(long i=pow(2, ledcBitWidth)-1; i >= 0; i--) {
            ledcWrite(ledcCH, i);
            delay(timeWait);
            Serial.print("LEDC Duty : ");
            Serial.println(i);
        }
    }

    Serial.println("volumeDuty End.");
    ledcWrite(ledcCH, 0);
}

void loop() {
    volumeDuty(NULL);
}

8bitの分解能は0-255の256値ですから、とりあえず初期値は適当に半分にして点灯させてみます。

その後メインループで0-255の間を繰り返し増減させています。

大体リニアに明るさが変化している感じですね。

pwm周波数が5000との事で、要するに1秒間に5000回更新されています。

これのデューティ比1/2という事は、1秒間の間に2500回OFFし2500回ONしているという計算。

全くチラつきは感じません。

実際チラつくとどうなるのかが気になりましたので、周波数を落としてみました。

人間の目は30Hz~50Hzくらいまでは感知できるらしいのですが、肉眼ではキッチリと50Hzでチラつきは見えなくなりました。

私の目は人並みという事か

しかし動画では多少はチラついて見える事から、実際にはちゃんと点滅しているのでしょう。

また、チラついている様な低周波数の時でもDuty比が1:1に近ければほぼ常灯している事から、ちゃんとPWMで出力されているんだなという事が想像できます。

オシロスコープでも持ってれば見る事が出来るのでしょうけれど・・・

さて次にDACによるコントロールを見ていきます。

ESP32 DAC(dacWrite)によるLEDの調光制御

ヘッダを見るとこちらは至極簡単で、そのまま0-255のレベルの範囲で出力できる様です。

DACに使えるGPIOピンが25,26と限られている様ですが、お手軽で良いですね。

簡単にコードに追加してみます。