Count how many pulses per second

That's because it wasn't getting enough power, probably because it's running off 5V through the internal pullup resistor which is about 20k ohms. Whatever you do, don't set that pin to OUTPUT!

GoForSmoke:
That's because it wasn't getting enough power, probably because it's running off 5V through the internal pullup resistor which is about 20k ohms. Whatever you do, don't set that pin to OUTPUT!

What do you mean. Which pin should I not set to output?

The one that you are using for INPUT to read the fan. I did forget that in Majenko's circuit (that I just looked at again) the internal pin pullup isn't the only possible power source to the transistor. It also gets Vcc (5V) through 10k ohms. When the transistor is OFF the pin will read HIGH. When the transistor is ON it grounds the power, the pin will read LOW, and your led gets 5V through 10k ohms which is enough to light it dim.

I bet you could put 220-1k ohms instead of the 10k resistor, get a brighter led and hurt nothing.
But you don't need to now since you know the fan data must be readable.

Use digital instead of analog read and set up a Pin Change Interrupt. The interrupt will stop the regular program, turn interrupts off, run a special -short- routine you make (like "pulse++;") and turn interrupts back on (plus some register saving you don't care about now) and then resume your regular code like nothing happened. Your program can watch microseconds go by (with micros()) until 1 second is up and see how many pulses were counted. You can know to within 4 microseconds I think.

If instead you just watch the pin you might be able to tell about how even the pulses are.

There is a pulseIn command to measure ulse widths but I see people get results with variance using it.

GoForSmoke:
The one that you are using for INPUT to read the fan. I did forget that in Majenko's circuit (that I just looked at again) the internal pin pullup isn't the only possible power source to the transistor. It also gets Vcc (5V) through 10k ohms. When the transistor is OFF the pin will read HIGH. When the transistor is ON it grounds the power, the pin will read LOW, and your led gets 5V through 10k ohms which is enough to light it dim.

I bet you could put 220-1k ohms instead of the 10k resistor, get a brighter led and hurt nothing.
But you don't need to now since you know the fan data must be readable.

Use digital instead of analog read and set up a Pin Change Interrupt. The interrupt will stop the regular program, turn interrupts off, run a special -short- routine you make (like "pulse++;") and turn interrupts back on (plus some register saving you don't care about now) and then resume your regular code like nothing happened. Your program can watch microseconds go by (with micros()) until 1 second is up and see how many pulses were counted. You can know to within 4 microseconds I think.

If instead you just watch the pin you might be able to tell about how even the pulses are.

There is a pulseIn command to measure ulse widths but I see people get results with variance using it.

Can you please give me an idea how that code would look like?

It looks like the code here:
http://arduino.cc/playground/Main/PcInt

I have started to try to learn the interrupt library. But i don´t get what they are doing here:

uint8_t latest_interrupted_pin;
uint8_t interrupt_count[20]={0}; // 20 possible arduino pins
void quicfunc() {
  latest_interrupted_pin=PCintPort::arduinoPin;
  interrupt_count[latest_interrupted_pin]++;
}

I understand that they are creating a function, but what is the uint8_t things?

uint8_t is unsigned integer 8 bits long. It's the same as byte or unsigned char.

Is this code ok?

#include <PinChangeInt.h>

int pulseCount = 0;
int inPin = 2;
int printVal = 0;

void pulseFunc(){
  pulseCount = pulseCount + 1;
  
}

void setup(){
 pinMode(inPin, INPUT); 
 PCintPort::attachInterrupt(inPin, &pulseFunc, RISING);
 Serial.begin(9600); 
}



void loop(){
  printVal = pulseCount * 60;
  Serial.println(printVal, DEC);
  delay(1000); 
  
}

Two things -

  1. You should reset pulseCount after each displaying so that you don't just accumulate a huge value.
  2. pulseCount is modified inside an interrupt. You should declare it volatile and wrap any non-interrupt based access to it in disable and enable interrupt calls.

majenko:
Two things -

  1. You should reset pulseCount after each displaying so that you don't just accumulate a huge value.
  2. pulseCount is modified inside an interrupt. You should declare it volatile and wrap any non-interrupt based access to it in disable and enable interrupt calls.

I've fixed the first one. Can you please try to explain the second one again, i didn't understand. I guess it has something to do with that i give pulseCount it's value inside a void?

A void has nothing to do with it.

When you change a value inside an interrupt routine there is no knowing what the program was doing at the time the interrupt routine was called. If you were doing anything with any variables that are changed inside the interrupt routine at the time the interrupt routine was called, then you will end up corrupting your data. You also have to let the compiler know that the variable should never be assumed to be what is cached in an internal register - it should always use the value in memory.

The second thing there is tackled by adding the "volatile" keyword when defining your variable:

volatile int pulseCount = 0;

The first, and more overlooked, problem is to place a cli(); before, and a sei(); after any access to the variables in question:

  cli();
  printVal = pulseCount * 60;
  pulseCount = 0;
  sei();

That will delay the interrupt from running while you are modifying the value outside the interrupt.

So the code should look like this:

#include <PinChangeInt.h>

volatile int pulseCount = 0;
int inPin = 2;
int printVal = 0;

void pulseFunc(){
  pulseCount = pulseCount + 1;
  
}

void setup(){
 pinMode(inPin, INPUT); 
 PCintPort::attachInterrupt(inPin, &pulseFunc, RISING);
 Serial.begin(9600); 
}



void loop(){
  cli();
  printVal = pulseCount * 60;
  pulseCount = 0;
  sei();
  Serial.println(printVal, DEC);
    
  delay(1000);
  
  
}

Looks good to me.

It works. But when i conected a small 5v fan it gets me very high numbers, i read somewere that the fan gives 2 pulses per round. So instead of 7200 rpm, the fan does 3600? Or what do you think?

I had that with a fan once - had to divide by 2 to get the real number.

himym:
It works. But when i conected a small 5v fan it gets me very high numbers, i read somewere that the fan gives 2 pulses per round. So instead of 7200 rpm, the fan does 3600? Or what do you think?

2 pulses per round of a 7200rpm fan would be 14400ppm (pulse per minute). Divide by 60 gives 240pps (pulse per second)

Riva:

himym:
It works. But when i conected a small 5v fan it gets me very high numbers, i read somewere that the fan gives 2 pulses per round. So instead of 7200 rpm, the fan does 3600? Or what do you think?

2 pulses per round of a 7200rpm fan would be 14400ppm (pulse per minute). Divide by 60 gives 240pps (pulse per second)

No, I think you misuderstand... He's measuring it at 7200 when in reality it's 3600 (which is a normal kind of figure for a small BLDC fan).

majenko:

Riva:

himym:
It works. But when i conected a small 5v fan it gets me very high numbers, i read somewere that the fan gives 2 pulses per round. So instead of 7200 rpm, the fan does 3600? Or what do you think?

2 pulses per round of a 7200rpm fan would be 14400ppm (pulse per minute). Divide by 60 gives 240pps (pulse per second)

No, I think you misuderstand... He's measuring it at 7200 when in reality it's 3600 (which is a normal kind of figure for a small BLDC fan).

Sorry, having a blond moment there. :slight_smile:

I now wanted to add that i could controll the fan with pwm. So i added this code. But it didn't work. Any idea? Becuase it works when I just use the serial read part.

#include <PinChangeInt.h>

volatile int pulseCount = 0;
int inPin = 2;
int pwmPin = 9;
int printVal = 0;
int pwmVal = 0;

void pulseFunc(){
  pulseCount = pulseCount + 1;

}

void setup(){
  pinMode(inPin, INPUT); 
  pinMode(pwmPin, OUTPUT);
  PCintPort::attachInterrupt(inPin, &pulseFunc, RISING);
  Serial.begin(9600); 
}



void loop(){
  cli();
  printVal = pulseCount * 60 / 2;
  pulseCount = 0;
  sei();
  Serial.println(printVal, DEC);
 
//This is the new part
  if(Serial.available() > 0 ){
    pwmVal = Serial.read(); 
    analogWrite(pwmPin, pwmVal); 
  }

  delay(1000);

Pin Change Interrupt does not let you select which edge to trigger with. It only works on change in pin state. OTOH you can trigger PCint through software by writing to the port register.

PCintPort::attachInterrupt(inPin, &pulseFunc, RISING); // RISING here is not correct