概要
前回はデジタル入出力と、アナログ入力を行いました。今回は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からデータ取得して返却の方がいいのかなーって思っていますが、構想がまとまっていません