Ⅳ. ESP32でのアナログ入力とSDカード装置

 ESP32を設置したブレッドボード上にマイクロSDカード装置を組み付けて、計測データの記録と読み込みができるようにします。さらにアナログ入力ポートに土壌湿度センサーをつなぎます。
 今回の組み付け・配線が終わると、ESP32版のMCUボードが完成です。

 ※スケッチのダウンロードは右側の[Download]ボタンをクリックしてください。    

1.SDカード装置の設置と配線

 マイクロSDカードスロットDIP化キットは、あらかじめ付属のヘッダーピンを半田付けしてブレッドボードに設置できるようにしてください。
 準備ができたらESP32開発ボードをブレッドボードから外します。ドライバーなどを使って、壊れないように注意してください。そしてマイクロSDカード装置を写真の位置に設置して、ESP32開発ボードを元の位置に差し込みます。
(1)電源とGNDの配線
 写真左を参考に、以下のようにジャンパーワイヤーで配線します。
  ・ESP386:GNDをブレッドボードの(-)へ。
  ・ESP386:3.3Vをブレッドボードの(+)へ。
  ・microSD:VDDをブレッドボードの(+)へ。
  ・microSD:VSSをブレッドボードの(-)へ。


(2)信号線の配線
 写真右上を参考にしながら、下表の「microSDカード装置の端子と接続先」に沿ってジャンパーコードで配線します。

 これでMCUボード内の配線は完了です。すでにRTCとはI2Cで接続済みですが、もう一度次のようになっていることを確認してください。
   ・データ線  写真の① RCT:SDA ---(黄色  )--> ESP32:GPIO21
   ・クロック線 写真の② RTC:SCL  ---(オレンジ)--> ESP32:GPIO22
   ・グランド  写真の③ RTC:GND ---(緑色  )--> ESP32:GND


2.土壌センサーのアナログ入力

 下図は「土壌湿度センサーYL-38の端子と接続先」です。ESP8266では [VCC]を計測ボードの5Vラインに接続していましたが、これを3.3Vラインに変更します。
 また、ESP8266のアナログ入力用TOUTピンの最大電圧は1.0Vであるため、CPUボード側に分圧回路を設けていましたが、ESP32はアナログ入力の電圧範囲が 0~3.3Vなので直接入力が可能になります。A0端子をいったん計測ボードにつないでから(中継してから)、ESP32のSVP(GPIO36)ピンに接続しています。


 すべての接続が終わった状態です。


3.SDカード装置等のハンドリング

(1)SDカード装置のハンドリング
 このテーマの冒頭でも述べたとおり、現時点ではファイルのタイムスタンプを扱うライブラリー(ESP8266でのSdFatに該当)が未完です。そこで、これに関連したヘッダーファイルのインクルードや、dateTimeコールバック関数は削除することになります。
 また、SDカード装置のポートやファイル名の定義、SDカード装置の初期設定、ファイル出力モードなども変更が必要になります。以下にこれらのポイントを整理します。
 ①インクルードファイルの変更
    #include
    SdFat SD;
       ↓
    #include

 ②SDカード装置番号の変更
    #define SDCARD_DRIVE 16  // SD card chip select number
       ↓
    #define SDCARD_DRIVE 5   // SD card chip select number (CS=GPIO5)

 ③dateTimeコールバック関数定義の削除
    // Set dateTime callback function to provide timestamp.
    SdFile::dateTimeCallback(dateTime);

 ④dateTimeコールバック関数本体の削除
    /*
    * Callback function to provide file timestamp.
    */
    void dateTime(uint16_t* date, uint16_t* time)
    {
       :
       :
    }

 ⑤ファイル名定義の変更
    #define DATA_FILE "datafile.txt"
       ↓
    #define DATA_FILE "/datafile32.txt"
    (補足)
       ファイル位置を明示しなければオープン処理に失敗します。

 ⑥SDカード装置初期設定の変更(必要に応じて)
    // Prepare SD card unit.
    if (SD.begin(SDCARD_DRIVE))
       ↓
    // Prepare SD card unit.
    if (SD.begin(SDCARD_DRIVE, SPI, 24000000, "/sd"))
    (補足)
       従来どおりで問題ないが、必要なら SPIクラスや動作周波数、マウント位置を指定できます。
       このメソッドはSD.h内で次のようにプロトタイプ宣言されています。
       bool begin(uint8_t ssPin, SPIClass &spi=SPI,
            uint32_t frequency=4000000, const char * mountpoint="/sd");

 ⑦ファイル出力モードの変更
    File df = SD.open(fname, FILE_WRITE);
       ↓
    File df = SD.open(fname, FILE_APPEND);
    (補足)
      従来のSDの open()では、FILE_WRITEを指定するとファイルの終端に追加書き出ししていま
      したが、ESP32では先頭から出力します。つまり、いつも1レコードしか書き込まれません。
      この問題は、新たな入出力モードFILE_APPENDを指定することで解決できます。

(2)土壌湿度計のハンドリング
 計測値の変換ロジックです。アナログ入力値がESP8266とは変わるため変更が必要です。アナログポートで取得した土壌湿度値を実測しながら、計測結果を0~100に変換するなど、定数部を環境に応じて調整してください。
    int measureSoilMoisture(int pin_no)
    {
      int val = 1023 - analogRead(pin_no);
      return (int)map(val, 56, 545, 0, 100);
    }
       ↓
    int measureSoilMoisture(int pin_no)
    {
      int val = analogRead(pin_no);
      int res = (int)map(val, 2650, 4100, 100, 0);
      if (res < 0)
        res = 0;
      else if (res > 100)
        res =100;
      return res;
    }

4.既存コードの変更

〔変更点〕
  ※以下のコードは変更部分だけをピックアップしたものです。
  3~4行: SdFatライブラリー未完のため削除。
  5行目:  替えてSDライブラリーを使用する。
  11行目: SDカード装置のChip select pinをGPIO5に変更。
  12行目: "(SENSOR_VP/GPIO36)"のコメントを追加。
  13行目: "/"を付加。
  35行目: Wire.begin()をWire.begin(SDA, SCL)に変更。
  46~48行: SdFileのコールバック関数定義を削除
  50行目: ファイル出力モードをFILE_WRITE→FILE_APPENDに変更して追加出力を指定。
  96~100行: 計測値の変換ロジックを修正。
  107~124行: SdFileのコールバック関数本体を削除。

#include <Wire.h>
#include <SPI.h>
////#include <SdFat.h>
////SdFat SD;
#include <SD.h>

// I2C Address
#define DS1307_ADDRESS 0x68   // Realtime clock

// SD card drive & File name
#define SDCARD_DRIVE    5     // SD card chip select number (CS=GPIO5)
#define ANALOG_PIN     A0     // Analog input pin (SENSOR_VP/GPIO36)
#define DATA_FILE    "/datafile32.txt"

		:
		:

/*****************************************************************************
 *                          Predetermined Sequence                           *
 *****************************************************************************/
void setup() {
    Serial.begin(115200);

    // Prepare SD card unit.
    if (SD.begin(SDCARD_DRIVE))
        bSD_Enabled = true;
    else {
        bSD_Enabled = false;
        Serial.println("SD Drive does'nt work!");
        return;
    }
    Serial.println("\nSD enabled!");

    // Prepare I2C protocol.
    Wire.begin(21,22);    //Define(SDA, SCL)
    
    // Create file.
    if (SD.exists(DATA_FILE)) {
        Serial.print("  File exists: "); Serial.println(DATA_FILE);
        if (SD.remove(DATA_FILE))
            Serial.println("  File removed!");
        else
            Serial.println("  Couldn't remove file!");
    }

/*    // Set dateTime callback function to provide timestamp.
    SdFile::dateTimeCallback(dateTime);
*/
    // Write data file.
    File df = SD.open(DATA_FILE, FILE_APPEND);
    if (df) {
        for (int i=0; i<8; i++) {
            df.println(sData[i]);
            df.close();
            delay(500);
        }
    }
    else
        Serial.println("Failed to create data file");
}

void loop() {
    if (bSD_Enabled && bAtFirst) {
        bAtFirst = false;
        
        File df = SD.open(DATA_FILE, FILE_READ);
        if (!df) {
            Serial.println("Couldn't open data file!");
            return;
        }
        Serial.println("Read file opened!");
        char buf[31];
        
        while (readln(&df, buf, 30) > 0) {
            Serial.print(buf);
        }
        df.close();
        Serial.println("File cloed!");
    }
    int val = measureSoilMoisture(ANALOG_PIN);
    Serial.println(val);
    delay(1000);
}
/*****************************************************************************/

		:
		:

/*
 * Measure soil moisture
 *    Return: moisture value(0~100)
 */
int measureSoilMoisture(int pin_no)
{
    int val = analogRead(pin_no);
    int res = (int)map(val, 2650, 4100, 100, 0);
    if (res < 0)
        res = 0;
    else if (res > 100)
        res =100;
    return res;
}

		:
		:

/*
 * Callback function to provide file timestamp.
 */
/* void dateTime(uint16_t* date, uint16_t* time)
{
    uint16_t year;
    uint8_t month, day, hour, minute, second;
    
    getDateTime(&dtClock);
    year = 2000 + ((int)(dtClock.year >> 4)) * 10 + (int)(dtClock.year & 0x0f);
    month = ((int)(dtClock.month >> 4)) * 10 + (int)(dtClock.month & 0x0f);
    day = ((int)(dtClock.day >> 4)) * 10 + (int)(dtClock.day & 0x0f);
    hour = ((int)(dtClock.hour >> 4)) * 10 + (int)(dtClock.hour & 0x0f);
    minute = ((int)(dtClock.minute >> 4)) * 10 + (int)(dtClock.minute & 0x0f);
    second = ((int)(dtClock.sec >> 4)) * 10 + (int)(dtClock.sec & 0x0f);
    *date = FAT_DATE(year, month, day);
    *time = FAT_TIME(hour, minute, second);
} */

5.スケッチの実行

 変更後のスケッチをesp32SD.inoの名称で保存して、[ツール]タブからシリアルモニタを開きます。
 ESP32開発ボードの右ボタン[FLASH]を押したまま左ボタン[RESET]を押下した後、IDEの「マイコンボードに書き込む」アイコンをクリックしてください。コンパイルとマイコンボードへの書き込みが終わると、シリアルモニターに次のように表示されます。「File closed!」に続く数値が土壌湿度です。


以上!