ArduinoでC++で作った自作ライブラリを使う方法

ここではArduino開発において、C++で外部ファイルにクラスを作り、その自作ライブラリを読み込んでビルドする方法を解説します。

具体的には、前回製作した匂いチェッカーのプログラムを、C++で外部ファイルのクラスに移し、それをメインプログラムで読み込んで動作させてみたいと思います。こうすることで、プログラムが整理され読みやすくなり、保守・メンテナンスが楽になります。

なお、前回作った匂いチェッカーはArduino互換機のESP32 PICOが使われた M5StickC PLUSを使用しました。プログラム中にM5Stack系のライブラリ関数が使われますが、Arudinoでも大枠は同じやり方で可能ですので、ぜひ参考にしてみて下さい。

 C++でArduinoの自作ライブファイルをつくる

C++の新規ファイルの追加

新規ファイルの追加
新規ファイルの追加

まず、Arduino IDEで同じプロジェクト内に新規ファイルを追加するには、画像のように「▼」ボタンを押してファイルを作成します。

「New Tab」をクリックすると、ファイル名を入力できますので、C++のファイル名を入力しましょう。ここでは「GasSensor.h」「GasSensor.cpp」の二つのファイルを作りました。

.hヘッダファイル

ヘッダファイルでは変数名や関数名の登録をしておきます。外部からアクセスされる関数などにはpublicを、内部のみで使用する変数にはprivateをしていしてあげます。

/*
    GasSensor.h - Library for Gas sensor.
    Created by Toshihiko Arai, July 6, 2021.
    Copylight https://101010.fun
*/

#ifndef GasSensor_h // 2重インクルードを防ぐ
#define GasSensor_h

#include "M5StickCPlus.h"

class GasSensor {
    public:
        GasSensor(); // ←コンストラクタと合わせる
        void setup();
        void readSensor();
    private :
        bool _isSetuped;
  
}; // ←セミコロン忘れずに
#endif

コンストラクタはクラスからインスタンスを作るときに呼び出されます。初期化するときに引数を渡したい場合は、関数と同様に括弧内に引数を記述します。

.cpp実装ファイル

次に、実装ファイルでコンストラクタや関数などの内容を書いていきます。先ほどのヘッダファイルをインクルードしましょう。

書き方としては クラス名::関数名 のように二つのコロンで繋げてあげるのがC++の特徴となってます。

それ以外の内容は、前回の匂いチェッカーのプログラムとほとんど同じです。inoファイルのsetup()loop()でやっていたことを、GasSensor::setup()GasSensor::readSensor()へ書き写しただけです。

/*
  GasSensor.cpp - Library for Gas sensor.
  Created by Toshihiko Arai, July 6, 2021.
  Copylight https://101010.fun
*/


#include "GasSensor.h"

#define PIN_HEATER 0
#define PIN_SENSOR 26
#define PIN_OUTPUT 36

uint16_t getColor(uint8_t red, uint8_t green, uint8_t blue){
    return ((red>>3)<<11) | ((green>>2)<<5) | (blue>>3);
}

const int SMELL_BAD = 1000;
const int SMELL_NORMAL = 4095;
const int SMELL_DIFF = SMELL_NORMAL - SMELL_BAD; // // 2500 - 2000

GasSensor::GasSensor() { // コンストラクタ
}


void GasSensor::setup() {
    if (!_isSetuped) {
        // M5.Lcd.setRotation(3);
        M5.Lcd.fillScreen(BLACK);
        M5.Lcd.setTextColor(WHITE);

        pinMode(PIN_HEATER,OUTPUT);
        pinMode(PIN_SENSOR,OUTPUT);
        digitalWrite(PIN_HEATER,LOW); // Heater Off
        digitalWrite(PIN_SENSOR,LOW); // Sensor Pullup Off

        pinMode(PIN_OUTPUT, INPUT);
        gpio_pulldown_dis(GPIO_NUM_25); // Disable pull-down on GPIO.
        gpio_pullup_dis(GPIO_NUM_25); // Disable pull-up on GPIO.
        _isSetuped = true;
        Serial.println("GasSensor 'setup' was completed!");        
    }
}


void GasSensor::readSensor() {
    int val = 0;
    int val_origin = 0;
    float rate = 0.0;
    
    delay(237);
    digitalWrite(PIN_SENSOR,HIGH); // Sensor Pullup On
    delay(3);
    val = analogRead(PIN_OUTPUT); // Get Sensor Voltage
    delay(2);
    digitalWrite(PIN_SENSOR,LOW); // Sensor Pullup Off
    
    digitalWrite(PIN_HEATER,HIGH); // Heater On
    delay(8);
    digitalWrite(PIN_HEATER,LOW); // Heater Off

//    Serial.println(val);
    val_origin = val;

    if (SMELL_BAD > val) {
        val = SMELL_BAD;
    } else if (SMELL_NORMAL < val) {
        val = SMELL_NORMAL;
    }
    val -= SMELL_BAD;
    rate = float(val) / float(SMELL_DIFF);
    Serial.println(rate);
    int red = int((1.0 - rate) * 255.0);
    int green = int(rate * 255.0);
//    Serial.println(red);
    M5.Lcd.fillScreen(getColor(red,green,0));
    M5.Lcd.setTextSize(2);
    M5.Lcd.setCursor(10, 10);
    M5.Lcd.printf("%d", val_origin);
    M5.Lcd.setTextSize(5);
    M5.Lcd.setCursor(35, 100);
    M5.Lcd.printf("%d", (int)(rate * 100.0));
}

.inoメインプログラムで読み込んでアップロード

最後にメインプログラムの内容を書き込みます。先ほど作った、C++の自作ライブラリファイルGasSensor.hをインクルードしましょう。

GasSensor gasSensor = GasSensor(); でクラスのインスタンスを作成します。

ここではBボタンが押された時、初めて匂いチェッカーのプログラムを起動するようにしています。また今後、複数のライブラリを追加して切り替えられるように、enumで管理してみました。外部ライブラリにすることで、非常に管理しやすくなり機能追加もしやすくなりました。また、何より、別のプロジェクトでも自作ライラリを使いまわせるようになります。ちょっとした資産になるわけです。

#include <M5StickCPlus.h>
#include "GasSensor.h"

enum project_num {
    GAS_SENSOR = 1,
};


int selected_num = 0;

GasSensor gasSensor = GasSensor();

void setup() {
  // put your setup code here, to run once:
    M5.begin();
    M5.Axp.ScreenBreath(9);
    Serial.begin(115200);
}

void loop() {
    M5.update(); // Buttonの状態更新のため必要
    if(M5.BtnB.wasPressed()){
        selected_num++;
        if (selected_num > 1) {
            selected_num = 0;
        }  

        switch (selected_num) {
        case GAS_SENSOR:
            gasSensor.setup();
            break;
        }

    }

    switch (selected_num) {
        case GAS_SENSOR:
            gasSensor.readSensor();
            break;
    }

}

Visual Studino CodeでArduino開発をはじめよう

さて、ここまででArduino IDEを使って作業を行いました。実際やってみるとArduino IDEでは非常にやりにくかったっと思います。C++を書いたり複数ファイルを管理したりするには、Arduino IDEでは限界があるでしょう。

そこで、インテリセンスやエクスプローラーが充実しているVisual Studino CodeでArduino開発を行いましょう。VS Codeでは、Microsoftが拡張機能にArduinoライブラリを出しています。それを使えばVS Codeからスケッチのアップロードなどが行えてとても快適な開発環境を構築できます。

詳しいやり方はこちらに書きましたので、ぜひ参考にしてみて下さい。

他にもArduino開発の他の選択肢として、PlatformIOを使う方法もありますので調べてみて下さい。

記事に関するご質問などがあればTwitterへお返事ください。
この記事で紹介した商品
M5Stackのオススメ参考書
M5Stack製品
M5StickCで使えるHat
関連記事