ソースコードの解説

目的

「温湿度センサー(DHT11) のアウトプットをBlynkアプリに表示(ESP -> Blynk)」で使用したコードが理解できるようになる。

目次

プログラムの全体図

ソースコードの説明

#define BLYNK_PRINT Serial    // Blynkライブラリーのデバッグ情報出力先を指定
#define BLYNK_DEBUG           // Blynkデバッグ情報を出力
#include <BlynkSimpleEsp32.h> // BlynkSimpleEsp32.h をインクルード
#include <DHT.h>              // DHT.h をインクルード
#define BLYNK_PRINT Serial    // Blynkライブラリーのデバッグ情報出力先を指定
#define DHTPIN 22             // DHTセンサーアウトプットピンの指定
#define DHTTYPE DHT11         // DHT型の指定
DHT dht(DHTPIN, DHTTYPE);     // DHTセンサーライブラリーを使うための設定

/***************************************/
/*** ここから 環境によって書き換える ***/
/***************************************/

//WiFi接続情報
const char* ssid     =  "<YOUR_SSID>";
const char* password =  "<YOUR_PASSWORD>";
//Blynk接続情報
const char* auth = "<YOUR_AUTH>";

void setup() {
    Serial.begin(115200);  //シリアル通信の速度を指定

    dht.begin(); //  DHT11の初期化

    // auth, ssid, pass を指定してBlynkの初期化
    Blynk.begin(auth, ssid, password);
}

void loop() {
    Blynk.run(); //  Blynkの起動
        
    float temperature = dht.readTemperature(); // 温度読み取り
    float humidity = dht.readHumidity();   // 湿度読み取り
      
    // 読み取りに失敗しているかチェック
    // 失敗している場合はもう一度、温湿度の読み取りをする
    if (isnan(temperature) || isnan(humidity)) {
       Serial.println("Failed to read from DHT sensor!");
       return;
    }
    
    //シリアルモニターに表示
    Serial.print("湿度: ");
    Serial.print(humidity);
    Serial.print(" *C\t");
    Serial.print("温度: ");
    Serial.print(temperature);
    Serial.println(" % ");
    
    // V0 ピンに対して温度の値を送信
    Blynk.virtualWrite(V0, temperature);
    
    // V1 ピンに対して湿度の値を送信
    Blynk.virtualWrite(V1, humidity);
    delay(2000);// 2秒間待つ
}

コメント

コメントを書く目的は、プログラムの働きを自分が理解したり、思い出したりするのを助けるためです。 また、他の人に、それを伝えるためでもあります。 コメントはコンパイラから無視され、コンピュータに出力されることはないので、チップ上のメモリを消費しません。

参照 - コメント 公式(英語)

参照 - コメント 非公式(日本語)

要するに、コメントを付けてプログラムの挙動を説明しています。

本資料では以下の部分で コメントを使用しています。

float temperature = dht.readTemperature(); // 温度読み取り
float humidity = dht.readHumidity();   // 湿度読み取り

プリプロセッサ

「プリプロセッサ」とはコンパイル前にソースプログラムに対して行われる前処理のことです。 一般にある処理を行うソフトウェアに対して、データ入力やデータ整形などの準備的な処理を行うソフトウェアのことである。

参照-プリプロセッサ

本資料では「#define」と「#include」がプリプロセッサです。

#define

#include

本資料では以下の部分で使用しています。

#define BLYNK_PRINT Serial    // Blynkライブラリーのデバッグ情報出力先を指定
#define BLYNK_DEBUG           // Blynkデバッグ情報を出力
#include <BlynkSimpleEsp32.h> // BlynkSimpleEsp32.h をインクルード
#include <DHT.h>              // DHT.h をインクルード
#define BLYNK_PRINT Serial    // Blynkライブラリーのデバッグ情報出力先を指定
#define DHTPIN 22             // DHTセンサーアウトプットピンの指定
#define DHTTYPE DHT11         // DHT型の指定

参照-第18章 プリプロセッサ

参照-プリプロセッサの働きとその使い方

ライブラリー

ライブラリ(英: library)は、汎用性の高い複数のプログラムを再利用可能な形でひとまとまりにしたものである。ライブラリと呼ぶ時は、それ単体ではプログラムとして作動できない、つまり実行ファイルではない場合がある。ライブラリは他のプログラムに何らかの機能を提供するコードの集まりと言える。

参照-ライブラリ

要するに、ライブラリを活用することで、自分で新しくプログラムを書く必要がなくなり手間を省くことができます。

本資料では以下の部分で使用しています。

#include <BlynkSimpleEsp32.h> // BlynkSimpleEsp32.h をインクルード
#include <DHT.h>          // DHT.h をインクルード
void setup(){
    ...
    // auth, ssid, pass を指定してBlynkの初期化
    Blynk.begin(auth, ssid, password);
    ...
    Blynk.virtualWrite(V1, humidity);
}
void loop(){
    Blynk.run(); //  Blynkの起動
    ...
    float temperature = dht.readTemperature(); // 温度読み取り
    float humidity = dht.readHumidity();   // 湿度読み取り
    ...
    // V0 ピンに対して温度の値を送信
    Blynk.virtualWrite(V0, temperature);
    
    // V1 ピンに対して湿度の値を送信
    Blynk.virtualWrite(V1, humidity);
}

関数

関数とは、コンピュータプログラム上で定義されるサブルーチンの一種で、数学の関数のように与えられた値(引数)を元に何らかの計算や処理を行い、結果を呼び出し元に返すもののこと。

参照 - 関数 【 function 】 ファンクション

サブルーチン

サブルーチンとは、コンピュータプログラムの中で特定の機能や処理をひとまとまりの集合として定義し、他の箇所から呼び出して実行できるようにしたもの。単に「ルーチン」とも呼ばれる。

参照 - サブルーチン 【 subroutine 】 サブルーティン

要するに、一度プログラムしたコードを再利用するために関数を用います。

本資料では以下の部分で関数を定義しています。

void setup(){
    ...
}
void loop(){
    ...
}

本資料では以下の部分で関数を利用しています(呼び出しています)。

Serial.begin(115200);
dht.begin();
Blynk.begin(auth, ssid, password);
Blynk.run();
dht.readTemperature();
dht.readHumidity();    
isnan(temperature);
isnan(humidity)
Serial.print("湿度: ");
Serial.print(humidity);
Blynk.virtualWrite(V0, temperature);
Blynk.virtualWrite(V1, humidity);
delay(2000);  

return

関数の実行を中止して、呼び出し元の関数に処理を戻します。

参照 - コメント 公式(英語)

参照 - コメント 非公式(日本語)

要するに、return の後のプログラムは実行されなくなります。

本資料では以下の部分で return を使用しています。

void loop() {
    Blynk.run(); //  Blynkの起動

    float temperature = dht.readTemperature(); // 温度読み取り
    float humidity = dht.readHumidity();   // 湿度読み取り
      
    // 読み取りに失敗しているかチェック
    // 失敗している場合はもう一度、温湿度の読み取りをする
    if (isnan(temperature) || isnan(humidity)) {
       Serial.println("Failed to read from DHT sensor!");
       return;
    }
    
    //シリアルモニターに表示
    Serial.print("湿度: ");
    Serial.print(humidity);
    Serial.print(" *C\t");
    Serial.print("温度: ");
    Serial.print(temperature);
    Serial.println(" % ");
    
    // V0 ピンに対して温度の値を送信
    Blynk.virtualWrite(V0, temperature);
    
    // V1 ピンに対して湿度の値を送信
    Blynk.virtualWrite(V1, humidity);
    delay(2000);// 2秒間待つ
}

setup() 関数

setup()はArduinoボードの電源を入れたときやリセットしたときに、一度だけ実行されます。setup()は省略できません。

参照 - setup()-公式(英語)

参照 - setup()-非公式(日本語)

参照 - Arduinoチュートリアル 基礎編

本資料では以下の部分で setup() 関数を定義しています。

void setup() {
    Serial.begin(115200);  //シリアル通信の速度を指定

    dht.begin(); //  DHT11の初期化

    // auth, ssid, pass を指定してBlynkの初期化
    Blynk.begin(auth, ssid, password);
}

loop() 関数

loop()関数はスケッチの心臓部であり、繰り返し実行されます。loop()は省略できません。

参照 - loop()

参照 - Arduinoチュートリアル 基礎編

本資料では以下の部分で loop() 関数を定義しています。

void loop() {
    Blynk.run(); //  Blynkの起動

    float temperature = dht.readTemperature(); // 温度読み取り
    float humidity = dht.readHumidity();   // 湿度読み取り
      
    // 読み取りに失敗しているかチェック
    // 失敗している場合はもう一度、温湿度の読み取りをする
    if (isnan(temperature) || isnan(humidity)) {
       Serial.println("Failed to read from DHT sensor!");
       return;
    }
    
    //シリアルモニターに表示
    Serial.print("湿度: ");
    Serial.print(humidity);
    Serial.print(" *C\t");
    Serial.print("温度: ");
    Serial.print(temperature);
    Serial.println(" % ");
    
    // V0 ピンに対して温度の値を送信
    Blynk.virtualWrite(V0, temperature);
    
    // V1 ピンに対して湿度の値を送信
    Blynk.virtualWrite(V1, humidity);
    delay(2000);// 2秒間待つ
}

変数

変数を用いることで、データを一定期間記憶し必要なときに利用することができます。

参照 - 変数 (プログラミング)

要するに、一度変数を用意すると、次回からは変数名だけでその値を再利用できます。

本資料では以下の部分で使用しています。

    float temperature = dht.readTemperature(); // 温度読み取り
    float humidity = dht.readHumidity();   // 湿度読み取り
    ...
    Serial.print(humidity);
    Serial.print(temperature);

データ型

データ型(データがた、data type)とは、コンピュータにおける データ(値)の種類に関する分類である。

参照 - データ型

浮動小数点数-float

整数よりも分解能が高いアナログ的な値が必要なときに使います。使用可能な値の範囲は3.4028235E+38から-3.4028235E+38までで、32ビット(4バイト)のサイズです。

参照 - float (浮動小数点型) 公式(英語)

参照 - float (浮動小数点型) 非公式(英語)

要するに、温度/湿度 を測って小数点以下も扱いたいような場合に、浮動小数点数を使います。

本資料では以下の部分で使用しています。

float temperature = dht.readTemperature(); // 温度読み取り
float humidity = dht.readHumidity();   // 湿度読み取り

int-整数型

int型(整数型)は、数値の記憶にもっともよく使われる型です。値の範囲は-32768から32767までです。

参照 - int(整数型) 公式(英語)

参照 - int(整数型) 非公式(日本語)

要するに、プログラムの中で値を整数で扱いたい場合に int 型を使用します。

本資料では後続資料の「演習で参考にするプログラム」で使用されています。

//ESP32にはhallRead()関数がデフォルトで定義されています。hallValue というint型の変数に、hallRead()関数を使用して結果を hallValue に代入します。
int hallValue = hallRead(); 

制御文

プログラムの実行(流れ)の制御を行う文

参照 - 制御文

if 文

if文は与えられた条件が満たされているかどうかをテストします。

参照 - if 公式(英語)

参照 - if 非公式(日本語)

要するに、条件を満たすか判定し、ある処理を実行したり実行しなかったり制御するために使用します。

本資料では以下の部分で使用しています。

    // 読み取りに失敗しているかチェック
    // 失敗している場合はもう一度、温湿度の読み取りをする
    // "||" は「または」を表す。
    if (isnan(temperature) || isnan(humidity)) {
       Serial.println("Failed to read from DHT sensor!");
       // 関数の処理を終了して、呼び出し元に戻る。
       return; 
    }

if else 文

if else文を使うと複数のテストをまとめることができ、単体のifより高度な制御が可能となります。

参照 - if else 公式(英語)

参照 - if else 非公式(日本語)

要するに、条件が満たされるかの判定を複数作りたい場合に使用します。

本資料では後続資料の「演習で参考にするプログラム」で使用されています。

// hallValue が10以下の場合(N極)
// hallValue が23以上の場合(S極)
if (hallValue < 10 || hallValue > 25) {
    // LEDを点灯させます
    digitalWrite(LED_BUILTIN, HIGH);
} else {
    // LEDを消灯させます。
    digitalWrite(LED_BUILTIN, LOW);
}

Serial.print, Serial.println

Serial.print

人間の読めるASCII文字の形でデータをシリアルポートに出力します.

参照 - Serial.print() 公式(日本語)

要するに、例えば、計測した温度や湿度をシリアルポートに出力することで、その値を人間が確認することができます。

本資料では以下の部分で使用しています。

Serial.print("湿度: ");
Serial.print(humidity);

Serial.println

Serial.print()と同じフォーマットですが、ニューライン(ASCIIコード10あるいは’’)を付けて送信します。

参照 - Serial.Println 公式(英語)

参照 - Serial.Println 非公式(日本語)

要するに、Serial.println()関数を使用すると、シリアルポートに文字列を出力し、かつ、改行してくれます。 Serial.print()関数の場合は改行は行われません。

本資料では以下の部分で使用しています。

Serial.println(" *C ");

Serial.begin

シリアル通信のデータレートをビット/秒(bps)で設定します

参照 - Serial.begin()公式(日本語)

要するに、シリアルモニターに値や文字列を表示させたい場合には Serial.begin(speed) を指定する必要があります。

本資料では以下の部分で使用しています。

 Serial.begin(115200);              //シリアル通信の速度を指定

delay

プログラムを指定した時間だけ止めます。単位はミリ秒です(1,000ミリ秒=1秒)。

参照 - delay()公式(英語)

参照 - delay()非公式(日本語)

要するに、プログラムを指定した時間だけ止めて、処理をゆっくり実行させたい場合に delay を使用します。例えば、LEDの点滅速度を調整する場合などに利用できます。

本資料では以下の部分で使用しています。

delay(2000);// 2秒間待つ

Blynkの利用

必要なライブラリをインクルード-Blynk

本資料では以下の部分で使用しています。

#include <BlynkSimpleEsp32.h> // BlynkSimpleEsp32.h をインクルード

Blynkの初期化

参照 - Blynk.begin()公式(英語)

本資料では以下の部分で使用しています。

void setup(){
    ...
    // auth, ssid, pass を指定してBlynkの初期化
    Blynk.begin(auth, ssid, password);
}

Blynkの起動

参照 - Blynk.run()公式(英語)

本資料では以下の部分で使用しています。

void loop(){
    Blynk.run(); //  Blynkの起動
    ...
}

Blynkにデータ送信

ディスプレイ系のウィジット(Value Display、Labeled Value、Gage、Graph、History Graph)は、BLYNK_READ() が呼び出されます。この中で Blynk.virtualWrite() という関数を実行し、ピン(V1など)に渡したい値を指定すると、スマートフォン側にその値が渡る仕組みになっています。 Blynk.virtualWrite(ピン, 渡したい値);

要するに、Blynk.virtualWrite() を使用することで Blynk サーバにデータを送ります。

本資料では以下の部分で使用しています。

void loop(){
    ...
    // V0 ピンに対して温度の値を送信
    Blynk.virtualWrite(V0, temperature);

    // V1 ピンに対して湿度の値を送信
    Blynk.virtualWrite(V1, humidity);
    delay(2000);// 2秒間待つ
}

参照 - Virtual pins control公式(英語)

参照 - 第3回 CPUの温度/周波数/負荷状態を見よう - 連載 IoTサービス「Blynk」を使ってRaspberry Piをスマホからコントロールしよう

Virtual ピン

参照 - Virtual pins公式(英語)

参照 - What is Virtual Pins

Raspberry PiとBlynkで部屋の気温をスマホで確認

本資料では以下の部分で使用しています。

void loop(){
    ...
    // V0 ピンに対して温度の値を送信
    Blynk.virtualWrite(V0, temperature);

    // V1 ピンに対して湿度の値を送信
    Blynk.virtualWrite(V1, humidity);
    ...
}