PICでPCファンコントローラを自作

自宅でLinuxサーバーが自室で常時稼動している。
こいつの排気用ファンが、予想していたよりも回転数が大きく
回転音がずっと気になっていたので、勉強がてらPIC12F1822を使って
FANコントローラーを作成。その備忘録を記す。

製作方針

  1. PIC12F1822のPWM機能を使って回転数をコントロールする
  2. 電源は、マザーボードのFAN用の電源ピン(12V)から取る
  3. 使用するFANは4pinタイプ(MOSFET内蔵)なので、PWMの信号を送るだけ
  4. PWMの周波数は、市販FANを参考に25kHzとする
  5. タクトスイッチを追加し、押すたびにPWMのDuty比を変更できるようにする
    (これにより回転数が可変になる)

Pickit3とPIC12F1822の接続

以下のように接続して書き込みを行う。抵抗とコンデンサを必ず接続する。
当初接続せずに書き込みを行っていたところ、これが原因だったのか何度か
書き込みを行うとPICが死んでしまう現象があった。

上手のようにピン接続した後、MPLAB X IDEから書き込みを行う手順とする。

FANコントローラーの回路図

PIC用の電源は、12Vラインからツェナーダイオードを使って
5.6Vとし、内部クロック8MHzで動作させる。PWMの信号はRA2から出力し、
回転数の変更は、RA1(プルアップ)からスイッチのON/OFF
を読み取って、プログラム内でDuty比を変更する。

FANコントローラーのプログラム

PWMの設定プログラムは、以前の投稿をもとに各種レジスタのパラメータを設定するだけ。
タクトスイッチのON/OFFをカウントして、Duty比をサイクリックに変更する。

/*
 * File:   main.c
 */
#include <xc.h>

// コンフィグレーション設定
#pragma config FOSC     = INTOSC   // 内部クロックを使用する(INTOSC)
#pragma config WDTE     = OFF      // ウォッチドックタイマー設定
#pragma config PWRTE    = ON       // 電源ONから64ms後にプログラムを開始する
#pragma config MCLRE    = OFF      // 外部リセットかデジタル入力(RA3)ピンとして使用するか
#pragma config CP       = OFF      // プログラムメモリの保護
#pragma config CPD      = OFF      // データメモリの保護
#pragma config BOREN    = ON       // 電源電圧降下常時監視機能
#pragma config CLKOUTEN = OFF      // CLKOUTピンをRA4ピンで使用する
#pragma config IESO     = OFF      // 外部・内部クロックの切替えでの起動設定
#pragma config FCMEN    = OFF      // 外部クロックの監視

#pragma config WRT    = OFF        // Flashメモリの保護
#pragma config PLLEN  = OFF        // クロックのプルアップ(x4)の設定 ※32MHzで使用する
#pragma config STVREN = ON         // スタックがオーバフローやアンダーフローしたらリセットをする
#pragma config BORV   = HI         // 電源電圧降下常時監視電圧(2.5V)設定
#pragma config LVP    = OFF        // 低電圧プログラミング機能

// delay用のクロック設定
#define _XTAL_FREQ 4000000         // delay用に必要(クロック4MHzを指定)

void main(void){
    // クロック設定
    // 内部4MHz
    OSCCON =  0b01101010;
    
    // ピン設定
    ANSELA = 0b00000000; // すべてデジタル
    OPTION_REG = 0b00000000; // デジタルI/Oに内部プルアップ抵抗を使用する
    TRISA = 0b00001010; // RA1(RA3は入力専用なので常に1)だけ入力
    WPUA = 0b00000010; // RA1は内部プルアップ抵抗を指定する
    
    // PWM設定(Timer2使用)
    // Clock = 4MHz, PWM = 25kHz, Prescala x4
    T2CON =   0b00000101;
    PR2 = 9;
    CCP1CON = 0b00001100;
    
    // duty比
    //CCPR1L =  0b00000000;//0.1 (0)
    //CCPR1L =  0b00000001;//0.2 (1)
    //CCPR1L =  0b00000010;//0.3 (2)
    //CCPR1L =  0b00000011;//0.4 (3)
    CCPR1L =  0b00000100;//0.5 (4)
    //CCPR1L =  0b00000101;//0.6 (5)
    //CCPR1L =  0b00000110;//0.7 (6)
    //CCPR1L =  0b00000111;//0.8 (7)
    //CCPR1L =  0b00001000;//0.9 (8)
    //CCPR1L =  0b00001001;//1.0 (9)
    
    // 初期化
    TMR2 = 0;
    PORTA  = 0b00000000;
    
    // タイマー2開始
    TMR2ON = 1;
    
    while(1){
        __delay_ms(500);
        // RA1がGNDへ接続(タクトスイッチON)
        if(RA1 == 0 ){
            if( CCPR1L >= 9 ){
                CCPR1L = 0;
            }else{
                if( CCPR1L + 2 >= 10 ){
                    CCPR1L = 9;
                }else{
                    CCPR1L+=2;
                }
            }
        }
    }
    return;
}

製作と実際の接続

回路図を参考に電源、FANに接続して回転数が変化するかを確認する。



すでにこの投稿で数週間経過しているが、問題なく動作している。