google-site-verification: google3bd66dd162ef54c7.html
FC2ブログ

Arduinoを使ったアクアリウム照明コントローラー(ソフト解説編)

 連載しているアクアリウム照明作りの話はこれがたぶん最終回。今回はソフト解説編です。

▼ミニ水草水槽(ポットアクアリウム)
ポットアクアリウム
 白に赤色LEDの光を多めに入れた状態です。

 先にお断りしておきますが、このソフトは以前作った物を寄せ集め、そこを出発点にしてあれこれ修正追加して作った物です。そんなことで、同じような機能の関数が複数あったり、グローバル変数が異常に多かったりします。これを公開するのはちょっと恥ずかしいのですが、未来の自分に対する伝言の意味を兼ねて記事にします。

 プログラムは1000行くらいあるので記事中にリストは記載しません。プログラムはこちら→20171029AquaLightCont.txt

 コンパイラの警告を「全て」にすると、EEPROMのライブラリの使い方にワーニングが出ています。「初期値」でコンパイルするとエラーは出ないので致命的なエラーは無いと思います。なお、コンパイル後に出るメモリーサイズなどの情報は下記です(Arduini IDE 1.8.1を使用)。かなりメモリーを使っていますがまだ余裕があると思います(たぶん)。

最大32256バイトのフラッシュメモリのうち、スケッチが18960バイト(58%)を使っています。
最大2048バイトのRAMのうち、グローバル変数が949バイト(46%)を使っていて、ローカル変数で1099バイト使うことができます。


 以下ポイントと思われる点を解説していきます。

◆RTCとの同期
 以前作ったソーラータイマースイッチではCPUを深いスリープに入れ、ピン割り込み(int0)で復旧させることでプログラムをタイマーに同期させていました。こうやれば省エネになるのですが、残念なことにPWMが止まってしまうのでLEDを調光することが出来ません。これではダメなので、ピンの状態をポーリングで検出する方式に変更しました。waitPin2Low()がその関数です。

◆明るさの制御
 一日の秒の値で各種動作タイミングを決定しています。なお秒の値は0時0分0秒から始まる連番です。値の最大は86339(24*3600-1)なので int(16ビット)の範囲を超えるのでlongで表現しています。

◆日の出、日の入り時刻の計算
 calcT1T2()関数で行っています。この関数については、以前の記事で詳しく解説していますが、日付と経緯度からその地点の日の出/日の入り時刻を計算するプログラムです。なお、東京の経緯度を使って計算しているので、これを変更したい場合は、float Longitude = 139.7414; float Latitude = 35.6581; の部分を修正します。
 まあそこまでやらなくても、日の出・日の入り時刻のオフセット値をボタン操作で設定出来るので、そちらを使った方が簡単だと思います。

◆照明明るさの設定プログラム
 ここがこのソフトの中心になる部分です。いろいろ方法を考えたのですが、照明の明るさ、変化速度、タイミングなどを柔軟に定義したかったので、関数の形で定義することにしました。そんなことで、ここを理解するにはArduino というか、C言語の基礎知識が必要です。

 照明プログラムは下記に示す LedContProgram()で定義しています。点灯パターンを修正したい場合はここを変更します。なお、このプログラムは見つけやすいように、プログラムリストの最後に置いてあります。

void LedContProgram(unsigned long x, int e ) {  // 明るさ変化パターン設定プログラム
// if文:イベント開始時刻(累積秒)。RedSetとWhiteSetの引数は下記
// 第一引数:明るさ設定値(0.003から1.0の値を設定)。
// 第二引数:明るさ遷移時間(秒)明るさは等比級数で変化
// 第三引数:実行(Execute)フラグ。ゼロならスロープ計算無し(高速実行される)
const float p = 0.75; // LED電流調整係数(1.0以下の値を入れる)

// 夜明け
if (x == (FixOnTime - 5UL) * 60UL) { // small ON 時刻の5分前
RedSet(0.10, 60, e); // 1分スロープで赤だけ10%点灯(真っ赤な朝焼け)
}
if (x == FixOnTime * 60UL ) { // small ON 時刻
RedSet(0.003, 300, e); // 5分スロープで赤消灯
WhiteSet(0.07, 60, e); // 1分スロープで白7%(夜明け前)
}

// 日の出から日中まで(3時間かけて増光)
// 日照の変化パターンに似せるため1時間置きに目標値を設定(指数関数で一気に変えてはダメ)
if (x == (mNumT1 + T1offset) * 60UL ) { // 日の出時刻なら
RedSet(0.45 * p, 3600, e); // 1時間スロープで赤45%
WhiteSet(0.45 * p, 3600, e); // 1時間スロープで白45%
}
if (x == (mNumT1 + T1offset + 60) * 60UL ) { // 日の出時刻 +1Hrなら
RedSet(0.83 * p, 3600, e); // 1時間スロープで赤83%
WhiteSet(0.83 * p, 3600, e); // 1時間スロープで白83%
}
if (x == (mNumT1 + T1offset + 120) * 60UL ) { // 日の出時刻 +2Hrなら
RedSet(1.0 * p, 3600, e); // 1時間スロープで赤100%点灯
WhiteSet(1.0 * p, 3600, e); // 1時間スロープで白100%点灯
}

// 日中から夕暮れ(3時間かけて減光)日没後はスモールライト点灯
if (x == (mNumT2 + T2offset - 180) * 60UL ) { // 日没時刻 3Hr前なら
RedSet(0.83 * p, 3600, e); // 1時間スロープで赤83%
WhiteSet(0.83 * p, 3600, e); // 1時間スロープで白83%
}
if (x == (mNumT2 + T2offset - 120) * 60UL ) { // 日没時刻 2Hr前なら
RedSet(0.45 * p, 3600, e); // 1時間スロープで赤45%
WhiteSet(0.45 * p, 3600, e); // 1時間スロープで白45%
}
if (x == (mNumT2 + T2offset - 60) * 60UL ) { // 日没時刻 1Hr前なら
RedSet(0.003, 3600, e); // 1時間スロープで赤消灯
WhiteSet(0.07, 3600, e); // 1時間スロープで白だけ7%点灯に移行(夕暮れ)
}

// 消灯前の演出
if (x == FixOffTime * 60UL) { // small OFF 時刻
RedSet(0.10, 300, e); // 5分スロープで赤10%点灯(夕焼け開始)
}
if (x == (FixOffTime + 10UL) * 60UL) { // small OFF 時刻10分後(真っ赤な夕焼け開始)
WhiteSet(0.003, 600, e); // 10分スロープで白消灯し、真っ赤にする(日没20分後)
}
if (x == (FixOffTime + 25UL) * 60UL) { // small OFF 時刻25分後
RedSet(0.003, 300, e); // 5分スロープで赤消灯(夜間)
}
}
 if文がいっぱいありますが、秒の値を見ていて、一致したら必要な処理を行うようになっています。プログラムのメインルーチンは1秒に一回処理を行いますが、その中で毎回この関数に飛んできて必要な設定を行うという仕掛けです。

 ここで呼んでいるWhiteSet() とRedSet()関数でLEDの明るさを決定するパラメーターを修正します。説明はリスト中のコメントに記載した通りですが、新しい明るさとその明るさに達するまでの秒数を指定しています。
 実際のLEDの明るさ(PWM出力の値)はWhiteLedOut()とRedLedOut()の関数で設定しており、ここでは目標値と変化率を反映した値を決めてPWM出力を行うようになっています。

  const float p = 0.75; というのはLEDの明るさを制限するために入れたもので、明るさを75%に制限しています。これは私の使用しているLEDライトの制限で、LEDの温度が上がり過ぎないためにこういう値を入れました。本当は最大(p=1.0)で使いたいところです。もしこのプログラムを使われる方がいらっしゃったら、この値はご自分の環境に合わせる必要があります。

◆液晶画面を使った値の入力プログラム
 このプログラムではキャラクタ液晶の画面とプッシュボタンを使った操作でいろいろなパラメーターの入力を行っています。その機能を実現するためのプログラムもがいろいろありすぎて、統一されていないのがこのプログラムの一番残念なところです。具体的には、lcdInput(), lcdInputSNRN(), lcdInputNNN, setV() とこれらに付随して出てくるlcdDispで始まる関数たちです。
 別の関数になったのは、小数点付きとか符号付き表示にしたいなど、個別の事情があるのですが、うまい吸収方法が見つからなかったたので、同じような内容の関数が乱立してプログラムの行数が多くなってしまったのが一番残念な点です。

◆まとめ
 これでArduinoを使ったアクアリウム照明コントローラー作りの一連の話はおしまい(のはず)です。

 これまでArduinoを使っていろいろな物を作ってきましたが、今回の物はこれまでと少し方向性が違っていて、見ていて綺麗だし、癒し効果もあって面白いです。あと、ここまでの機能を持った水槽用照明用のコントローラーはちょっと世の中に無い気がするので、作って良かったです。

 (今頃になって)アクアリウムライトについて調べてみると、赤、青、白のLEDを使うものが多いようです。確かPWMのピンはまだ余っていたと思うので、三色混合のプログラムを作るのも面白いかも知れません。

Arduinoを使ったアクアリウム照明コントローラー(操作解説編)

 小さな水草水槽用に作った照明コントローラーの話の続きです。前回の機能解説編に続き、今回は操作解説編です。ちなみにこういう小さな水槽は、ポットアクアリウムと呼ぶようで、この呼び方が一番しっくりきます。

 機能については前の記事に書いた通りで、普段は電源を入れっ放しにしておくだけで、特に触る必要はありません。ただ初期設定として、下記の設定が必要です。
 1) 日の出/日の入り時刻のオフセット値
 2) 早朝/夜間のイルミネーション(スモールライト)点灯時刻
 3) 時計合わせ

▼操作スイッチ (これは液晶を外した状態の写真ですが、実際には液晶を付けたままで行います)
操作スイッチ
 基板の手前に並べたスイッチで操作します。左から [Reset] [Dec] [Inc] [Enter] [Manual] です。以下の記事で例えば [Dec] と書いてあれば Dec ボタンという意味です。
 操作の原則は [Dec] と [Inc] で値を増減させ、 [Enter] で値を確定して次の項目へ移動します。

◆通常の表示
▼開始画面
開始メッセージ
 電源投入時にこの画面を約1秒表示します。

▼動作中の表示
通常表示
 通常はこの画面を表示します。
 1行目が現在時刻で、その右はLED出力をパーセント値で表示しています。wは白、赤は赤色LEDの出力です。この画面のw49+r49は白49%、赤49%の出力であることを示しています。なお、実際のLEDの明るさは0-255の数値で設定していますが表示スペースの関係で2桁のパーセント表示にしました。100%はMxと表示します(Max)

 二行目はこの日の、日の出と日の入り時刻です。

◆動作中のスイッチ操作
 動作中にボタンを押すと情報の表示画面へ移ります。ボタンを離すと元の表示に戻ります。

▼ [Dec] 押すと、オフセット値表示
日の出日の入りオフセット付き表示
 現在の設定値が表示されます。このままリセットボタンを押すと値の変更画面に入ります。

▼ [Inc] 押すと、スモールライトの点灯時間を表示
スモールライト点灯、消灯時刻表示
 スモールライトは、早朝や夜間にイルミネーションとして弱く点灯させるもので、この画面から現在の設定時刻を確認出来ます。このままリセットボタンを押すと値の変更画面に入ります。

▼ [Enter] 押すと、年月日表示
年月日表示
 1行目を、年月日 時分表示に変更します。

◆リセットボタンと同時押し
 以下の項目はリセットボタンと同時押しで起動します。操作としては先に指定のボタンを押しておいて、そのままリセットを押して離します。

▼[Reset] + [Dec] でソーラータイマーオフセット値の変更
オフセット設定開始表示
 この開始画面が出た後で [Dec] を離すと下記の画面に変わり、オフセットの入力が可能になります。

日の出時刻オフセット入力画面 日の入り時刻オフセット入力画面
 値は[Inc] [Dec]で行い、[Enter] で値が確定します。ON time の入力が終わればOFF time の入力画面に変わります。入力が終わるとメイン画面に戻ります。Offsetの値は±4.0hrまで設定可能です。なお、オフセット値は0.1hr単位の値(6分単位)で設定するので要注意。

▼ [Reset] + [Inc] でスモールライト点灯時刻設定
スモールライト時刻設定開始画面
 上記の開始画面が表示され、[Inc] を離すと下記の画面に変わります

スモールライト時刻設定
 カーソルが表示されている場所の入力が可能です。[Enter] を押すと順順次カーソルが移動して、最後の入力の確定でメニューを抜けます。
 変な値(例えば昼間にスモール点灯など)を設定した場合は、たぶんその通りの動作をすると思います。普通はスモール ONは一年間で一番夜明けの早い時刻より前(例えば5:00)。スモールのOFFは一番日没が遅い時刻より後に設定します(例えば19:00)。

▼ [Reset] + [Dec] + [Inc]で時刻合わせ
時計セット
 開始画面を表示し、ボタンから手を離せば時刻合わせ画面が出ます。

年月日時分入力
 年月日、時分の順で設定します。分の値を決定([Enter] を押したタイミング)を00秒として時刻合わせが行われます。なお、時計は電源を切っても動き続けています。

◆マニュアルスイッチ
 これはスライドスイッチです。 [Manyual]スイッチをONにすると、LED出力をマニュアルで調整出来ます。LEDの強制点灯や色の具合を確かめたい場合などに使います。
マニュアル設定画面
 白と赤のLEDの出力を0-100のパーセントで指定します。設定した値(明るさ)はリアルタイムで反映されます。
 値の増減は [Inc] [Dec] で行い、項目の変更(赤白の切り替え)は [Enter] で行います。 [Manual] スイッチをOFFにすると通常のプログラム運転状態に戻り、LEDの明るさも(ほぼ)元のプログラムの設定値に戻ります。
 なお、マニュアルで設定した値はEEPROMに記憶していて、次回マニュアルモードにした時は前回の値で開始します。(マニュアルのままリセットした場合は記憶されません)

◆共通事項
・各操作メニューの起動と終了は内部の1秒タイマーのタイミングで行っているので、ボタン操作に対して反応が少し遅れることがあります。

・操作の途中で[Reset]を押して抜けると、設定は無効になり EEPROMへの記録も行われません。

・まっさらなCPUや、他のことに使っていたCPUは、EEPROMに変な値が入っている可能性があります(未使用CPUは0xFFになっています)。プログラムで異常値は修正していますが、予期しない値になっている可能性があります。変な値の場合は手入力で修正して下さい。

・ここに書いてある項目以外の変更はプログラムの修正が必要になります。

・動作開始時に照明プログラムを現在時刻名までシミュレートすることで照明の明るさを設定しています。この処理には少し時間が掛かるため、24時に近づくほどプログラムの開始が遅くなります。マニュアルからの復帰時も同じ現象が起きます。

◆プログラム
 プログラムはこちら→ 20171029AquaLightCont.txt
 ファイルはShift-JISエンコードです。拡張子を.inoに変えればArduino IDEで読めます。このプログラムはArduino UNO(及びその互換機、ATmega328P単独動作)で使うことを想定しています。

 ここにプログラム解説も書こうと思っていたのですが、記事が長くなってしまったので、次の記事に廻すことにしました。
カレンダー
09 | 2017/10 | 11
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31 - - - -
プロフィール

ラジオペンチ

Author:ラジオペンチ
電子工作を中心としたブログです。たまに近所(東京都稲城市)の話題など。60過ぎて視力や器用さの衰えを感じつつ日々挑戦!
コメントを入れる時にメールアドレスの記入は不要です。なお、非公開コメントは受け付けていません。

記事が気に入ったらクリックを!
最新記事
カテゴリ
最新コメント
リンク
FC2カウンター
検索フォーム
月別アーカイブ
RSSリンクの表示
QRコード
QRコード