PulseIn() command with Hall Effect Switch

Hey guys

Im using the A1120 Hall Effect Switch to measure rpm of a motor. I am trying to use the PulseIn() command to measure the frequency of the pulses its sending. However.. its not working. What are my options? I am fairly new to this. Here is the source code im using.

int pin = 7;
unsigned long duration;

void setup()
{
  pinMode(pin, INPUT);
}

void loop()
{
  duration = pulseIn(pin, LOW);
}

The way the switch works is that its on high 500mv and then drops to 0 everytime the magnet passes it.

Any help will be greatly appreciated.

Heres the link to the Sensor

http://www.allegromicro.com/en/Products/Part_Numbers/1120/

Thank you Again.

That hall effect switch has a open drain output pin, which means you have to provide a pull-up resistor to +5vdc. You can use the internal pull-up for the input pin by adding:

void setup()
{
pinMode(pin, INPUT);
digitalWrite(pin, HIGH);

}

Give that a shot and see what you get.

Lefty

PS: Thanks Dave for the PM, I edited the error

Thanks Lefty!! Ill give that a shot and see how that goes. Ill keep you posted.

That program only measures the time it takes the magnet to pass the sensor. You want the time between magnet passes so you need a :- pulseIn(pin, HIGH);

Thank you guys. It worked like a charm!

However i have a question regarding my implementation.. im unsure if i should ask here or in the software section but since it pertains to the problem ill ask here anyways

The way im measuring rpm is by the frequency of the rotations.

So what im doing is getting the PulseIn() of both the highs and lows.. and adding them to get the total time period... and then calculating the frequency that way.

So my code looks like this

int pin = 7;
unsigned long lowduration;
unsigned long highduration;
unsigned long timeperiod;

void setup()
{
  pinMode(pin, INPUT);
 digitalWrite(pin, HIGH);
}

void loop()
{
  lowduration = pulseIn(pin, LOW);
  highduration = pulseIn(pin, HIGH);
  timeperiod = lowduration + highduration;
}

Is this a good way of doing it or can i just measure the frequency with just one command? Whats a better way of doing this.

Thank you all again.

Refer to this post and look at the code at the end:

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1274834441

It helped me as I am also measuring RPM. PulseIn works but not as accurately as you may want, so the solution in the post above may suit you better. Its more complex but you get the result. At about 20,000rpm there is an error of about 30rpm or so, so its pretty damn good really.

Thanks a BUNCH WanaGo your code is awesome!! Very accurate i must say.

Thank you again

I am having another issue however. I am using this code to monitor the rpm of the motor… and when the rpm deviates from what i want… i adjust the PWM accordingly. Thats what i want my code to ultimately do.

Here is an example:
My motor should be running at 7200 rpm.

When the hall sensor gives me an rpm reading below 7200 it should adjust the PWM accordingly to bring it back up to 7200.

The logic i am using is this:

DutyCycle = [4369 - (RPM - 7200)*X]

4369 is my OCR1B value which is required to run the motor at 7200.

RPM is whatever RPM i am measuring.

X is the factor i need to adjust my pwm by to change my rpm by 1.

However this doesnt work as it floods the OCR1B register =(

Here is my code for your reference It includes the code from WanaGo.

//-------------------------------------------------------------------------------------
// ArduECU version 0.01 alpha
// Compiled with Arduino v0018
//
// Thanks to the members of the arduino.cc forum for their assistance

// Many comments removed to fit sketch into forum posting box...

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, peakRPM;                               // 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.
const int __REV_GAUGE_PIN = 3;                        // 100uA meter on this pin, with 50K current-limiting resistor


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.

int outputPsuB = 10;  // Timer1-B
int dutycycle = 4369; //50% duty cycle

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
  peakRPM = 0;                                        // Max recorded RPM to zero
  pinMode(__REV_GAUGE_PIN,OUTPUT);                    // Set pin 3 to be output
  
  pinMode(outputPsuB, OUTPUT);  // select Pin as ch-B
  
  TCCR1A = B00100001; // PWM, Phase and frequency correct - change at OCR1A
  TCCR1B = B10010;  // prescaling by 8 the system clock

}

// ------------------------------------------------------------------------------------------------
// 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.
//
// Version Date        By  Comment
// -------|-----------|---|------------------------------------------------------------
//   0.01a 26-May-2010 JAV Created (with an assist from BenF from the arduino.cc forum
//
// ------------------------------------------------------------------------------------------------
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
  
  
  //Serial.print("dutycycle: ");
  //Serial.println(dutycycle);
  //Generation of PWM Signal
  OCR1A = 8197; // 122.0Hz at 8197us|140Hz at 7143us
  OCR1B = dutycycle; // 99.9% DC at 8196|40% DC at 7071


  // 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.
    if (lastRPM > peakRPM)
      peakRPM = lastRPM;                        // New peak 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
    }
  }
  
  // Calculate temperatures
  // not implemented yet
  
  
  
  // 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...
    
    // For now, send everything plaintext. Maybe compression would be a good thing, later down the line...
    Serial.print("uECUv0.01|CurrentRPM: ");                  // Send ID - ditch this for something smaller
    Serial.print(lastRPM);                       // Current RPMs
    Serial.print("|");                           // Field Separator
    Serial.print(peakRPM);                       // Peak RPMs
    Serial.print("|");                           // Field Separator
    Serial.print(dutycycle);                     // Temperature #1 (water in)
    Serial.print("|");                           // Field Separator
    Serial.print(0);                             // Temperature #2 (water out)
    Serial.print("|");                           // Field Separator
    Serial.print(0);                             // Temperature #3 (exhaust gas)
    
    //Start of compare of RPM values
    if(lastRPM != 7300 && dutycycle <= 8196 && dutycycle >= 10)
    {
      dutycycle = 4369 - ((lastRPM - 7300)/60)*(0.82);
    }
    else if(dutycycle > 8196 || dutycycle < 10)
    {
       digitalWrite(outputPsuB,LOW);
    }
    else
    {
      
    }
    
    // Debugging
    // Serial.print("|");                           // Field Separator
    // Serial.print(ticks_per_rev);                 // clock ticks in the last rpm

    // That'll do for bnow
    Serial.println();                            // EOL.

    msSinceSend = millis();                      // Reset the timer
    
    if (Serial.available()) {
      char cmd = Serial.read();
      if (char('R') == cmd) {
        peakRPM=0;
      }
      Serial.flush();
    }
    
  }

  // Set the RPM gauge value in real-time...
  if (lastRPM < 1000) {
    // Sub-1000 RPMs, map to between 0-255
    analogWrite(__REV_GAUGE_PIN,map(lastRPM,0,1000,0,255));
  } else {
    // If RPMs > 1000, write 255 (=meter FSD); but we've got bigger problems if the RPMs ever get this high...
    analogWrite(__REV_GAUGE_PIN,255);  
  }

}

Thank you guys once again.