【2014/05/10】ひとまず計測できました。結果と感想を追記。
【2014/05/06】3.6節にINA226の通信方式について追記しました。
【2014/04/28】電力センサ基板の取り付けとバッテリー駆動のテストを追記しました。
【2014/04/20】LCD表示動画とケース作成パートを追記しました。
【2014/03/30】時刻取得を試してみました。
今回はIntelから発売されているArduino互換開発ボードGalileoをレビューします。
今回のレビューはいつもの製品単体レビューだけではなく、Galileoを中心にいろいろな機械を使った開発の楽しさをレビューです。
内容は以下のとおりです。
1.Galileoとは
2.今回作るモノ
3.製作のための機能確認
4.製作の過程
5.完成品の動作確認
”インテル® Galileo 開発ボードは、インテル® アーキテクチャーを採用した新しい Arduino* 互換開発ボード・ファミリーの最初の製品です。この製品は、経験の浅い設計者の方にとっても、ひとつ上のレベルの設計を目差す設計者の方にとっても、使いやすいプラットフォームになっています。”(Intelホームページより)
インテルが作ったArduino互換機です。仕様は以下のとおりです。
CPU:Quark SoC X1000(最大400MHz)
RAM:256MB(DDR3-800)
OS:Linux
PCIe Mini Card スロット ×1
Arduino 1.0準拠拡張コネクタ(Uno R3と互換のピン配置)
5Vと3.3Vのシールドに対応
デジタルI/Oピン×14
アナログ入力×6
シリアルポート×1
ICSPヘッダ×1
リアルタイムクロック搭載(バックアップ用電池接続コネクタ搭載)
USBホストコネクタ(microUSB AB)×1
USBクライアントコネクタ(microUSB B)×1
MicroSDスロット×1イーサネット
RJ45コネクタ×1
RS-232準拠シリアルポート(ステレオミニジャック)×1
IOが非常に充実していて、400MHzのパワフルなプロセッサを搭載しています。中央近くにあるヒートスプレッダのついていないCPUがIntel Quarkです。
Arduinoだとそんなに発熱は気にならないのですが、パワフルなだけあって、CPU付近は触れないくらい熱くなります。
Galileo上面 MiniPCIE以外の端子は上面についています。
Galileo下面 Mini-PCIEスロットに加え、下面にも多くの部品が実装されています。
Arduino互換が推されていますが、基本的にはLinux搭載のマシンです。
そのためArduinoの開発環境はGalileo独自で、スケッチはLinux上のプログラムとして走るようになっています。
当然リアルタイムOSではなく、IO速度や割り込みなど、Arduinoに劣る部分もあります。
とはいえ圧倒的な演算性能と豊富な端子群が搭載されていることで独自の使い方ができると思います。
今回はベランダにつるしてある太陽光発電パネルの発電電圧、電流、電力のロギングシステムを作ります。
結線のイメージは下図のとおりです。
計測ポイント1で充電状態の計測、計測ポイント2でGalileoの消費電力を計測します。
太陽光パネルの出力がわずかなので、今回はロガーのほうが電気を食う状況になると思われます。12Vバッテリーから電気をとる方法もありかと思っています。
Galileoでやる機能を列挙すると以下のとおりです。
・電流電圧センサからデータ取得、メモリに蓄積する
・1秒ごとに平均電力・電流・電圧をSDカードに記録する(テキストファイル)
・SFTPサーバ機能で外部アクセスができる
・LANコンバータを通してホームネットワークに接続する
・SDカード記録と同時かそれより遅い間隔でLCDに現在のステータス表示する。
Galileoと電力計測センサはボックスに収納します。
製作するにあたって、必要な機能を個別で確認してゆきます。
SDカードなしでもGalileoにはLinuxが入っていますが、より高機能なものもIntelから提供されています。
ダウンロードしたイメージをSDカードのルートに保存、Galileoの電源を入れるとSDカードから起動して、スケッチが保存されるようになります。SSHサーバなどいくつかの機能も追加されており、本格的に利用するにはSDカードは必須です。
Galileo本体にはRJ45端子(LAN端子)の横にイヤホンジャックがついています。これは音声を出力するものではなく、RS232Cの通信をするシリアル通信端子です。
100円ショップのイヤホンから取り出した3.5㎜イヤホン端子を利用してケーブルを作成しました。端子の先端(青ケーブル)を2ピン、真ん中(白ケーブル)を3ピン、手前(黒ケーブル)を5ピンにつなげると通信ができます。
はんだ付けのあとグル―ガンで固着、熱収縮チューブで保護しています。
RS232Cのメス端子は秋月電子で購入したものです。ブレッドボードにさせるので便利です。
パソコンからボーレート115200で接続するとシリアルコンソールとしてLinuxの操作ができます。Linuxからは/dev/ttyS1として見えており、デフォルトでシリアルコンソールに使われていますが、Inittab.infのttyS1と書いてある部分を書きかえるとコンソール以外の入出力に使えました。
Arduinoから利用できたら最高だったのですが、Arduino特有のシリアル通信クラスであるSerial,Serial1,Serial2のどれでもアクセスできませんでした。
Linux側のPythonにシリアル通信のライブラリを入れたところ、ttyS1経由で通信できましたが、Pythonに慣れてないので基本的には使いません。
シリアルコンソールの画面
LANケーブルを挿すと起動した後にDHCPでIPアドレスをとってきます。SDカードから起動するLinuxではSSHサーバが自動的に立ち上がっているので、シリアルコンソールなどでipアドレスを確認してSSHでログインできます。
ファイル操作はSCPがデフォルトでできて、SFTPは設定ファイルを書きかえると使えました。SCPでもSFTPでも実用上は気にしないのですが、できるようにしました。
データアクセスは心配なさそうということが確認できました。
GalileoはIOが遅いと聞いていたので、下記リンクを参考にアナログ入力を1000回読み込むテストをしました。 ArduinoUnoもベンチマークとして使いました。
結果は以下のとおりでした。
Arduino Uno: 113ms
Galileo: 7447ms
読むだけで7.5msかかるので、10ms以上で済む用途に限られると考えたほうが良いでしょうか。
今回の用途は1秒平均の計測なので遅いとはいえ問題ないレベルです。
SDカードへの保存にはArduino標準のSDライブラリをつかえるので、SD.hをインクルードしてやれば簡単に使えます。
ここでは動作の検証としてアナログ入力を保存するスケッチを動かしてみました。
目的からして高速な変動を追うわけではないので3Hzのアナログ電圧を3ms間隔で出力させたものを読み取り、記録させました。
出力には下記製品とLabViewというプログラム開発ソフトを使いました。
LabViewは↓の図のとおりブロック図で手軽にプログラミングできて、対応製品だと簡単にIOを使えるため非常におすすめです。今回は学生版を使いましたが、Arduinoとセット販売をされているものだと比較的安価に入手できます。
LabViewのプログラム(左)と信号設定(中央)、発生信号の確認(右)
写真を忘れたので後日もう一度配線して追加します。
SDカードに保存したデータをパソコンで読み取ってエクセルでグラフ化してみました。
波形は読み取れるので3Hz程度の変動なら追従できるようです。ノイズがあるとどうなるかわかりませんが。
SDカードからグラフ化(時間は記録しなかったので横軸はデータ点数です)
今回の目標の1秒間隔の保存では、7ms位の間隔で1秒平均をとれば1秒値は信頼できると大雑把に考えて進めます。
今回は電圧・電流・電力センサにStrawberryLinuxから出ているINA226を使います。使い方はインターネット上で詳しく書いている方がいらっしゃったので、真似たり、テキサスインスツルメンツのデータシートを参考に勉強します。本製作ではきちんと仕様をみて平均化設定などを適切にしておきたいです。
使い方としてはWire.hというライブラリでINA226にアクセス、I2Cというプロトコルの通信をさせることになります。端子はA4とA5を使います。3.5節でアナログ入力を直接使いましたが、実際はそんなに高速通信でなくてよいのかもしれません。I2Cを使うということはINA226が届いてから知りました。。。
テスト計測の対象としてUSB端子を使いました。
スマホのUSBホスト電圧、電流を計測
接続して計測した画面です。電流電圧に加えて電力も演算してくれるスグレモノです。負荷としては3.8で使う無線LANコンバータを使っています。
ちなみに予備含めて3個用意してもらったのですが、1個は電圧入力を逆にしてしまい、逆電流で破壊しました。
[05/06追記]INA226との通信方法と2台接続
コードを書くにあたり、I2Cプロトコルの中身を勉強して、さらに複数台接続の方法を調べました。
INA226との通信方法
INA226とはWire.hを使って通信します。データシートやウェブ上の先行例を見ながら調べたところ、初期設定などの書き込みについては下図のとおりの方法ということがわかりました。(違っていたらすみません)
最初に利用するINA226のアドレスを送信、次に操作するレジスタを選択(基本設定、電圧値、電流値など)、そして書き込みの上位8ビット、下位8ビットを送り、通信終了ということになります。
利用するレジスタとしては、書き込み用に0番の”Configuration Register”、5番の"Calibration"の2つ、データ読み取りに2番の”Bus Voltage”、3番の"Power"、4番の"Current"です。
読み取りについては詳細に書きませんが、書き込みの手順2までをやって、readRegister関数を使うと2バイトデータを上位、下位、1バイトずつ返してきます。そのため、最初に読み取った値x256+2番目に読み取った値が計測値になります。
2台接続
今回2台のINA226を使いますが、接続は下図のように並列にしてやればよいそうです。電源とSCL、SCAを並列につないでいます。
普通はプルアップ抵抗が必要だそうですが、Arduinoは内蔵しているので不要とのことです。
識別については、アドレス設定ピンでアドレスを操作できるので、アドレスが重複しないようにします。4x4の合計16通りになります。アドレスとピンの対応はデータシートのTable.7に書いてありました。
アドレス設定ピン A1,A2に1,G,C,Dのいずれかを割り振る
INA226の性能確認としてRS232C接続のデジタルマルチメータと同時計測を行います。
【2014/05/10】
実際の条件でないと温度ドリフトや変動をどこまで見ればよいかなどが見極められないので、完成品の項目でテスタでの連続計測と比較します(Todo)。
LANコンバータで無線接続をします。給電はGalileoのUSBホストを将来的には使う予定です。コンバータは以下の製品を買いました。
本当は以下の製品をZigsowに用意していただいたのですが、コンバータ機能はありませんでした・・・。屋外に持っていくまでの中継アクセスポイントに使います。
設定は簡単で、パソコンから設定してしまえばあとはGalileoにさすだけで使えました。
ロガーとして1秒ごとに時刻を取得しますが、方法について考えていなかったので、コミュニティではにゃさんに教えていただいたLinuxのシステム時刻を使いたいと考えています。
14/03/30 時刻取得と記録
今回は1秒ごとに時刻を取得してデータと一緒に記録します。時刻あわせと取得の二つが必要になります。基本的にはLinuxの機能を利用します。
・時刻をあわせる
Ubuntuなどの普通のLinuxでは時刻合わせはntpdなどのパッケージをインストールして、ntp(Network Time Protocol)を使って時刻サーバと簡単に同期できます。しかしながらインテルの配布しているLinuxイメージではgccなどのビルドツールがないため、ntpdを容易にインストールできませんでした。
ひとまずは使う前にdateコマンドで時刻を手動合わせしておいて、時刻取得だけArduinoプログラム上でやることにします。
dateコマンドで引数としてMMDDHHmmYYの順番で数字を与えると時刻設定ができます。
MMは月、DDは日、HHは時、mmは分、YYは西暦下二桁です。
標準時としての時刻ですが、記録する分には関係ないので日本時間で与えています。
dateコマンドで時刻合わせ
・時刻を取得・記録する
こちらは計測と同時に行うのでArduinoのプログラムで実現します。基本的にはC言語のtimeライブラリを使います。
メイン処理としてデータ計測、さらに1秒ごとに時刻とデータを記録するというのが今回の目標なので、1秒ごとにattachinterruptを使ったタイマ割り込みをして記録を進めます。
スケッチはこの節の最後に記載しますが、ダミーのメイン処理としてアナログ読み込み、割り込み処理として1秒ごとに時刻取得・シリアルで時刻送信・SDカードに時刻記録するものを作りました。
結果としては1秒ちょうどが出ていないからか、時刻が飛んでしまうことがありました。とはいえLinuxの時刻がずれなければ、時刻と対応した出力はきちんと取れます。
今後精度改善をやるかもしれませんが、制御のようにタイミングが正確である必要はないので、ひとまずよしとします。
記録したデータはSFTPですぐに確認できます。Galileoの強みですね。
SFTPでSDカードのデータを取得
シリアル通信でも時刻送信
・スケッチ
今回使ったスケッチです。1秒サイクルの確認として割り込み時にLED点滅をさせています。
#include <TimerOne.h>
#include <sys/time.h>
#include <SD.h>
File datafile;
const int nsample=1000;
int SensorPin=A1;
int Value;
void setup()
{
Serial.println("Initializing SD card...");
Serial.println(SD.begin());
if (!SD.begin(4)) {
Serial.println("initialization failed!");
return;
}
Serial.println("initialization done.");
pinMode(13, OUTPUT);
Serial.begin(9600);
Timer1.initialize(1000); //タイマーの時間刻み
Timer1.attachInterrupt( timerIsr,1000000 ); // 割り込みの時間刻み設定
}
void loop()
{
unsigned long lpCnt1, num, Time, Val1, Val2;
delay(1000);
for(lpCnt1=0; lpCnt1<1000; lpCnt1++){
Value = analogRead(SensorPin);
}
for(lpCnt1=0; lpCnt1<1000; lpCnt1++){
}
}
void timerIsr()//割り込み処理
{
char buf[64];
time_t now;
struct tm t1;
now = time(NULL);
gmtime_r(&now, &t1);
sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d\r\n",
t1.tm_year+1900, t1.tm_mon+1, t1.tm_mday,t1.tm_hour, t1.tm_min, t1.tm_sec);
Serial.print(buf);
if(!SD.exists("datelog.txt")){//SDカード上にファイルがない場合作成
Serial.println("datelog.txt does not exist, creating.");
system("touch /media/mmcblk0p1/datelog.txt");
}
datafile=SD.open("datelog.txt",FILE_WRITE);
if(datafile){
datafile.print(buf);
datafile.close();
}
// LED点滅
digitalWrite( 13, digitalRead( 13 ) ^ 1 );
}
電力表示用にLCDを使います。一応できたのですが、、、LCD表示している間は処理が止まるということを全く考えていませんでした。
非同期で表示する方法があるのかもしれませんが、計測と同時にやるには要検討です。とりあえず表示抜きでロガー機能だけ完成させて行きます。
[14/04/20]動画を追加しました。
確認した機能を使って実際の製作です。内容としてはケースの作成、プログラムの作成、全体の設置です。
Galileoとセンサ類をバラックで放置するのは嫌なのでプラスチックボックスに入れます。
今回はタカチGB140-35DをZigsow様に用意してもらいました。
面積としてはGalileoと電流電圧計測チップが2つ入るようなものです。固定用の改造は予備実験と並行して進めました。
まずGalileoだけ固定してみたところです。M3の樹脂製ねじを使っています。Galileoの四隅には4㎜の穴が開いているので、寸法が大雑把でもなんとか固定できました。。
固定には樹脂製のねじとスペーサ的なおねじ、めねじが切ってある六角棒を使いました。
問題が2つあり、1つ目は今回選定、用意してもらったLCDディスプレイシールドがボタン付きの基板に乗っているせいで箱に入らないことです。
基板からディスプレイ部分だけ切り離して対策しようと考えています。
もう一つは電源端子で、そのままだとプラグがはみ出すのでケース脇のIOパネル部まで配線を伸ばそうと考えています。
【14/04/20】
IOパネルとケースを切り出しました。LAN端子の高さを間違えて、下側に2㎜弱の空間が開いています。動作に支障はないのでとりあえずそのままです。
リュータやヤスリ、ピンバイスなどの手作業でやったのですが、プラスチックが柔らかく切り出しやすい素材でした。
IO端子側 LANとイヤホンジャック、USB、USBホストの端子にアクセスできます
電源側 ひとまず電源用マイクロUSBだけですが、電流、電圧計の端子をつける予定
液晶がはまるように切り出した上面
とりあえずケースに入れた状態でも動くことは確認できました。
中身は雑ですが、なんとかLCD含めて箱に収まりました。CPUは放熱フィンを付けています。
閉じた状態で一晩回したら結構熱くなっていました。バラックだと逃げるはずの熱が全部こもるためです。夏に向けて課題になりそうなので、全機能が完成したら対応したいと思います。
ケース作成は 電力センサ基板の取り付けとそれに合わせた端子、配線の取り回しでひとまず終了です。
【2014/04/28】電力センサ基板のとりつけとバッテリー接続
Galileoの横にセンサ基板を取り付けました。ケースの外側に端子台を付けたいので、INA226の端子台は取り外す予定です。配線がカオス状態ですが、とりあえず動いています。
手前の一番左、白い基板はセンサを並列にするため5V電源、アナログ端子の分配を行っています。
センサ基板の取り付けと配線
LCDが熱を持ってしまうため放熱フィンは取り外しました。CPUに良かれと思ったのですが、熱問題は難しいです。
電源につなげたmicro-USB端子でモバイルバッテリーとの接続・駆動もできました。
LCD表示のスケッチ駆動時、電流は0.5から0.6Aでした。
Anker Astro3Eを使ってバッテリ―駆動
■ケース完成(ファンレスVer.)
全部の基板を格納してケースを完成しました。計測用端子は端子台で外に出して、ワニ口クリップを繋げています。
左写真の左側にある穴はファン取り付けの布石です。右写真の側にファンを排気で取り付ける予定です。
端子台ラベルは随分前に買ったメモプリを使って作成しました。テプラを持っていないので代用です。粘着力はあるので、勝手にはがれることは無いと思っています。
【2014/05/10】第一段階のプログラムを作成(LCD表示抜き)
■第一段階プログラムの仕様
予備検討からLCDを1秒間隔で動かすのは難しいことがわかったので、以下の機能でArduinoスケッチを作成することにします。スケッチは長いので記事の末尾に記載します。
1.遅延処理10ms刻みで電力・電流・電圧を測定、それまでの測定の平均値を算出
2.1sごとに割り込み処理で平均電力・電流・電圧をSDカードに保存、測定データをクリア
・電力センサ設定
INA226の設定は以下の通りにしました。平均化時間を長くすればGalileo側の負担は減りますが、積算値計算など後々追加したいので、Galileo側で高サンプルデータを持っている方が便利と判断しました。
キャリブレーションレジスタ:0x1400(10進で5120 データシート式1から最大電流16.384Aに対応)
バス電圧conversion time:1.1ms 電圧計測用電圧
シャント電圧conversion time:1.1ms 電流計測用電圧
平均化回数:16回
以上でおそらく1.1x16ms単位で更新されるはずです。
SDカード保存では”datalog.txt”というファイルに追記していくようにしています。
・時刻など、手作業が必要な部分
起動後、スケッチを動かすまえに時刻合わせをしておく必要があります。また、データは適宜消去してやる必要があります。
■完成システム外観
今後追記します。
■第一段階プログラムを使った計測
完成した筐体とプログラムを使って少し計測をしてみました。ひとまず第一段階としては完成です。昼間に計測を行ったのですが、時刻合わせをしていないので0時になっています。
バッテリー入力というのが最初のイメージ図の計測ポイント1、Galileo消費が計測ポイント2です。全体に右肩上がりですが、温度のドリフトなのか、実際に日射や消費電力が変わっているのかはわかりません。とはいえ、概ね期待したとおりに時刻とデータの記録はできました。
Zigsow様には5月中旬を開発完了と申請したので、最低限の機能しか実装できていませんが、節目ということで感想を書きます。開発は継続していきます。
■想定と違ったこと・こうだったら良いのに
まず、ハード面でArduinoに劣っている部分があるということです。具体的には割り込みタイミングの精度・遅さとGPIOの遅さです。Arduinoではすぐ終わるLCD表示も普通にやっただけではすごく遅くなりました。
また、ソフト面では、Arduinoスケッチからシリアルポートにアクセスできないのも歯がゆいところです。基板についているのにシールドを買うというスマートじゃない方法しかないのは残念です。これが使えたらRS232接続の電流・電圧計をスケッチ中で簡単に使えました。あとは純正のLinuxではビルドツールが入っていない、Arduinoライブラリと完全互換ではないなど、いくつか不親切なところがあるというところです。
性能ではない問題では、パワフルだからか発熱がすごいのも気になりました。
■Galileoだからよかったこと
GalileoはArduino互換ですが、LinuxPCでもあり、いろんなポートを持っているということが特徴です。
今回の内容では大した開発はしていない上、Galileoじゃなくてもできるというのは感じました。
ですが一番意識したこととして、Galileoの機能を最大限使って楽をするということがありました。
例えば、今回の内容を別のボードでやることを考えてみると、
・Arduino
無線LAN、SDカードのシールドか基板を用意して、FTPサーバ機能をスケッチに書くという風になるかと思います。そうすると通信処理などをスケッチに入れないといけないので面倒です。ハードの数も増えますし、スケッチも面倒になります。
・RaspberryPi
これは触ったことがありませんが、周辺機器は変わらないと思います。Linuxが入るのでFTPサーバは簡単にできます。ですがループ処理など、スケッチではなくC言語やスクリプト言語になって少し面倒になるかもしれません。要するに純粋なパソコンプログラミングになるので面倒になりそうです。
ではGalileoは、というと
・Galileo
FTPサーバ・コンソールなど、典型的な管理機能はLinuxの資産を有効活用、Arduino的なループ、タイミングの必要な処理はスケッチを利用というハイブリッド開発が可能。スケッチならプログラミングの手間も減って、タイミングも簡単にできる。
今回実施した内容を振り返っても、Galileoじゃないとできなかったと思っています。同じ手順でほかのボードを使うと、どこかで手作業の量が増えるということです。
■全体の感想
一言であらわすなら、Arduino機能が使えるミニPC といったところでしょうか。
私はパソコンはWindowsしか使っていなくて、ArduinoもLEDチカチカのレベルだったのですが、
LinuxかArduinoどちらか簡単な方を選ぶことで、未熟でも効率的に欲しいものがつくれました。また、電子工作をまじめにやってみたくなりました。
このような魅力的な製品に触れる機会をくださってありがとうございました。
付録
・作成したコード
■第一段階コード LCD表示なし、電力・電圧・電流を計測
#include <TimerOne.h>
#include <sys/time.h>
#include <SD.h>
#include <LiquidCrystal.h>
#include<Wire.h>
File datafile; //ログファイル
int nsample;//現在のサンプリング数
char temp_raw[6];//温度文字列
long count=0;//データカウント 割り込みごとにリセット
double v0cum,v1cum,i0cum,i1cum,p0cum,p1cum;//積算電圧、電流、電力;
double v0ave,v1ave,i0ave,i1ave,p0ave,p1ave;//平均電圧、電流、電力
#define NELEMS(arg) (sizeof(arg) / sizeof((arg)[0]));
//以下電力センサINA226の設定 アドレス以外は2機共通
//
const byte INA226_ADDR_0 = B1000001;//バッテリー側
const byte INA226_ADDR_1 = B1000101;//Galileo側
// INA226 Registers
#define INA226_REG_CONGIGURATION_REG 0x00 // Configuration Register (R/W)
#define INA226_REG_CALIBRATION 0x05 // Calibration (R/W)
#define INA226_REG_BUS_VOLTAGE 0x02 // Bus Voltage (R)
#define INA226_REG_POWER 0x03 // Power (R)
#define INA226_REG_CURRENT 0x04 // Current (R)
const word INA226_CAL_VALUE = 0x1400; // INA226 Calibration Register Value データシート式1を参照
const byte INA226_CONFIG = 0x00;
const byte INA226_SHUNTV = 0x01;
const byte INA226_BUSV = 0x02;
const byte INA226_POWER = 0x03;
const byte INA226_CURRENT = 0x04;
const byte INA226_CALIB = 0x05;
const byte INA226_MASK = 0x06;
const byte INA226_ALERTL = 0x07;
const byte INA226_DIE_ID = 0xff;
// INA226 Operating Mode (Mode Settings [2:0])
#define INA226_CONF_MODE_POWER_DOWN (0<<0) // Power-Down
#define INA226_CONF_MODE_TRIG_SHUNT_VOLTAGE (1<<0) // Shunt Voltage, Triggered
#define INA226_CONF_MODE_TRIG_BUS_VOLTAGE (2<<0) // Bus Voltage, Triggered
#define INA226_CONF_MODE_TRIG_SHUNT_AND_BUS (3<<0) // Shunt and Bus, Triggered
#define INA226_CONF_MODE_POWER_DOWN2 (4<<0) // Power-Down
#define INA226_CONF_MODE_CONT_SHUNT_VOLTAGE (5<<0) // Shunt Voltage, Continuous
#define INA226_CONF_MODE_CONT_BUS_VOLTAGE (6<<0) // Bus Voltage, Continuous
#define INA226_CONF_MODE_CONT_SHUNT_AND_BUS (7<<0) // Shunt and Bus, Continuous (default)
// INA226 動作設定
#define INA226_CONF_VSH_1100uS (4<<3) // シャント電圧(電流計測)収束時間1.1ms (default)
#define INA226_CONF_VBUS_1100uS (4<<6) // バス電圧(電圧計測)収束時間1.1ms (default)
#define INA226_CONF_AVG_16 (2<<9) // 平均化回数 16回
#define INA226_CONF_RESET_INACTIVE (0<<15) //リセットビット無効
static void writeRegister(byte reg, word value, byte addr)
{//アドレスを指定してレジスタに書き込んで閉じる
Wire.beginTransmission(addr);
Wire.write(reg);
Wire.write((value >> 8) & 0xFF);
Wire.write(value & 0xFF);
Wire.endTransmission();
}
static void setupRegister(void)
{//INA226の初期設定関数 両方共通なので一気に設定
writeRegister(INA226_REG_CONGIGURATION_REG,
INA226_CONF_RESET_INACTIVE
| INA226_CONF_MODE_CONT_SHUNT_AND_BUS
| INA226_CONF_VSH_1100uS
| INA226_CONF_VBUS_1100uS
| INA226_CONF_AVG_16
, INA226_ADDR_0);
writeRegister(INA226_REG_CONGIGURATION_REG,
INA226_CONF_RESET_INACTIVE
| INA226_CONF_MODE_CONT_SHUNT_AND_BUS
| INA226_CONF_VSH_1100uS
| INA226_CONF_VBUS_1100uS
| INA226_CONF_AVG_16
, INA226_ADDR_1);
writeRegister(INA226_REG_CALIBRATION, INA226_CAL_VALUE, INA226_ADDR_0);
writeRegister(INA226_REG_CALIBRATION, INA226_CAL_VALUE, INA226_ADDR_1);
}
static word readRegister(byte reg, byte addr)
{//アドレスを指定してレジスタの値を読み取る
word res = 0x0000;
Wire.beginTransmission(addr);
Wire.write(reg);
if(Wire.endTransmission() == 0) {
if(Wire.requestFrom((int)addr, 2) >= 2) {
res = Wire.read() * 256;
res += Wire.read();
}
}
return res;
}
void setup() {
// put your setup code here, to run once:
pinMode(13, OUTPUT);
//シリアルポート開
Serial.begin(9600);
//IPアドレス取得
// system("/etc/init.d/networking restart");
//INA226セットアップ
Wire.begin();
setupRegister();
//SDカードセットアップ
Serial.println("Initializing SD card...");
Serial.println(SD.begin());
if (!SD.begin(4)) {
Serial.println("initialization failed!");
return;
}
Serial.println("initialization done.");
Timer1.initialize(1000); //タイマーの時間刻み設定 1ms
Timer1.attachInterrupt( timerIsr,1000000 ); // 割り込みの時間刻み設定 1000ms
}
void loop() {
// put your main code here, to run repeatedly:
char buf[64];
long voltage0,voltage1; // 電圧 (mV) ゲインは一定で1.25(V)データシートP14以降参照
short current0,current1; // Current (mA) CAL_VALUEからゲインは0.5 (LSB=0.0005(A)=0.5(mA))
long power0,power1; // Power (μW) ゲインは12.5mW
voltage0 = (long)((short)readRegister(INA226_REG_BUS_VOLTAGE, INA226_ADDR_0)) * 1250L; // LSB=1.25mV
current0 = (short)readRegister(INA226_REG_CURRENT, INA226_ADDR_0)*0.5;
power0 = (long)readRegister(INA226_REG_POWER, INA226_ADDR_0) * 12500L; // LSB=25mW
voltage1 = (long)((short)readRegister(INA226_REG_BUS_VOLTAGE, INA226_ADDR_1)) * 1250L; // LSB=1.25mV
current1 = (short)readRegister(INA226_REG_CURRENT, INA226_ADDR_1)*0.5;
power1 = (long)readRegister(INA226_REG_POWER, INA226_ADDR_1) * 12500L; // LSB=25mW
v0cum+=voltage0/1000000.0;//一旦整数型に入れないとうまくいかなかった。
i0cum+=current0/1000.0;
p0cum+=power0/1000000.0;
v1cum+=voltage1/1000000.0;
i1cum+=current1/1000.0;
p1cum+=power1/1000000.0;
count++;
v0ave=v0cum/count;
i0ave=i0cum/count;
p0ave=p0cum/count;
v1ave=v1cum/count;
i1ave=i1cum/count;
p1ave=p1cum/count;
//Serial.println(v1ave);//デバッグ用シリアル出力
//Serial.println(i1ave);
// Serial.println(p1ave);
delay(10);
// Serial.println(count);
}
//
void timerIsr()
{
char buf[128];
time_t now;
struct tm t1;
//積算値とカウントのリセット
v0cum=0;
i0cum=0;
p0cum=0;
v1cum=0;
i1cum=0;
p1cum=0;
count=0;
now = time(NULL);
gmtime_r(&now, &t1);
sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d,%f,%f,%f,%f,%f,%f\n",
t1.tm_year+1900, t1.tm_mon+1, t1.tm_mday,t1.tm_hour, t1.tm_min, t1.tm_sec,v0ave,i0ave,p0ave,v1ave,i1ave,p1ave);
Serial.print(buf);
if(!SD.exists("datalog.txt")){
Serial.println("datalog.txt does not exist, creating.");
system("touch /media/mmcblk0p1/datalog.txt");
}
datafile=SD.open("datalog.txt",FILE_WRITE);
if(datafile){
Serial.println(datafile.size());
datafile.print(buf);
datafile.close();
}
//LCD操作
//lcd.setCursor(0, 0);//今後考える
// lcd.print(buf);
// LED点滅
digitalWrite( 13, digitalRead( 13 ) ^ 1 );
}
蒼-aoi-さん
2014/03/30
私、この開発スタイル好きです!あるものはうまく使う!
私の座右の銘に通じるものがありまして、大変共感しております!
この電流センサ面白いですね。今度買ってみよう。
最終形は、製品っぽい感じになりそうで、楽しみです!
いぐなっちさん
2014/03/30
と思ったら、製品版の価格ものすごい^^;
ソースコードも私のと違って、無駄がなく美しいです。
kilifさん
2014/03/31
ありがとうございます。
技術も時間も限られた中では、既存のリソースをうまく使うのが効率が良いと私も思っています。(コストと相談ですがf^^;)。
全部自分で作れるのも素晴らしいことですが、自分でやることが最小限になるほうがバグも少ないと思います。
電流センサは直流をどうやって測定するかわからなかったので検索したら偶然見つけましたが、家庭用には丁度良いですね。
製品っぽいといえば聞こえは良いですが、適当にケースを選んだら予想外に実装密度が高くなってしまいました。苦労しそうです。
kilifさん
2014/03/31
確かにLabView製品版はすごく高いんですよね^_^;
VisualStudioみたいに無償版があったら一気に広まると思うのですが…
あと本文にも書いた安価なLabview・Arduinoセットがスイッチサイエンスで売ってたと思ったのですが、終わってしまったみたいです(それでもWindowsくらいの価格ですが)。
ソースは・・・お褒め頂いてあれなのですが、
必要な機能をネット上で集めてくるスタイルのせいかもしれません。コピペ一歩手前というかなんというか。。。