Raspberry Pi + Ubuntu + .NET Core で GPIO「Part3 PWM ファンコントロール」

使用機材や環境設定などは以前の記事をご参照ください。

ファンの仕様については以下を参照しています。

実験に使用しているファンは自作 PC 用のものです。PWM 対応(4Pin)のものならなんでも OK だと思います。

回転数を読み取る

基本ファン仕様

オープンコレクタで、3番ピンが Sensor です。GND は共有です。

入力回路

回路図

Sensor ピンをプルアップして使います。

  • ここでは 12V (電源電圧)にプルアップしています。
    • 仕様によるとファン内のトランジスタに流せる電流 Ic は 10mA 以下となっているので、プルアップ抵抗は最低でも 1200Ω 必要です。
  • Raspberry Pi 側の 3.3V でプルアップしてもよく、その際は MOSFET を介さず GPIO にそのまま接続できそうです。しかし、ファン側の実装がおかしかった場合には GPIO を破壊されかねないので MOSFET で回路を分けました。
  • GPIO 側は Raspberry Pi の 3.3V 系で構成します。

波形観測

  • 上(黄色):GPIO 端子
    • MOSFET を通しているので信号は反転しますが、パスルを数えるだけなので問題ありません。
    • 綺麗に 0V-3.3V の波形になっています。
  • 下(水色):Sensor 端子
    • ファンが出力している信号を観測しているものです。
    • 綺麗に 0V-12V の波形になっています。

コード実装と結果

コード実装

依存ライブラリは以下のとおり。

パスルのデコード

  • ファンから出力されるパルス信号は 1 回転に 2 つとの事です。
  • 30 倍にすれば RPM にできます。
const int pin = 19;

Console.WriteLine("Pulse scan.");

using var controller = new GpioController();
controller.OpenPin(pin, PinMode.InputPullUp);

using var pulseStream = new Subject<Unit>();
controller.RegisterCallbackForPinValueChangedEvent(
    pin,
    PinEventTypes.Rising,
    (sender, args) => { pulseStream.OnNext(Unit.Default); });

using var subscribe =
    pulseStream.Buffer(TimeSpan.FromSeconds(1))
         .Subscribe(list =>
         {
             Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff]} {list.Count} counts/Sec. {list.Count / 2} RPS. {list.Count * 60 / 2} RPM.");
         });

Console.WriteLine($"Press <Enter> to exit.");
Console.ReadLine();

controller.ClosePin(pin);

Console.WriteLine("exit.");

出力結果

ここで使用したファンは 2800 RPM の製品なので、正しく計測できているでしょう。

[15:55:49.420] 93 counts/Sec. 46 RPS. 2790 RPM.
[15:55:50.421] 93 counts/Sec. 46 RPS. 2790 RPM.
[15:55:51.422] 93 counts/Sec. 46 RPS. 2790 RPM.
[15:55:52.422] 93 counts/Sec. 46 RPS. 2790 RPM.
[15:55:53.423] 93 counts/Sec. 46 RPS. 2790 RPM.
[15:55:54.424] 94 counts/Sec. 47 RPS. 2820 RPM.
[15:55:55.420] 93 counts/Sec. 46 RPS. 2790 RPM.
[15:55:56.421] 92 counts/Sec. 46 RPS. 2760 RPM.
[15:55:57.421] 93 counts/Sec. 46 RPS. 2790 RPM.
[15:55:58.422] 93 counts/Sec. 46 RPS. 2790 RPM.
[15:55:59.422] 93 counts/Sec. 46 RPS. 2790 RPM.
[15:56:00.423] 93 counts/Sec. 46 RPS. 2790 RPM.
[15:56:01.423] 93 counts/Sec. 46 RPS. 2790 RPM.
[15:56:02.424] 93 counts/Sec. 46 RPS. 2790 RPM.
[15:56:03.420] 93 counts/Sec. 46 RPS. 2790 RPM.
[15:56:04.421] 92 counts/Sec. 46 RPS. 2760 RPM.
[15:56:05.421] 93 counts/Sec. 46 RPS. 2790 RPM.
[15:56:06.422] 93 counts/Sec. 46 RPS. 2790 RPM.
[15:56:07.422] 93 counts/Sec. 46 RPS. 2790 RPM.
[15:56:08.419] 93 counts/Sec. 46 RPS. 2790 RPM.
[15:56:09.420] 94 counts/Sec. 47 RPS. 2820 RPM.
[15:56:10.420] 93 counts/Sec. 46 RPS. 2790 RPM.
[15:56:11.417] 93 counts/Sec. 46 RPS. 2790 RPM.
[15:56:12.421] 93 counts/Sec. 46 RPS. 2790 RPM.
[15:56:13.420] 93 counts/Sec. 46 RPS. 2790 RPM.
[15:56:14.420] 94 counts/Sec. 47 RPS. 2820 RPM.
[15:56:15.420] 93 counts/Sec. 46 RPS. 2790 RPM.
[15:56:16.421] 92 counts/Sec. 46 RPS. 2760 RPM.

PWM 制御

基本ファン仕様

PWM 端子は ファン内部で 5V になるように調整されているそうです。

  • オープン状態にすれば Duty 比 100% と同じ波形になります。3 ピンの M/B 端子に接続した際に PWM 端子が未接続となり 100% 回転になるのも同じことです。
  • GND に接続すれば Duty 比 0% の波形になります。
  • その他の割合はパルス信号の Duty 比によって制御します。
  • 周波数は 25KHz です。

制御回路と波形観測

やり方は以下の 2 つ考えられますが、それぞれ PWM 端子の波形はこのようになりました。いずれもファンコントロールには成功しています。

MOSFET で PWM 端子を GND にスイッチングする

回路図の橙枠 5V 供給部分がないパターン
MOSFET が OFF になった直後から 5V に向けての立ち上がりが遅いようです。ファン側の 5V 電力が不足している?

② 5V の PWM パルス信号を生成して送信する

回路図の橙枠 5V 供給があるパターン
Raspberry Pi 側の 5V を利用して PWM 端子への電力供給ができるので、立ち上がりが改善しています。入力ラインの抵抗値を下げることで、さらに立ち上がりを改善することもできます。

※100Ωに換装した例 (やる場合は消費電力に注意)

コードと結果

コード実装

PWM 信号を出力する実装は以前の記事を参照してください。
MOSFET によって波形は反転し Duty 比も逆転してしまうので、これはコード実装で解決します。

出力結果

Duty 比を変化させながら、同時に回転数も取得してみました。