Arduino開発環境用の「ライブラリ」を作成してみる

はじめに

前回作成したAnalog Devices ADT7410に対応する「ライブラリ」っぽいArduino用スケッチを、実際にArduino開発環境用(Arduino IDE)で使用できる「ライブラリ」としてまとめてみたいと思います。

前提条件

使用する用語については以下のことを念頭に置いています:

  • Arduinoソフトウェア開発環境あるいはArduino IDEは「Arduino IDE」と記述しています。
  • Arduino IDEとは、特に言及がない場合にはArduino IDE 1.5.3ベースの「Arduino Software Package Version 1.5.3 – Intel 1.0.4」を指します。
  • ディレクトリーおよびフォルダーはArudino IDE内部の記述に沿って「フォルダ」と記述しています。
  • ライブラリーはArudino IDE内部の記述に沿って「ライブラリ」と記述しています。

今回作成する「ライブラリ」は以下の環境で動作確認を行いました:

  • Arduinoソフトウェア開発環境(Arduino IDE)の1.5以降用の「ライブラリ」を作成することを前提としています。それ以前では作成方法が異なります。
  • Intel EdisonおよびIntel Galileo Gen 1 / Gen 2向けに配布されているArduino IDE 1.5.3ベースの「Arduino Software Package Version 1.5.3 – Intel 1.0.4」を使用しました。
  • 「ライブラリ」の動作確認は前回Intel Galileo Gen 1 / Gen 2(各5Vおよび3.3V)およびIntel Edison Moduleを搭載したIntel Edison Board for Arduino(5Vおよび3.3V)、インテル株式会社版Eaglet、スイッチサイエンス版Eagletで行い、Intel Galileo Gen 1の5Vとインテル株式会社版Eagletでは正常に動作しないことを確認済みです。
  • 今回の動作確認は主にIntel Galileo Gen 2で実施しました。

Arduinoの「ライブラリ」に必要なファイル

「ライブラリ」はスケッチからincludeするヘッダー・ファイル、ソース・ファイルのほかにサンプルのスケッチ、「ライブラリ」自体の情報を示すプロパティー・ファイル、また任意のエクストラ・ファイルから構成されます。

Arduinoの「ライブラリ」の「フォルダ」構造

それぞれのファイルをそれぞれの「フォルダ」に収める形となっています。まず、「ライブラリ」は固有の「フォルダ」名を持つ必要があります。今回は「ADT7410」としました。この「フォルダ」内にサンプルのスケッチを入れるexamplesフォルダ、任意のファイル(追加のドキュメントなど)を入れるextraフォルダ、ヘッダー・ファイルやソース・ファイルを入れるsrcフォルダを用意します。

「ライブラリ」のお約束に合わせた修正

前回作成したクラスは、命名規則や基本的な記述の仕方が「ライブラリ」の標準と一致していません。そこで以下の修正を行いました:

  • 関数(メソッド)の1文字目を大文字ではなく小文字に統一しました。
  • 既存の他のチップを採用した温度センサー用の「ライブラリ」を参考にして、センサーから温度を得る関数(メソッド)の名称を「get(取得)」から「read(読む)」に変更しました。
  • ヘッダー・ファイルに以下の内容を追加:
    #if (ARDUINO >= 100)
    #include "Arduino.h"
    #else
    #include "WProgram.h"
    #endif

    古いArduino IDEで動作させることがなければ「#include "Arduino.h"」だけでも大丈夫です。もっとも、今回のこの「ライブラリ」の構造は1.5以降用なので、ヘッダー・ファイルを流用することがない限りにおいて前述の1行記述だけでも問題ないはずです。

  • 他の「ライブラリ」の処理を参考に、I2Cの初期化を行う「Wire.begin()」という記述を「ライブラリ」内部で行うようにしました。

Arduinoの「ライブラリ」のヘッダーとソース

ファイル名はヘッダー・ファイルとソース・ファイルで、拡張子が「.h」と「.cpp」で異なる以外は同じにします。

これらの変更をしたヘッダー・ファイルとソース・ファイルを以下に示します:

adt7410.h

//////////////////////////////////////////////////////////
// Sketch library for ADT7410 (Analog Devices, Inc.)
// Header file.
// Programmed by KEI SAKAKI. https://kei-sakaki.jp/

#ifndef INCLUDED_KEI_SAKAKI_ADT7410_H
#define INCLUDED_KEI_SAKAKI_ADT7410_H

#if (ARDUINO >= 100)
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

class ADT7410 {
  protected:
    int i2c_address;
  public:
    enum {
      DEFAULT_I2C_ADDRESS = 0x48
    };
    
    ADT7410(int i2c_address = DEFAULT_I2C_ADDRESS);
    virtual ~ADT7410();
    virtual int readTemperatureRaw(bool width16 = false);
    virtual float readTemperature(bool width16 = false);
    virtual void softwareReset();
    virtual void shutdown();
};

#endif

adt7410.cpp

//////////////////////////////////////////////////////////
// Sketch library for ADT7410 (Analog Devices, Inc.)
// Programmed by KEI SAKAKI. https://kei-sakaki.jp/

#include "adt7410.h"
#include "Wire.h"

ADT7410::ADT7410(int i2c_address) {
  Wire.begin();
  this->i2c_address = i2c_address;
  softwareReset();
}

ADT7410::~ADT7410() {
}

int ADT7410::readTemperatureRaw(bool width16) {
  int raw;
  
  Wire.beginTransmission(i2c_address);
  Wire.write(0x03);                  // 0x03 : Configuration Register
  Wire.write(width16 ? 0x80 : 0x00);  // bit7 : Resolution : 0 = 13-bit resolution / 1 = 16-bit resolution. (see Data Sheet Rev.A Page 13)
  Wire.endTransmission();

  Wire.requestFrom(i2c_address, 2);
  raw = (Wire.read()) & 0xff;
  raw <<= 8;
  raw |= (Wire.read()) & 0xff;  // high byte order

  if(!width16) {
    raw >>= 3;  // 13-bit mode : bit 0-2 : flags
  }

  return raw;
}

float ADT7410::readTemperature(bool width16) {
  float temp;
  int raw = readTemperatureRaw(width16);
  
  // (see Data Sheet Rev.A Page 12)
  if(width16) {
    if(raw & 0x8000) {
      raw =- 65536;
    }
    temp = ((float) raw) / 128.0f;
  } else {
    if(raw & 0x1000) {
      raw =- 8192;
    }
    temp = ((float) raw) / 16.0f;
  }
  
  return temp;
}

void ADT7410::softwareReset() {
  Wire.beginTransmission(i2c_address);
  Wire.write(0x2f);  // 0x2f : Software reset
  Wire.endTransmission();
  delayMicroseconds(200);  // ADT7410 need 200 us after reset (see Data Sheet Rev.A Page 19)
}

void ADT7410::shutdown() {
  Wire.beginTransmission(i2c_address);
  Wire.write(0x03);  // 0x03 : Configuration Register
  Wire.write(0x60);  // bit5-6 : 00 = Continuous / 01 = One shot / 10 = 1 SPS mode / 11 = shutdown(Power down) (see Data Sheet Rev.A Page 14)
  Wire.endTransmission();
}

Arduinoの「ライブラリ」を使用するサンプルのスケッチ

作成した「ライブラリ」の使用例を示すスケッチを作成します。普通にスケッチを保存した時のように、スケッチの名称を冠した「フォルダ」名とその中のファイルをそのままexamplesフォルダ内に作成(またはコピー)します。

今回はシンプルな使用例ということで実行すると温度を「シリアルモニタ」で確認することができる「Simple」というスケッチを作成することにします。「ライブラリ」内ではexamplesフォルダ内にSimpleというフォルダを作成し、その中にサンプルのスケッチをSimple.inoというファイル名で作成します。

Simple.ino

//////////////////////////////////////////////////////////
// Sketch library for ADT7410 (Analog Devices, Inc.)
// Example Sketch.
// Programmed by KEI SAKAKI. https://kei-sakaki.jp/

#include <Wire.h>
#include <adt7410.h>

ADT7410* adt7410;

void setup() {
  Serial.begin(115200);
  Serial.println("ADT7410 (Analog Devices, Inc.) Temperature IC Control Library Demo");
  adt7410 = new ADT7410();
}

void loop() {
  Serial.println(adt7410->readTemperature(true), 4);
  delay(1000);
}

library.properties

「ライブラリ」の各種情報をArduino IDEに提供するためのファイルをlibrary.propertiesというファイル名で作成し、「ライブラリ」の「フォルダ」直下(今回はADT7410フォルダの直下)に置きます。

今回のADT7410用「ライブラリ」における記述内容は以下のとおりです:

name=ADT7410
version=1.0
author=KEI SAKAKI
email=contact@kei-sakaki.jp
sentence=Analog Devices ADT7410 Temperature Sensor Library
paragraph=Measurement of 16 bits and 13 bits is supported.
url=https://kei-sakaki.jp/
architectures=*
dependencies=Wire
core-dependencies=arduino (>=1.5.0)

文字コードはUTF-8で記述します。各項目の記述内容は以下の通りです:

項目 内容
name この「ライブラリ」の名称。
version この「ライブラリ」のバージョン。
email 連絡先メール・アドレス。
sentence この「ライブラリ」の使用目的を説明する文。
paragraph この「ライブラリ」のより長い説明文。
url この「ライブラリ」のプロジェクトに関連するURL。
architectures カンマ区切りで「ライブラリ」がサポートするアーキテクチャのリスト。
特定のアーキテクチャに依存するコードを含まない場合には「*」とする。
dependencies スペース区切りで依存する他の「ライブラリ」の名称のリスト。
core-dependencies 必要とする「コア・ライブラリ」(例えばArduino IDE)とそのバージョン。

keyword.txt

Arduino IDE内のエディターで編集中に強調表示するキーワードを指定するファイルです。library.propertiesファイルと同様に、「ライブラリ」の「フォルダ」直下(今回はADT7410フォルダの直下)に置きます。今回のADT7410用「ライブラリ」における記述内容は以下のとおりです:

#######################################
# Datatypes (KEYWORD1)
#######################################

ADT7410 KEYWORD1

#######################################
# Methods and Functions (KEYWORD2)
#######################################

readTemperatureRaw  KEYWORD2
readTemperature KEYWORD2
softwareReset   KEYWORD2
shutdown    KEYWORD2

※実際には空白ではなくタブ区切りです。

キーワードとなる文字列と表示の仕方を示すKEYWORD1およびKEYWORD2の間はタブで区切ります。KEYWORD1はオレンジ、KEYWORD2はブラウンでそれぞれ表示されます。※1

その他にもいくつかの装飾キーワードがありますが、それについての説明は省略します。

作成した「フォルダ」と「ファイル」の構造

ここまでの説明で「フォルダ」および「ファイル」を作成/設置すると、以下のような構造になります:※2

ADT7410/examples/
ADT7410/examples/Simple/
ADT7410/examples/Simple/Simple.ino
ADT7410/extra/
ADT7410/src/adt7410.cpp
ADT7410/src/adt7410.h
ADT7410/keywords.txt
ADT7410/library.properties

「ライブラリ」のzipファイル化

作成した「フォルダ」構造をそのままトップのADT7410を含む形でzipファイルにします。ここではエクスプローラーの機能でzipファイル化し、ADT7410.zipというファイル名にします。

「ライブラリ」のインストールとサンプルの実行

作成したzipファイル化された「ライブラリ」をArduino IDEへインストールしてみます。

Arduino IDEはzipファイル化した「ライブラリ」をそのままインストールすることができます。別途展開する必要はありません(展開された状態の「ライブラリ」をインストールする場合は、ファイルを選択するダイアログでzipファイルの代わりにlibrary.propertiesファイルの存在する「フォルダ」を選択します。今回のケースであればADT7410フォルダの直下を選択することになります)。

  1. Arduino IDEを起動します。
  2. メニューを「スケッチ」→「ライブラリを使用」→「ライブラリをインストール…」と選択します。

    Arduino IDEにライブラリのインストールを開始

  3. 「インストールするライブラリを含むZIPファイルまたはフォルダを指定してください。」というダイアログが表示されるので、インストールする対象のzipファイル(今回はADT7410.zip)を選択します。

    Arduino IDEにインストールするライブラリの選択

  4. 「ライブラリ」を正常にインストールできると「ライブラリをインストールしました。メニューの「ライブラリの使用」を見てください。」と表示されます。

    Arduino IDEにライブラリのインストールを完了

    正常にインストールできなかった場合には下側の黒いメッセージ領域にエラー・メッセージが英文で表示されます。

  5. メニューを「スケッチ」→「ライブラリを使用」と選択すると一番下※3に「ADT7410」が表示されていることが確認できます。

    Arduino IDEのライブラリにADT7410がインストールされている

  6. 続いてサンプルのスケッチを開いてみます。メニューから「ファイル」→「スケッチの例」→「ADT7410」→「Simple」と選択します。

    Arduino IDEにADT7410のサンプル・スケッチがインストールされている

  7. サンプルのスケッチを開くことができます。

    Arduino IDEにインストールされたADT7410のサンプル・スケッチを開いてみた

  8. 右の矢印を向いた「マイコンボードに書き込む」アイコンをクリックすることで、コンパイルとIntel GalileoあるいはIntel Edisonへの転送を行い、実行できることが確認できます。出力は「シリアルモニタ」で確認できます。

残課題

  • keywords.txtファイルで指定したキーワードの強調指定が表示に反映されていません。このメモの作成時点では原因がわかりませんでした。
  • 依存関係でWireを指定しているつもりですが、「ライブラリ」としてADT7410を選択するとWire.hを同時にincludeするようにはしてくれないため、そのままビルドするとエラーになるという問題があります。これがそういうものなのかどうなのかは、このメモの作成時点では不明でしたので、そのままにしています。

作成した「ライブラリ」の配布

使用条件

  • このソフトウェアは現状のままで提供される、一切保証のないソフトウェアです。作成者および権利者は一切の責任を負いません。これに同意する場合に限り、本ソフトウェアを使用することができます。
    THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

ダウンロード

  • Arduino Library for Analog Devices ADT7410 : ADT7410.zip

まとめ

「ライブラリ」にコードをまとめることにより、次回以降に同じデバイスを再度使用する場合の手間が大幅に削減できます。またコードの配布が簡単になるなどのメリットがあります。特定のデバイス用のコードを作成する際には、「ライブラリ」として構築して以後の手間を削減し、スケッチの固有部分のコーディングに集中できるようにしていくことをお勧めします。また、それと同時に可能であれば構築した「ライブラリ」を一般公開していただければ嬉しく思います。

参考ページ

今回のこのメモを作成するにあたり、以下のページを参考にしました:

関連記事


  • より正確な表現をすると実際に表示される色はArduino IDEの設定によります。
  • 「フォルダ」の区切りは「/」を使用しています。
  • すでに他の「ライブラリ」を別にインストールしている場合には必ずしもこのようにはなりません。

Arduino開発環境用の「ライブラリ」を作成してみる」への3件のフィードバック

  1. Shoo

    温度センサーを、複数チャンネル(別アドレス)使いたい場合、ライブラリをどう変更したら良いでしょうか?

    返信
    1. KEI SAKAKI 投稿作成者

      「ライブラリ」はそのままで大丈夫です。

      コンストラクターの引数でアドレスを受け取ることができますので、必要数分だけインスタンスを作成していただけばご希望のように動作させることができます:

      //////////////////////////////////////////////////////////
      // Sketch library for ADT7410 (Analog Devices, Inc.)
      // Example Sketch.
      // Programmed by KEI SAKAKI. https://kei-sakaki.jp/

      #include <Wire.h>
      #include <adt7410.h>

      ADT7410* adt7410_1;
      ADT7410* adt7410_2;

      void setup() {
        Serial.begin(115200);
        Serial.println("ADT7410 (Analog Devices, Inc.) Temperature IC Control Library Demo");
        adt7410_1 = new ADT7410(0x48); // 1st ADT7410
        adt7410_2 = new ADT7410(0x49); // 2nd ADT7410
      }

      void loop() {
        Serial.println(adt7410_1->readTemperature(true), 4);
        Serial.println(adt7410_2->readTemperature(true), 4);
        delay(1000);
      }

      このような感じです。

      返信
  2. 大槻哲也

    非常に丁寧な記事で興味深く読ませて頂きました。
    ここで、大変恐れ入ります。基本的なことを理解で来ていないようで四苦八苦していますが、
    例えば、
    #include
    SoftwareSerial mySerial(6, 7); // RX, TX
    でソフトシリアルを、ライブラリ側で宣言し正しく動作しているのですが、ライブラリの呼び出し側ではどうしても同じソフトシリアルが使えないものになっています。
    作ったライブラリの中からでも呼び出せるようにするにはどのようにすればよろしいでしょうか。

    大変恐縮ですが、教えて頂けないでしょうか。

    返信

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です