この記事では、前回のM5StickCと冷却ファンを使った回転速度制御のおまけとして、冷却ファンの回転数を取得する方法について紹介します。
前回のM5StickCで冷却ファンを使った回転速度制御の方法については、次の記事で紹介しています。 本記事を読まれる前に確認してみてください!
この記事では、M5StickCと冷却ファンを使って回転速度制御をしていきます。 M5StickCから冷却ファンの回転を制御できれば、扇風機のように、自由に風量を変えることができます! 今回の冷却ファンは次のものを使います。パソコン用[…]
今回の冷却ファンは次のものを使います。 パソコン用の120㎜冷却ファンでLED搭載なので光らせることができます。 LEDを光らせる方法については次回の記事で掲載予定です。
Cooler Master MasterFan MF120 Halo
前回、冷却ファンの回転制御で使用した電子回路を使って、ファンの回転数を取得するための回路を追加します。
冷却ファンの回転数を取得するには?
今回使っているパソコンの冷却ファンなどでは、写真のような4ピンのコネクタがついています。
コネクタ部は以下のような仕様になっています。

今回は、回転センサーのコネクタピンから冷却ファンが回転した際に発生するパルス信号を取得し、パルス信号の周期から回転数を計算するという方法を考えてみます。
パルスセンサーの仕組みとは?
パルスセンサーは,ファン1回転につき,2周期の矩形波(パルス波形)を出力するセンサーで,回転速度を検出するのに,最適なセンサーです。
出力される波形は、次のようなイメージです。
1回転で2周期ということは、波が2回来るということなので、波が下がるタイミングから次の波が下がるタイミングまでが1周期ということになります。
今回は、パルスセンサーの信号をM5StickCのGPIOで受信し、波が高い状態(HIGH)から低い状態(LOW)に下がるタイミングで外部割込みを発生させ、Intervalを求める処理を実行します。
外部割込みには、attachInterruptというArduinoの機能を使います。
関数 | |
attachInterrupt( interrupt, function, mode) |
外部割込みを発生させます。 |
modeで指定する値は、次のとおりで、今回はFALLINGを使います。
LOW :ピンがLOWのとき発生
CHANGE: ピンの状態が変化したときに発生
RISING :ピンの状態がLOWからHIGHに変わったときに発生
FALLING :ピンの状態がHIGHからLOWに変わったときに発生
これでプログラムから回転パルスを読み取る仕組みができました。
回路の「浮き」を解消するプルアップ抵抗とは?
回転パルスセンサーのコネクタピンは、「オープンコレクト」になっていて、次の図のようにM5StickCと直接つなぐだけではセンサーが1を出力しても1の電位になりません。
電源がつながっていない(浮いた状態である)からです。
こういった場合は、プルアップをする必要があります。
今回の冷却ファンの回転センサーにはだいたい5V10mAの電流が流れるようにしたいため、プルアップをする際には次の図のように5V電源とセンサーの間に抵抗を入れて調節します。
これを「プルアップ抵抗」といいます。
今回は5Vの電源を追加して、1kΩの抵抗を入れました。
(計算上は0.5Ωでよいかと思いましたが手元にあるもので代用しました。)
また、M5StickCの電源も同じ5Vの電源からM5StickCの5V入力ピンに入れるようにしました。
これでパソコンに接続することなく冷却ファンの回転速度制御と回転数の測定ができます。
実際の回路はこうなる!
実際にブレッドボードに配線をする際には次の図のようなイメージになります。
前回、冷却ファンの回転速度制御で使用したものに以下の部品を追加しています。
抵抗 | 1KΩの抵抗(1つ) |
レッドボード上の5VとM5StickCの5V入力の結線 | ジャンパ線(1本) |
ファンコネクターの回転センサーとM5StickCの接続 |
ジャンパ線(1本) |

ブレッドボード |
5V電源作成用に1枚(追加) |
DC電源アダプター |
5V1.5Aのセンタープラス 外径5.5㎜、内径2.1㎜のもの |
ブレッドボード用DCジャック |
ブレッドボード用DCジャックDIP化キット(完成版) |
ブレッドボード①への5V電源接続用 |
ジャンパ線(2本) |
今回追加した部品(ジャンパ線をのぞく)
抵抗

・カーボン抵抗(炭素皮膜抵抗)
1W1kΩ (100本入) CFS100J1KB
・カーボン抵抗(炭素皮膜抵抗)
1/2W1kΩ (100本入) CFS50J1KB
秋月電子さんの通販サイトURLはこちらです。
ブレッドボード
コスパ最強のブレッドボード。両端に「+」と「ー」のラインがあります。よく3枚で〇〇〇円というのはありますが、1枚から買えて価格も抑えてあるのでよいと思います。価格も良心的です。Amazonで確認
電源アダプター
5V1.5A出力の電源アダプターです。PSEマーク認証がとられているものを選定しています。この商品はセンタープラスの電源アダプタです。
外径5.5㎜、内径2.1㎜のアダプター付きのものです。
Amazonで確認
ブレッドボード用DCジャックDIP化キット(完成版)

型番:AE-DC-POWER-JACK-DIP
秋月電子さんの通販サイトURLはこちらです。
パルスセンサーを使ってM5StickCで回転数を計算する
それでは回転パルスセンサーの信号を使用してM5StickC上で冷却ファンの回転数を計算してみましょう。
計算するだけでは、おもしろくないのでまたM5StickCのディスプレイ上に表示してみます。
今回は、後での使いまわしを考慮して、ファンの回転パルスセンサーから周期を取得するための関数Fan_Rotate_Sence()を作っています。
また、回転速度を変えるために、PWMの設定を次の通りとしています。
- 起動時は、デューティ比は0%に設定
- M5StickCのディスプレイ横にあるボタンを押すとデューティ比が
0%→25%→50%→75%→100%という形で変化 - 周波数は25KHz、分解能は8ビット
今回使う冷却ファンの製品仕様を見ると回転速度は、650-1800 rpm ± 10%なので、デューティ比と回転数の関係は次の表のようになると想定できます。
デューティ比(%) | 回転数(rpm) |
0% | 650rpm |
25% | 937rpm |
50% |
1225rpm |
75% | 1512rpm |
100% | 1800rpm |
M5StickCの画面にデューティ比(%)と回転数(rpm)をディスプレイ上に表示しますので、実際の値を後で確認しますね!
冷却ファン回転速度制御プログラム
Arduino IDEを起動して、「ファイル」メニューから「新規ファイル」を選択し、表示されるスケッチに以下のように記述します。
Arduino IDE スケッチ例
//-------------------------------------------------------------------------------- | |
// M5StickC 冷却ファンPWM制御 テストプログラム | |
// M5StickC Cooling fan PWM control test program. | |
// | |
// ボタン制御 | |
// Btn1:G37 →押すとデューティ比を0%→25%→50%→75%→100% | |
// 表示制御 | |
// ファンに送信しているPWMのデューティ比に応じてボリューム表示する | |
// テキストでデューティ比をディスプレイに表示する | |
// ファンの回転数(rpm)をディスプレイに表示する | |
// | |
//-------------------------------------------------------------------------------- | |
// ------------------------------------------------------------ | |
// ライブラリインクルード部 Library include section. | |
// ------------------------------------------------------------ | |
#include <M5StickC.h> // M5StickC 用ライブラリ | |
const uint8_t btn1 = 37; // 物理ボタン1(G37)の定義 | |
const uint8_t FAN_PWM = 26; // ファン回転数制御用PWM制御 PWM control for fan speed control. | |
const uint8_t FAN_SENSOR = 36; // ファン回転数計算用GPOの定義 | |
int btn1_cur_value = 0; // 物理ボタン1のステータス格納 | |
int btn1_last_value = 0; // 物理ボタン1の前回ステータス格納 | |
int display_rotation = 0; // 画面向きの初期化 | |
String duty_str = ""; // デューティ比の表示用テキスト格納 | |
// PWM制御用の定数 Constants for PWM control. | |
const uint8_t CH0 = 0; // PWM送信チャネル PWM transmission channel. | |
const double PWM_FREQ = 25000; // PWM周波数 PWM frequency. | |
const uint8_t PWM_BIT = 8; // PWM分解能 PWM resolution. | |
int cur_duty_val = 0; // 現在のデューティ比の格納 | |
// ファン回転数取得用定義 | |
unsigned long lastPulse_T; // 前回の割込み時の時間を格納 | |
unsigned long pulse_Interval=0; // パルスのインターバルを格納 | |
uint16_t rpm; // 1分中の回転数を格納 | |
// ------------------------------------------------------------ | |
// PWM出力用の関数 Function for PWM output. | |
// Send_PWM() | |
// ------------------------------------------------------------ | |
void Send_PWM(int cur_duty_val) { | |
ledcWrite(CH0, cur_duty_val); // 指定されたデューティ比のPWM信号を送信 | |
} | |
// ------------------------------------------------------------ | |
// FAN回転パルス(立下り)検出用の関数 Function for FAN rotation pulse (falling) detection. | |
// Fan_Rotate_Sence() | |
// ------------------------------------------------------------ | |
void Fan_Rotate_Sence() { | |
unsigned long cur = micros(); // 割込み発生時の時間を格納 | |
unsigned long dif = cur - lastPulse_T; // 前回の割込み時間との差分 | |
pulse_Interval = (pulse_Interval - (pulse_Interval >> 2)) + (dif >> 2); // インターバルの計算 | |
lastPulse_T = cur; // 前回の割込み時間の更新 | |
} | |
// ------------------------------------------------------------ | |
// ディスプレイ出力用の関数 Function for Display output. | |
// display_output() | |
// ------------------------------------------------------------ | |
void display_output(int cur_duty_val){ | |
// プログラムタイトル表示部分 | |
M5.Lcd.setTextSize(1); // テキストサイズの指定 | |
M5.Lcd.fillScreen(BLACK); // 画面の塗りつぶし Screen fill. | |
M5.Lcd.setTextColor(WHITE, BLACK); // テキストカラーの設定 | |
M5.Lcd.setCursor(0, 0, 2); // カーソル位置とフォントの設定 | |
M5.Lcd.print("Cooling Fan PWM Ctrl"); // ディスプレイに表示(プログラム名) | |
// デューティ比[0%]の場合の処理 | |
if (cur_duty_val == 0) { | |
// ボリューム表示部分 | |
M5.Lcd.fillRect(5, 60, 3, 10, RED); // ボリュームバー1(0%) | |
duty_str = "00" + String(cur_duty_val); // デューティ比表示用テキスト編集 | |
} | |
// デューティ比[25%]の場合の処理 | |
else if (cur_duty_val == 25){ | |
// ボリューム表示部分 | |
M5.Lcd.fillRect(5, 60, 3, 10, RED); // ボリュームバー1(0%) | |
M5.Lcd.fillRect(12, 50, 3, 20, RED); // ボリュームバー2(25%) | |
duty_str = "0" + String(cur_duty_val); // デューティ比表示用テキスト編集 | |
} | |
// デューティ比[50%]の場合の処理 | |
else if (cur_duty_val == 50){ | |
// ボリューム表示部分 | |
M5.Lcd.fillRect(5, 60, 3, 10, RED); // ボリュームバー1(0%) | |
M5.Lcd.fillRect(12, 50, 3, 20, RED); // ボリュームバー2(25%) | |
M5.Lcd.fillRect(18, 40, 3, 30, RED); // ボリュームバー3(50%) | |
duty_str = "0" + String(cur_duty_val); // デューティ比表示用テキスト編集 | |
} | |
// デューティ比[75%]の場合の処理 | |
else if (cur_duty_val == 75){ | |
// ボリューム表示部分 | |
M5.Lcd.fillRect(5, 60, 3, 10, RED); // ボリュームバー1(0%) | |
M5.Lcd.fillRect(12, 50, 3, 20, RED); // ボリュームバー2(25%) | |
M5.Lcd.fillRect(18, 40, 3, 30, RED); // ボリュームバー3(50%) | |
M5.Lcd.fillRect(24, 30, 3, 40, RED); // ボリュームバー4(75%) | |
duty_str = "0" + String(cur_duty_val); // デューティ比表示用テキスト編集 | |
} | |
// デューティ比[100%]の場合の処理 | |
else if (cur_duty_val == 100){ | |
// ボリューム表示部分 | |
M5.Lcd.fillRect(5, 60, 3, 10, RED); // ボリュームバー1(0%) | |
M5.Lcd.fillRect(12, 50, 3, 20, RED); // ボリュームバー2(25%) | |
M5.Lcd.fillRect(18, 40, 3, 30, RED); // ボリュームバー3(50%) | |
M5.Lcd.fillRect(24, 30, 3, 40, RED); // ボリュームバー4(75%) | |
M5.Lcd.fillRect(30, 20, 3, 50, RED); // ボリュームバー5(100%) | |
duty_str = String(cur_duty_val); // デューティ比表示用テキスト編集 | |
} | |
M5.Lcd.setTextColor(GREEN, BLACK); // テキストカラーの指定 | |
M5.Lcd.setCursor(40, 20, 7); // カーソル位置とフォントカラーの設定 | |
M5.Lcd.print(duty_str); // ディスプレイに表示(デューティ比) | |
M5.Lcd.setCursor(140, 50, 2); // カーソル位置とフォントカラーの設定 | |
M5.Lcd.print("%"); // ディスプレイに表示(プログラム名) | |
} | |
void setup() { | |
// M5StickCの初期化と動作設定 Initialization and operation settings of M5StickC. | |
M5.begin(); // 開始 | |
M5.Lcd.setRotation(1); // 画面の向きを変更(右横向き)Change screen orientation (left landscape orientation). | |
M5.Axp.ScreenBreath(12); // 液晶バックライト電圧設定 LCD backlight voltage setting. | |
M5.Lcd.fillScreen(BLACK); // 画面の塗りつぶし Screen fill. | |
M5.Lcd.setCursor(40, 0, 1); // カーソル位置とフォントカラーの設定 | |
// シリアルコンソールの開始 Start serial console. | |
Serial.begin(115200); // シリアルコンソール開始 | |
delay(500); // 処理待ち | |
// 出力GPIOの設定 | |
pinMode(FAN_PWM, OUTPUT); // PWM出力用ピンG26の設定 | |
// 入力GPIOの設定 | |
pinMode(FAN_SENSOR, INPUT); // ファン回転数計算のための信号用ピンG0の設定 | |
// PWM出力設定・制御 | |
ledcSetup(CH0, PWM_FREQ, PWM_BIT); // PWMのチャネル設定 PWM Chanel set | |
ledcAttachPin(FAN_PWM, CH0); // GPIOとチャネルの紐づけ Linking GPIO and channel. | |
Send_PWM(cur_duty_val); // PWM信号の送信 | |
// FAN回転パルス取得関連の初期化と設定 | |
lastPulse_T = 0; // 前回割込み時の時間を初期化 | |
pulse_Interval = 0; // パルスのインターバルを初期化 | |
attachInterrupt(FAN_SENSOR, Fan_Rotate_Sence, FALLING); // FAN_SENSOR用GPIO(G36)が立ち下がった(FALLING)ときに関数を実行 | |
// ディスプレイ表示 | |
display_output(cur_duty_val); // デューティ比に応じたディスプレイ表示 | |
} | |
void loop() { | |
// M5StickC のボタンが押された際のステータスを格納 | |
btn1_cur_value = digitalRead(btn1); // read the value of BUTTON | |
// ボタン1が押された場合の処理 | |
if(btn1_cur_value != btn1_last_value){ | |
if(btn1_cur_value==0){ | |
// Duty比の変更 | |
if (cur_duty_val==100){cur_duty_val=0;} // デューティ比は0~100まで25刻みで変化させる | |
else {cur_duty_val = cur_duty_val + 25;} | |
display_output(cur_duty_val); // デューティ比に応じたディスプレイ表示 | |
Send_PWM(256 * cur_duty_val / 100); // PWM信号の出力 | |
} | |
else { | |
} | |
btn1_last_value = btn1_cur_value; | |
} | |
if (pulse_Interval != 0) { // インターバルが0以外の時 | |
rpm = 60000000 / (pulse_Interval * 2); // 1分あたりの回転数(RPM)を求める | |
M5.Lcd.setCursor(100, 70, 1); // カーソル位置とフォントカラーの設定 | |
M5.Lcd.print(String(rpm) + "rpm"); // ディスプレイに表示(FAN回転数) | |
Serial.print("Duty ratio : "); | |
Serial.print(cur_duty_val); | |
Serial.print("% RPM : "); | |
Serial.print(rpm); | |
Serial.println("rpm"); | |
} | |
else { // インターバルが0の時(0除算の回避) | |
M5.Lcd.setCursor(100, 70, 1); // カーソル位置とフォントカラーの設定 | |
M5.Lcd.print("0rpm"); // ディスプレイに表示(FAN回転数) | |
} | |
} |
M5Stack/M5StickCへの書き込み
- 「ファイル」メニューから「名前を付けて保存」で任意の名前を付けて保存します。
- 「ツール」メニューから「ボード」情報を確認し、M5StickCであるか確認します。
この際、「シリアルポート」にマイコンを接続したCOMポートが指定されているかも確認します。 - 「ツール」メニューから「シリアルモニタ」を選択してシリアルモニタを起動します。
- 「スケッチ」メニューから「マイコンボードに書き込む」を選択します。
プログラム実行結果
M5StickCのディスプレイのデューティ比の下にファンの回転数(rpm)が表示されれば成功です。
実際にボタンをおしてDuty比を変えるとファンの回転数も変化します。
事前に想定したデューティ比と回転数の組み合わせとだいたい同じ結果が得られました!
これで冷却ファンの回転速度をM5StickCを使って制御できました。
今回の記事は以上になります。
次回は、冷却ファンのLEDを光らせてみます。単色、複数色、アニメーションなど行ってみたいと思います!お楽しみに!
Cooler Master MasterFan MF120 Halo
これからはじめる方にお勧めの参考図書はこちら!