上位に戻る arudinoで、PCファンを温度制御する 初版2025/09/2

サーバ更新に伴って、余っていたRyzenのリテールファンを冷却ファンとして使用。ついでに手持部品で、温度で回転数を
制御してみました

  1. 仕様

    ■arudinoのpwm信号を使って、CPUファン(pwmファン)を制御します
    CPUファンの制御で使われる周波数は、およそ20kHzで、人間の耳では聞こえない帯域になっています
    以前換気扇を作った時、2線式のPCファンの電源をpwm制御したところ、arudinoでは、490Hz 又は980Hzで、可聴周波数帯の
    為、かなりコイル鳴きがうるさく、結局pwm信号を平滑して直流に戻して制御しました
    今回使用したRyzenのリテールファンは、pwm制御用のファンの為か、980Hzでpwm制御しましたが、コイル鳴きはありません
    でした

    ■温度制御方式
    目標温度制御で、以前、PID制御を使いましたが、今回は目標温度がそれほどシビアでもないし、外気の温度で、どのような目標値
    にするかなどめんどいので、単純に比例制御することにしました
    但し、温度上限の値については、リモコンで設定変更できるようにしています


    ※回転数は、実際のファンの回転数ではなく、arudinoの設定値です
    (0〜255)

    ■リモコン制御、値の表示
    7セグメントに、排気温度、回転数設定値、上限温度設定値を表示します
    排気温度と、回転数設定値は、交互に表示されます
    赤外線リモコンを使って、点灯、消灯、上限温度設定が行えるようにします

  2. 回路図


    ちなみに、4線式のPCファンの端子は以下のようになっています



  3. 使った部品
    Ryzenのリテールファン





    動作の様子


  4. プログラム
    #include <IRremote.hpp>
    #include <OneWire.h>
    #include <DallasTemperature.h>
    #include <Arduino.h>
    #include <TM1637Display.h>


    // Data wire is plugged into port 2 on the Arduino
    #define ONE_WIRE_BUS 2  //温度センサー
    // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
    OneWire oneWire(ONE_WIRE_BUS);
    // Pass our oneWire reference to Dallas Temperature.
    DallasTemperature sensors(&oneWire);
    // Module connection pins (Digital Pins)
    #define CLK 4
    #define DIO 3
    TM1637Display display(CLK, DIO);
    const byte ___C[] = {
        SEG_D, // _
        SEG_D, // _
        SEG_D, // _
        SEG_A | SEG_E | SEG_F | SEG_D, // C
     };
    const byte ___F[] = {
        SEG_D, // _
        SEG_D, // _
        SEG_D, // _
        SEG_A | SEG_E | SEG_F | SEG_G, // F
     };

    int IR_RECEIVE_PIN = 11;
    int PWMfan=6;
    int fan_vol=255;
    int countt=50;
    int fan_min=150;
    float temp_min=20;
    float temp_max=39;
    int hflgg=0;

    void setup() {
      Serial.begin(9600);
      IrReceiver.begin(IR_RECEIVE_PIN);
      pinMode(PWMfan,OUTPUT);
      sensors.begin();
    }
    int ccomand;


    void irjyusin(){
      if (IrReceiver.decode()) {
        switch(IrReceiver.decodedIRData.command){

          case 0x50:
                  Serial.println("選局上");
                  if (temp_max<50){
                    temp_max=temp_max+1;
                    Serial.print("設定温度:");
                    Serial.println(temp_max);
                    hyouji(temp_max);
                    }

                  break;
          case 0x51:
                  Serial.println("選局下");
                  if (temp_max>25){
                    temp_max=temp_max-1;
                    Serial.print("設定温度:");
                    Serial.println(temp_max);
                    hyouji(temp_max);              
                    }  
                  break;

          case 0x65:
                  Serial.println("音声ON");
                  hflgg=1;
                  break;

          case 0x64:
                  Serial.println("消音");
                  hflgg=0;
                  display.clear();
                  break;                                            
        }
     
        IrReceiver.printIRResultShort(&Serial);
        Serial.println();
        IrReceiver.resume();
      }

    }

    void keisoku(){
      sensors.requestTemperatures(); // Send the command to get temperatures
      float atai=sensors.getTempCByIndex(0);
      // Check if reading was successful
      if (atai != DEVICE_DISCONNECTED_C)
      {
        Serial.print("計測値:");
        Serial.println(atai);
        hyoujic(atai);
        float ans=(((255-fan_min)/(temp_max-temp_min))*(atai-temp_min))+fan_min;
        if (ans>255){ans=255;}
        if (ans<150){ans=150;}


        fan_vol=ans;
        Serial.print("ファン出力:");
        Serial.println(fan_vol);
        analogWrite(PWMfan,fan_vol);

      }
      else
      {
        Serial.println("Error: Could not read temperature data");
      }

     
    }

    void hyoujic(float Temp){
        if(hflgg==0){return;}
        String ss = String(Temp);
        ss.replace(".", "");
    //    Serial.println(ss);
        String sss = String(ss.charAt(0))+String(ss.charAt(1))+String(ss.charAt(2));
        display.clear();
        display.setBrightness(0x01); //MAX 0x0f
        display.setSegments(___C); // - or blank
        display.showNumberDecEx(sss.toInt(),0x40,true,3,0);
    }
    void hyouji(float Temp){
        if(hflgg==0){return;}  
        String ss = String(Temp);
        ss.replace(".", "");
    //    Serial.println(ss);
        String sss = String(ss.charAt(0))+String(ss.charAt(1))+String(ss.charAt(2));
        display.clear();
        display.setBrightness(0x01); //MAX 0x0f
        display.showNumberDecEx(sss.toInt(),0x40,true,3,0);
    }
    void hyoujik(int kaiten){
        if(hflgg==0){return;}  
        String ss = String(kaiten);
        ss.replace(".", "");
    //    Serial.println(ss);
        String sss = String(ss.charAt(0))+String(ss.charAt(1))+String(ss.charAt(2));
        display.clear();
        display.setBrightness(0x01); //MAX 0x0f
        display.setSegments(___F); // - or blank
        display.showNumberDecEx(sss.toInt(),0,true,3,0);
    }



    void loop() {
    irjyusin();
    delay(100);
    countt=countt-1;
    if(countt==25){
      hyoujik(fan_vol);
    }
    if(countt<1){
    keisoku();
    countt=50;
    }


    }


    ちなみに、温度表示の場合は、最終桁に、Cを表示 回転数の場合は、Fを表示させています
    プログラム上の対応は、以下のようになっています







    以上間違い等ありましたら、以下ご意見箱にお願いします

   

    ご意見箱