Looking for guidance in frequency measurement

Seems like it does just what I'd expect:

currentTimeStamp: 0
serialLastWriteTimeStamp: 0
currentTimeStamp - serialLastWriteTimeStamp: 0

Do you not get zeros?

These happen almost intantaneously and read the same millis() millisecond:

    currentTimeStamp = millis();
    serialLastWriteTimeStamp = millis();

I'd swap their order and put a delay in between to see something other than zeros.

I read a bunch of posts asking why millis doesn't start at zero and how to reset it to 0, and I guess I misunderstood what I was reading as you're right, it reads zero upon each start and with a delay I get usable values.

I'm almost there I guess. My DMM says 20hz, however I took another example to try and read the frequency on an input pin and I have not implemented it correctly because it prints out "Hz: inf" .

[edit] I've tried a few variations and the only thing I can surmise is that pulseIn blocks the loop, as the hz drop from 20 to 0 on my meter when I use pulseIn?

unsigned long currentTimeStamp;
unsigned long serialLastWriteTimeStamp;

int Htime;              //integer for storing high time
int Ltime;                //integer for storing low time
float Ttime;            // integer for storing total time of a cycle
float f_frequency;        //storing frequency

void setup()
{
    Serial.begin(9600);
    while (!Serial)
    {
      ; // Wait for serial to connect
    }
    Serial.println("");
    delay(2000);
   
    Serial.println("Frequency Demo");

    pinMode(7,INPUT);
    pinMode(8, OUTPUT);

    currentTimeStamp = millis();
    serialLastWriteTimeStamp = millis();

}

void loop()
{
    currentTimeStamp = millis();
 
    digitalWrite(8, HIGH);
    delay(25);
    digitalWrite(8, LOW);
    delay(25);

    if (currentTimeStamp > serialLastWriteTimeStamp)
    {
        Htime=pulseIn(7,HIGH);      //read high time
        Ltime=pulseIn(7,LOW);        //read low time
        Ttime = Htime+Ltime;

        f_frequency=1000000/Ttime;    //getting frequency with Ttime is in Micro seconds
        Serial.print("Hz: "); Serial.println(f_frequency);
        serialLastWriteTimeStamp = (millis() + 1000);
    }
    
}

Looks like Ttime, Ltime and Htime are all zero.

I don't use pulseIn much, but it gives zeros if it doesn't detect a pulse:

Are you feeding anything into pin 7?

Well good news, my meter and serial out are saying the same thing. Thank you @DaveX . In case someone comes upon this in a search, the below code will output a frequency of 20hz, from pin 8 to pin 49. You'll need to install FreqMeasure by Paul Stoffregen in your sketch library as well.


#include <FreqMeasure.h>


double sum=0;
int count=0;

void setup()
{
    Serial.begin(9600);
    FreqMeasure.begin();
    while (!Serial)
    {
      ; // Wait for serial to connect
    }
    Serial.println("");
    delay(2000);
   
    Serial.println("Frequency Demo");

    pinMode(8, OUTPUT);
}

void loop()
{

    digitalWrite(8, HIGH);
    delay(25);
    digitalWrite(8, LOW);
    delay(25);

    if (FreqMeasure.available()) 
    {
        // average several reading together        
        sum = sum + FreqMeasure.read();
        count = count + 1;
        if (count > 30) 
        {
            float frequency = FreqMeasure.countToFrequency(sum / count);
            Serial.println(frequency);
            sum = 0;
            count = 0;
        }
    }
}

Oh -- In your #22 code you had pin 8 connected to pin 7, but since pulseIn() blocks, pin 8 isn't getting toggled while pulseIn was waiting for a cycle.

I'd suggest a non-blocking reader (like FreqMeasure or FreqCount) and a non-blocking toggler like:

void pinUsToggler(uint32_t interval) {
  const byte pin = 8;
  static uint32_t last = 0;
  static byte pinState = LOW;
  if (micros() - last >= interval) {
    pinState = pinState != LOW ? LOW : HIGH;
    digitalWrite(pin, pinState);
    last += interval;
  }
}
...

void loop(void){
   ...
   pinUsToggler(25000);
   ...
}

Here's some code I was trying in Wokwi:

// WokwiMegaScope setup: https://wokwi.com/projects/390819455604080641
// for https://forum.arduino.cc/t/looking-for-guidance-in-frequency-measurement/1232046
#include <FreqCount.h> // https://www.pjrc.com/teensy/td_libs_Count.html
#include <FreqMeasure.h> // https://www.pjrc.com/teensy/td_libs_FreqMeasure.html

// wiring
const byte MeasurePin = 49; // ICP4 on a Mega // doesn't work on Wokwi
const byte CountPin = 47; // T5 on a Mega
const byte TonePin = 13; //

// measure vars
unsigned long count = 0;
unsigned long sum = 0;

// the setup function runs once when you press reset or power the board
void setup() {
  Serial.begin(115200);
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
  FreqMeasure.begin(); //
  FreqCount.begin(1000); // 1000ms

  Serial.print("FreqMeasure on pin ");
  Serial.print(MeasurePin);
  Serial.print("FreqCount on pin ");
  Serial.print(CountPin);
  // tone(TonePin,1000);
  pinMode(TonePin, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  if (FreqMeasure.available()) {
    // Won't work on Wokwi because ICP not implemented
    // average several reading together
    sum = sum + FreqMeasure.read();
    count = count + 1;
    if (count > 30) {
      float frequency = FreqMeasure.countToFrequency(sum / count);
      Serial.println(frequency);
      sum = 0;
      count = 0;
    }
  }
  if (FreqCount.available()) {
    unsigned long count = FreqCount.read();
    Serial.print(" Count:");
    Serial.println(count);
  }
  pinUsToggler(25000);
}

void pinUsToggler(uint32_t interval) {
  const byte pin = TonePin;
  static uint32_t last = 0;
  static byte pinState = LOW;
  if (micros() - last >= interval) {
    pinState = pinState != LOW ? LOW : HIGH;
    digitalWrite(pin, pinState);
    last += interval;
  }
}

using MegaScope - Wokwi ESP32, STM32, Arduino Simulator plus some extra connections:

Here is a slight update to my example, the update determines when the frequency is null using a timeout, otherwise it keeps the last frequency count even when the signal is terminated. It also prevents the function from thinking (for a short period of time) that the signal state is one during a reset.

The below code will output a frequency of ~200hz, from pin 8 to pin 49 on an Arduino Mega. You'll need to install FreqMeasure by Paul Stoffregen in your sketch library as well.



#include <FreqMeasure.h>


double sum=0;
int count=0;
unsigned long currentTime;
unsigned long lastSerialPrintTime;
unsigned long lastFreqUpdateTime;
unsigned long pinLowTime;
unsigned long pinHighTime;
int lastFreqUpdateTimeOut = 2000;
bool engineRunning = false;
float frequency = 0;

void setup()
{
    Serial.begin(9600);
    FreqMeasure.begin();
    while (!Serial)
    {
      ; // Wait for serial to connect
    }
    Serial.println("");
    delay(2000);
   
    Serial.println("Frequency Demo");

    pinMode(8, OUTPUT);
    digitalWrite(8, LOW);
    pinHighTime = (millis() + 1);

    lastSerialPrintTime = millis();
    lastFreqUpdateTime = millis();
    frequency = 0;
}

void loop()
{
    currentTime = millis();

    int pinState = digitalRead(8);
    if ((currentTime >= pinHighTime) && (pinState == 0))
    {
        digitalWrite(8, HIGH);    
        pinLowTime = (currentTime + 4);
    }
    
    if ((currentTime >= pinLowTime) && (pinState == 1))
    {
        digitalWrite(8, LOW);
        pinHighTime = (currentTime + 1);
    }

    if (FreqMeasure.available()) 
    {
        sum = sum + FreqMeasure.read();
        count = count + 1;
        if (count > 100) 
        {
            frequency = FreqMeasure.countToFrequency(sum / count);
            //Serial.println(frequency);
            sum = 0;
            count = 0;
            //lastFreqUpdateTime = millis();
            lastFreqUpdateTime = (millis() + lastFreqUpdateTimeOut);
        }
    }

    if ((currentTime - lastSerialPrintTime) > 500)
    {
        //if (((currentTime - lastFreqUpdateTime) > lastFreqUpdateTimeOut) || (frequency < 10))
        if ((currentTime > lastFreqUpdateTime) || (frequency < 10))
        {
            Serial.println("Engine is off");
            engineRunning = false;
            frequency = 0;
        }
        else
        {
            Serial.print("Engine is running, hz is: "); Serial.println(frequency);
            engineRunning = true;
        }

        lastSerialPrintTime = millis();
    }
}


Here's a Wokwi simulation with a non-blocking software pulse generator function and a non-blocking software frequency measuring function, along with FreqCount (FreqMeasure does not work in Wokwi)

The software functions seem to work up to about 20kHz on an Uno before they begin to interfere with each other.

Thanks, I have never heard of wokwi until you posted about it. I will have to look into using that.