最終更新日: 2012年1月13日

賢い扇風機を作る

さて何を作ろうか…Arduinoで楽しんでいて意外にもこれで悩んでしまします。
簡単に思いつくのが温度センサーを利用した何か。ということで、まぁ定番かもしれないけど、FANコントローラーを作成。
職場の机に扇風機を設置している人も結構いるかと思うけど、自分も12Vのファンを置いてます。これを温度で制御することにしよう。たかがファンの回転数制御でマイコン制御にする必要も無いだろ…と思うけど、目的じゃない。手段を楽しめればいいのです。

動作仕様

温度センサは秋月で売ってたLM35Dを使うことにしました。5V単独電源で、温度に応じてリニアなアナログ電圧が出力されるのでそのままArduinoのANALOG IN端子に接続すればOKです。
出力は、PWM出力をCRのフィルタで平滑し、MOS FETでファンに流れる電流を制御します。

回転数を人間が制御できるよう、ボタンを2個用意し、それぞれ回転数UP,DOWNに割り当てます。回転数が変更さrたら、その時の温度と制御値(PWM出力の値)を記録するようにします。その記録はとりあえず3点の温度を記録するようにします。例えば現在、15度、20度、25度の温度での回転数を記録していたとします。現在の温度が16度にて回転数が変更された場合、16度という温度は今まで記録している温度の中で 15度が最も近いので、15度での回転数を消去、16度での回転数を記録します。あとは、記録している3点の温度と回転数と現在の温度から、制御すべき回転数を算出して制御します。例えば温度が17度になったら、20度の回転数と16度の回転数からリニアに補完して回転数を求めます。

記録したデータはEEPROMに保存するようにします。ただし変更されたら即座にEEPROMに保存するのではなく、変更された後、変更されない時間がある程度経過してから書き込むようにします。EEPROMの書き換えには限度があるので、なるべく書き換え回数を減らすようにします。まぁ100000回保証ですからそんなことしなくても充分だとは思うけど、精神衛生上。

さらに、起動直後等「とにかく暑い!」という時のために「ターボモード」を装備します。これはボタンを2個同時に押す事でターボモード起動となり、回転数は最大になります。ターボモードは一定時間続き、その後通常モードとなります。ターボモード中に何かボタンを押すとターボモードを終了します。

そして、記録データをイニシャライズする機能も必要です。これは2個のボタンを長時間(10秒くらい)押したままにすることで機能します。現在の温度と回転数でイニシャライズすることにより、もし今までに極端に高い、または低い温度で記録したデータがあれば、それを消去できます。

そしてまたさらに… EEPROMには4個のバンクを設定できるようにしました。例えば「今記録しているデータよりも少し高速回転させたい」というような場合のために、温度と回転数の関連を4パターンまで独立に記録できるようにしました。

 

ハードウエア

ハードは至ってシンプルです。
まず温度センサーは電源を接続し、その出力をATMega168のアナログ入力に接続しただけです。
回転数出力は、PWM出力をCRフィルタで平滑、さらに分解能を上げるため抵抗で分圧し、FETのGateに接続しています。ファンは12Vのものを使用しています。電源も12V、秋月や千石等で売ってる12VのACアダプターから供給するようにしています。
あとはプッシュスイッチ、バンク切り替えスイッチを、単純にATMega168の端子に接続しただけです。

ソフトウエア

タイマー関連の変更

ファンを制御する電流はPWMで制御されているわけですが、特に低速においてファンからPWM周波数に起因すると思われる音が聞こえてしまいます。そこでPWM周波数を上げる事にしました。しかしそのためにはArduino標準でPWMがどのように設定されているのか…確認したところ、以下の部分のようです。

wireing.c : init()
	// on the ATmega168, timer 0 is also used for fast hardware pwm
	// (using phase-correct PWM would mean that timer 0 overflowed half as often
	// resulting in different millis() behavior on the ATmega8 and ATmega168)
#if !defined(__AVR_ATmega8__)
	sbi(TCCR0A, WGM01);
	sbi(TCCR0A, WGM00);
#endif  
	// set timer 0 prescale factor to 64
#if defined(__AVR_ATmega8__)
	sbi(TCCR0, CS01);
	sbi(TCCR0, CS00);
#else
	sbi(TCCR0B, CS01);
	sbi(TCCR0B, CS00);
#endif

ATMega168のマニュアルを見るとPWMにはFastモードとPhase collectモードの2種類があるようですが、ArduinoではFastモードを使い、さらにタイマー入力のプリスケールとして1/64が設定されているということです。ということで、プリスケールを1/8に変更することにしました。具体的にはTCCR0のCS00をゼロにします。スケッチ上のsetup()にて以下のようにしました。

My Sketch
void setup() 
{ 
  中略
  // set timer 0 prescale factor to 8
  sbi(TCCR0B, CS01);
  cbi(TCCR0B, CS00);

これによってdelay()関数の実時間も変わるので、それなりにパラメーターを変更する必要があります。(※)

その他変更

使用した温度センサー、LM35Dは10mV/℃という出力特性です。つまり100度で1V。標準ではArduinoのA/Dコンバーターは5Vがフルスケールなのでかなり無駄です。ちょうどATMega168には基準電圧を1.1Vに変更するモードがあったのでこれを利用することにしました。制御レジスタはどれだろ…と調べたら、なんてことはない、単に、
analogReference(INTERNAL);
これだけでした。いやぁ、Arduinoってほんと簡単です。


(※)ここまではArduinoにあまり詳しくない頃に書いたのですが、delay()関数等はTimer0が使われ、そして今回使ったD6端子のPWM出力もTimer0を使うからであって、他のTimer1,2を使うPWM出力端子を使えばdelay()等の実行に影響を与えることなくPWM出力の周波数を変えることが可能ですね。

実装

もちろんまずはブレッドボードで動作確認。

レミゼのピンは意味ありません(笑)。
まぁ、それほど複雑な回路じゃないので、そのまま万能基板にマウントして配線。

(この写真では、まだバンク切り替えスイッチをマウントしてません)
そして実際に使ってみると、なかなか面白いです。こりゃ作って正解。
職場では結構室温の変化があるのですが、何度か調整しているうちにいい感じに覚えてくれて、いい感じに調整してくれます。
当初、おバカネタとして作ろうとしていたのですが、結構便利で満足しました。



home | Elec top

inserted by FC2 system