4 PIN Lüfter richtig steuern - Pfeifen beseitigen

Hallo,

nach 2 Nächten und vielen Fehlversuchen möchte ich mich an euch wenden.

Mein Tablett im Dock mag das Wetter gerade nicht. Es taktet arg herunter und ich mag eine "coole" Lösung dafür haben.

Ich habe noch einen Lüfter von Arctic Cooling gefunden, der 4 Pins hat. (F8 PWM Rev. 2)
Über den seriellen Port steuere ich die Drehzahl und ob ein / aus. Ich nutze dafür ein Python-Script, dass CPU-Last und Taktfrequenz aus dem Surface ausliest und entsprechend gegensteuert, BEVOR das Tablett langsamer wird. Nebenbei ist das ganze somit automatisch an/aus, wenn das Tablett im Dock steckt.

Nach vielem Googeln und einigen Sketches hat diese Anleitung am besten funktioniert:
http://www.frag-duino.de/index.php/maker-faq/41-steuerung-eines-4-pin-cpu-luefters-mit-arduino

Es funktioniert im großen und ganzen, jedoch pfeift das Teil sehr ordentlich, sobald ich die Drehzahl regele. Das muss wohl dieses berühmte 25khz-PWM-Problem sein.

Ich habe darauf hin z.B. hier Controlling 4-pin computer fans - PWM at 25khz? - #19 by system - Interfacing - Arduino Forum

Meinen Sketch ergänzt:
void setup(){
TCCR5A = B00100011; // Fast PWM
TCCR5B = B11001; //no prescalering
OCR5A = 639; //count to 639 (16MHz/(640-1)=25 kHz)
OCR5B = 315; //set PWM to 50%

Diesen Teil des Codes verstehe ich aber nicht wirklich:-(
Ich VERMUTE, dass ich nicht mehr mit digitalWrite sondern immer mit OCR5B = X steuern muss. Kann das sein?

Noch einige Infos:

  • Das Pfeifen verschwindet, wenn der Lüfter direkt ohne Arduino läuft.
  • Das Regeln funktioniert ganz gut. Zwischen 1-9 am Ser-Port verändert sich die Drehzahl entsprechend.
  • Die ausgelesene Drehzahl kann jedoch nicht passen. Laut Spezifikation läuft der Lüfter zwischen 850 - 2000 RPM. Angezeigt werden mir jedoch Werte zwischen 1700 und 3000.
  • Mein Lüfter hat eine Minimal-Drehzahl. D.h. "AUS" werde ich mit einem Transistor zusätzlich schalten müssen. - VORHER muss aber das Gepfeife weg.

Wo kann / muss ich ansetzen? Einfach Code-Einfügen ist nicht meine Art, aber diese Timer-Beeinflussung oben entzieht sich meinem Verständnis.

Ich bin nun an dem Punkt, wo ich das auf jeden Fall lösen möchte und wenn es irgendwie geht auch verstehen, was ich da genau tue.

Für Tipps bin ich dankbar. Wenn ich Infos vergessen habe, bitte nachfragen.

Vielen Dank!

welchen Arduino hast du, und welchen PWM Pin nutzt du?

ardubu:
welchen Arduino hast du, und welchen PWM Pin nutzt du?

Für den Sketch aus dem ersten Link spielt das keine Rolle, da wird die PWM ja per Software gestellt. Der zweite Codeschnipsel stellt die PWM-Frequenz auf der Registerebene ein, sollte damit mit analogWrite ganz normal aufgerufen werden können. Und den ersten Sketch mit dem zweiten zu verwursteln bringt somit exakt gar nichts.

ardubu:
welchen Arduino hast du, und welchen PWM Pin nutzt du?

Ich benutze ein UNO Rev. 3

RPM habe ich an 2. Control an 6.

Ich glaube, ich habe die richtigen erwischt und nicht verwechselt, da Drehzahl und Steuerung ja durchaus reagieren.

sth77:
Und den ersten Sketch mit dem zweiten zu verwursteln bringt somit exakt gar nichts.

Okay, der zweite Teil (TCCR5A ...) fliegt wieder raus.
Somit bin ich wieder beim Original-Sketch. Mit dem Pfeifen.

Das ganze sieht nach murks aus. Du solltest als Anfänger das direkte schreiben in die Register weglassen.
Pin5 und 6 solltest du ebenfalls aussen vor lassen. Soweit mir bekannt ist, läuft auf dem dahinter liegenden Timer die Generierung für millis().

Versuch es mal mit Pin9.

void setup() { pinMode(9, OUTPUT); }
void loop() { analogWrite(9, /*WERT*/); }

Pin 6 läuft auf dem UNO mit 980 Hz PWM Frequenz

wenn du Pin 9 oder 10 nimmst und die Zeile
TCCR1B = TCCR1B & 0b11111000 | 0x01;
in das Setup schreibst
hast du eine PWM Frequenz von ca. 31 kHz

Hey. Das sieht schon ziemlich gut aus.
Dieser Code steuert wunderbar.
Das Pfeiffen ist deutlich weniger.

Bei Analogwrite mit Werten unter 60 kommen Störgeräusche wieder.
Bei ca. 30 wird es sehr deutlich.

Ich fürchte aber, das liegt am Lüfter selbst.

Die Steuerung tut aber was sie soll. - Und das so einfach.

  int speed;
  char eingabe;

void setup() { 
   Serial.begin(9600);

  speed=0;
  pinMode(9, OUTPUT); 
  }
  
void loop() { 
  

    if (Serial.available()){
    eingabe = Serial.read() - 48; // ASCII 0-9 lesen
    speed= map(eingabe,0,9,0,255);
    Serial.print("Speed ");
    Serial.println(speed);
    }
      
  analogWrite(9,speed); 
  
  }

ardubu:
Pin 6 läuft auf dem UNO mit 980 Hz PWM Frequenz

wenn du Pin 9 oder 10 nimmst und die Zeile
TCCR1B = TCCR1B & 0b11111000 | 0x01;
in das Setup schreibst
hast du eine PWM Frequenz von ca. 31 kHz

Danke! Das hat gefehlt. Nun ist alles perfekt leise.

Klasse!

Hier zur Erklärung wie man allgemein die PWM Frequenz ändert wie ardubu das gemacht hat:
http://playground.arduino.cc/Main/TimerPWMCheatsheet

Dabei wird der Teiler durch den der Prozessortakt dividiert wird verkleinert, so dass der Timer schneller läuft. Danach kann man ganz normal analogWrite() verwenden

Okay, das lese ich mir mal etwas genauer durch.

Da die 25khz nicht genau getroffen werden, kann es deshalb sein, dass nur

analogWrite(9,speed) - Werte zwischen 28und 254 funktionieren?

Ich lese inzwischen auch die u/min aus.
255 = volle Drehzahl, aber es wird eine viel zu niedrige Drehzahl ausgeben. Niedriger als bei 254.
Werte unter 28 erzeugen eine sehr geringe Drehzahl, melden jedoch extrem hohe Werte vom Lüfter zurück.

Es funktioniert alles. Es geht jetzt nur noch um das Verständnis.

Das ändert lediglich die Frequenz. Also die Zeit zwischen zwei gleichen Flanken. Mit analogWrite() änderst du das Puls/Pausen-Verhältnis.

7cookies:
Da die 25khz nicht genau getroffen werden, kann es deshalb sein, dass nur

analogWrite(9,speed) - Werte zwischen 3 und 254 funktionieren?

Nein, PWM funktioniert unabhängig von der Frequenz. Da geht es ausschließlich um das Puls-Pause-Verhältnis. Der Lüfter hat aber auch noch eine interne Elektronik, da kann es durchaus einen eingeschränkten Regelbereich geben.

7cookies:
Es funktioniert alles. Es geht jetzt nur noch um das Verständnis.

Lobenswert, an dieser Stelle noch weiterzumachen!

Wer lesen kann ist klar im Vorteil. In diesem Fall ich.

Die Kurve ist wie man so schön sehen kann überhaupt nicht liniear ansteigend.
Das erklärt auch die Sprünge.

Dazu kommt wohl, dass die Elektronik des Lüfters die Werte wohl "anpasst" und nicht unbedingt dass zurückgibt, was eine echte RPM wäre.

Dieser Sketch hier macht einen ganz guten Job. Die voreingestellten Werte habe ich durch probieren ein wenig eingegrenzt.

//FORUMSEINTRAG: http://forum.arduino.cc/index.php?topic=340978.0

#define PIN_CONTROL 9
#define INTERRUPT_GELB 0  // Interrupt 0 == Pin 2
#define UPDATE_ZYKLUS 1000 // Jede Sekunde 1 ms Ausgabe der Geschwindigkeit.
#define MAX_SPEED 225 //Durch probieren ermittelt
#define MIN_SPEED 35  //Durch probieren ermittelt
#define FAN_FLANKEN 4 //Komisch, aber passt

int speed;
char eingabe;



volatile int counter_rpm = 0;
int rpm = 0;
unsigned long letzte_ausgabe = 0;

void setup() { 
  TCCR1B = TCCR1B & 0b11111000 | 0x01; //
  Serial.begin(9600);
  speed=MIN_SPEED; //Langsam beginnen
  pinMode(PIN_CONTROL, OUTPUT); 
  attachInterrupt(0, rpm_fan, FALLING);
  }
  
void loop() { 
  analogWrite(PIN_CONTROL,speed); 
  
    if (Serial.available()){
       detachInterrupt(0); //Interrupt aus
    eingabe = Serial.read() - 48; // ASCII 0-9 lesen

    //Geschwindigkeit mappen
    speed= map(eingabe,0,9,MIN_SPEED,MAX_SPEED);

    //Counter zurücksetzen
     counter_rpm = 0;
     letzte_ausgabe = millis(); 
     
    attachInterrupt(INTERRUPT_GELB, rpm_fan, FALLING); //Interrupt an
    }
      
  

  if (millis() - letzte_ausgabe >= UPDATE_ZYKLUS){
    // Interrupt deaktivieren um das rechnen nicht zu unterbrechen.
    detachInterrupt(0);
 
    // RPM errechnen und ausgeben:
    Serial.println((counter_rpm * 60UL) / FAN_FLANKEN) ;
    
    // Counter zuruecksetzen
      counter_rpm = 0;
 
    // Zeitpunkt setzen
    letzte_ausgabe = millis();
 
    // Interrupt wieder aktivieren
    attachInterrupt(INTERRUPT_GELB, rpm_fan, FALLING);
  }
  
  }

  // Interrupt zaehlt den RPM-Counter hoch
void rpm_fan(){
  counter_rpm++;
}

counter_rpm muss so deklariert werden:

volatile int counter_rpm;

Und sicherheitshalber so ausgeben:

Serial.println((counter_rpm * 60UL) / FAN_FLANKEN) ;

Sonst hast du einen Integer-Überlauf wenn counter_rpm * 60 größer als ca. 32000 wird, was aber glaube ich nicht auftritt.

Thx.
Ich habe das mal geändert und werde mir volatile mal für die Zukunft merken:-)