Servicing Two Interrupts on a MEGA2560....(Int1 Fails)

OK,… I’m not an expert,… I always consider my self a learner,… but I am really baffled as to what is going on with my code and why it will not reading the fan speed on INT1, on the 2560. INT0 counting works fine and I get lots of clock pulses in order to calculate RPM,… however INT1 does not want to seem to play ball, even though I have verified the clock signal is present on Pin3,… there just does not seem to be enough counts going in,… I wondered if it was the INT0 was taking priority,… but not the case,… as I have left INT0 disabled and INT1 counts are still way too low…
Have included snippets of code,… and attached full listing a full code is too big.

The essence of the code is it counts pulse ( from fan ) for a cycle ( approx 22seconds ) the calculates the speed from the number of pulses / by time…

Am I missing the obvious,… any suggestions gratefully received:-

thanks for looking

Code as follows

volatile unsigned long rpmCHcount = 0;//see http://arduino.cc/en/Reference/Volatile
volatile unsigned long SwitchRPMcounter = 0;
//float rpmCH0 = 0;
//float rpmSW1 = 0;
volatile unsigned long lastmillisCH0 = 0;
volatile unsigned long lastmillisSW1 = 0;


float FanRPM[3];
int FanSpeed[3] = {0, 0, 0 };
int PercentSpeed[3];

// ----------------------------
void CHrpm(){ /* this code will be executed every time the interrupt 0 (pin2) gets low.*/
  rpmCHcount++;
}

void SwitchRPM(){ /* this code will be executed every time the interrupt 1 (pin3) gets low.*/
  SwitchRPMcounter++;
}

------------------------------------
// Fan Setup ---------------
  pinMode(2, INPUT);	   // Pin 2 is input to which a switch is connected = INT0
  pinMode(3, INPUT);
  attachInterrupt(0, CHrpm, RISING);    // enable the interrupt
  attachInterrupt(1, SwitchRPM, RISING);    // enable the interrupt


---------------------------------------


void GetFanFrequency(byte ISRindx)
{
  float MillsTime;
  Serial.print("CH RPM >");
  Serial.println(rpmCHcount);
  
  Serial.print("SW RPM >");
  Serial.println(SwitchRPMcounter);
   
  if ( ISRindx == 0 )
  {

    if (millis() - lastmillisCH0 > 1000) 
    { /*Uptade every one second, this will be equal to reading frecuency (Hz).*/

      detachInterrupt(0);    //Disable interrupt when calculating

      MillsTime = millis() - lastmillisCH0;

      FanRPM[0] = ( rpmCHcount / ( MillsTime / 1000 ) ) * 30;  /* Convert frecuency to RPM, note: this works for one
      // interruption per full rotation. For two interrups per full rotation use rpmcount * 30.*/

      rpmCHcount = 0;         // Restart the RPM counter
      lastmillisCH0 = millis();  // Update lasmillis
      
      attachInterrupt(0, CHrpm, FALLING); //enable interrupt
    }

  }

  // -------------------------------------

  if ( ISRindx == 1 )
  {

    if (millis() - lastmillisSW1 > 1000) 
    { /*Update every one second, this will be equal to reading frecuency (Hz).*/

      detachInterrupt(1);          //Disable interrupt when calculating
      
      Serial.print("Mills >");
      Serial.println(millis());

      Serial.print("Last Mills >");
      Serial.println(lastmillisSW1);

      MillsTime = millis() - lastmillisSW1;
      
      Serial.print("Millis() - Last Mills >");
      Serial.println(MillsTime);

      Serial.print("rpm SW Count >");
      Serial.println(SwitchRPMcounter); 

      FanRPM[1] = ( SwitchRPMcounter / ( MillsTime / 1000 ) ) * 30;  /* Convert frecuency to RPM, note: this works for one
      // interruption per full rotation. For two interrups per full rotation use rpmcount * 30.*/

      SwitchRPMcounter = 0;             // Restart the RPM counter
      lastmillisSW1 = millis();   // Update lasmillis
      
      attachInterrupt(1, SwitchRPM, FALLING); //enable interrupt
    }

  }

  Serial.print("Stored 0 RPM >");
  Serial.println(FanRPM[0]);
  
  Serial.print("Stored 1 RPM >");
  Serial.println(FanRPM[1]);
  
}

RadFanV33.ino (22.7 KB)

void SwitchRPM(){ /* this code will be executed every time the interrupt 1 (pin3) gets low.*/
  SwitchRPMcounter++;

Then WHY does attachInterrupt() use RISING? Sometimes, the best thing to do with useless comments is to delete them.

  float MillsTime;

Nonsense. Not only does millis() NOT return a float, the name means nothing. fhzdfjdsj wouls be an equally good name.

Detaching and attaching interrupts is not the same as disabling and enabling interrupts. The latter is faster and preferred.

PaulS: Detaching and attaching interrupts is not the same as disabling and enabling interrupts. The latter is faster and preferred.

Yes, but if he disables and then tries to do all those Serial prints he may run into some problems.

You should try to have your interrupts disabled for as short a time as possible. Disable them, read the values you want out into temporary variables, and then re-enable them. Then after all the work is done you can sit back and print stuff out to the Serial.

Tx Guys,.. I have set all the attachInterrupt calls to use RISING,.. and set the function millis() to write to an unsigned long,... Although it was working in the INT0 function,... but point taken, what I had was wrong. Anyway,.. disabling ALL interrupts with CLI SEI etc,.. during one part of routine,.. would prevent interrupts on the other fan being counted,... as far as I can work out in my way of thinking,.. ( but this is limited Arduino knowledge I have to say ).

Printing during the function,.. is purely for debug,... once counting is correct I plan to remove it... once I find out where all my clock pulses have gone on INT1.

Your point about comments,... do they get complied into the code,.. I assumed they are stripped at compile, before downloading the exe?

disabling ALL interrupts with CLI SEI etc,… during one part of routine,… would prevent interrupts on the other fan being counted,.

That’s not what PaulS meant.

If (and its a biginners error to think that you do) you really do need to turn off an interrupt then you do it just for that interrupt not for the whole M/C.

You can set/clear the right bit in the interrupt control register or use a flag in the ISR its self.

Mark

You can set/clear the right bit in the interrupt control register or use a flag in the ISR its self.

Ah sorry,.. understand what you are saying... is this quicker than attachInterrupt/detachInterrupt routine then??

Anyway further work on test rig seems to show that INT1 is pulled LOW,..... if I disconnect my input signal from the fan,.. there's lots of nice pulses.... Connect lead to pin3 on Ardiuno board... and its like tying into a short,....

Do I need

  pinMode(2, INPUT);
  pinMode(3, INPUT);

Don't know why INT1 seems to be pulled Low,.. as daughter board does not appear to have short....

Rgrds

I have tried the following (cut-down) program on both an UNO and a Mega2560,.. and the apparent short to ground is the same.

the daughter board does not ring out for any shorts... unless I'm missing the obvious...

volatile unsigned long rpmCHcount = 0;//see http://arduino.cc/en/Reference/Volatile
volatile unsigned long SwitchRPMcounter = 0;
volatile unsigned long lastmillisCH0 = 0;
volatile unsigned long lastmillisSW1 = 0;

unsigned long MillsTime;
float FanRPM[3];

void CHrpm() { /* this code will be executed every time the interrupt 0 (pin2) gets low.*/
  rpmCHcount++;
}

void SwitchRPM() { /* this code will be executed every time the interrupt 1 (pin3) gets low.*/
  SwitchRPMcounter++;
}


void setup() {
  // put your setup code here, to run once:
  Serial.begin(38400);       // Used to type in characters
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  
  Serial.println("Setting Fan speeds");
  analogWrite( 5 , 15);
  analogWrite( 9 , 15);
}

void loop() {
  // put your main code here, to run repeatedly:
  delay(2000);
  Serial.println("Running Loop");
//  GetFanFrequency(0);

  GetFanFrequency(1);
  
  Serial.print("\n\n\n");
}


void GetFanFrequency(byte ISRindx)
{

  Serial.print("CH RPM >");
  Serial.println(rpmCHcount);
  
  Serial.print("SW RPM >");
  Serial.println(SwitchRPMcounter);
   
  if ( ISRindx == 0 )
  {

    if (millis() - lastmillisCH0 > 1000) 
    { /*Uptade every one second, this will be equal to reading frecuency (Hz).*/

      detachInterrupt(0);    //Disable interrupt when calculating

      MillsTime = millis() - lastmillisCH0;

      FanRPM[0] = ( rpmCHcount / ( MillsTime / 1000 ) ) * 30;  /* Convert frecuency to RPM, note: this works for one
      // interruption per full rotation. For two interrups per full rotation use rpmcount * 30.*/

      rpmCHcount = 0;         // Restart the RPM counter
      lastmillisCH0 = millis();  // Update lasmillis
      
      attachInterrupt(0, CHrpm, RISING); //enable interrupt
    }

  }

  // -------------------------------------

  if ( ISRindx == 1 )
  {

    if (millis() - lastmillisSW1 > 1000) 
    { /*Update every one second, this will be equal to reading frecuency (Hz).*/

      detachInterrupt(1);          //Disable interrupt when calculating
      
      Serial.print("Mills >");
      Serial.println(millis());

      Serial.print("Last Mills >");
      Serial.println(lastmillisSW1);

      MillsTime = millis() - lastmillisSW1;
      
      Serial.print("Millis() - Last Mills >");
      Serial.println(MillsTime);

      Serial.print("rpm SW Count >");
      Serial.println(SwitchRPMcounter); 

      FanRPM[1] = ( SwitchRPMcounter / ( MillsTime / 1000 ) ) * 30;  /* Convert frecuency to RPM, note: this works for one
      // interruption per full rotation. For two interrups per full rotation use rpmcount * 30.*/

      SwitchRPMcounter = 0;             // Restart the RPM counter
      lastmillisSW1 = millis();         // Update lasmillis
      
      attachInterrupt(1, SwitchRPM, RISING); //enable interrupt
    }

  }

  Serial.print("Stored 0 RPM >");
  Serial.println(FanRPM[0]);
  
  Serial.print("Stored 1 RPM >");
  Serial.println(FanRPM[1]);
  
}

unless I'm missing the obvious...

Like actually attaching the interrupt handlers in setup()?

Like making the comments match what the code actually does?

Do you have pullup or pulldown resistors on those interrupt lines?

well added

attachInterrupt(0, CHrpm, RISING); //enable interrupt
 attachInterrupt(1, SwitchRPM, RISING); //enable interrupt

To the setup portion of the code and that does not appear to make any difference... ( INT0) was and still is working,.. ) but this would not be the first funny. But point taken I need to attach the interrupt handlers during setup.

have not tried pull-ups as yet as my clk signal drives high and low,.. ie it is not open collector... Drive signal is derived from a 74AC14,.. schmitt trigger.. and as far as I can tell the data sheet shows output is driven high and low,.. so I don't believe I need pull-ups, and my signal goes more or less between the rails,.. ( less than 100mv off ).

Tx & Rgds

diyhouse: so I don't believe I need pull-ups.

But you're not getting pulses.

No, not yet,.... but the hex schmitt drives a good signal which I can see on a scope,.. when I attach it to Pin3 ( INT1 ) it basically pulls it to ground, ( well within a few milli-Volts ). and INT0 works perfectly...

Tried a 5K6 pull-up... no change... hummmm back to the drawing board

Does the functioning interrupt change if you swap wires going to pins 2 and 3?

Have not tried swapping signals around but the output from the 7414 is good on both channels,.. its just when I connect the one to INT1 aka pin3 on the 2560 it gets pulled to ground,.. and the 7414 starts to get warm as the power is dissipated....

I have tried running the blink prog,... and toggling the state of pin2 and 3,.. and without a load it certainly changes state,.. I was concerned is was shorted internally to ground,..

So in my small uneducated Arduino world,.. something is configuring Pin3 to ground, is this possible.

Am I right in using INT (Zero) and INT (ONE),... as pins 2 and 3 respectively on the mega2560?

Tx

Am I right in using INT (Zero) and INT (ONE),... as pins 2 and 3 respectively on the mega2560?

From the Mega page:

External Interrupts: 2 (interrupt 0), 3 (interrupt 1), 18 (interrupt 5), 19 (interrupt 4), 20 (interrupt 3), and 21 (interrupt 2). These pins can be configured to trigger an interrupt on a low level, a rising or falling edge, or a change in level. See the attachInterrupt() function for details.

Think I might have discovered the problem,.... when my daughter board is plugged in to the Arduino ( either Mega or UNO ),... there seems to be a 10R load to ground from the sense pin on the plug/pin I use for the fan input...

When the daughter board is not plugged in, the connection is completely open,.. so hence my assumption,... that all was fine with board.

Need some more time to get to the bottom of this....

but thanks for input though,... was sort of getting a little baffled

Sussed-it,....

During my playing on a previous iteration at the breadboard stage,.. it would seem I swapped the connection wires for Gnd and sense return,.... so although the daughter board itself was fine,.. when I connected all my connecting cables up,.. ( to the fan driver board ),.. then the problem occurred....

Connecting cable sorted,.. things seem to be behaving themselves...

thanks again,. for input,.. I have tidied up some s/w things that I had wrong, and not quite correct...

rgds