I want to control and monitor the speed of a 4-pin PC fan using an esp8266.
When there is no PWM control signal sent to the fan from the esp this code reports the fan speed correctly. However, when the esp PWM control signal is connected to the fan things go wrong with the speed reporting, but the fan speed actually responds as expected to the PWM signal.
The setup:
- The fan is driven from a 12V supply and the NodeMCU v2 esp8266 is powered by USB from a PC. The 12V supply and the esp8266 have a common ground through the esp’s GND pin; and
- The tach signal from the fan is pulled up the 3.3V pin of the esp and is connected to pin D3 of the esp.
When the system is connected in this state (no PWM signal) the fan speed is at maximum and its speed is correctly reported in the serial monitor at approximately 1410 RPM. I have used the debugging tools in VisualMicro to watch the vaue of the interruptCounter
variable in the computFanSpeed()
function during operation and its value gets to 49 before it is reset to zero after exiting loop()
.
The PWM signal originates from esp pin D1 and is measured to be 2.0V using a multimeter. When this PWM signal is connected to the PWM input of the fan it responds as expected, however the speed reported in the serial monitor climbs to a non-sensible number (123300 RPM). The value of interruptCounter
variable in the computFanSpeed()
function gets to 4180 before it is reset to zero after exiting loop()
.
I don’t understand where things are going wrong – specifically why is the handleIinterrupt()
function being triggered when the fan is operating under PWM control by the esp?
Another note: For some reason if any value other than 0 is provided to the pin
argument in the attachInterrupt('pin', 'ISR', 'mode')
function the fan speed recorded in the serial monitor is 0 RPM. I have tried a several combinations of different pins and values for 'pin' and have not been able to have the speed reported in the serial monitor - it always shows 0 RPM.
volatile int interruptCounter; //counter use to detect hall sensor in fan
int RPM; //variable used to store computed value of fan RPM
unsigned long previousmills;
//NODEMCU ESP8266
#define tachInputPIN 4
#define pwmOutputPin 5
#define sensorInterrupt 0
#define pwmDuty 630
#define calculationPeriod 1000 //Number of milliseconds over which to interrupts
void setup()
{
Serial.begin(115200);
previousmills = 0;
interruptCounter = 0;
RPM = 0;
//NODEMCU esp8266
analogWriteFreq(8000);
pinMode(pwmOutputPin, OUTPUT);
attachInterrupt(sensorInterrupt, handleInterrupt, RISING);
pinMode(tachInputPIN, INPUT);
}
void loop()
{
// NODEMCU esp8266
analogWrite(pwmOutputPin, pwmDuty);
if((millis() - previousmills) > calculationPeriod) {// Process counters once every second
detachInterrupt(sensorInterrupt);
computeFanSpeed();
displayFanSpeed();
previousmills = millis();
interruptCounter = 0;
attachInterrupt(sensorInterrupt, handleInterrupt, RISING);
}
}
void ICACHE_RAM_ATTR handleInterrupt() { //This is the function called by the interrupt
interruptCounter++;
}
void computeFanSpeed() {
//interruptCounter counts 2 pulses per revolution of the fan over a one second period
RPM = (0.5) * (interruptCounter / (calculationPeriod/1000)) * 60;
}
void displayFanSpeed() {
Serial.print(RPM, DEC); //Prints the computed fan speed to the serial monitor
Serial.print(" RPM\r\n"); //Prints " RPM" and a new line to the serial monitor
}