Determine the frequency of a PWM pulse

Hello, I would like to find out the frequency of a PWM pulse that is created with the analogWrite command.

What is the easiest way to do that?

What is the easiest way to do that?

Look it up.

About 500 hz

Do you have a scope?
Do you have a DVM with frequency option?

A pulse is a single thing. It does not have a frequency.

...R

Sorry I mean a signal. And I forgot to mention that I cannot look it up as it was kind of an exam question how we could measure it.

Is the OP confusing pulse repetition rate with frequency? A square wave pulse has an infinite number of frequencies. The shape of the pulse determines the frequencies it contains.

Paul

decsis:
Hello, I would like to find out the frequency of a PWM pulse that is created with the analogWrite command.

What is the easiest way to do that?

Connect the PWM output pin to an input pin that is enabled for hardware interrupts. With an Arduino UNO these are pins 2 and 3.

Then program an interrupt handling for RISING or FALLING flank and start PWM output.

The PWM period then is the time difference of the micros() timer between two hardware interrupts. PWM frequency then is the reciprocal value of the PWM period.

Thanks for your suggestion Jurs. I tried it by connecting the pins 2 and 10 and with the following code:

#define READ_PIN 2
#define PWM_OUTPUT 10

volatile int lowTime = 0;
volatile int highTime = 0;

void setup() {
Serial.begin(9600);
pinMode(READ_PIN,INPUT);
pinMode(PWM_OUTPUT,OUTPUT);
analogWrite(PWM_OUTPUT,120);

attachInterrupt(0, rising, RISING);

}

void loop() {

}

void rising(){
attachInterrupt(0, falling, FALLING);
highTime = micros();
}

void falling(){
attachInterrupt(0, rising, RISING);
lowTime = micros();
int freq = (double)1000000/(double(lowTime- highTime));
Serial.println(freq);
}

Unfortunately, I get really weird numbers like
1453
1760
2232
3048
4807
11363

What did I do wrong?

You used a print statement in an interrupt service routine.

decsis:
What did I do wrong?

The only correct thing is: variables declared 'volatile' if the same variable is accessed from interrupt handling and normal code.

The rest ist: Totally weird interrupt handling.

Perhaps try this one:

#define FREQPIN 2
#define FREQINT 0
#define PWM_OUTPUT 10

// volative variables for interrupt handling
volatile uint16_t count_ISR;
volatile uint32_t time_ISR;

void freqCounter() // interrupt handling
{
  count_ISR++;
  time_ISR=micros();
}

float readFrequency() {  // calculating frequency from counts and time
  static uint32_t lastFreqTime;
  noInterrupts();
  uint16_t freqCount= count_ISR;
  count_ISR=0;
  uint32_t freqTime= time_ISR-lastFreqTime;
  lastFreqTime= time_ISR;
  interrupts();
  return 1000000.0*freqCount/freqTime;
}

void setup() {
  Serial.begin(9600);
  attachInterrupt(0,freqCounter,RISING);
  analogWrite(PWM_OUTPUT,120);
}

void loop() {
  static uint32_t lastTime;
  if (millis()-lastTime>=1000) // Calculate and show result once every second
  {
    lastTime+=1000;
    float f= readFrequency();
    Serial.println(f,3);
  }
}

decsis:
What did I do wrong?

Here are a few things. This list may not be exhaustive.

Consider how many characters you'll print, and how often you'll print them. If the frequency were, say, 200, would the sketch have time to print all the characters at 9600 bits per second?

Here's what the code appears to do:

  • Wait for the rising edge
  • Record the time
  • Wait for the falling edge
  • Record the time
  • Subtract those two values
  • Calculate a frequency

It looks like it measures the time between the rising edge and falling edge, and calculates frequency from that. Is that what you wanted to measure?

The sketch Serial.print()'s from within an ISR. Once the processor enters an ISR, it won't respond to other interrupts. Serial.print() puts characters into the transmit buffer, and lets the USART interrupt send them. If the buffer is full, Serial.print() waits until there's room in the buffer for all the characters that it's trying to send. With the bit rate at 9600, the buffer will fill quickly. What will happen when Serial.print() finds the buffer full inside the ISR?

Finally, I can't duplicate your results on an Arduino Uno. Using the posted sketch without modification, I get:

1041
1041
1041
1041
1041
1

then nothing, presumably because the Serial transmit buffer fills, and the USART transmit ISR can't execute to empty it. Changing the bit rate to 115200, I get 1041's for as long as I'm willing to watch the display. Is this really the code you used to get those results?

With a high bit rate, the sketch sort of works - in that it doesn't lock up - because the Serial transmit buffer empties faster than it fills. That doesn't mean that Serial.print()'ing from inside an ISR is a reasonable thing to do. It's almost certain to lock up your sketch sooner or later. If you're unlucky enough to get the sketch to work with a Serial.print() inside an ISR, it will be ferociously hard to troubleshoot when it later fails, almost inevitably. The way to happiness is to instead set some sort of flag in the ISR, examine the flag in loop(), and, when it's found set, print and reset it. You'll still need to be careful not to outrun the Serial buffer