ESP32-DevKitC-32Dボードの基本的な使い方 ~Arduino IDE編~

  未分類

ESP32-DevKitC-32DはESP-WROOM-32Dを搭載したボードです。

USB接続するだけで使え手軽にESP32の世界を楽しめます。ESP-WROOM-32Dには1つのモジュール内にWi-FiとBluetooth LEの通信機能が含まれています。マイコンとしても優秀ですが、通信機能を有しているという点が大きな特徴です。

開発環境は大きく2つあります。1つはArduino IDEを使う方法。もう1つはESP-IDFという専用の開発環境を使用する方法です。本ページではまずこれら2つの方法でLEDを点滅させるところから初めてみます。

■Arduino IDEを使う方法 ~IDEの準備~

①まずArduino IDEを起動します。

インストールしていない方はこちらからインストールします。

②”ファイル”→”環境設定”を開きます。

③”追加のボードマネージャのURL”の部分に次のURLをコピーして貼り付けます。
https://dl.espressif.com/dl/package_esp32_index.json

④OKボタンを押します。

⑤”ツール”→”ボード”をクリックし更に右側に表示される”ボードマネージャ”をクリックします。

⑥先ほどURLを環境設定の部分で指定しているので、一覧に”esp32 by Espressif Systems”というボードが表示されますので、これを選択します。

⑦”インストール”ボタンを押します。
→これでボードに必要なファイルが自動的にダウンロードされてインストールされます。

⑧インストールが完了すると”ツール”→”ボード”の一覧に”ESP32 Dev Module”という名前が表示されますので、これを選択します。

⑨続いて、ESP32-DevKitC-32DとArduino IDEが通信する手段を選択します。
ESP32-DevKitC-32Dはパソコンと接続すると仮想COMポートが作られます。仮想COMポートはSilicon Labs社のCP210xデバイスを使っています。ESP32-DevKitC-32Dをパソコンと接続したらWindowsのデバイスマネージャーの”ポート(COMとLPT)”のツリーから、”Silicon Labs CP210x USB to UART Bridge(COMx)”を探してCOMポート番号を調べておいてください。

上図例ではCOM6になっています。

⑩”ツール”→”シリアルポート”をクリックして手順9で確認したESP32-DevKitC-32Dのポート番号を選択します。

これで最初の設定は完了です。

■Arduino IDEを使う方法 ~プログラムを書いてみる~

 

それではプログラムを早速書いてみましょう。ここでは最も簡単なLED点滅プログラムを書いてみます。200ミリ秒間隔で指定したピンをHigh-Lowさせるだけのプログラムです。

今回はピンとして32ピンを指定しました。適宜変更してスケッチを書いてみてください。

※但し35,34は入力専用なので使えません。

int LED = 32;
void setup() {
  pinMode(LED,OUTPUT);
}

void loop() {
  digitalWrite(LED,HIGH);
  delay(200);
  digitalWrite(LED,LOW);
  delay(200);
}

とても簡単です。

では早速コンパイルをしてみましょう。ツールバー画面左上にある「レ」のボタン(検証ボタン)を押します。

ファイルを保存していない場合にはファイル保存のダイアログが表示されますので適当なディレクトリに保存してください。

コンパイルは少し時間がかかります。プログラムに誤りがなければ「コンパイルが完了しました」と表示され、その下のアウトプットウインドウに使用されたフラッシュの容量等が表示されます。

コンパイルが正常完了したことを確認して次に進みます。

■ハードウエアの準備

ESP32-WROOM-32DはGPIOがHレベルの時3.3Vです。

今回はピンの状態が視認しやすいようにLEDを取り付けます。上記例では32ピンにLEDを接続します。LEDはピンには直結できません。必ず抵抗器を通して接続します。下図は接続例です。ブレットボードなどに装着するとより簡単に配線ができます。

抵抗器は150Ω~470Ω程度の間で選択します。順方向電圧が1.8V、順方向電流が8mA程度のLEDだとすると200Ω程度の抵抗器が必要になります。

LEDは足の長い方がアノード(A)、足の短い方がカソード(K)です。通常はA側をGPIO側にK側をGNDと接続します。該当ピンがHレベルになると電流が流れてLEDが点灯します。

■Arduino IDEを使う方法 ~プログラムを書き込む~

ではボードに書き込んでみましょう。

ツールバー2番目の右向き「→」マークのボタンを押してみてください。

書き込みが始まります。IDEウインドウ下にオレンジ色の文字で進捗状況が表示されます。書き込みが完了すると「ボードへの書き込みが完了しました」と表示されます。

32ピンと接続したLEDが点滅していることを確認してください。

点滅する周期を変更したりしてプログラムを変えてみてお試しください。

書き込み時にエラーが表示されて失敗する場合には?

書き込み実行時に「A fatal error occurred: Failed to connect to ESP32: Timed out waiting for packet header」という表示が出て、書き込みに失敗する場合があります。

これはESP-WROOM-32Dが書き込みモードに入るタイミングの問題となり手動で”BOOT”ボタンを押すことで解決します。書き込み実行する時に転送が開始されたら本体にある”BOOT”ボタンを押し続けます。最後まで押し続けなくても、オレンジ色の進捗状況の表示が出たら離してもOKです。スイッチの押すタイミングがありますので、何回か試行してタイミングをつかんでください。

書き込み実行時に「A fatal error occurred: Failed to connect to ESP32: Timed out waiting for packet header」と表示されるのは本体の故障ではありません。

 

教えて!Goolge先生!!

開発を行ってると様々な問題に直面します。ソフトウエアを作る時やコンパイルした時、書き込みを実行した時、そしてプログラムを動かした時・・・そんな時はぜひGoogleで検索しましょう。

特に「エラーメッセージ」や「エラーコード」が表示される場合にはその内容全文をGoogleで検索してみてください。ESP32シリーズは世界中のユーザーが使用しており、貴方が今経験している問題は”たぶん”過去に多くの先人が経験しているものだと思います。
先人達はブログなどで解決策や原因を記載していることがほとんどです。ほとんどの問題はGoogleで検索すれば解決策が見つかります。
きっと、今貴方が困っていることは過去に誰かが困っていたことだと思われます。そしてそういった情報はほとんどの場合においてGoogleで調べれば関連ページがヒットします。

「おかしい!」「壊れてるんじゃないか!?」「不良品??」そう思う前に検索してみてください。きっと解決策が見つかるはずです。

 


■アナログ出力を使ってPWM制御してみる

上の例では32ピンをデジタルピンとして設定としてLEDをON/OFFにしてみました。デジタル設定の場合出力はHighかLowのいずれかです。つまり点灯か消灯です。

しかし、ピンをアナログ出力ピンとして設定するとPWM出力が可能となります。PWMとはPulse Width Modulationの略で日本語ではパルス幅変調といいます。パルス波のデューティー比を変化させる変調方式です。デューティー比とは簡単に言えば、パルス波を出した時の「Highの期間」と「Lowの期間」の割合ことです。例えばHigh期間とLow期間が同じ時間であればデューティー比50%といいます。

※出展 https://en.wikipedia.org/

LEDを接続している場合デューティー比を変えると、それはLEDの明るさの変化として現れます。デューティー比が大きい、すなわちHighの期間が長ければLEDは明るく点灯しますし、デューティー比が小さければLEDは暗くなります。

ESP32ではすべてのピンではありませんが多くのピンでアナログ出力ピンとして設定できます。32ピンも設定できますのでここではそれを利用します。なおGPIO32ピンはアナログピン番号は”A4″ですので注意してください。


LEDの明るさをソフトに明るして、ソフトに暗くするプログラムを作ってみましょう。

ESP32でPWMを使う場合にはledcWrite()関数を使います。

※Arduinoで使える analogWrite() 関数はESP32では利用できません。

 

const int ledPin = A4; 

void setup() {
  ledcSetup(0, 10000, 8);
  ledcAttachPin(ledPin, 0);
}

void loop() {
  static uint8_t brightness = 0;
  static int diff = 1;

  while(1){
    ledcWrite(0, brightness);
  
    if (brightness == 0) {
      diff = 1;
    } else if (brightness == 255) {
      diff = -1;
    }
   
    brightness += diff;
    
    delay(5);
  }

}

ledcSetup(uint8_t chan, double freq, uint8_t bit_num);

chan 利用するチャネル。0~15を指定
freq 基本となるPWMの周波数 ここでは10KHzを指定
bit_num デューティ比を表す分解能のビット数 ここでは8ビットなので256段階

 

brightness変数は明るさを示します。0は消灯です。この値を増減させます。

diff = 1 は変化する率です。1ずつ増減させて0~255の範囲で増減させます。ここの値を大きくするとLEDの明滅の早さが変わります。

ledcWrite(uint8_t chan, uint32_t duty);

chan 利用するチャネル。0~15を指定
duty デューティ比を指定、ここでは8ビットなので指定できる値は0~255

 

5ミリ秒の遅延を入れてwhile文でループすることで明滅を繰り返し実行しています。

変数diffの値を変えて明滅速度が変わることを確認してみてください。

下図はオシロスコープで波形を観察したものです。10KHzの波形のデューティー比が繰り返し変わっていることが確認できます。


■ピンの状態を取得してみる

ここまでの例ではピンを出力に設定してLEDのON/OFFを試しました。続いてGPIOを入力設定にしてその状態に応じて処理を分岐するプログラムを作ってみましょう。

入力と聞くと「スイッチを付けなくては」と思いますが、幸いなことにこのESP32-DevKitC-32Dには2つのスイッチが付いています。1つはENピンと接続されていてプログラムでは使えませんが”BOOT”と書かれたスイッチはGPIO0と接続されており実験に利用できます。

GPIO0を入力ピンとして使ってみましょう。入力ピンの場合にはスイッチを押していない時にピンの論理状態をHighにするか、Lowにするかをプルアップ又はプルダウンによって決めなければいけません。ESP32では指定したピンを入力ピンに設定するとともにそのピンを内部プルアップする機能があります。これを使えば外部にプルアップ用抵抗器を接続する必要がなく利用できます。但し、プルダウンの設定はできませんのでご注意ください。

次のプログラムはGPIO0のスイッチを押した時にLEDが点灯、離すと消灯するプログラムです。

const int ledPin = 32; 
const int swPin = 0; 

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(swPin, INPUT_PULLUP);
}

void loop() {

  int sw_state = digitalRead(swPin);

  if (sw_state==HIGH){ 
    digitalWrite(ledPin, LOW); 
  }else{
    digitalWrite(ledPin, HIGH); 
  }
}

適当にファイル名を付けて保存してコンパイルして書き込んでみてください。

内容はとても簡単です。pinMode()では入力ピンとする時にだけINPUT_PULLUPを引数として指定すると内部プルアップが有効になります。

ピンの状態はdigitalRead()関数で読み込みます。戻り値はint型変数に代入します。その値をif文で判定します。スイッチを押していない時はプルアップによりGPIO0はHighレベルなのでLEDは消灯に、押した時はLowなのでLEDを点灯させます。

 



■ちょっと応用編 ~WEBサーバー機能でブラウザからLEDを制御をする~

次に同じ回路でスケッチを変更しWEBサーハー機能を試してみましょう。ESP32はWi-Fi通信機能が付いていますのでそのままWi-Fiに接続できます。またTCP/IPなどネットワーク接続に必要なプロトコルスタックを内蔵しているので簡単にネットワーク通信ができます。

WEBサーバー機能を使うことでブラウザから本機にアクセスしてLEDを消灯させたり点灯させたり、点滅させたり制御ができます。

1からプログラムを書くのはちょっとしんどい・・そんな時はArduino IDEでしスケッチ例がたくさん利用できます。ここではWi-Fiサーバーのスケッチ例を使い、その内容を少し変更させてWEBサーバー機能を試してみましょう。

①Arduino IDEの”ファイル”→”スケッチ例”をクリックします。

②”ESP32 Dev Module用のスケッチ例”という部分があるのでその中にある”WiFi”→”SimpleWebServer”をクリックします。

③WiFiサーバーのサンプルスケッチが読み込まれます。実はほとんどの内容はこれで完成しています。ここでは下記のように少しプログラムを改造してみましょう。

まず下記のSSIDとパスワードを定数に代入する部分にはご自分のWi-Fi環境のSSIDとパスワードをセットしてください。これが間違っているとそもそもWi-Fiに接続できないのですべて失敗してしまいます。

const char* ssid     = "";
const char* password = "";

では次のようにスケッチを変更してみましょう。

#include <WiFi.h>

const char* ssid     = "ssid";
const char* password = "password";

const char html[] =
    "<!DOCTYPE html><html lang='ja'><head><meta charset='UTF-8'>\
    <title>Hello Wifi</title></head>\
    <body>\
      <div>\
        <h2>LEDテストページ</h2>\
      </div>\
      <div>\
        <p>32ピンのLEDを<span style=\"color: #ff0000;\"><strong>点灯</strong></span>させるには <a href=\"/H\">ここ</a>をクリックします.</p>\
      </div>\
      <div>\
        <p>32ピンのLEDを<span style=\"color: #0000ff;\"><strong>消灯</strong></span>させるには <a href=\"/L\">ここ</a>をクリックします.</p>\
      </div>\
      <div>\
        <p>32ピンのLEDを<span style=\"color: #339966;\"><strong>点滅</strong></span>させるには下のボタンを押します.</p>\
      </div>\
      <div><form method=\"get\" action=\".\">\
        <input type=\"submit\" name=\"blink\" value=\"点滅開始\" />\
      </form></div></body></html>";

WiFiServer server(80);

void setup()
{
    Serial.begin(115200);
    pinMode(32, OUTPUT); 

    delay(10);

    // We start by connecting to a WiFi network

    Serial.println();
    Serial.println();
    Serial.print("Connecting to ");
    Serial.println(ssid);

    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    Serial.println("");
    Serial.println("WiFi connected.");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
    
    server.begin();
}

int mode_f=0;

void loop(){
  
  if (mode_f==1){
    blinkLED();    
  }
  
 WiFiClient client = server.available();  

  if (client) {                             
    Serial.println("New Client.");           
    String currentLine = "";      
         
    while (client.connected()) {           

      if (client.available()) {             
        char c = client.read();            
        Serial.write(c);     

        if (c == '\n') {      
          if (currentLine.length() == 0) {
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println();

            client.print(html);            
            client.println();
            break;
          } else {
            currentLine = "";
          }
          
        } else if (c != '\r') {  
          currentLine += c;   
        }

        //----------------------
        
        if (currentLine.endsWith("GET /H")) {
          digitalWrite(32, HIGH);  
          mode_f=0;
        }
        
        if (currentLine.endsWith("GET /L")) {
          digitalWrite(32, LOW);
          mode_f=0;
        }

        if (currentLine.endsWith("GET /?blink")) {
          blinkLED();
          mode_f=1;
        }
       
      }
    }
    
    client.stop();
    Serial.println("Client Disconnected.");
  }
}

void blinkLED(){
  digitalWrite(32, LOW);
  delay(200);
  digitalWrite(32, HIGH);
  delay(200);    
}

内容としては最初のhtml配列のところで、HTMLデータを代入しています。注意すべき点は行替えのところには”\”(もしくはバックスラッシュ)を入れることです。Arduino IDEのフォント設定が英語フォントの場合には\はバックスラッシュとして表示されます。

また”(ダブルクォーテーション)は、\” として書くことも注意してください。間違えるとブラウザでアクセスした時正しいページが表示されません。特にタグの部分の文字列に注意してください。

この部分以外はほぼそのままですが、LEDが接続されたGPIOのピン番号を32ピンに変更しています。

またデフォルトのスケッチ例だと点灯と消灯しかありませんので、この例では点滅する部分を追加しています。またブラウザで表示した時デフォルトの場合には点灯と消灯のリンク表示ですが、この例ではボタンを表示させて点滅機能を割り当てています。

★LED点灯/消灯/点滅の仕組み★

LED点灯時は http://yourAddress/H

LED消灯時は http://yourAddress/L

LED点滅時は http://yourAddress/?blink

へ飛ぶように作られています。いずれもHTTPのGETメソッドを使っています。一番簡単な方法なのでGETメソッドを使っていますが、改造すればもちろんPOSTメソッドでも作れます。

もう1つポイントとしては、ボタンです。ボタンはtype属性をsubmitとしています。その前にaction属性を使ってボタンが押された時、ページのトップに移動するようにしています。そうしないと、例えば  http://192.168.0.100/H の状態でボタンを押すと http://192.168.0.100/H/?blink となってしまい正しく判定ができなくなってしまうためです。


さてここまで書けたらコンパイルして実際のボードを書き込んでみましょう。

ボードに書き込む前にシリアルターミナルを表示させておきます。そうすることでモジュールが正しくWi-Fiに接続できたか、またDHCPで割り当てられたIPアドレスがいくつなのかを知ることができます。

Arduino IDEの”ツール”→”シリアルモニタ”をクリックしてシリアルモニターを表示させておきましょう。

スケッチに間違いがなければコンパイル後、書き込みが実行されます。もしエラーが表示された場合には間違いがないかよく確認してください。

 


プログラムが動作すると動作ログがシリアルモニターに表示されます。

下図のように接続されたSSIDと本機に割り当てらたれIPアドレスが表示されますのでこれを控えておきます。

もし接続できない場合にはSSIDやパスワードが間違っている可能性があります。

では早速このIPアドレスにブラウザから接続してみましょう。ブラウザを起動してアドレス欄にIPアドレスを入力してエンターキーを押します。

上図のように表示されればOKです。

「ここ」の部分をクリックしてその通りにLEDが点灯したり消灯したりするか確認してください。

続いて「点滅開始」をクリックするとLEDが点滅すること確認してください。なおこのプログラムでは割込を使わずに点滅するサブルーチンをloop関数の中で定期的に呼び出して点滅させています。loop関数内ではWi-Fiの処理も行っておりWi-Fiの処理の方に時間がかかると点滅が止まる場合があります。このプログラムはデモなのでその点はあまり気にしていませんが、より実用的なプログラムを書く場合には割込を使うなど工夫が必要になります。

※割込例はスケッチ例内にある”Ticker”→”Blinker”などが参考になります。

 

■もっと応用編 ~スイッチを押すとLINEに通知する~

もう少し複雑なプログラムにも挑戦してみましょう。

皆様お使いになっていると思うメッセージングサービスのLINEに通知を送る内容です。ESP32-DevKitC-32DのGPIO0のスイッチが押されると、LINEで”スイッチが押されました”と通知されるプログラムを作ってみましょう。

LINEに通知をするにはいくつかの方法があります。今回は “LINE Notify“というサービスを使ってみます。あらかじめ登録しておいたグループに対して通知を送れます。その他にはIFTTTというサービスを使った方法もあります。

まずは”LINE Notify“を友達に追加します。”LINE Notify“のページに飛ぶとトップページにQRコードが表示されますのでスマホのLINEアプリでこのQRコードをスキャンして友達を追加してください。


最初に「アクセストークン」と呼ばれる文字列を取得します。このトークンを使うことでESP32プログラム内からLINEに対して通知が送れるようになります。

① ”LINE Notify“にアクセスしてログインしてください。

② 右上のアカウント名のところをクリックすると下にメニューが表示されますのでその中から「マイページ」を選択します。

③ 「アクセストークンの発行」のところにある「トークンを発行する」ボタンを押します。

④ トークン名は通知される時に表示されますので、ここでは適当に「ESP32スイッチ」とかにしておきます。続いて「通知を受信するトークルームを選択してください」のところではグループを選択しますが、自分だけが受信する場合には「1:1でLINE Notifyから通知を受け取る」にチェックを入れて発行するを押してください。

⑤ トークンが発行されます。このトークンはとても大切ですので必ず控えておいてください。赤文字で表示されたトークンを続いて作るプログラムの中で使用します。


では早速プログラムを書いてみましょう。今回はGPIO0を内部プルアップされた入力ピンとして使用し、スイッチが押されると(GP0がLowになると)LINEに通知が飛ぶようにします。

Wi-Fiへの接続部分などは先の例と同じですので解説は省略します。

#include <WiFi.h>
#include <ssl_client.h>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>

const char* ssid = "your ssid";
const char* password = "your password";

const char* host = "notify-api.line.me";
const char* token = "your LINE Notify token";

const int ledPin = 32; 
const int swPin = 0; 

void wificonnection(){
  
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED){
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());  
}

void send_message(String message) {
  
  WiFiClientSecure client;
  Serial.println("Connecting to LINE API Server..");
  
  if (!client.connect(host, 443)) {
    Serial.println("Connection failed");
    return;
  }
  
  Serial.println("Connected!");
  
  String query = String("message=") + message;
  String request = String("") +
               "POST /api/notify HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "Authorization: Bearer " + token + "\r\n" +
               "Content-Length: " + String(query.length()) +  "\r\n" + 
               "Content-Type: application/x-www-form-urlencoded\r\n\r\n" +
                query + "\r\n";
  client.print(request);

  while (client.connected()) {
    String line = client.readStringUntil('\n');
    Serial.println(line);
    if (line == "\r") {
      break;
    }
  }

  String line = client.readStringUntil('\n');
  Serial.println(line);
}

void setup() {
  Serial.begin(115200);
  
  pinMode(ledPin, OUTPUT);
  pinMode(swPin, INPUT_PULLUP);

  delay(10);

  wificonnection();
  
}

void loop() {

  int sw_state = digitalRead(swPin);

  if (sw_state==HIGH){ 
    digitalWrite(ledPin, LOW); 
  }else{
    digitalWrite(ledPin, HIGH);
    send_message("GP0ボタンが押されました!");
  }
}

プログラム中の your ssid と your password には実際にご利用のWi-Fi環境のパラメーターを記述してください。

もう一カ所修正する部分は “const char* token = “your LINE Notify token”;“ の部分です。your LINE Notify token の部分には先ほどの手順で発行したLINE Notifyのトークンをそのままコピーしてください。

修正部分は上記の箇所のみです。

今回はシリアルターミナルでログを見たいのでArduino IDEの”ツール”→”シリアルモニタ”を選択してモニターを表示させておいてください。では早速コンパイルして書き込んでみてください。

書き込みが成功するとシリアルモニターにWi-Fiへの接続状況が表示されます。接続が正しく完了すると本機に割り当てられたIPアドレスが表示されます。

続いて本体の”BOOT”ボタン(GPIO0ボタン)を1回押してください。LINE APIのサーバーに接続を試みます。成功すれば下記のようにログに表示されます。

Connecting to LINE API Server..
Connected!

続いて処理が行われます。処理中はLEDが点灯しています。処理が5秒から10秒程度で完了しLINE Notifyに通知が送られてきます。スマホ等で確認してみましょう。

どうでしょうか?正しく通知は送られてきましたか?

この仕組みを使えばいろいろと応用ができそうです。もちろんGPIOを増やして使うこともできますし、変化のあったGPIO毎にメッセージ内容も変えられるのでいろいろと楽しめそうです。