#include <TimerOne.h>
#define FAN1_POWER_PIN 8
#define FAN1_CTRL_PIN 9
// Possible Leonardo Pin Change Interrupt Pins:
// PB0 = RXLED = PCINT0, PB1 = SCK = PCINT1, PB2 = MOSI = PCINT2, PB3 = MISO = PCINT3
// PB4 = 8 = PCINT4, PB5 = 9 = PCINT5, PB6 = 10 = PCINT6, PB7 = 13 = PCINT7
#define FAN1_RPM_SIG 13
// see Possible Pin Change Interrupt Pins
#define FAN1_RPM_SIG_NAME PCINT7
// see Possible Pin Change Interrupt Pins PCINT*_vect
#define FAN1_RPM_SIG_INTERRUPT PCINT7_vect
volatile int x;
void setup()
{
// switch interrupts off while messing with their settings
cli();
// Pin Change Interrupt Control Register
PCICR = (1 << PCIE0);
//PCICR = 0x01;
// Pin Change Mask Register
PCMSK0 = (1 << FAN1_RPM_SIG_NAME);
// turn interrupts back on
sei();
Serial.begin(9600);
while(!Serial)
{
;
}
// initialize timer1, and set a 25kHz frequenze
Timer1.initialize(40);
// setup pwm on pin 9, 50% duty cycle
Timer1.pwm(FAN1_CTRL_PIN, 512);
pinMode(FAN1_POWER_PIN, OUTPUT);
digitalWrite(FAN1_POWER_PIN, HIGH);
Serial.println("ende setup");
}
void loop()
{
int i;
for(i = 0; i < 1000; ++i)
{
Timer1.pwm(FAN1_CTRL_PIN, i);
Serial.print("i = ");
Serial.println(i);
delay(10);
}
delay(1000);
for(i = 1000; i > 1; --i)
{
Timer1.pwm(FAN1_CTRL_PIN, i);
Serial.print("i = ");
Serial.println(i);
delay(10);
}
delay(1000);
Serial.print("x ");
Serial.println(x);
}
// FAN - Pin Change Interrupt
ISR(FAN1_RPM_SIG_INTERRUPT)
{
if (digitalRead(FAN1_RPM_SIG) == 1) ++x;
}
Es funktioniert alles, bis auf der Teil, der den Interrupt betrifft für die RPM Messung. Bei der TimerOne Library muss man für das Leonardo allerdings eine andere Version als die Offizielle benutzen, da die Pinbelegung für das Leonardo eine andere ist als beim UNO Google Code Archive - Long-term storage for Google Code Project Hosting.
Und bei einem 3-Pin Lüfter der mit einem N-Kanal angesteuert wird kannst du glaube ich nicht das Signal messen, weil du dem Lüfter durch den Transistor ständig die Masse wegnimmst. Dafür brauchst du einen P-Kanal.
Aber der MOSFET stört auch nicht, oder seh ich das faslch? Denn wenn der Leonardo nicht laufen würde, würde der Lüfter auf volle Leistung laufen. Mit dem MOSFET dazwischen ist er aus, wenn der Leonardo auch nicht läuft.
Ich werde es Morgen mal ausprobieren, aber ich erwarte mir keine Besserung. Weil das Leonardo sich scheinbar aufhängt, oder die serielle Schnittstelle außer Kraft gesetzt wird.
Das hier ist auch der einzige Teil im Sketch für den MOSFET. Die Pins sind unterschiedliche für POWER und PWM SIG, deswegen seh ich hier auch kein Problem.
Und ich rede jetzt nicht vom Code, sondern von der Hardware.
Du hast den Mosfet in die Versorgungsleitung des FANs geschalten.
Im FAN ist aber eine Elektronik, die selbstständig die Regelung der Drehzahl übernimmt, gesteuert von dem PWM Signal .
Was du machst, ist mittels FET die Elektronik im FAN ständig aus und ein zu schalten!
Wie schon gesagt, das kann nicht funktionieren.
Nimm entweder den FET raus, oder nimm einen "dummen" 2-Pin FAN.
Ich glaube du hast den Sketch nicht richtig angeschaut, ich schalte den MOSFET genau einmal an und nicht an und aus um die Spannung zu ändern. Denn wie gesagt, der Lüfter läuft ohne den Interrupt Teil und macht auch die gewünschten Geschwindigkeitsänderungen, wie ich sie im unteren Teil beschreibe.
Setup:
Interrupt auf Pin 13 einschalten (RPM Signal)
serielle Schnittstelle initialisieren und warten bis der serielle Monitor am Rechner geöffnet wird (USB)
PWM Signal initialisieren Pin 9
PWM Duty cycle auf 50% setzen Pin 9
Leonardo Pin 8 als Ausgang definieren (MOSFET)
MOSFET einschalten und FAN mit 12V versorgen Pin 8
serielle Schnittstelle "ende setup" ausgeben
Loop:
PWM Signal Pin 9 von 0 - 97% duty cycle laufen lassen und aktuelle Einstellung auf der seriellen Schnittstelle ausgeben mit 10ms delay
eine sekunde warten
PWM Signal Pin 9 von 97 - 0% duty cycle laufen lassen und aktuelle Einstellung auf der seriellen Schnittstelle ausgeben mit 10ms delay
eine sekunde warten
Ausgabe Variable x die in der Interrupt Routine hochgezählt wird
Interrupt an Pin 13:
Variable x hochzählen, wenn an Pin 13 ein high Pegel gemessen wird.
Ich bin ziemlich sicher, dass du den Interrupt Vektor falsch benannt hast. Bei Pin Change Interrupts teilen sich immer 8 Pins einen Vektor. Das ist ja der Grund weshalb man danach abfragen muss welcher Pin tatsächlich ausgelöst hat wenn man mehr also einen aktiviert hat!
Der Atmega32u4 hat genau einen Pin Change Interrupt Vektor:
PCINT0
Und nicht:
PCINT7_vect
Siehe Datenblatt Seite 61
Das steht doch auch so bei der Beschreibung des PCICR Registers:
The corresponding interrupt of Pin Change Interrupt Request is executed from the PCI0 Interrupt Vector
Das hier kannst du dir sparen wenn du nur einen PC Interrupt hast:
if (digitalRead(FAN1_RPM_SIG) == 1)
Wenn du nur PCINT7 im Masken Register aktiviert hast, weißt du dass dieser ausgelöst hat. Bei mehreren PC Interrupts wäre dies allerdings nötig, da die im Gegensatz zu den normalen externen Interrupts nur einen Vektor haben.
Wieso verwendest du nicht einfach die externen Interrupts? Davon hast du 5 Stück und die kannst du einfach mit attachInterrupt() ansprechen