アフィリエイト広告
アフィリエイト広告

冷却ファンの PID制御 (2) / パルス周期と回転数

冷却ファンの回転数を検出し、PID制御する回路を作ります。

前回は、ファンを回して回転数センサから出力を取りだし、表示するための回路を作りました。回路は、ファンの PWM駆動回路、回転数パルスの検出回路、そして 7セグメントLED 表示器の回路です。

冷却ファンの PID制御 (1) / ファンモータ PWM駆動回路
冷却ファンの回転数を検出し、PID制御する回路を作ります。 以前から何度か回してみている冷却ファン。こいつの PWM駆動はやりましたけど、回転数を検出するのは、これまでちゃんとやってなかったです。そこで、ファンの回転数を検出してフィードバッ...

今回は、じっさいにファンを動かして、出力される回転数パルスを検出してみましょう。

Arduino のスケッチ

回転数パルスの検出と表示を Arduino でおこないますので、スケッチを書きます。

7セグメントLEDドライバ TM1630 の扱いについては、過去記事を参照してください。

  1. class TM1630 {
  2. private:
  3.   const byte DISPLAY_MODE = 0x00;
  4.   const byte WRITE_REG_AUTO_ADDR = 0x40;
  5.   const byte WRITE_REG_FIXED_ADDR = 0x44;
  6.   const byte READ_KEY_SCAN = 0x42;
  7.   const byte SET_DISPLAY_ADDR = 0xC0;
  8.   const byte DISPLAY_OFF = 0x80;
  9.   const byte DISPLAY_ON = 0x88 | 0x84;
  10.   const byte STB_ENABLE = LOW;
  11.   const byte STB_DISABLE = HIGH;
  12.   const int DOT_POSITION = 2;
  13.   const byte digit[12] = {
  14.     0b01111110, // 0
  15.     0b00001100, // 1
  16.     0b10110110, // 2
  17.     0b10011110, // 3
  18.     0b11001100, // 4
  19.     0b11011010, // 5
  20.     0b11111010, // 6
  21.     0b01001110, // 7
  22.     0b11111110, // 8
  23.     0b11011110, // 9
  24.     0b00000000, // 10:blank
  25.     0b00100000 // 11:dot
  26.   };
  27.   const byte dioPin = 10;
  28.   const byte clkPin = 11;
  29.   const byte stbPin = 12;
  30.   const byte numberOfDigits = DISPLAY_MODE & 1 ? 5 : 4;
  31.   const byte blank = 10;
  32.   const byte dot = 11;
  33.   byte gridData[];

TM1630 のクラス宣言とメンバ変数。
TM1630 のコマンド定義、7セグメントLED のセグメントデータ定義などです。ほとんど定数ですので、ここで代入などやっちゃってます。
12行目は小数点位置の指定。パルス周期を表示させるために、整数部 2桁、小数点以下 2桁に設定しています。

  1. public:
  2.   TM1630() {
  3.     pinMode(dioPin, OUTPUT);
  4.     pinMode(clkPin, OUTPUT);
  5.     pinMode(stbPin, OUTPUT);
  6.     gridData[numberOfDigits] = {0};
  7.     digitalWrite(stbPin, STB_ENABLE);
  8.     shiftOut(dioPin, clkPin, LSBFIRST, DISPLAY_MODE);
  9.     digitalWrite(stbPin, STB_DISABLE);
  10.     digitalWrite(stbPin, STB_ENABLE);
  11.     shiftOut(dioPin, clkPin, LSBFIRST, WRITE_REG_AUTO_ADDR);
  12.     digitalWrite(stbPin, STB_DISABLE);
  13.     digitalWrite(stbPin, STB_ENABLE);
  14.     shiftOut(dioPin, clkPin, LSBFIRST, DISPLAY_ON);
  15.     digitalWrite(stbPin, STB_DISABLE);
  16.   }

コンストラクタ。
ピンモードの定義、TM1630 のモードの設定、転送を行ないます。データの転送時間を短くするために、モード設定をコンストラクタにいれてみました。

  1.   void displayNumbers(int n) {
  2.     for (byte i = 0; i < numberOfDigits; i++) {
  3.       int exponentialInDecimal = pow(10, i) + 0.5;
  4.       bool zeroSuppression = (0 != i) && (DOT_POSITION < i) && (exponentialInDecimal > n);
  5.       gridData[i] = zeroSuppression ? blank : n / exponentialInDecimal % 10;
  6.     }
  7.     digitalWrite(stbPin,STB_ENABLE);
  8.     shiftOut(dioPin, clkPin, LSBFIRST, SET_DISPLAY_ADDR | 0x00);
  9.     for (byte i = 0; i < numberOfDigits; i++) {
  10.       shiftOut(dioPin, clkPin, LSBFIRST, digit[gridData[i]]);
  11.       shiftOut(dioPin, clkPin, LSBFIRST, DOT_POSITION == i ? digit[dot] : 0);
  12.     }
  13.     digitalWrite(stbPin, STB_DISABLE);
  14.   }
  15. };

メンバ関数。表示データの処理と転送を行ないます。
61 ~ 65行目は、表示データを桁ごとに分割するとともに、小数点位置、ゼロサプレスの処理をしています。転送に要する時間は、約 1ms です。

  1. class PulseDetector {
  2. private:
  3.   const byte sensorPin = 7;
  4.   unsigned long pulsePeriod;
  5. public:
  6.   PulseDetector () {
  7.     pinMode(sensorPin, INPUT);
  8.   }
  9.   unsigned long detectPulses() {
  10.     pulsePeriod = pulseIn(sensorPin, HIGH);
  11.     pulsePeriod += pulseIn(sensorPin, LOW);
  12.     return pulsePeriod;
  13.   }
  14. };

パルス検出のクラス。
パルスは、HIGHの幅とLOWの幅を加算して、パルス周期としています。これで連続した HIGH、LOW を検出できるんですかね? よくわからんです。

  1. TM1630 ledDisplay;
  2. PulseDetector pulseDetector;
  3. void setup() {
  4. }
  5. void loop() {
  6.   static unsigned long interval = 1000;
  7.   static unsigned long previousMillis = 0;
  8.   static unsigned long pulsePeriod;
  9.   static unsigned int numberToDisplay;
  10.   unsigned long currentMillis = millis();
  11.   if(interval <= currentMillis - previousMillis) {
  12.     pulsePeriod = pulseDetector.detectPulses();
  13.     delayMicroseconds(3);
  14.     numberToDisplay = pulsePeriod * 0.1;
  15.     ledDisplay.displayNumbers(numberToDisplay);
  16.     previousMillis = currentMillis;
  17.   }
  18. }

オブジェクトの生成とloop()関数。
1秒毎にパルスを検出し、パルス周期を 7セグメントLED に表示させています。
110行目の delayMicriseconds() は、ここでちょっとだけ時間をとらないと代入処理がうまくいかないためにいれてます。なんなんでしょうね?よくわかりません。
111行目。取得されるパルス周期の値は 5桁です。最下桁を切り捨てて、ミリ秒 (小数点以下 2桁) での表示ができるようにしています。

検出したパルス周期と回転数

できた回路とスケッチでファンを回転させ、出力された回転数パルスの周期を表示させると、最低速時約 26.4ms ~ 最高速時約 13.7ms となりました。パルス数に換算すると、37.9 ~ 73.0pps です。

ところで、ファン 1回転で何パルス出力されるのでしょうか? どこかのサイトで 1回転 2パルスだと書かれていたように思うのですが、定かではありません。

ファンの回転数を実測する

じっさいにファンが何回転しているか、測定してみましょう。

回転数を測定する方法は? 非接触で簡単に測定するといえば、ストロボスコープでしょうか。
ストロボスコープとは、回転体に回転と同期した点滅する光をあてることで、回転体が静止して見える、というしくみを利用した回転数を測定する装置。

でも、そんな装置ないよ。なんのなんの、簡単に作っちゃいましょう。

Lチカの回路と、スケッチ例 Blink を使います。
LED は、できるだけ明るく点灯させるために 30mA 弱の電流を流したいので、トランジスタ 2SC1815 で駆動しましょう。Arduino のスケッチ例 Blink をちょっと改造して、ON の時間を delayMicroseconds() で指定します。OFF 時間は delay() のままです。

ファンの回転数パルスが 50pps になるように、回転速度を調整しておきます。
ファンの羽は 7枚です。もし、1回転 1パルスだとすると毎秒 50 回転ですから、ストロボ周期を毎秒 350 回にすれば、羽が止まって見えるはずです。

動画1. ストロボ周期 50x7pps のとき

LED の ON 時間を 860μs (要調整)、OFF 時間を 2ms として、光を羽に照射したときのようすが、左の動画1 です。

誤差があるので多少動きますが、羽がほぼ止まっているように見えています。
LED は点灯しているように見えますが、高速で点滅しています。点灯した瞬間にだけ羽が映し出されているわけです。

でも、羽の幅がじっさいの大きさの半分に見えます。これは、半回転ごとに光があたっているため。羽の枚数が奇数ですから、半回転では羽の位置が半分だけズレるからです。

つまり、ファンの回転数は半分の毎秒 25 回転であることが予想されます。

動画2. ストロボ周期 25x7pps のとき

今度は、回転数を毎秒 25 回転と仮定し、ストロボ周期を毎秒 175 回としてみます。LED の ON 時間を 710μs (要調整)、OFF 時間を 5ms としたときのようすが、動画2 です。

今度はどうでしょうか。羽が止まっているように見えますね。羽の幅も、じっさいの幅と同じに見えています。

ということで、ファンの回転数は 25rps、回転数パルス 50pps、1回転 2パルスであることがわかりました。

ファンの回転数範囲は 1140 ~ 2190rpm となります。最初に想定したとおりの数値ですね。

7セグメントLED の表示を回転数にする

スケッチをちょっと修正し、回転数を表示するようにしました。修正箇所は、以下の 2箇所です。

  1.   const int DOT_POSITION = -1;

DOT_POSITION を -1 とすると、小数点を表示しません。

  1.     numberToDisplay = 30000000 / pulsePeriod;

表示値を、毎分の回転数に換算しています。

次回は Arduino から回転数を制御します

これで、ファンを PWM制御し、回転数を 7セグメントLED に表示できるようになりました。でも、単純に回転数を表示しているだけではつまらないですねぇ。Arduino で PID制御するためには、こいつでファンの回転数を制御しないといけません。

ということで、次回は、ファンの回転数を Arduino の出力で制御できるようにしてみたいと思います。

タイトルとURLをコピーしました