zoologist 发表于 2023-7-14 09:40:07

4Pin 风扇转速控制器

对于风扇来说,只要供电就能工作。最开始的电脑使用的都是这种风扇。但是随着技术的发展,人们发现需要对这个风扇进行控制,因为风扇转的快噪音和功耗都会随之增加。于是,加上一根反馈线,让用户能够得知当前的转速。但是这样会遇到另外的两个问题:第一个问题是风扇电压变化,反馈线上的电压也会随之变化,范围大了读取这个反馈会很麻烦。第二个问题是:电压和风扇转速转速关系并不是线性的。比如,一个 12V 的风扇,12V时转速是 2000CPM,10V供电时转速时1000CPM,但是如果11V供电时,转速很可能是 1100CPM。风扇的转速和风力噪音直接相关,用户想要得到一个大概的转速非常困难。最终 Intel 推出了一个方案:通过 PWM 来控制风扇转速,然后使用5V信号作为当前转速反馈引脚。我们最常见到的CPU的风扇通常都是 4 Pin的。供电要求12V,控制的PWM 为 5V 25KHz,转速反馈引脚为 5V输出。

有些风扇是存在最低转速的,意思是哪怕有PWM已经为0仍然能够旋转,有些不存在最低转速,PWM比较低的时候就会停止转动。
了解了上述知识就可以得知我们为了实现控制 CPU 风扇,需要提供12V电源,提供25Khz的 PWM 信号,以及读取 5V 的转速输出。电路设计如下,我们使用Arduino Uno作为主控。外部12V供电进入(DC1)之后,经过一个DC-DC降压模块(来自DFROBOT的DFR0831,DC-DC降压模块7~24V转5V/4A),降压为5V提供给 Arduino 作为风扇控制,然后风扇的转速反馈信号经过U3上拉后进入Arduino即可读取。最终转速和当前的PWM设定显示在一个 1602LCD上。
PCB 设计如下,可以看到板子上带有4个按钮用于控制 PWM ,分别是-1、-10、+1、+10这样用户可以快速的改变 PWM 设置。
代码设计如下:#include <LiquidCrystal_I2C.h>
// 保存当前设定的 PWM 值
#include<EEPROM.h>

LiquidCrystal_I2C lcd(0x3F, 16, 2);

// PWM 发生器相关定义
const byte OC1A_PIN = 9; //PWM输出引脚为 D9
// 定义 PWM 频率
const word PWM_FREQ_HZ = 25000; //Adjust this value to adjust the frequency
const word TCNT1_TOP = 16000000 / (2 * PWM_FREQ_HZ);
const int BTN1 = 13;
const int BTN2 = 12;
const int BTN3 = 11;
const int BTN4 = 10;

// 计算转速相关定义
const int TOTAL = 10; // 计算10次输出一次,这是一个简单的滤波
int InterruptPin = 2;// 接收风扇中断 D2
volatile long int counter = 0;
volatile long int t;
byte p = 0;
byte SavedPWM = 0;
byte lastPWM = -1;
byte pwm;
long int Elsp=0;

void setup() {
pinMode(BTN1, INPUT_PULLUP);
pinMode(BTN2, INPUT_PULLUP);
pinMode(BTN3, INPUT_PULLUP);
pinMode(BTN4, INPUT_PULLUP);

pinMode(OC1A_PIN, OUTPUT);

// Clear Timer1 control and count registers
TCCR1A = 0;
TCCR1B = 0;
TCNT1= 0;

// Set Timer1 configuration
// COM1A(1:0) = 0b10   (Output A clear rising/set falling)
// COM1B(1:0) = 0b00   (Output B normal operation)
// WGM(13:10) = 0b1010 (Phase correct PWM)
// ICNC1      = 0b0    (Input capture noise canceler disabled)
// ICES1      = 0b0    (Input capture edge select disabled)
// CS(12:10)= 0b001(Input clock select = clock/1)

TCCR1A |= (1 << COM1A1) | (1 << WGM11);
TCCR1B |= (1 << WGM13) | (1 << CS10);
ICR1 = TCNT1_TOP;

Serial.begin(115200);
Serial.setTimeout(300);

pinMode(InterruptPin, INPUT);
attachInterrupt(0, speedX, FALLING );

lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("PWM Fan CNT");

// PWM 存在地址0 上
SavedPWM = EEPROM.read(0);

if (SavedPWM>100) {
      SavedPWM=0;
    }
// 将上一次保存的 PWM 设定进去
setPwmDuty(SavedPWM);
pwm = SavedPWM;
lastPWM = pwm + 1;
}

void loop() {
if (pwm != lastPWM) {
    Serial.println(pwm);
    setPwmDuty(pwm);
    lastPWM = pwm;
    Elsp=millis();
}

// 计算当前转速
long int avg = 0;
counter = 0;
delay(1000);

p = (p + 1) % TOTAL;
t = (long int)(counter * 60 / 2);

for (byte i = 0; i < TOTAL; i++) {
    avg = avg + t;
}

// 输出转速
Serial.print("Current speed: ");
Serial.println(avg / TOTAL);

lcd.setCursor(0, 1);
lcd.print("Fan Speed:");
lcd.print(avg / TOTAL);
lcd.print("      ");

counter = 0;
pinMode(BTN1, INPUT_PULLUP);
if (digitalRead(BTN1) == LOW) {
    delay(5);
    if ((digitalRead(BTN1) == LOW) && (pwm > 9)) {
      pwm = pwm - 10;
    }
}
if (digitalRead(BTN2) == LOW) {
    delay(5);
    if ((digitalRead(BTN2) == LOW) && (pwm > 0)) {
      pwm = pwm - 1;
    }
}
if (digitalRead(BTN3) == LOW) {
    delay(5);
    if ((digitalRead(BTN3) == LOW) && (pwm <=100-10)) {
      pwm = pwm + 10;
    }
}
if (digitalRead(BTN4) == LOW) {
    delay(5);
    if ((digitalRead(BTN4) == LOW) && (pwm <100)) {
      pwm = pwm + 1;
    }
}

// 每隔5秒检查 pwm 是否已经改变,如果改变则保存
if ((SavedPWM!=pwm)&&(millis()-Elsp>5000)) {
      Serial.println("Save current pwm");
      Elsp=millis();
      SavedPWM=pwm;
      EEPROM.write(0,pwm);
    }
}

void setPwmDuty(byte duty) {
Serial.print("Set pwm "); Serial.println(duty);
lcd.setCursor(0, 0);
lcd.print("Current pwm:");
lcd.print(duty);
lcd.print("");
OCR1A = (word) (duty * TCNT1_TOP)/ 100;
}


void speedX()//中断函数
{
counter++;
}


zoologist 发表于 2023-7-14 09:43:14

本帖最后由 zoologist 于 2023-7-14 14:34 编辑

工作测试的视频:

https://www.bilibili.com/video/BV14L411U7cF/

本文提到的电路图和PCB(立创 EDA)

木子呢 发表于 2023-7-14 14:31:49

666,蹲一个后续完整步骤过程~

三春牛-创客 发表于 2023-7-17 21:52:46

不错不错

三春牛-创客 发表于 2023-7-17 21:56:03

赞赞赞赞

花生编程 发表于 2023-7-18 21:31:29

厉害厉害

花生编程 发表于 2023-7-18 21:34:46

赞赞赞赞赞
页: [1]
查看完整版本: 4Pin 风扇转速控制器