
M5Stack Din Meterを使って、ラジエーターのファンやポンプのスピードを制御するデバイスを作りました。うちではPCの外部にラジエーターを設置しているため、PCのマザーボードから制御することができません。そのためPCとは単独で動作するコントローラーが必要でした。実は3年近く前にAtomS3で作っていて、今回はこの改良版になります。
Din Meterを選んだ理由

Din Meterはディスプレイにロータリーエンコーダーが付いていて、ノブがボタンになっています。メニューを選択したり値を指定するような操作にとても適しています。もう一つ便利なのが、電源がUSBだけでなく、入力電圧6-36Vにも対応している点です。内部にDC-DCコンバーターを内蔵しており、Groveポートの5Vも内部で生成してくれます。今回使用するケースではファン用の12Vの電源を与えるだけで済むのがメリットです。
主な機能
Din Meterの特徴を生かして4つのメニューを作りました。
1. モード選択
2. ファンのスピード
3. ポンプのスピード
4. 情報

ロータリーエンコーダーでメニューを選択してボタンを押すことで、その値を変更できるようになっています。ModeについてはAuto/Manualのトグル動作、情報は表示のみです。
接続方法
Din Meterには2ポートのGroveポートがあり、合計で4つのGPIO入出力が可能です。今回は以下のように接続しました。
Port-A (13) サーミスタの値取得
Port-A (15) ポンプのスピード(PWM出力)
Port-B (2) ファンの回転数取得
Port-B (1) ファンのスピード(PWM出力)

サーミスタの値取得
サーミスタは以下のような配線で繋がっています。
flowchart LR GND --- 抵抗4.7K --- GPIO13 --- サーミスタ10K --- 5V
NTCサーミスタは温度が下がると抵抗値が高くなり、温度が上がると抵抗値が低くなる特徴があります。実は当初は以下のような配線にしていました。
flowchart LR GND --- サーミスタ10K --- GPIO13 --- 抵抗10K --- 5V
ところが表示される水温が19℃よりも下がらない謎の現象が起こりました。外の気温が0℃で実際の水温は10℃くらいなのに、表示の温度は下がらなくなってしまうのです。水冷PCとして使うぶんには特に問題はないのですが、気味が悪いので原因を追究することにします。
この回路は5Vを抵抗で分圧して測定していますが、温度が下がってサーミスタの抵抗値が上がったことで、GPIOに3.3V以上の電圧がかかってしまいました。3.3V以上の電圧は測定できないため、上限値になってしまったということです。この対策として抵抗の位置を入れ替えました。
PWM出力
ポンプとファンのPWMはGPIOから直接出力しています。本当はTTLレベルで与えないといけないのですが、3.3Vを出力しても動くのでOKです。
回転数の取得
ファンの回転数はGPIO 2をプルアップして、ファンと接続しています。ファンが回転するとパルスが出るので、それを割り込みを使ってカウントする仕組みです。
// ファンの回転数をカウントする
volatile uint32_t pulseCount = 0;
volatile uint32_t lastPulseTime = 0;
void IRAM_ATTR tachISR() {
uint32_t now = micros();
if (now - lastPulseTime > 500) {
pulseCount++;
lastPulseTime = now;
}
}
// FAN 回転数取得の設定
pinMode(GPIO_FANRPM_PIN, INPUT_PULLUP); // FAN Sense Pin
attachInterrupt(digitalPinToInterrupt(GPIO_FANRPM_PIN), tachISR, FALLING);ちなみに2パルスで1回転分らしいので、検出回数は2で割る必要があります。そしていざ回転数を計測してみると…、ちゃんと計測できるときもあれば、なぜか回転数が 20000rpm とか異常な値が出ることもあります。なんか波形がおかしいのかな??

それっぽい波形が出てますね。36Hzだから (36/2) * 60 = 1080rpmで妥当なもんです。ノイズ対策とかいろいろ試したものの大きな効果はなく、これはこのまま放置することにしました。ただの情報表示で制御には影響しませんからね。
Webインターフェース
本デバイスは屋外に設置することを想定しているので、室内からコントロールできるようにする必要があります。内蔵のWebサーバーにアクセスすることで、現在のステータスやモードの切り替え、設定値の変更ができるようになっています。ページデザインもPC・スマホ両対応にしました。このへんはAIに丸投げです。便利な世の中になったなぁ~。


URLは http://gamingfan.local/conf です。
const char* MDNS_NAME = "gamingfan"; // mDNSに登録するホスト名URLを変更したい場合はここを編集してみてください。もしホスト名でアクセスできないときは、IPアドレスでもアクセスできます、LCDの右下のInfo欄に表示されている数字がIPアドレスの4つ目なので、ネットワークが 192.168.10.0/24 なら192.168.10.205 のようになります。
モード切り替え
ファンの制御にはマニュアルモードとオートモードがあります。マニュアルモードは指定したスピードで回します。オートモードは水温に応じてスピードを変えるもので、通常はオートモードを使います。
ポンプは固定
ポンプのスピード(水流の速さ)はオートモードでも固定です。水流は速ければいいというものではなく、冷え切らないままPCに戻ってしまったら意味がありません。普段は30%くらいで動かすようにしています。
電源投入時はフルスピード
電源投入してからWiFi接続が完了するまでの20秒間は、動作確認や、低速スタートで止まってしまうことを避けるため、ファンとポンプを強制100%にしています。
プログラム
今回作成したプログラムは GitHub にアップしました。
旧バージョンでは仮想EEPROM(?)に保存していましたが、今回はFatFSに保存するようにしています。そのためArduino IDEの設定でPartition Schemaを “Default 4MB with ffat (1.2MB APP/1.5MB FATFS)” にします。
編集が必要な箇所は以下の通りです。M5ATOMS3_5V0は12V入力時のGroveポートの5Vピンの実測値を入力します。これが違うと温度が正しく取得できません。
// 設定 WiFi
const char* WIFI_SSID = "****";
const char* WIFI_PASS = "****";
#define M5ATOMS3_5V0 5.50 // 12V入力時のGroveポート電圧実測値以下は必要に応じて変更できます。
#define EMARGENCY_TEMP 50 // 強制的にファンをフル回転にする温度
#define TEMP_HISTERESIS 0.8 // 温度判定にヒステリシスを持たせる範囲
#define START_PUMP_TIME 20 // 電源投入後、ポンプをフル回転させる時間
#define START_PUMP_SPEED 100 // 電源投入後、ポンプをフル回転させるスピード
その他ファンのスピードやポンプのスピードはWebの設定画面で変更するので、プログラムはそのままでかまいません。
ケースの製作
ケースは3Dプリンターで作成しました。STLファイルはプログラムと同じところにアップしています。


Din Meterはケースに適当に穴を開けて嵌め込むだけでそれっぽくなるので便利ですね。中にはケーブルや基板を雑に収納するエリアを設けました。12Vの電源入力のためにDCジャックを取り付け、Din Meterへと供給します。

長くてかさばるケーブルをケースの中にしまい込んだらフタをします。

完成!
これで水温で自動制御するファンコントローラーができました!