Detecting frequency of square wave

I am using the above linked code to measure frequency of a square wave input to one of the digital pins of an Arduino Uno. The program works perfectly to detect accurate frequencies of square wave signals generated using a function generator. The issue comes when I use my hardware generated square wave and the same program starts giving infinite frequency values. For reference, both square wave signals look identical on an oscilloscope.

Would anybody have any thoughts on what I could be missing here?

The scope shows the two identical waveforms:

Also when you zoom in on the transients?

That would be a cycle of zero length. Perhaps there is a coding problem.

void setup() 
{
  unsigned long startTime = 0;  
  unsigned long stopTime = 0; 
}

This 'setup()' does nothing because it only initializes variables that are local to setup();

Missing: pinMode(7, INPUT);

How long are your cycles? Each digitalRead() takes about 6 microseconds and 'micros()' counts by 4.

Thanks for your response, John.

You are right. I had to do a global initialization for startTime and stopTime to run the code. I also added pinMode(7,INPUT) to the setup() but still keep seeing 62500 as the frequency which makes me think the time period it's recording is 0. I am using a 0.79Hz square wave as an input.

I noticed that it starts giving the right output for higher frequencies (~1kHz) but not able to do so for lower frequencies that I need it to work for (0.5Hz-1Hz).

Yes, they are identical

No, you're not, because that code cannot compile.

So, where is your code?

Sorry this is my first time posting. Hope this format works:

unsigned long startTime;
unsigned long stopTime;
float time_period;
float frequency;

void setup() {
Serial.begin(9600);
startTime = 0;
stopTime = 0;
pinMode(2, INPUT);
}

void loop() {
// Serial.println(digitalRead(2));

while (digitalRead(2)) { //wait for low on pin 2

}
while (!digitalRead(2)) { //wait for high on pin 2

}

startTime = micros(); //high detected, set start time

while (digitalRead(2)) { //wait for low on pin 2

}
stopTime = micros(); //low detected, set stop time

time_period = 2* (stopTime - startTime);
frequency = 1000000/time_period;

Serial.println(frequency);

}

Nope.
Use code tags.




unsigned long startTime;
unsigned long stopTime;
float time_period;
float frequency;

  
void setup() {
  Serial.begin(9600);
  startTime = 0;
  stopTime = 0;
  pinMode(2, INPUT); 
}

void loop() {
 // Serial.println(digitalRead(2));
  
  while (digitalRead(2)) {  //wait for low on pin 2

  }
  while (!digitalRead(2)) { //wait for high on pin 2

  }

  startTime = micros();     //high detected, set start time

  while (digitalRead(2)) {  //wait                                                                                                                                                                                                                                                                                                                                                                                           for low on pin 2

  }
  stopTime = micros();    //low detected, set stop time


  time_period = 2* (stopTime - startTime);
  frequency = 1000000/time_period;
  
  Serial.println(frequency);
   
  
}

Don't you mean 16? 62500 Hz is a 16 microsecond cycle time.

0.79 Hz should be a duration of 1,265,822 microseconds.

The "(Warning: untested and incomplete armchair code fragment. Worth what you paid for it...)" that you quoted above only measures the high part of the wave. If it's a square wave then you would just need to divide the frequency by 2. If it is a pulse wave you will be off by some unknown factor.

Here is the code with some deficiencies corrected:

unsigned long startTime = 0;
unsigned long stopTime = 0;

void setup()
{
  Serial.begin(115200);
  delay(200);

  pinMode(7, INPUT);

  Serial.println();
  Serial.println("Starting");
}

void loop()
{
  while (digitalRead(7) != LOW)    //wait for low on pin 7
  {
  }

  while (digitalRead(7) == LOW)   //wait for high on pin 7
  {
  }

  startTime = micros();     //high detected, set start time

  while (digitalRead(7) != LOW)    //wait for low on pin 7
  {
  }

  while (digitalRead(7) == LOW)    // wait for end of low on pin 7
  {
  }

  stopTime = micros();    // low detected, set stop time

  unsigned long elapsedTime = stopTime - startTime;
  Serial.print("Duration in microseconds: ");
  Serial.println(elapsedTime);

  Serial.print("Frequency in Hz: ");
  Serial.println(1000000.0 / elapsedTime);

  delay(3000); // Display every 3 seconds
}

Thanks, John. I just tried this code out. This also works perfectly for the 0.79Hz square wave generated using a function generator but not for the one generated using the hardware :frowning:

If I increase the frequency to 1kHz, it starts working for hardware generated square wave too. I wonder if it's something related to my sampling rate that might be incorrect?

My best guess is the "the hardware" is faulty in some way. Does "the hardware" share a Ground with the Arduino?

Yes it shares a ground. If I look at the serial data coming in from the hardware, that's also a clean square wave. Not sure what's wrong here

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.