1

I'm working with the Arduino Due ans I used the following code:

// period of pulse accumulation and serial output, milliseconds
#define MainPeriod 100
long previousMillis = 0; // will store last time of the cycle end
volatile unsigned long duration=0; // accumulates pulse width
volatile unsigned int pulsecount=0;
volatile unsigned long previousMicros=0;

void setup()
{
  Serial.begin(19200); 
  attachInterrupt(6, myinthandler, RISING);
}

void loop()
{
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= MainPeriod) 
  {
    previousMillis = currentMillis;   
    // need to bufferize to avoid glitches
    unsigned long _duration = duration;
    unsigned long _pulsecount = pulsecount;
    duration = 0; // clear counters
    pulsecount = 0;
    float Freq = 1e6 / float(_duration);
    Freq *= _pulsecount; // calculate F
    // output time and frequency data to RS232
    Serial.print(currentMillis);
    Serial.print(" "); // separator!
    Serial.print(Freq);
    Serial.print(" "); 
    Serial.print(_pulsecount);
    Serial.print(" ");
    Serial.println(_duration);
  }
}

void myinthandler() // interrupt handler
{
  unsigned long currentMicros = micros();
  duration += currentMicros - previousMicros;
  previousMicros = currentMicros;
  pulsecount++;
}

to measure the frequency.

I can measure frequencies higher than 1.5kHz accurately, but I can't seem to measure lower frequencies.

How can I measure lower frequencies, say 400Hz and above?

Thanks.

1
  • What is the output on a 400mHz wave? Just 0 and 0? Or wildly varying results? – Gerben Jul 28 '14 at 20:30
1

It seems you have a problem of concurrent access to duration and pulsecount variables which are inter-related; with your code, it is possible that (and I guarantee that it will):

  1. loop() reads duration value (in line unsigned long _duration = _duration;) but gets interrupted before executing the next line
  2. myinthandler() changes both duration and pulsecount (it cannot be interrupted as it is already triggered by an interrupt)
  3. loop() proceeds to where it was interrupted (after myinthandler() returns) and executes line unsigned long _pulsecount = pulsecount;: the values in _duration and _pulsecount do not match anymore!

To protect the access to pulsecount and duration variables, you have to disable interrupts inside loop() just for the time you get their values:

void loop() {
    ...
    // Disable interrupts while we get and reset duration and pulsecount
    cli();
    unsigned long _duration = duration;
    unsigned long _pulsecount = pulsecount;
    duration = 0; // clear counters
    pulsecount = 0;
    // Now we can re-enable interrupts again
    sei();
    ...
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.