2023年11月19日日曜日

raspberry pi : FANをPWM制御する (C言語)

目的:

ラズベリーパイのFAN (PWM制御対応のFAN> を PWM 制御 する。

背景:

ラズベリーパイのケースについているFAN から音が出るようになった。
(5V ファン を 3.3V 駆動 )
この為、PWM制御対応の5V FAN を購入し、説明書通り、/boot/config.txt に
dtoverlay=gpio-fan,gpiopin=18,temp=55000
を追加したところ、 指定温度 (55℃) 以上 で ON, 未満で OFF となり、FAN が 定期的に 全力回転 していた。(PWM制御ではなく、 ON/OFF 制御 )
この為、PWM制御 (回転数制御) できるようにする。

概要

PWM制御については、「C言語で LED 調光 (pigpio を使用した PWM 制御) 」を参照。
pigpiod(デーモン)を使用した hardware_PWM (ユーザ権限で実行可能) を使用し、指定温度範囲で 段階的に FAN回転数 を変える様にする。
尚、コード作成は C言語 で行う。

構成

raspberry pi : raspberry pi 4
FAN : PWM制御端子付き の 5V FAN
使用 GPIO : 18 pin


PWM FAN 制御用コード

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pigpiod_if2.h>

int get_temp(void) {
  static int tmp = 0;
  FILE *fp;
  char rdt[16];

  fp = fopen("/sys/devices/virtual/thermal/thermal_zone0/temp","r") ;
  if (fp != NULL ) {
    fgets(rdt,16,fp) ;
    fclose(fp);
    tmp = atoi(rdt) / 1000 ;
  }

  return tmp ;
}

void usage(void)
{
  printf("Usage: pigpio_pwnfan [option]\n");
  printf("\n");
  printf("  option\n (default)") ;
  printf("    -l n ... Low temperature (50)    'C\n");
  printf("    -h n ... hi  temperature (60)    'C\n");
  printf("    -p n ... PWM output pin  (18)    12/18(ch0) or 13/19(ch1)\n");
  printf("    -f n ... PWM Frequency   (10000) Hz\n");
  printf("\n");
}

int main(int argc, char **argv) {
  int gpio_pin = 18;      // hardware PWM Pin
  int pwm_freq = 10000;   // hardware PWM frequency
  int pwm_duty = 0 ;      // hardware PWM duty
  int tmp_low  = 50;      // cold temperature
  int tmp_hi   = 60;      // hot temperature
  int temp     = 0 ;      // detect twmperature
  int pi       = 0 ;
  int opt      = 0 ;

  // command line option 
  while ((opt = getopt(argc, argv, "l:h:p:f:")) != -1) {
    switch (opt) {
      case 'l':
        tmp_low = atoi(optarg);
        break;
      case 'h':
        tmp_hi  = atoi(optarg);
        break;
      case 'p':
        switch((gpio_pin = atoi(optarg))) {
          case 12:
          case 13:
          case 18:
          case 19:
            break;
          default:
            usage();
            exit(1);
        }
        break;
      case 'f':
        pwm_freq = atoi(optarg);
        break;
      default:
        printf("\n");
        usage();
        exit(1);
    }
  }

  if (tmp_low >= tmp_hi)
  {
    usage();
    exit(1);
  }


  // pigpio start
  pi = pigpio_start(0,0) ;
  if (pi<0) {
    printf ("pigpio start error !!") ;
    exit(1) ;
  }

  // PWM control
  while (1)
  {
    temp = get_temp();
    if (temp <= tmp_low) {
      pwm_duty = 0;
    } else if(temp >= tmp_hi) {
      pwm_duty = 1000000 ;       // 100%
    }else {
      pwm_duty = ((temp - tmp_low) * 1000000) / (tmp_hi - tmp_low) ;
    }

    hardware_PWM(pi,gpio_pin, pwm_freq, pwm_duty) ;

    sleep(10);
  }


  return 0;
}

コード概要

  1. get_temp(void)
    raspberry pi のCPU温度を取得する。
    温度の取得は /sys/devices/virtual/thermal/thermal_zone0/temp を読み込む事で行う。
  2. usage(void)
    オプション不正時の書式の表示を行う。
  3. main(int argc,char **argv) PWM FAN 制御 本体。
    1. command line option 解析部分 getopt を して オプションの解析を行う。
      unistd.h をインクルードする必要がある。
      -l : 下限温度。この温度より下は FAN停止。(省力時 50℃) -h : 上限温度。この温度より上は FAN全速。(省略時 60℃) -p : GPIO PIN番号。12/18(ch0) 又は 13/19(ch1) (省略時 18) -f : PWM 周波数 (省略時 10000 (10KHz) )
  4. pigpio start pigpio_start(0,9) (pigpio の 初期化) を実行。 戻り値が負の場合、異常終了。
  5. PWM control PWM 制御 本体。 設定温度の間、検出温度の応じてデューティを 0~100% の間で変化させる。 無限ループで、 温度の取得, PWM 設定 を行った後、10秒間 スリープする。 ( 10秒間隔で PWM制御 )

コンパイル

gcc -Wall -pthread -o pigpio_pwmfan pigpio_pwmfan.c -lpigpiod_if2 -lrt

実行

pigpiod 開始

sudo systemctl enable pigpiod.service
sudo systemctl start pigpiod.service

実行 (動作確認)

pigpio_pwmfan&
で実行し、FAN がPWM制御されていること(全速でないこと)を確認する。

停止

作成した FAN制御プログラムは サービスとして実行するため、動作確認で実行したプロセスを以下で終了させる。
ps
で pigpio_pwmfan の PIDを確認し、
kill [PID]
で pigpio_pwmfan を終了させる。

サービスへの登録

再起動時等、自動で開始するようにサービスに登録する。

ユニット定義ファイルの作成

/etc/systemd/system に ユニット定義ファイルを作成する。

ユニット定義ファイル例
[Unit]
# サービスの説明。内容は任意
Description=PWM FAN Control
# このUnitより先に起動するべきUnitを設定
After=local-fs.target
  
[Service]
# 実行するコマンドやスクリプトを記述
ExecStart=/usr/local/bin/pigpio_pwmfan
# サービス停止時の Kill する単位を設定
KillMode=process
# プロセスの起動方法を指定
Type=simple
# サービス停止時の再起動条件 (no は再起動しない)
Restart=always
 
[Install]
# 該当ユニットへの弱い依存関係を設定
WantedBy=multi-user.target

FAN制御プログラムの サービス登録、実行

sudo systemctl enable pigpiod.service
sudo systemctl start pigpiod.service






0 件のコメント:

コメントを投稿