前回、SDカードI/Fを自作(手作り)し、SDライブラリのサンプルプログラムを使って、動作を確認するところまで到達しました。SDカードのデータにアクセスするプログラムの検討を開始したところで途中終了してしまったので、まず、SDカードアクセスプログラムを完成させます。
さらに、SDカードI/Fを使って、バッテリ駆動などで独立動作させた場合のデータの書き出し先に使うことを想定し、DHT11を使った気温・湿度測定機能を追加、最終的に、測定データをSDカードに書き出すアプリケーションを試行してみたいと思います。
前回、SDカードアクセスプログラムの仕様まで検討してあったのですが、プログラムの完成まで至りませんでした。以下、完成版プログラムをリンクしておきます。
完成版プログラム:portbl_logger.ino
実験サンプル:【 】内はシリアルモニタからの送信データ
OK+ SD initialize...
OK: SD initialize done.
RDY
【ls】
OK+ ls /
SYSTEM~1/
INDEXE~1 76
WPSETT~1.DAT 12
MML_SE.TXT 871
MML_KIYO.TXT 266
MML_KOI.TXT 274
MML_RURU.TXT 79
MML_RED.TXT 866
TST_EX~1.UNK 59
TST_DATA.CSV 96
ファイル名の後ろの数値は、ファイルサイズ(バイトカウント)です。サブディレクトリがあった場合、1階層下のファイルまで走査して表示します。多数のファイルを格納したSDカードを読み込むと、暫く制御が戻ってこないのでご注意ください。
実験サンプル:【 】内はシリアルモニタからの送信データ
【cat,mml_kiyo.txt】
OK+ cat mml_kiyo.txt
--------
play
# きよしこの夜
G44.,A48,G44
E42.
G44.,A48,G44
E42.
#
:
#
C54,G44,E44
G44.,F48,D44
C42.
end
--------
OK: cat
表示したファイルは、「#5-8 MMLで音楽を奏でる」で使ったMMLファイルです。以前は、シリアルモニタからダウンロードして演奏させたのですが、SDカードから読み込みながら演奏することもできそうです。
ファイル名は、大文字で表示されますが、小文字で指定してもアクセス可能です。こちらも、大きなファイルを表示すると、暫く制御が戻ってこなくなるので、ご注意ください。
ここから先は、XMODEMに対応した通信ソフトウェア(Tera Termを推奨)で実験します。
実験サンプル:【 】内はTera Termからの送信データ
【xsend,mml_kiyo.txt】
OK+ xsend ready, waiting... (266byte, 3block)
OK: xsend bytes=384 errs=0
【xsend】/【xrecv】コマンドは、Arduinoから見て、送信【xsend】/受信【xrecv】するコマンドとなっているので、Tera Term側から見ると、XMODEM受信/XMODEM送信に対応します(受信⇔送信がてんこしゃんこ)。
【xsend】コマンドを実行して「waiting」と表示されたら、Tera Termの「Fileメニュー ⇒ Transfer ⇒ XMODEM ⇒ Receive」を実行してください。受信するデータのファイル名を問い合わせるウインドウが開きますので、適切な名前を指定してください。
下の方に「Binary」のチェックボックスが見えます。こいつがちょっと厄介。XMODEMなんて、時代遅れで、問題も抱えているプロトコルを真面目にサポートするつもりはないのだろうけど、XMODEMって、バイナリデータの転送プロトコルではなかったのか?そこに「Binary」などと言うチェックボックスがついていることに戸惑い。
で、実際にやってみると、困ったことが。
どっちもどっちだけど、まだマシと思える方を選択して続けると、進行状況のウインドウが表示され、転送したデータ数がカウントアップされて行きます。ウインドウが自動的に閉じたら、転送終了です。
次は、PC(Tera Term)から受信したデータをSDカードに書き込むテストです。
実験サンプル:【 】内はTera Termからの送信データ
【xrecv,file.bin】
OK+ xrecv ready, waiting...
OK: xrecv bytes=512 errs=0
【xrecv】コマンドを実行して「waiting」と表示されたら、Tera Termの「Fileメニュー ⇒ Transfer ⇒ XMODEM ⇒ Send」を実行してください。送信するデータのファイル名を問い合わせるウインドウが開きますので、適切なファイルを指定してください。進行状況のウインドウが表示され、転送したデータ数がカウントアップされて行きます。ウインドウが自動的に閉じたら、転送終了です。
Tera TermでXMODEMの転送が始まると、Arduinoからのメッセージは全てXMODEMに吸い取られてしまうので、万一、回復不可能なエラーが起きて途中で転送を終了した場合には、パイロットLED(pin_PILT)が点灯するようになっています。その場合は、Tera Termの進行表示ウインドウをCancelボタンで閉じてください。……転送は失敗しています。
※XMODEMで送受信する場合、転送データを直接SDカードにリード/ライトしています。従って、SDカードのアクセス速度と、Serialの転送速度の比によっては、SDカードのリード/ライトが間に合わず、転送エラーになる場合があります。その場合、Serialの転送速度を落として転送してください。
「バッテリ駆動」のアプリケーションをイメージした時、まず、思い当たるのは乾電池の使用、です。Arduinoの5V電源を作り出すには、例えば、アルカリ乾電池4本を直列にした場合の1.5V×4=6Vを降圧レギュレートして5Vにする方法が考えられます。しかし、実は、eneloop等のリチウムイオン充電池を使う場合、電圧が1.2Vなので、4本直列にしても1.2V×4=4.8Vにしかならず、5Vに届きません。
経済的には、充電池を使いたいところなので、「充電池専用」と考えると、4本直列で4.8Vなら、ATmega328 @16MHzのTYP電圧値約4.2Vに対して、まだ余裕があるので、レギュレータを通すことなく、直接駆動するという手もあります。
※ATmega328の定格電圧と最大動作周波数については、「#5-10 電源電圧を計測する」を参照してください。
ただし、同じ形の電池なので、間違ってアルカリ乾電池を使ってしまうと、Arduinoに6Vが供給されてしまい、絶対最大定格違反となります(最悪の場合、壊れてしまう)。今一つ、ですね。
※正確には、ATmega328Pの絶対最大定格は、Vcc(ABS.MAX)=6.0Vなので、「違反」とまで言うと、言い過ぎかもしれません。しかし、絶対最大定格とは、「その値を超えてはならない」ことを示すスペックなので、オンスペックである時点でアウト!だと思っています。
最近ではスマホなどの予備バッテリとしてモバイルバッテリが沢山出回っています。しかも、想定用途がスマホであるだけに、出力が5VのUSB端子になっていることが多いので、これを使うのが一番手っ取り早いと考えました。
今回使うのは、以下図の様な、単三型eneloop×2本から5VのUSB出力を備えたモバイルバッテリです。
上図の様に、単三型eneloop×2本がちょうど入るサイズの筐体に、スイッチやUSBコネクタの付いたキャップが被さった形になっています。eneloop×2本直列では2.4Vにしかならないので、キャップ部分に2.4→5[V]の昇圧レギュレータが入っているのだと思われます。
5VのUSB出力になっているので、USBケーブルでUNOと接続したら、電源供給終了です。
※近頃は、単一型〜単四型と言った規格サイズと異なる、18650とか言う規格サイズのバッテリと、それを使ったモバイルバッテリが幅を利かせているようなので、Amazon等で探してみてください。
稼働時間を推定しておきましょう。今回使用する単三型eneloopの公称スペックは、1,900mAh@1.2Vです。出力電圧が1.2Vで、100mAの電流を19時間流せますよ(電流と時間の積が1,900mAh)、と言う意味です。eneloopを2本直列にして使うモバイルバッテリなので、1,900mAh@2.4Vと言うことですね。
ATmega328のデータシートによると、ATmega328単体で、10mA@5V(@16MHz)くらいの値が記載されています。当然、その時のATmega328内部ユニットの動作状況で前後するので、参考値です。
ATmega328単体の消費電流が10mAとして、UNO基板上その他周辺回路での消費電流を加えて、UNOの消費電流を15〜20[mA]程度で見積もりました。以降、UNOの電流値を15mAと仮定して推定を続けます。
※感覚的には、15mAと言う値は、「ちょっと小さいな」と感じます。しかし、電流を測定可能なデバッグ環境が手元に無いので、データシートの値を使うしかなく、この数値で検討してみます。
再びモバイルバッテリに戻って、このモバイルバッテリは2.4Vから5Vへ昇圧しているので、昇圧レギュレータの変換効率を90%と仮定、変換前後の電力一定として電流時間積(mAh)を計算してみると:
1,900mAh×2.4V×0.90(効率)=A×5.0V …… Aが5V昇圧時の電流時間積
A≒821mAh@5V
UNOの消費電流値を15mAと見積もりましたので、821mAh/15mA≒54.7h、2日間とちょっと、ですね。思ったよりも長く稼働できそうです。
一方、人によっては「短い」と思うかもしれません。PCやAC電源などから離れて、敢えてバッテリで駆動するロガを作ろうというのですから、本来なら、1か月に一度とか1週間に一度とかの頻度で、蓄積したデータを回収し、その時に新しいバッテリと交換すれば長期間のデータログが可能となります。
2日でバッテリが底をついてしまう様では、1週間に2〜3回、データ回収とバッテリ交換をしなければならず、長期間のデータログに使用するのは厳しいでしょう。
いずれにせよ今回の実験は、一回始めたら結果が出るまでに2日以上を要することは覚悟しておかなければなりません。
※後日、USB電圧・電流計を使って、装置の消費電流値を測定した結果については、本ページ末の「アップデート」をご覧ください。
今回は、DHT11モジュールを使いましたが、AM2302でもOKです。それぞれ、以下の記事をご参照ください。
DHT11:「#2-4 二代目のスタータキット購入」
AM2302:「第6回 気温と湿度の測定」、等、Season 1全般
DHT11モジュールとArduinoの接続は以下の通りです。
Arduino UNO | 接続 | DHT11モジュール |
5V | → | + |
GND | ⇔ | − |
D5 | ⇔ | S |
本来であれば、UNOや周辺回路が正常動作できる電圧かどうかを判定して、動作を停止するなどの処置が必要なのですが、今回は、電源電圧を測定して、気温・湿度と一緒にログに記録する方法を取ります。電源電圧の測定に関しては、「#5-10 電源電圧を計測する」をご参照ください。
上図の様に、外付けに5kΩ:1kΩの抵抗分圧回路を作っておいて、ArduinoのA0端子に接続しておきます。
バッテリ電圧をそのまま直結している場合は、電流消費に伴って、徐々にバッテリ電圧が低下して行き、どこかでArduino(や周辺回路)の動作限界を迎える、と言ったストーリになることが予想されます。しかし、今回使うモバイルバッテリは、昇圧レギュレータを通っているので、「入力電圧の低下に伴う、昇圧電圧値の変化がどうなるの?」と言う問題であり、回路構成によって、挙動は異なってくるでしょうね……。
その点も、実験で確かめてみましょう。
測定した気温・湿度データと、電源電圧(Vcc)データをCSV形式(カンマ区切りテキスト)でSDカード上のファイルに書き込んで行きます。
<経過時間[ms]>,<電源電圧[mV]>,<気温×10[℃]>,<湿度×10[%RH]>
:
以下、エラー処理を省略した、書き込み手順部分のコードです。
// log to file
sprintf (lbuf,"%ld,%d,%d,%d",msec,vcc,tmp,hum);
fout=SD.open (fname_log, FILE_WRITE);
fout.println (lbuf);
fout.close ();
SD.open()で指定している書き込み属性FILE_WRITEは、SDライブラリでは、「読み・書き・追記可能なモード」となっています。SD.open()した直後は、ファイルの末尾(EOF)をファイルポインタが指しているため、そのまま書き出せば、追記になります。
ログの出力に関しては、非常に都合の良い書き込みモードです。
ファイルを頭から書き込み直したい場合は、fout.seek()を使って、ファイルポインタを操作してから書き込み処理を実行します。いずれの場合も、開いた時のファイルサイズより小さくすることはできないので、最初から、真っ新な状態で、ファイルへ書き込みたい場合は、あらかじめSD.remove()でファイルを消去しておいてから、改めてSD.open()で書き込みファイルを開く必要があります。
※本来、電源電圧が低下して正常動作しなくなってくると、エラー表示したり、動作を停止したりする必要があるので、細かく、かつ、蛇足気味にエラーチェックが入っています。実際のチェック内容に関しては、完成版プログラム(portbl_logger.ino)を参照してください。
なお、SDライブラリを使って新規に作成したファイルのタイムスタンプをWindowsで確認すると、「2000/01/01 1:00:00」になっていました。RTCとか搭載されていないと、Arduinoでは時間がわかりませんからね。決め打ちになっているみたいです。
以上より、モバイルバッテリ、自作SDカードI/F、DHT11、パイロットLED、電源電圧分圧回路を、UNOと接続して、独立動作(バッテリ駆動)の気温・湿度ロガを稼働させてみます。SDカードI/Fの回路図は、「#6-5 microSDカードI/Fを自作する」を参照してください。
ポータブルロガのプログラム(portbl_logger.ino)には、シリアルモニタから受け付けるコマンドに、ロギングを開始/停止するコマンドを用意してあります。
しかし、USBでホストPCと接続した状態ならまだしも、バッテリ駆動で独立動作させる場合、シリアルにコマンドを流し込むのは、容易ではありません。
プログラム(portbl_logger.ino)の先頭付近に以下の様な#defineがあるので、LOG_FILEにログファイル名を指定、LOG_STARTを"true"に設定することで、「電源投入と同時にロギングを開始する」様にして、コンパイル&UNOへ書き込んでおいてください。
#define LOG_START true // true for start logging on power-on
#define LOG_FILE "D1906xx.CSV" // log file name (<max_log_name)
※ファイル名バッフアは、終端記号('\0')を含めてmax_log_name(=32)バイトしか確保していないので、ディレクトリの下にファイルを出力したい場合は、ディレクトリ名まで含めた文字数に注意してください。必要に応じてファイル名バッファサイズ(max_log_name)を拡張してください。
以下、実験中の様子です。
ただの気温・湿度ログとしては、ちょっと頻度が高すぎる気もしますが、15秒毎に測定して、microSDカードにデータを蓄積しています。
モバイルバッテリの出力電圧が徐々に低下して、Arduino稼働不可能な電圧まで低下した時、Arduinoの挙動次第では、SDカードのファイルシステムを破壊してしまわないとも限りませんが、こればっかりはやってみないとわからないので、まずは実験してみて、どういう状態になるのか?確認し、状況次第で対策を考えることにします。
気温・湿度の測定に関しては、たまたま手元にあったセンサがそれだったというだけで、あまり意味はありません。今回の実験の趣旨は、モバイルバッテリから供給される電源電圧の変化や、何時間くらい動作可能なものか、電源電圧低下による誤動作が起きないか、と言った基本的な部分の検証にあります。
2019/06月の中旬、23:43頃にモバイルバッテリの電源スイッチをONして、Arduino(気温・湿度ロガ)に電源の供給を開始しました。
独立動作させるため、起動すると自動的に気温・湿度測定を開始して、ログに出力する様、#define LOG_STARTと、LOG_FILEを設定してコンパイル&書き込んでおきました。
結果として、約15時間後に動作を停止しました。……想定していたより、だいぶ短かったですね(拍子抜け)……。想定との差分は以下の様な要因が考えられます。
筆者のデバッグ環境では、どこの想定値に狂いがあったのか、知る術がありません。
以下、測定した気温・湿度のグラフです。
横軸は測定開始からの経過時間、左軸は室温、右軸は湿度です。
DHT11なので、室温・湿度とも、整数値でしか測定できません(「#2-4 二代目のスタータキット購入」)。このため、だいぶ粗く量子化されたグラフになっています。このデータは「おまけ」なので、特にこれ以上コメントすることはありません。
※AM2302を使うと、小数点以下1桁まで測定することが可能です。詳しくは、「第6回 気温と湿度の測定」等、Season 1全般をご覧ください。
※本文執筆時のプログラム(portbl_logger.ino)が間違っていて、気温データの小数点以下が常に0になっていました。プログラム修正済みです。
下図が、肝心な電源電圧の推移グラフです。
以下、雑感です。
実験の結果、独立動作で、測定データの整合性を確認できないままログを取り続けるのは危険だとわかったので、各測定と測定データに対して、エラーチェックとデータの整合性チェックを実施し、エラーを検出した時にパイロットLED(pin_PILT)に表示するように改定しておきました。
if (errcod!=ErrNo)
{
// ERROR: show error status, but continue logging
digitalWrite (pin_PILT, LOW);
delay (250);
for (idx=0; idx>errcod; idx--)
{
delay (250);
digitalWrite (pin_PILT, HIGH);
delay (250);
digitalWrite (pin_PILT, LOW);
}
}
正常時(errcod=0)は、15秒に一度、データの測定とログ出力を実行する間、ピカッと短くパイロットLEDが光ります。
何らかのエラーを検出した場合は、上のコードで、エラーコードに従ってパイロットLEDを点滅するようになっています。例えば、errcod=-3の場合、測定を実行したことを示す短い点灯の後で、3回(=abs(errcod))点滅します。ジャンパ線の接触が悪かった場合など、測定開始直後に異常を検知できるため、長時間無駄な測定データをロギングするような悲劇を回避できるはずです。
現時点では、エラーを検知しても、そのままデータログを継続していますが、電源電圧の低下を検知した場合、動作を停止するなど、何らかの手立てを講じる必要があるかもしれません(アプリケーションと周辺回路構成による)。
稼働時間を延ばすには、兎に角、消費電流を削っていくしかありません。以下の様な方法が考えられます。
あ、アト、他力本願ですが、「大容量のバッテリを使う」と言う手もありますね(1^^;)っ。
前回自作したSDカードI/Fを使って、microSDカードとのデータ転送(XMODEM)やリスト表示、ディレクトリの作成、削除など、基本操作ができるようにして見ました。バッテリ駆動の独立動作まで行かなくても、ACアダプタでも何でも、電源さえ供給しておけば、ホストPCが無い所でデータを記録できることに利点を見いだせる用途はあるはずです。
「#6-8 ATmegaのEEPROMを使ってみる」にて、SDカードの差し替えが可能な様に、【mount】/【umount】コマンドを実装したのに伴い、本ページからリンクしているプログラム(portbl_logger.ino)にも、【mount】/【umount】コマンドを追加しました。
本ページからダウンロードできるプログラム(portbl_logger.ino)も、新バージョンに差し替えてあります。ただし、本文中の解説やコードは旧バージョンのままとなっていることにご注意ください。
後日、「#7-4 USB電圧・電流計で電流を測定する」の回で、入手したUSB電圧・電流計を使い、ポータブル気温・湿度ロガの消費電流値を測定しました。
何と!本ページの見積もり15mAは大嘘で、70mAも流していることが判明しました。「稼働時間の推定」節で計算した、モバイルバッテリの電流時間積約821mAh@5Vから推定する稼働時間は、821mAh/70mA≒11.7hであり、実際の稼働時間約15hと比べて、オーダが合ってきます。
見積もりが、甘々でしたm(1__)m。