はじめに
前回作成した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
フォルダの直下を選択することになります)。
- Arduino IDEを起動します。
- メニューを「スケッチ」→「ライブラリを使用」→「ライブラリをインストール…」と選択します。
- 「インストールするライブラリを含むZIPファイルまたはフォルダを指定してください。」というダイアログが表示されるので、インストールする対象のzipファイル(今回は
ADT7410.zip
)を選択します。 - 「ライブラリ」を正常にインストールできると「ライブラリをインストールしました。メニューの「ライブラリの使用」を見てください。」と表示されます。
正常にインストールできなかった場合には下側の黒いメッセージ領域にエラー・メッセージが英文で表示されます。
- メニューを「スケッチ」→「ライブラリを使用」と選択すると一番下※3に「ADT7410」が表示されていることが確認できます。
- 続いてサンプルのスケッチを開いてみます。メニューから「ファイル」→「スケッチの例」→「ADT7410」→「Simple」と選択します。
- サンプルのスケッチを開くことができます。
- 右の矢印を向いた「マイコンボードに書き込む」アイコンをクリックすることで、コンパイルと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 – Arduino style guide
- Arduino – Arduino Style Guide for Writing Libraries
- Writing a Library for Arduino
- Arduino IDE 1.5 Library specification · arduino-Arduino Wiki · GitHub
- Arduino IDE keywords « Spencer Bliven
関連記事
- より正確な表現をすると実際に表示される色はArduino IDEの設定によります。
- 「フォルダ」の区切りは「
/
」を使用しています。 - すでに他の「ライブラリ」を別にインストールしている場合には必ずしもこのようにはなりません。
温度センサーを、複数チャンネル(別アドレス)使いたい場合、ライブラリをどう変更したら良いでしょうか?
「ライブラリ」はそのままで大丈夫です。
コンストラクターの引数でアドレスを受け取ることができますので、必要数分だけインスタンスを作成していただけばご希望のように動作させることができます:
このような感じです。
非常に丁寧な記事で興味深く読ませて頂きました。
ここで、大変恐れ入ります。基本的なことを理解で来ていないようで四苦八苦していますが、
例えば、
#include
SoftwareSerial mySerial(6, 7); // RX, TX
でソフトシリアルを、ライブラリ側で宣言し正しく動作しているのですが、ライブラリの呼び出し側ではどうしても同じソフトシリアルが使えないものになっています。
作ったライブラリの中からでも呼び出せるようにするにはどのようにすればよろしいでしょうか。
大変恐縮ですが、教えて頂けないでしょうか。