pulsein command limit

Hello~

I modified "detect frequency and duty cycle "source code on website, but now when I input a square pulse (“1Hz” 50% duty cycle) to pin8 ,10, 11, 13, then arduino has only detect HIGH or LOW, if arduino detect signal is HIGH first, then it will pass LOW signal and LCD display 2Hz vice versa , but if input frequency more then 4Hz, there is can works properly…

does pulsein command has 4Hz limit or my source code have some problem?

#include <Wire.h>

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,20,4);

#define FAIL_PIN1 8
#define FAIL_PIN2 10
#define FAIL_PIN3 11
#define FAIL_PIN4 13
#define READ_DELAY 10

static double duty;
static double freq;
static double FANspeed;
static long highTime = 0;
static long lowTime = 0;
static long tempPulse;
static long lastSeen;

void setup()
{
Serial.begin(9600);
// initialize the lcd
lcd.init();
lcd.backlight();

// PWM input pin
pinMode(FAIL_PIN1,INPUT);
pinMode(FAIL_PIN2,INPUT);
pinMode(FAIL_PIN3,INPUT);
pinMode(FAIL_PIN4,INPUT);
}

void loop(){

lcd.clear();

readPWM(FAIL_PIN1);
lcd.setCursor(0,0);
lcd.print(“FQ1=”);
lcd.print(freq);
lcd.setCursor(10,0);
lcd.print(" DT=");
lcd.print(duty);

readPWM(FAIL_PIN2);
lcd.setCursor(0,1);
lcd.print(“FQ2=”);
lcd.print(freq);
lcd.setCursor(10,1);
lcd.print(" DT=");
lcd.print(duty);

readPWM(FAIL_PIN3);
lcd.setCursor(0,2);
lcd.print(“FQ3=”);
lcd.print(freq);
lcd.setCursor(10,2);
lcd.print(" DT=");
lcd.print(duty);

readPWM(FAIL_PIN4);
lcd.setCursor(0,3);
lcd.print(“FQ4=”);
lcd.print(freq);
lcd.setCursor(10,3);
lcd.print(" DT=");
lcd.print(duty);

delay (2000);

}

// ---------------------------------------------
//Takes in reading pins and outputs pwm frequency and duty cycle.
void readPWM(int readPin)
{
highTime = 0;
lowTime = 0;
lastSeen = millis();
while((millis()-lastSeen)<READ_DELAY)
{
tempPulse = pulseIn(readPin,HIGH);

if(tempPulse>highTime){
highTime = tempPulse;
}
}
lastSeen = millis();
while((millis()-lastSeen)<READ_DELAY)
{
tempPulse = pulseIn(readPin,LOW);

if(tempPulse>lowTime){
lowTime = tempPulse;
}
}
freq = ((double) 1000000)/(double (lowTime+highTime));
duty = (100*(highTime/(double (lowTime+highTime))));

}

I’m not sure if it’s related, but pulseIn has a default timeout parameter:

timeout (optional): the number of microseconds to wait for the pulse to start; default is one second (unsigned long)

So, if for some reason you don’t get the HIGH or LOW you’re looking for within one second, it’ll fail. To rule out this possibility, state an explicit timeout with a larger value, e.g. 2,000,000.

Hello~ igendel

thanks for your help, I understand the pulsein time out is one second, but base on 1Hz duty 50%, the HIGH or LOW level is only 0.5s.
I tried to use "tempPulse = pulseIn(readPin,LOW,2000000), the arduino still pass either HIGH or LOW signal.
Any suggestion please inform me, thanks.

tempPulse = pulseIn(readPin,HIGH,2000000);
tempPulse = pulseIn(readPin,LOW,2000000);

igendel is correct, and the extended timeout needs to be on both pulses.

When I tested your sketch with the extended timeout on one pin, with a 500ms square wave pulse I was reading frequency 1 and Duty cycle 50%. When I uses a 250 ms pulse the frequency was 2. With a serial print out of tempPulse I could see times for both high and low.

HIGH
497746
LOW
497744
HIGH
497740
LOW
498768

Hello~ cattledog

You are right, I tried to add pulsein delay time both HIGH and LOW parameter again, the 1Hz 50% duty can be detect now.

many thank you and igendel.

No problem.

For clarity and future reference, I will add the pulseIn doesn't see current level, only level change. So, for instance, if you look for HIGH, and the pin input is currently HIGH too, pulseIn will NOT start counting - it will wait until the pin goes LOW then HIGH again, or until timeout.