概要
前回はデジタル入出力と、アナログ入力を行いました。今回はPWM出力を行いたいと思います。ライブラリを最新版にしてから実行するようにしてください。
PWMとは?
PWMとはデジタル出力を高速でオン、オフすることで明るさなどを調整するための仕組みです。

上記の場合、8スロットにわけて、2スロット分だけオンをした場合になります。全体の25%の時間がオンになっていますので、LEDなどは25%の明るさで光ります。

こちらは、8スロットにわけて、4スロット分だけオンをした場合になります。全体の50%の時間がオンになっていますので、LEDなどは50%の明るさで光ります。

上記が実際の出力をオシロスコープで測定した図ですが、0%、50%、100%の順番で出力を変更されているのがわかります。
スケッチ
#include <M5StickC.h> #include <LinxESP32.h> #include <LinxESP32WifiListener.h> #include <LinxSerialListener.h> LinxESP32* LinxDevice; void setup() { M5.begin(); M5.Lcd.setRotation(3); M5.Lcd.fillScreen(BLACK); LinxDevice = new LinxESP32(); // PWM & Servo Setup uint8_t pwmList[] = {0, 26}; // Max16Ch {0, 26, ...} uint16_t pwmFrequency = 12000; // LED:12000, Servo:50 for (int i = 0; i < sizeof(pwmList); i++) { ledcSetup(i, pwmFrequency, 8); pinMode(pwmList[i], OUTPUT); ledcAttachPin(pwmList[i], i); } LinxWifiConnection.Start(LinxDevice, 44300); LinxSerialConnection.Start(LinxDevice, 3); } void loop() { LinxWifiConnection.CheckForCommands(); LinxSerialConnection.CheckForCommands(); M5.update(); if (millis() % 1000 == 0) { M5.Lcd.setCursor(0, 0); M5.Lcd.println("LinxESP32"); M5.Lcd.print("IP : "); M5.Lcd.println(WiFi.localIP()); byte macAddress[6]; WiFi.macAddress(macAddress); M5.Lcd.printf("MAC : %02X:%02X:%02X:%02X:%02X:%02X\n", macAddress[0], macAddress[1], macAddress[2], macAddress[3], macAddress[4], macAddress[5]); } if (M5.Axp.GetBtnPress() != 0) { ESP.restart(); } delay(1); }
上記はM5StickCで画面に表示もするスケッチ例です。PWMを使う場合にはあらかじめ、どのGPIOをPWMに使うのかを設定しておく必要があります。
// PWM & Servo Setup uint8_t pwmList[] = {0, 26}; // Max16Ch {0, 26, ...} uint16_t pwmFrequency = 12000; // LED:12000, Servo:50 for (int i = 0; i < sizeof(pwmList); i++) { ledcSetup(i, pwmFrequency, 8); pinMode(pwmList[i], OUTPUT); ledcAttachPin(pwmList[i], i); }
上記が設定部分になります。PWMチャンネル0にGPIO0、PWMチャンネル1にGPIO26を設定しています。また、PWMの周波数もここで設定します。通常のPWMの場合は12000(12kHz)ぐらいでいいと思いますが、サーボを利用する場合には50に設定してください。
共存する場合にはループではなくて、個別に設定をしたほうがシンプルになると思います。
LINX – PWM 1 Channel.vi

上記の画面で、PWMのチャンネル数と出力比を設定します。PWMはGPIOではなく、PWMチャンネル番号の0から15を指定するので間違えないようにしてください。Duty Cycleは0から1までを設定できるので、0.5を指定すると50%の出力となります。
いつものRunではなく、その隣にあるRun Continuousボタンを押すと、パラメータを変更したものがすぐに反映して便利です。

処理内容もシンプルです。
LINX – PWM N Channel.vi

こちらも他のNチャンネルと一緒ですね。

処理もシンプルです。
LINX – Digital Write Square Wave.vi

こちらはtone関数で圧電スピーカーを鳴らすような処理です。ESP32はtone関数が無いので、PWMを使うようになっていますので、GPIOではなくPWMチャンネル数を指定してください。

また、このサンプルは音がなり終わる前に次のループが始まってしまうのでWaitを追加しました。実際のところLabVIEWを使って音を鳴らすのであればアクティブブザーなどを使って、通常のデジタル出力をしたほうがいいと思います。
LINX – Servo 1 Channel.vi

サーボを使う場合には、PWM周波数を50Hzに設定する必要があります。LabVIEWからはマイクロ秒単位のパルス幅を指定することで制御します。
SG90サーボの場合は、データシート上500マイクロ秒から2400マイクロ秒が指定できますが、このサンプルは2500まで設定できるので注意してください。
まとめ
PWMまわりを動くようにしてみました。アナログ出力も使えるようにしようとしたのですが、Arduino UNOでもサポートしておらず、サンプルもないので対応しないことにしました。
コメント
ありがとうございます。「LinxESP32」ライブラリを活用させていただいています。ESP32でI2Cセンサーを使いたかったので、一部改変させて使わせていただきました。
NIのディスカッションフォーラムの北東北LabVIEWユーザー会に以下のタイトルで記事を書きました。
ESP32でLINX(その2)「ESP32 MH-LIVE Mini KitとI2C接続のCCS811空気品質センサー」
誤った点などがあれば訂正したいと思いますので、お時間のある時に一読願えれば幸いです。
おー、I2Cも触ってみようと思いつつ手が出ていませんでした
本当はコールバック関数とかを登録して、自由に使える方が良さそうですよね
アナログチャンネル41以上をコールバック用にして、コールバック関数でI2Cからデータ取得して返却の方がいいのかなーって思っていますが、構想がまとまっていません