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

ここではArduino開発において、C++で外部ファイルにクラスを作り、その自作ライブラリを読み込んでビルドする方法を解説します。 具体的には、前回製作した匂いチェッカーのプログラムを、C++で外部ファイルのクラスに移し、それをメインプログラムで読み込んで動作させてみます。こうすることで、プログラムが整理され読みやすくなり、保守・メンテナンスが楽になります。 なお、前回作った匂いチェッカーはArduino互換機のESP32 PICOが使われた __M5StickC PLUS__を使用しました。プログラム中にM5Stack系のライブラリ関数が使われますが、Arudinoでも大枠は同じやり方で可能ですので、ぜひ参考にしてみて下さい。

▼ 半導体不足のため入手困難な場合は、ひとつ前のモデルのM5StickCも選択に入れてみてください。

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

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

新規ファイルの追加
新規ファイルの追加
まず、Arduino IDEで同じプロジェクト内に新規ファイルを追加するには、画像のように「▼」ボタンを押してファイルを作成します。 「New Tab」をクリックすると、ファイル名を入力できますので、C++のファイル名を入力しましょう。ここでは「GasSensor.h」「GasSensor.cpp」の二つのファイルを作りました。

.hヘッダファイル

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

cpp
/*
    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()へ書き写しただけです。

cpp
/*
  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で管理してみました。外部ライブラリにすることで、非常に管理しやすくなり機能追加もしやすくなりました。また、何より、別のプロジェクトでも自作ライラリを使いまわせるようになります。ちょっとした資産になるわけです。

cpp
#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を使う方法もありますので調べてみて下さい。

関連記事

最後までご覧いただきありがとうございます!

▼ 記事に関するご質問やお仕事のご相談は以下よりお願いいたします。
お問い合わせフォーム

人気のArduino互換機
Arduinoで人気の周辺パーツ
あると便利な道具
Arduinoのオススメ参考書

▼ Arduino初心者向きの内容です。ほかのArduino書籍と比べて図や説明がとてもていねいで読みやすいです。Arduinoで一通りのセンサーが扱えるようになります。

▼ 外国人が書いた本を翻訳したものです。この手の書籍は、目からうろこな発見をすることが多いです。

▼ Arduinoの入門書を既に読んでいる方で、次のステップを目指したい人向きの本です。C言語のプログラミングの内容が中心です。ESP32だけでなく、ふつうのArduinoにも役立つ内容でした。

Seeed Studio関連製品
ATmega32U4搭載ボード
関連記事