Go Down

Topic: Traction Control for Motorcycle using hall sensors to measure wheel speed. (Read 1 time) previous topic - next topic

akmcgregor

Hi, I am very new to programming and am unable to duplicate a code to read two wheel sensors. Through many weeks of research I have come up with a code to accurately measure the RPM of one wheel sensor using a hall sensor connected through the interrupt pin (0) which later I will convert to KM/H. I am using a timer to measure between interrupts to calculate RPM. I can't seem to work out how to attach another interrupt (1) to read the second sensor.

Below I have included the code I am using for one sensor (which is working) as well as the code I have attempted for two sensors (which is not).

If someone can please point me in the right direction I would be forever grateful.

P.S. I have searched for many hours but cannot find any examples of how to connect a second interrupt.

aarg

Unless the sketch is too large, it's better if you post your code, rather than attach it. When it's attached, we have to download it, create a folder then open your code in our IDE. And afterwards, the folder remains unless we navigate to the "Temp" folder and manually remove it. It's much easier to just view the code in your post.

Please post your code using code tags. The code tags make the code look
Code: [Select]
like this
when posting source code files. It makes it easier to read, and can be copied with a single mouse click. Also, if you don't do it, some of the character sequences in the code can be misinterpreted by the forum code as italics or funny emoticons.
  ... with a transistor and a large sum of money to spend ...
Please don't PM me with technical questions. Post them in the forum.

PaulS

Quote
P.S. I have searched for many hours but cannot find any examples of how to connect a second interrupt.
Interrupt 0 is on pin 2. Interrupt 1 is on pin 3. The process for attaching an interrupt handler to interrupt vector 1 is exactly the same as attaching to interrupt vector 0.
The art of getting good answers lies in asking good questions.

akmcgregor

Code: [Select]

extern volatile unsigned long timer0_overflow_count;  // Record the most recent timer ticks
volatile boolean ticks_valid;                         // Indicates a valid reading
volatile unsigned long ticks_per_rev;                 // Number of ticks counted in the current revolution
unsigned long msSinceRPMReading;                      // Number of mSec since the last rpm_sense (used to spot zero RPM)
float lastRPM;                                        // Most recent RPM reading, and highest RPM recorded since last reset

const float __TICKS_TO_RPMS = 15e6;                   // Convert clock ticks to RPM by dividng ticks into this number
                                                      // The number will change if there are more magnets in an rpm
                                                      //   (e.g. 2 magnets = 29296.875)
const unsigned int __WAIT_BEFORE_ZERO_RPM = 2000;     // Number of mS to wait for an rpm_sense before assunming RPM = 0.

unsigned long msSinceSend;                            // mSec when the last data was sent to the serial port
const unsigned int __WAIT_BETWEEN_SENDS = 1000;       // Number of mS to wait before sending a batch of data.
float kmh;

void setup()
{

  Serial.begin(9600);                                 // Initialise serial comms.
  msSinceSend = millis();                             // Data sent counter

  attachInterrupt(0, rpm_sense, RISING);              // RPM sense will cause an interrupt on pin2
  msSinceRPMReading = 0;                              // If more than 2000 (i.e. 2 seconds),
                                                      // then RPMs can be assumed to be zero (< 15rpm
                                                      // at most, with a single magnet, no small IC
                                                      // can run that slowly).
  lastRPM = 0;                                        // Current RPM to zero
  
 }

// ------------------------------------------------------------------------------------------------
// FUNCTION: RPM-SENSE
//
// Called whenever the RPM sense signal rises. In my setup, the hall effect switch is normally
// high, goes low when a south pole is introduced to the sensor, and rises back to high as the
// magnet goes away. Thus, the RPM sense is called on the trailing edge of the magnet.
// ------------------------------------------------------------------------------------------------
void rpm_sense()
{
  static unsigned long pre_count;               // Last timer0_overflow_count value
  unsigned long ticks_now;                      //

  ticks_now = timer0_overflow_count;            // Read the timer

  byte t = TCNT0;
  if ((TIFR0 & _BV(TOV0)) && (t<255))
    ticks_now++;
  ticks_now = (ticks_now << 8) + t;

  if (pre_count == 0) {                         // First time around the loop?
    pre_count = ticks_now;                      // Yes - set the precount, don't use this number.
  } else {
    ticks_per_rev = ticks_now - pre_count;      // No - calculate the number of ticks...
    pre_count = ticks_now;                      // ...reset the counter...
    ticks_valid = true;                         // ...and flag the change up.
  }
}

void loop()
{
  unsigned long thisMillis = millis();          // Read the time once

  // Calculate RPM
  if (ticks_valid) {                            // Only come here if we have a valid RPM reading
    unsigned long thisTicks;
    
    noInterrupts();
    thisTicks = ticks_per_rev;
    ticks_valid = false;
    interrupts();
    
    lastRPM = __TICKS_TO_RPMS / thisTicks;      // Convert ticks to RPMs
    ticks_valid = false;                        // Reset the flag.
    msSinceRPMReading = thisMillis;             // Set the time we read the RPM.
    
  } else {
    // No tick this loop - is it more than X seconds since the last one?
    if (thisMillis - msSinceRPMReading > __WAIT_BEFORE_ZERO_RPM) {
      lastRPM = 0;                              // At least 2s since last RPM-sense, so assume zero RPMs
      msSinceRPMReading = thisMillis;           // Reset counter
    }
  }
 
  kmh = (lastRPM * 1.8 * 60 / 1000);
  
  // Is it time to send the data?
  if (thisMillis < msSinceSend)                  // If thisMillis has recycled, reset it
    msSinceSend = millis();
    
  if (thisMillis - msSinceSend > __WAIT_BETWEEN_SENDS) {
    // Yes: Build the serial output...
    
    Serial.print("RPMs = \t");
    Serial.print(lastRPM);                       // Current RPMs
    Serial.print("\t KM/H \t");
    Serial.print(kmh);
    Serial.println();                            // EOL.

    msSinceSend = millis();                      // Reset the timer
    
  }  }

akmcgregor

Code: [Select]

extern volatile unsigned long timer0_overflow_count;  // Record the most recent timer ticks
extern volatile unsigned long timer1_overflow_count;  // Record the most recent timer1 ticks
volatile boolean ticks_valid;                         // Indicates a valid reading
volatile boolean ticks_valid1;                        // Indicates a valid reading
volatile unsigned long ticks_per_rev;                 // Number of ticks counted in the current revolution
volatile unsigned long ticks_per_rev1;                // Number of ticks counted in the current revolution
unsigned long msSinceRPMReading;                      // Number of mSec since the last rpm_sense (used to spot zero RPM)
unsigned long msSinceRPMReading1;                     // Number of mSec since the last rpm_sense1 (used to spot zero RPM)
float lastRPM;                                        // Most recent RPM reading recorded since last reset
float lastRPM1;                                       // Most recent RPM1 reading recorded since last reset

const float __TICKS_TO_RPMS = 15e6;                   // Convert clock ticks to RPM by dividng ticks into this number
                                                      // The number will change if there are more magnets in an rpm
                                                      //   (e.g. 2 magnets = 29296.875)

const float __TICKS_TO_RPMS1 = 15e6;                  // Convert clock ticks to RPM by dividng ticks into this number
                                                      // The number will change if there are more magnets in an rpm
                                                      //   (e.g. 2 magnets = 29296.875)

const unsigned int __WAIT_BEFORE_ZERO_RPM = 2000;     // Number of mS to wait for an rpm_sense before assunming RPM = 0.
const unsigned int __WAIT_BEFORE_ZERO_RPM1 = 2000;    // Number of mS to wait for an rpm_sense before assunming RPM = 0.

unsigned long msSinceSend;                            // mSec when the last data was sent to the serial port

const unsigned int __WAIT_BETWEEN_SENDS = 1000;       // Number of mS to wait before sending a batch of data.


void setup()
{
  Serial.begin(9600);                                 // Initialise serial comms.
  msSinceSend = millis();                             // Data sent counter

  attachInterrupt(0, rpm_sense, RISING);              // RPM sense will cause an interrupt on pin2
  msSinceRPMReading = 0;                              // If more than 2000 (i.e. 2 seconds),
                                                      // then RPMs can be assumed to be zero (< 15rpm
                                                      // at most, with a single magnet, no small IC
                                                      // can run that slowly).
  lastRPM = 0;                                        // Current RPM to zero
}

  attachInterrupt(0, rpm_sense, RISING);              // RPM sense will cause an interrupt on pin2
  msSinceRPMReading = 0;                              // If more than 2000 (i.e. 2 seconds),
                                                      // then RPMs can be assumed to be zero (< 15rpm
                                                      // at most, with a single magnet, no small IC
                                                      // can run that slowly).
  lastRPM = 0;                                        // Current RPM to zero
}

// ------------------------------------------------------------------------------------------------
// FUNCTION: RPM-SENSE
//
// Called whenever the RPM sense signal rises. In my setup, the hall effect switch is normally
// high, goes low when a south pole is introduced to the sensor, and rises back to high as the
// magnet goes away. Thus, the RPM sense is called on the trailing edge of the magnet.
// ------------------------------------------------------------------------------------------------
void rpm_sense()
{
  static unsigned long pre_count;               // Last timer0_overflow_count value
  unsigned long ticks_now;                      //

  ticks_now = timer0_overflow_count;            // Read the timer

  byte t = TCNT0;
  if ((TIFR0 & _BV(TOV0)) && (t<255))
    ticks_now++;
  ticks_now = (ticks_now << 8) + t;

  if (pre_count == 0) {                         // First time around the loop?
    pre_count = ticks_now;                      // Yes - set the precount, don't use this number.
  } else {
    ticks_per_rev = ticks_now - pre_count;      // No - calculate the number of ticks...
    pre_count = ticks_now;                      // ...reset the counter...
    ticks_valid = true;                         // ...and flag the change up.
  }
}

void rpm_sense1()
{
  static unsigned long pre_count1;               // Last timer1_overflow_count value
  unsigned long ticks_now1;                      //

  ticks_now1 = timer1_overflow_count;            // Read the timer1

  byte t = TCNT1;
  if ((TIFR1 & _BV(TOV1)) && (t<255))
    ticks_now1++;
  ticks_now1 = (ticks_now1 << 8) + t;

  if (pre_count1 == 0) {                         // First time around the loop?
    pre_count11 = ticks_now;                      // Yes - set the precount, don't use this number.
  } else {
    ticks_per_rev1 = ticks_now1 - pre_count1;      // No - calculate the number of ticks...
    pre_count1 = ticks_now1;                      // ...reset the counter...
    ticks_valid1 = true;                         // ...and flag the change up.
  }
}


void loop()
{
  unsigned long thisMillis = millis();          // Read the time once

  // Calculate RPM
  if (ticks_valid) {                            // Only come here if we have a valid RPM reading
    unsigned long thisTicks;
    
    noInterrupts();
    thisTicks = ticks_per_rev;
    ticks_valid = false;
    interrupts();
    
    lastRPM = __TICKS_TO_RPMS / thisTicks;      // Convert ticks to RPMs
    ticks_valid = false;                        // Reset the flag.
    msSinceRPMReading = thisMillis;             // Set the time we read the RPM.
    
  } else {
    // No tick this loop - is it more than X seconds since the last one?
    if (thisMillis - msSinceRPMReading > __WAIT_BEFORE_ZERO_RPM) {
      lastRPM = 0;                              // At least 2s since last RPM-sense, so assume zero RPMs
      msSinceRPMReading = thisMillis;           // Reset counter
    }
  }

{
  unsigned long thisMillis1 = millis();          // Read the time once

  // Calculate RPM
  if (ticks_valid) {                            // Only come here if we have a valid RPM reading
    unsigned long thisTicks1;
    
    noInterrupts();
    thisTicks1 = ticks_per_rev1;
    ticks_valid1 = false;
    interrupts();
    
    lastRPM1 = __TICKS_TO_RPMS1 / thisTicks1;      // Convert ticks to RPMs
    ticks_valid = false;                        // Reset the flag.
    msSinceRPMReading1 = thisMillis1;             // Set the time we read the RPM.
    
  } else {
    // No tick this loop - is it more than X seconds since the last one?
    if (thisMillis1 - msSinceRPMReading1 > __WAIT_BEFORE_ZERO_RPM) {
      lastRPM1 = 0;                              // At least 2s since last RPM-sense, so assume zero RPMs
      msSinceRPMReading1 = thisMillis1;           // Reset counter
    }
  }

 
  // Is it time to send the data?
  if (thisMillis < msSinceSend)                  // If thisMillis has recycled, reset it
    msSinceSend = millis();
    
  if (thisMillis - msSinceSend > __WAIT_BETWEEN_SENDS) {
    // Yes: Build the serial output...
    
      // Is it time to send the data?
  if (thisMillis1 < msSinceSend1)                  // If thisMillis has recycled, reset it
    msSinceSend1 = millis();
    
  if (thisMillis1 - msSinceSend1 > __WAIT_BETWEEN_SENDS) {
    // Yes: Build the serial output...
    
    
    Serial.print("RPMs = \t");
    Serial.print(lastRPM);                       // Current RPMs
    Serial.print("\t RPMs = \t");
    Serial.print(lastRPM1);                       // Current RPMs
    Serial.println();                            // EOL.
    
    msSinceSend = millis();                      // Reset the timer
    msSinceSend1 = millis();                      // Reset the timer

    
  }  }

PaulS

Code: [Select]
extern volatile unsigned long timer0_overflow_count;  // Record the most recent timer ticks
extern volatile unsigned long timer1_overflow_count;  // Record the most recent timer1 ticks
volatile boolean ticks_valid;                         // Indicates a valid reading
volatile boolean ticks_valid1;                        // Indicates a valid reading
volatile unsigned long ticks_per_rev;                 // Number of ticks counted in the current revolution
volatile unsigned long ticks_per_rev1;     

If the variables for the interrupt handler on vector 1 get a 1 in the name, the ones for the interrupt handler on vector 0 should have a 0 in the name.

Code: [Select]
  attachInterrupt(0, rpm_sense, RISING);              // RPM sense will cause an interrupt on pin2
  msSinceRPMReading = 0;

Why is this not in setup()?

You can NOT use the same handler for both interrupts.
The art of getting good answers lies in asking good questions.

aarg

Quote
Normally you should use digitalPinToInterrupt(pin), rather than place an interrupt number directly into your sketch. The specific pins with interrupts, and their mapping to interrupt number varies on each type of board. Direct use of interrupt numbers may seem simple, but it can cause compatibility trouble when your sketch is run on a different board.
https://www.arduino.cc/en/Reference/AttachInterrupt
  ... with a transistor and a large sum of money to spend ...
Please don't PM me with technical questions. Post them in the forum.

akmcgregor

Code: [Select]

extern volatile unsigned long timer0_overflow_count;  // Record the most recent timer ticks
extern volatile unsigned long timer1_overflow_count;  // Record the most recent timer1 ticks
volatile boolean ticks_valid;                         // Indicates a valid reading
volatile boolean ticks_valid1;                        // Indicates a valid reading
volatile unsigned long ticks_per_rev;                 // Number of ticks counted in the current revolution
volatile unsigned long ticks_per_rev1;                // Number of ticks counted in the current revolution
unsigned long msSinceRPMReading;                      // Number of mSec since the last rpm_sense (used to spot zero RPM)
unsigned long msSinceRPMReading1;                     // Number of mSec since the last rpm_sense1 (used to spot zero RPM)
float lastRPM;                                        // Most recent RPM reading recorded since last reset
float lastRPM1;                                       // Most recent RPM1 reading recorded since last reset

const float __TICKS_TO_RPMS = 15e6;                   // Convert clock ticks to RPM by dividng ticks into this number
// The number will change if there are more magnets in an rpm
//   (e.g. 2 magnets = 29296.875)

const float __TICKS_TO_RPMS1 = 15e6;                  // Convert clock ticks to RPM by dividng ticks into this number
// The number will change if there are more magnets in an rpm
//   (e.g. 2 magnets = 29296.875)

const unsigned int __WAIT_BEFORE_ZERO_RPM = 2000;     // Number of mS to wait for an rpm_sense before assunming RPM = 0.
const unsigned int __WAIT_BEFORE_ZERO_RPM1 = 2000;    // Number of mS to wait for an rpm_sense before assunming RPM = 0.

unsigned long msSinceSend;                            // mSec when the last data was sent to the serial port
unsigned long msSinceSend1;

const unsigned int __WAIT_BETWEEN_SENDS = 1000;       // Number of mS to wait before sending a batch of data.
const unsigned int __WAIT_BETWEEN_SENDS1 = 1000;


attachInterrupt(digitalPinToInterrupt(2), rpm_sense, RISING);              // RPM sense will cause an interrupt on pin2
msSinceRPMReading = 0;                              // If more than 2000 (i.e. 2 seconds),
// then RPMs can be assumed to be zero (< 15rpm
// at most, with a single magnet, no small IC
// can run that slowly).
lastRPM = 0;                                        // Current RPM to zero

attachInterrupt(digitalPinToInterrupt(3), rpm_sense1, RISING);              // RPM sense will cause an interrupt on pin3
msSinceRPMReading1 = 0;                              // If more than 2000 (i.e. 2 seconds),
// then RPMs can be assumed to be zero (< 15rpm
// at most, with a single magnet, no small IC
// can run that slowly).
lastRPM1 = 0;                                        // Current RPM to zero

void setup()
{
  Serial.begin(9600);                                 // Initialise serial comms.
  msSinceSend = millis();                             // Data sent counter

  msSinceSend1 = millis();

}
// ------------------------------------------------------------------------------------------------
// FUNCTION: RPM-SENSE
//
// Called whenever the RPM sense signal rises. In my setup, the hall effect switch is normally
// high, goes low when a south pole is introduced to the sensor, and rises back to high as the
// magnet goes away. Thus, the RPM sense is called on the trailing edge of the magnet.
// ------------------------------------------------------------------------------------------------
void rpm_sense()
{
  static unsigned long pre_count;               // Last timer0_overflow_count value
  unsigned long ticks_now;                      //

  ticks_now = timer0_overflow_count;            // Read the timer

  byte t = TCNT0;
  if ((TIFR0 & _BV(TOV0)) && (t < 255))
    ticks_now++;
  ticks_now = (ticks_now << 8) + t;

  if (pre_count == 0) {                         // First time around the loop?
    pre_count = ticks_now;                      // Yes - set the precount, don't use this number.
  } else {
    ticks_per_rev = ticks_now - pre_count;      // No - calculate the number of ticks...
    pre_count = ticks_now;                      // ...reset the counter...
    ticks_valid = true;                         // ...and flag the change up.
  }
}

void rpm_sense1()
{
  static unsigned long pre_count1;               // Last timer1_overflow_count value
  unsigned long ticks_now1;                      //

  ticks_now1 = timer1_overflow_count;            // Read the timer1

  byte t = TCNT1;
  if ((TIFR1 & _BV(TOV1)) && (t < 255))
    ticks_now1++;
  ticks_now1 = (ticks_now1 << 8) + t;

  if (pre_count1 == 0) {                         // First time around the loop?
    pre_count11 = ticks_now;                      // Yes - set the precount, don't use this number.
  } else {
    ticks_per_rev1 = ticks_now1 - pre_count1;      // No - calculate the number of ticks...
    pre_count1 = ticks_now1;                      // ...reset the counter...
    ticks_valid1 = true;                         // ...and flag the change up.
  }
}


void loop()
{
  unsigned long thisMillis = millis();          // Read the time once

  // Calculate RPM
  if (ticks_valid) {                            // Only come here if we have a valid RPM reading
    unsigned long thisTicks;

    noInterrupts();
    thisTicks = ticks_per_rev;
    ticks_valid = false;
    interrupts();

    lastRPM = __TICKS_TO_RPMS / thisTicks;      // Convert ticks to RPMs
    ticks_valid = false;                        // Reset the flag.
    msSinceRPMReading = thisMillis;             // Set the time we read the RPM.

  } else {
    // No tick this loop - is it more than X seconds since the last one?
    if (thisMillis - msSinceRPMReading > __WAIT_BEFORE_ZERO_RPM) {
      lastRPM = 0;                              // At least 2s since last RPM-sense, so assume zero RPMs
      msSinceRPMReading = thisMillis;           // Reset counter
    }
  }

  {
    unsigned long thisMillis1 = millis();          // Read the time once

    // Calculate RPM
    if (ticks_valid) {                            // Only come here if we have a valid RPM reading
      unsigned long thisTicks1;

      noInterrupts();
      thisTicks1 = ticks_per_rev1;
      ticks_valid1 = false;
      interrupts();

      lastRPM1 = __TICKS_TO_RPMS1 / thisTicks1;      // Convert ticks to RPMs
      ticks_valid = false;                        // Reset the flag.
      msSinceRPMReading1 = thisMillis1;             // Set the time we read the RPM.

    } else {
      // No tick this loop - is it more than X seconds since the last one?
      if (thisMillis1 - msSinceRPMReading1 > __WAIT_BEFORE_ZERO_RPM) {
        lastRPM1 = 0;                              // At least 2s since last RPM-sense, so assume zero RPMs
        msSinceRPMReading1 = thisMillis1;           // Reset counter
      }
    }


    // Is it time to send the data?
    if (thisMillis < msSinceSend)                  // If thisMillis has recycled, reset it
      msSinceSend = millis();

    if (thisMillis - msSinceSend > __WAIT_BETWEEN_SENDS) {
      // Yes: Build the serial output...

      // Is it time to send the data?
      if (thisMillis1 < msSinceSend1)                  // If thisMillis has recycled, reset it
        msSinceSend1 = millis();

      if (thisMillis1 - msSinceSend1 > __WAIT_BETWEEN_SENDS) {
        // Yes: Build the serial output...


        Serial.print("RPMs = \t");
        Serial.print(lastRPM);                       // Current RPMs
        Serial.print("\t RPMs = \t");
        Serial.print(lastRPM1);                       // Current RPMs
        Serial.println();                            // EOL.

        msSinceSend = millis();                      // Reset the timer
        msSinceSend1 = millis();                      // Reset the timer


      }
    }


This is the new code with a few errors fixed. If you can see what I did, which was just duplicate the first code. Is this the correct way to go about it or am I on the wrong track? I cannot find any info about using two interrupts on two different pins.

Thanks

akmcgregor

This is my latest attempt. I believe it should work but comes up with an error message

"Exit status 1 error compiling for board"

What does this mean?

Code: [Select]

extern volatile unsigned long timer0_overflow_count;  // Record the most recent timer ticks
extern volatile unsigned long timer1_overflow_count;  // Record the most recent timer1 ticks
volatile boolean ticks_valid;                         // Indicates a valid reading
volatile boolean ticks_valid1;                        // Indicates a valid reading
volatile unsigned long ticks_per_rev;                 // Number of ticks counted in the current revolution
volatile unsigned long ticks_per_rev1;                // Number of ticks counted in the current revolution
unsigned long msSinceRPMReading;                      // Number of mSec since the last rpm_sense (used to spot zero RPM)
unsigned long msSinceRPMReading1;                     // Number of mSec since the last rpm_sense1 (used to spot zero RPM)
float lastRPM;                                        // Most recent RPM reading recorded since last reset
float lastRPM1;                                       // Most recent RPM1 reading recorded since last reset

const float __TICKS_TO_RPMS = 15e6;                   // Convert clock ticks to RPM by dividng ticks into this number
// The number will change if there are more magnets in an rpm
//   (e.g. 2 magnets = 29296.875)

const float __TICKS_TO_RPMS1 = 15e6;                  // Convert clock ticks to RPM by dividng ticks into this number
// The number will change if there are more magnets in an rpm
//   (e.g. 2 magnets = 29296.875)

const unsigned int __WAIT_BEFORE_ZERO_RPM = 2000;     // Number of mS to wait for an rpm_sense before assunming RPM = 0.
const unsigned int __WAIT_BEFORE_ZERO_RPM1 = 2000;    // Number of mS to wait for an rpm_sense before assunming RPM = 0.

unsigned long msSinceSend;                            // mSec when the last data was sent to the serial port
unsigned long msSinceSend1;

const unsigned int __WAIT_BETWEEN_SENDS = 1000;       // Number of mS to wait before sending a batch of data.
const unsigned int __WAIT_BETWEEN_SENDS1 = 1000;



void setup()
{
  Serial.begin(9600);                                 // Initialise serial comms.
  msSinceSend = millis();                             // Data sent counter

  msSinceSend1 = millis();

attachInterrupt(digitalPinToInterrupt(2), rpm_sense, RISING);              // RPM sense will cause an interrupt on pin2
msSinceRPMReading = 0;                              // If more than 2000 (i.e. 2 seconds),

lastRPM = 0;                                        // Current RPM to zero

attachInterrupt(digitalPinToInterrupt(3), rpm_sense1, RISING);              // RPM sense will cause an interrupt on pin3
msSinceRPMReading1 = 0;                              // If more than 2000 (i.e. 2 seconds),

lastRPM1 = 0;                                        // Current RPM to zero
}

void rpm_sense()
{
  static unsigned long pre_count;               // Last timer0_overflow_count value
  unsigned long ticks_now;                      //

  ticks_now = timer0_overflow_count;            // Read the timer

  byte t = TCNT0;
  if ((TIFR0 & _BV(TOV0)) && (t < 255))
    ticks_now++;
  ticks_now = (ticks_now << 8) + t;

  if (pre_count == 0) {                         // First time around the loop?
    pre_count = ticks_now;                      // Yes - set the precount, don't use this number.
  } else {
    ticks_per_rev = ticks_now - pre_count;      // No - calculate the number of ticks...
    pre_count = ticks_now;                      // ...reset the counter...
    ticks_valid = true;                         // ...and flag the change up.
  }
}

void rpm_sense1()
{
  static unsigned long pre_count1;               // Last timer1_overflow_count value
  unsigned long ticks_now1;                      //

  ticks_now1 = timer1_overflow_count;            // Read the timer1

  byte t = TCNT1;
  if ((TIFR1 & _BV(TOV1)) && (t < 255))
    ticks_now1++;
  ticks_now1 = (ticks_now1 << 8) + t;

  if (pre_count1 == 0) {                         // First time around the loop?
    pre_count1 = ticks_now1;                      // Yes - set the precount, don't use this number.
  } else {
    ticks_per_rev1 = ticks_now1 - pre_count1;      // No - calculate the number of ticks...
    pre_count1 = ticks_now1;                      // ...reset the counter...
    ticks_valid1 = true;                         // ...and flag the change up.
  }
}


void loop()
{
  unsigned long thisMillis = millis();          // Read the time once

  // Calculate RPM
  if (ticks_valid) {                            // Only come here if we have a valid RPM reading
    unsigned long thisTicks;

    noInterrupts();
    thisTicks = ticks_per_rev;
    ticks_valid = false;
    interrupts();

    lastRPM = __TICKS_TO_RPMS / thisTicks;      // Convert ticks to RPMs
    ticks_valid = false;                        // Reset the flag.
    msSinceRPMReading = thisMillis;             // Set the time we read the RPM.

  } else {
    // No tick this loop - is it more than X seconds since the last one?
    if (thisMillis - msSinceRPMReading > __WAIT_BEFORE_ZERO_RPM) {
      lastRPM = 0;                              // At least 2s since last RPM-sense, so assume zero RPMs
      msSinceRPMReading = thisMillis;           // Reset counter
    }
  }

  {
    unsigned long thisMillis1 = millis();          // Read the time once

    // Calculate RPM
    if (ticks_valid) {                            // Only come here if we have a valid RPM reading
      unsigned long thisTicks1;

      noInterrupts();
      thisTicks1 = ticks_per_rev1;
      ticks_valid1 = false;
      interrupts();

      lastRPM1 = __TICKS_TO_RPMS1 / thisTicks1;      // Convert ticks to RPMs
      ticks_valid = false;                        // Reset the flag.
      msSinceRPMReading1 = thisMillis1;             // Set the time we read the RPM.

    } else {
      // No tick this loop - is it more than X seconds since the last one?
      if (thisMillis1 - msSinceRPMReading1 > __WAIT_BEFORE_ZERO_RPM) {
        lastRPM1 = 0;                              // At least 2s since last RPM-sense, so assume zero RPMs
        msSinceRPMReading1 = thisMillis1;           // Reset counter
      }
    }


    // Is it time to send the data?
    if (thisMillis < msSinceSend)                  // If thisMillis has recycled, reset it
      msSinceSend = millis();

    if (thisMillis - msSinceSend > __WAIT_BETWEEN_SENDS)
      // Yes: Build the serial output...

      // Is it time to send the data?
      if (thisMillis1 < msSinceSend1)                  // If thisMillis has recycled, reset it
        msSinceSend1 = millis();

      if (thisMillis1 - msSinceSend1 > __WAIT_BETWEEN_SENDS1) {
        // Yes: Build the serial output...


        Serial.print("RPMs = \t");
        Serial.print(lastRPM);                       // Current RPMs
        Serial.print("\t RPMs = \t");
        Serial.print(lastRPM1);                       // Current RPMs
        Serial.println();                            // EOL.

        msSinceSend = millis();                      // Reset the timer
        msSinceSend1 = millis();                      // Reset the timer


      } }
}
 
   

PaulS

You have some variables that are related to what happens on interrupt 1. They have 1 in the name.

You have some variables that are related to what happens on interrupt 0. They do not all have 0 in the name. Why not! I am NOT going to guess whether a variable that does not have 0 in the name is related to interrupt 0, or not.

Quote
"Exit status 1 error compiling for board"

What does this mean?
It means that you did not look at ALL of the messages.
The art of getting good answers lies in asking good questions.

akmcgregor

The reason that they do not have a 0 on them is because I have taken a working code for one rpm reading and tried to duplicate it to read a second sensor aswell, so I just added a one on the end of second reading. I don't know if this is the correct way of doing it or not. I don't understand the comment about not reading all the messages. I have tried to understand what you have told me to change and implement it in the code. Have I missed something? Can you just explain to me how to add another interrupt on another pin as I cannot find any examples of how to do this. Thanks for your help.

PaulS

Quote
I don't know if this is the correct way of doing it or not.
Go back to the code that worked for one sensor. Put 0 in the names of all variables involved in reading that one sensor.

Compile, link, and test.

Then, make a copy of all the variables with 0 in the name, and ONLY those variables (and functions), and change the 0 to 1 in the pasted copy.

Compile, link, and test.

If compilation fails at any step, make the compiler output window bigger and copy ALL of the text in the window to your post.
The art of getting good answers lies in asking good questions.

akmcgregor

Thank you PaulS for your suggestions. I did what you told me and managed to get the sketch to compile but when it reads a sensor it just freezes serial display until the sensor stops reading. Have you got anymore suggestions to fix this issue?
Thanks

Code: [Select]

extern volatile unsigned long timer0_overflow_count;  // Record the most recent timer ticks

volatile boolean ticks_valid0;                         // Indicates a valid reading
volatile boolean ticks_valid1;
volatile unsigned long ticks_per_rev0;                 // Number of ticks counted in the current revolution
volatile unsigned long ticks_per_rev1;
unsigned long msSinceRPMReading0;                      // Number of mSec since the last rpm_sense (used to spot zero RPM)
unsigned long msSinceRPMReading1;
float lastRPM0;                                        // Most recent RPM reading, and highest RPM recorded since last reset
float lastRPM1;
const float __TICKS_TO_RPMS0 = 15e6;                   // Convert clock ticks to RPM by dividng ticks into this number
const float __TICKS_TO_RPMS1 = 15e6;                                                      // The number will change if there are more magnets in an rpm
                                                      //   (e.g. 2 magnets = 29296.875)
const unsigned int __WAIT_BEFORE_ZERO_RPM0 = 2000;     // Number of mS to wait for an rpm_sense before assunming RPM = 0.
const unsigned int __WAIT_BEFORE_ZERO_RPM1 = 2000;
unsigned long msSinceSend0;                            // mSec when the last data was sent to the serial port
unsigned long msSinceSend1;
const unsigned int __WAIT_BETWEEN_SENDS0 = 1000;       // Number of mS to wait before sending a batch of data.
const unsigned int __WAIT_BETWEEN_SENDS1 = 1000;
float kmh0;
float kmh1;
void setup()
{

  Serial.begin(9600);                                 // Initialise serial comms.
  msSinceSend0 = millis();                             // Data sent counter
 
 
  attachInterrupt(0, rpm_sense0, RISING);              // RPM sense will cause an interrupt on pin2
  msSinceRPMReading0 = 0;                              // If more than 2000 (i.e. 2 seconds),
                                                      // then RPMs can be assumed to be zero (< 15rpm
                                                      // at most, with a single magnet, no small IC
                                                      // can run that slowly).
  lastRPM0 = 0;                                        // Current RPM to zero

 
 }

// ------------------------------------------------------------------------------------------------
// FUNCTION: RPM-SENSE
//
// Called whenever the RPM sense signal rises. In my setup, the hall effect switch is normally
// high, goes low when a south pole is introduced to the sensor, and rises back to high as the
// magnet goes away. Thus, the RPM sense is called on the trailing edge of the magnet.
// ------------------------------------------------------------------------------------------------
void rpm_sense0()
{
  static unsigned long pre_count0;               // Last timer0_overflow_count value
  unsigned long ticks_now0;                      //

  ticks_now0 = timer0_overflow_count;            // Read the timer

  byte t0 = TCNT0;
  if ((TIFR0 & _BV(TOV0)) && (t0<255))
    ticks_now0++;
  ticks_now0 = (ticks_now0 << 8) + t0;

  if (pre_count0 == 0) {                         // First time around the loop?
    pre_count0 = ticks_now0;                      // Yes - set the precount, don't use this number.
  } else {
    ticks_per_rev0 = ticks_now0 - pre_count0;      // No - calculate the number of ticks...
    pre_count0 = ticks_now0;                      // ...reset the counter...
    ticks_valid0 = true;                         // ...and flag the change up.
  }

                              // Data sent counter
  msSinceSend1 = millis();
 
  attachInterrupt(1, rpm_sense1, RISING);              // RPM1 sense will cause an interrupt on pin3
  msSinceRPMReading1 = 0;                              // If more than 2000 (i.e. 2 seconds),
                                                      // then RPMs can be assumed to be zero (< 15rpm
                                                      // at most, with a single magnet, no small IC
                                                      // can run that slowly).
  lastRPM1 = 0;                                        // Current RPM to zero

 
 }

// ------------------------------------------------------------------------------------------------
// FUNCTION: RPM-SENSE
//
// Called whenever the RPM sense signal rises. In my setup, the hall effect switch is normally
// high, goes low when a south pole is introduced to the sensor, and rises back to high as the
// magnet goes away. Thus, the RPM sense is called on the trailing edge of the magnet.
// ------------------------------------------------------------------------------------------------
void rpm_sense1()
{
  static unsigned long pre_count1;               // Last timer0_overflow_count value
  unsigned long ticks_now1;                      //

  ticks_now1 = timer0_overflow_count;            // Read the timer

  byte t1 = TCNT0;
  if ((TIFR0 & _BV(TOV0)) && (t1<255))
    ticks_now1++;
  ticks_now1 = (ticks_now1 << 8) + t1;

  if (pre_count1 == 0) {                         // First time around the loop?
    pre_count1 = ticks_now1;                      // Yes - set the precount, don't use this number.
  } else {
    ticks_per_rev1 = ticks_now1 - pre_count1;      // No - calculate the number of ticks...
    pre_count1 = ticks_now1;                      // ...reset the counter...
    ticks_valid1 = true;                         // ...and flag the change up.
  }
}


void loop()
{
  unsigned long thisMillis0 = millis();          // Read the time once

  // Calculate RPM
  if (ticks_valid0) {                            // Only come here if we have a valid RPM reading
    unsigned long thisTicks0;
   
    noInterrupts();
    thisTicks0 = ticks_per_rev0;
    ticks_valid0 = false;
    interrupts();
   
    lastRPM0 = __TICKS_TO_RPMS0 / thisTicks0;      // Convert ticks to RPMs
    ticks_valid0 = false;                        // Reset the flag.
    msSinceRPMReading0 = thisMillis0;             // Set the time we read the RPM.
   
  } else {
    // No tick this loop - is it more than X seconds since the last one?
    if (thisMillis0 - msSinceRPMReading0 > __WAIT_BEFORE_ZERO_RPM0) {
      lastRPM0 = 0;                              // At least 2s since last RPM-sense, so assume zero RPMs
      msSinceRPMReading0 = thisMillis0;           // Reset counter
    }
  }
 
  kmh0 = (lastRPM0 * 1.8 * 60 / 1000);
 
  // Is it time to send the data?
  if (thisMillis0 < msSinceSend0)                  // If thisMillis has recycled, reset it
    msSinceSend0 = millis();
   
  if (thisMillis0 - msSinceSend0 > __WAIT_BETWEEN_SENDS0) {
    // Yes: Build the serial output...

{
  unsigned long thisMillis1 = millis();          // Read the time once

  // Calculate RPM
  if (ticks_valid1) {                            // Only come here if we have a valid RPM reading
    unsigned long thisTicks1;
   
    noInterrupts();
    thisTicks1 = ticks_per_rev1;
    ticks_valid1 = false;
    interrupts();
   
    lastRPM1 = __TICKS_TO_RPMS1 / thisTicks1;      // Convert ticks to RPMs
    ticks_valid1 = false;                        // Reset the flag.
    msSinceRPMReading1 = thisMillis1;             // Set the time we read the RPM.
   
  } else {
    // No tick this loop - is it more than X seconds since the last one?
    if (thisMillis1 - msSinceRPMReading1 > __WAIT_BEFORE_ZERO_RPM1) {
      lastRPM0 = 1;                              // At least 2s since last RPM-sense, so assume zero RPMs
      msSinceRPMReading1 = thisMillis1;           // Reset counter
    }
  }
 
  kmh1 = (lastRPM1 * 1.8 * 60 / 1000);
 
  // Is it time to send the data?
  if (thisMillis1 < msSinceSend1)                  // If thisMillis has recycled, reset it
    msSinceSend1 = millis();
   
  if (thisMillis1 - msSinceSend1 > __WAIT_BETWEEN_SENDS1) {
    // Yes: Build the serial output...
   
    Serial.print("RPMs = \t");
    Serial.print(lastRPM0);                       // Current RPMs
    Serial.print("\t KM/H \t");
    Serial.print(kmh0);
    Serial.print("\t RPMs = \t");
    Serial.print(lastRPM1);                       
    Serial.print("\t KM/H \t");
    Serial.print(kmh1);
    Serial.println();                           

    msSinceSend0 = millis();                      // Reset the timer
    msSinceSend1 = millis();
  }  }
  }
}

PaulS

Why are you attaching the interrupt handler for the second interrupt (1) in the interrupt handler for the first interrupt (0)?
The art of getting good answers lies in asking good questions.

PaulMurrayCbr

I just wrote something exactly like this for a dude on these boards. It wasn't two hall effect sensors, but speedo and tacho data. Same thing though. The code is public domain open-source, so you could go have a look at it:

https://github.com/PaulMurrayCbr/arduino_dougsauto_tacho


http://paulmurraycbr.github.io/ArduinoTheOOWay.html

Go Up