今回はESP32(arduino)で4ピンファンの回転数検知、制御を行う方法を紹介します。
4ピンファンとは
一番簡単なファンであれば+と-をつなげれば回りますが、騒音と冷却性能のバランスでダイナミックに回転数を制御したい場合に使われるのが4ピン端子のファンです。現状、PCのCPUの放熱などに使われるファンは4ピン端子のものが主流です。
自作PC用のCPUクーラーは冷却フィン+電動ファンのセットでも1000円程度から購入が可能で、冷却性能も高いのでDIYの冷却用部品として使う場合も有能です。
今回はこの4ピンファンをESP32マイコン(Arduino)から制御する方法を紹介します。
4ピンファンのピンアサイン
1番目からGND、電源、回転数のパルス出力、回転数のパルス入力の順になっています。
PCパーツとして購入したものであれば電源は12Vです。これよりも低い電圧でも動きますが、電圧と回転数/動作の可否はファンにより異なります。
回転数検知のピンはオープンコレクタ出力で、ファン1回転ごとに2周期のパルス(ハイインピーダンス/GNDへのショート)が出力されます。マイコンのGPIO入力をプルアップしておき、パルスの立ち上がり(もしくは立下りないしはその両方)をカウントすれば回転数を読み取ることができます。
回転数設定のピンは25kHzの矩形波を入力します。回転数は矩形波のDuty比で決まります。このピンはファン側でプルアップされているようです。
4番ピンをGNDに接続すればそのファンの最低回転数で回ります。(Duty=0%)
今回の検証で使用したマイコンとファン(参考)
Amazonで購入できる最安クラスのファンです。CPU用のファンであれば数十W程度の発熱は余裕でこなせる能力があります。秋葉原などではCPUの付属品がジャンクとしてもっと安く売られていることもあります。
例1:回転数の検知
先に述べたように、3番ピンから1回転につき2パルス出力されますので
- 指定パルスの吐き出しに何秒かかったか
- 指定秒数の間に何パルス吐き出されたか
上記のどちらかのアルゴリズムを組めばOKですが、今回は後者の”指定秒数内の間に何パルス吐き出されたか”という方法でやってみました。パルスの検出はピン入力割込みを使用し、秒数のカウントはdelay関数を使用しました。厳密に回転数を測定したい場合には考えることがたくさんありますが、大雑把な測定であればこれで十分でしょう。
回路図
ファンの3番ピンをESP32のGPIO2に接続しているだけです。GPIO2はソフトウェアで内部プルアップして使います。
Arduinoスケッチ
GPIO2番ピンの立下りを検知してintr()関数を割り込み発生させて変数Numをカウントアップしています。
変数Numをリセットしたとdelayで1000ミリ秒(=1秒)待機してから値を読み出します。1秒当たりのカウント数に30をかければ1分あたりの回転数になります。
int INPUT_PIN = 2; volatile int Num; void setup() { Serial.begin(9600); pinMode(INPUT_PIN, INPUT_PULLUP); attachInterrupt(INPUT_PIN, intr, FALLING); } void loop() { Num = 0; delay(1000); int RPM = Num * 30; Serial.println(RPM); } void intr(){ Num++; }
例2:回転数の設定
ファンの4番ピンに25kHzのパルスを入力します。
ledcWrite関数を使用します。25kHz、分解能8bit(0~255)として設定しました。ESP32では10bitや12bitなどもっと細かく設定もできますが今回のようなファン制御ではあまり意味がない気がします。
回路図
GPIO4番ピンにファンの4番ピンを接続しているだけですね。
Arduinoスケッチ
PWM制御用の関数ledcを使いました。dutyは100としてあります。最大255なのでdutyは40%ぐらいですね。
int OUTPUT_PIN = 4; void setup() { ledcSetup(0, 25000, 8); ledcAttachPin(OUTPUT_PIN, 0); } void loop() { ledcWrite(0,100); }
例3:回転数の検知と設定
例1と例2を組み合わせた例です。dutyを変えながら回転数を検出してシリアルに出力しています。
回路図
Arduinoスケッチ
特に捻りはありません。5秒ごとにdutyをカウントアップしながら回転数RPMを測定してシリアルに出力しています。
int OUTPUT_PIN = 4; int INPUT_PIN = 2; volatile int Num; void setup() { Serial.begin(9600); pinMode(INPUT_PIN, INPUT_PULLUP); attachInterrupt(INPUT_PIN, intr, FALLING); ledcSetup(0, 25000, 8); ledcAttachPin(OUTPUT_PIN, 0); } void loop() { for (int i = 0; i < 256; i++) { ledcWrite(0, i); delay(1000); Num = 0; delay(5000); int RPM = Num * 30 / 5; Serial.print(i); Serial.print(","); Serial.println(RPM); } } void intr() { Num++; }
dutyの設定と回転数について
上記スケッチと回路で出力した結果をグラフにしてみました。
回転数は1100~2400RPMでした。少し高めですが概ねカタログスペック通りです。
また、このファンの場合、dutyの設定値として意味があるのは80~170の間ぐらいでした。それよりも外側では最大/最低回転数で制限されていることがわかります。この辺りの挙動がファンによって全く異なるのかこんなもんなのかはわかりませんが、使う前に確認はしておきたいところですね。
また、duty100%としたときには最大回転数ではなく、それよりもすこし遅い速度で回っているのも面白いポイントです。
まとめ
普段からマイコンを使っていればごく簡単な制御ですね。気を付けたいのはdutyを0%にしても回転数は0にならないということです。最低回転数はファンによりますが、1RPMなど極端に遅い速度でファンを回転させるのは構造上難しいですからね。
ですから、完全にファンをとめる制御まで行いたい場合には電源そのものをトランジスタなどでON/OFFする必要があります。マイコンで電源ラインを操作する方法については以下の過去の記事をご参照ください。
コメント