Subtitute for function pulseIn

Okay, so here’s an early version of pulseIn. Right now I’m just using digitalRead but I’ll be replacing that with some code that directly reads from the port state register this evening. Once I do that we can get much better precision; I wanted to start with existing system calls for simplicity.

I’ve also got to add some math to support custom timeouts. Currently, this function will wait for 10 seconds before aborting. I’ll also use my function generator and scope to do some more precise measurments of the loop timing.

Keep in mind this is code isn’t suitable for production use! This is only meant as a preview, please check this thread tomorrow as I’ll have a Github repository up that you can follow. :smiley:

unsigned long pulseIn(uint8_t pin, uint8_t state) {
    
    unsigned long pulseWidth = 0;
    unsigned long loopCount = 0;
    unsigned long loopMax = 5000000;
    
    // While the pin is *not* in the target state we make sure the timeout hasn't been reached.
    while ((digitalRead(pin)) != state) {
        if (loopCount++ == loopMax) {
            return 0;
        }
    }
    
    // When the pin *is* in the target state we bump the counter while still keeping track of the timeout.
    while ((digitalRead(pin)) == state) {
        if (loopCount++ == loopMax) {
            return 0;
        }
        pulseWidth++;
    }
    
    // Return the pulse time in microsecond!
    return pulseWidth * 2.36; // Calculated the pulseWidth++ loop to be about 2.36uS in length.
}

And here’s an entire sketch that triggers an Ultrasonic Sensor then prints the number of pings, echo pulse time and distance in inches and centimeters to a Digole I2C Display. I’m sure you can see how to easily modify this to fit your needs. Note: Inches doesn’t return a floating point value when called from a print statement. I need to add some maths to make that happen.

int trigger = D2;
int echo = D3;
int ping = 0;
unsigned long triggerTarget;


void setup() {
    pinMode(trigger, OUTPUT);
    pinMode(echo, INPUT);
    digitalWrite(trigger, LOW);
    Wire.begin();
}

void loop() {
    
    // Pull the trigger pin high for roughly 10uS then pull it low and wait another 10uS.
    triggerTarget = micros();
    while (micros() < triggerTarget + 10) {
        digitalWrite(trigger, HIGH);
    }
    while (micros() < triggerTarget + 20) {
        digitalWrite(trigger, LOW);
    }
    
    // Read the return echo then convert it to in and cm.
    unsigned long sonar = pulseIn(echo, HIGH);
    float in = sonar / 148;
    int cm = sonar / 58;
   
    // Output the readings to a Digole I2C Display.
    Wire.beginTransmission(0x4E);
    Wire.print("CL");
    Wire.print("TT");
    Wire.print("Ping: ");
    Wire.print(ping);
    Wire.write(0x00);
    Wire.print("TRT");
    Wire.print("TT");
    Wire.print("Echo: ");
    Wire.print(sonar);
    Wire.print("uS");
    Wire.write(0x00);
    Wire.endTransmission();
    delay(25);
    Wire.beginTransmission(0x4E);
    Wire.print("TRT");
    Wire.print("TT");
    Wire.print(in);
    Wire.print("in / ");
    Wire.print(cm);
    Wire.print("cm");
    Wire.write(0x00);
    Wire.endTransmission();
    
    // Bump the ping counter.
    ping++;
    
    // Wait one second.
    delay(1000);
}

unsigned long pulseIn(uint8_t pin, uint8_t state) {
    
    unsigned long pulseWidth = 0;
    unsigned long loopCount = 0;
    unsigned long loopMax = 5000000;
    
    // While the pin is *not* in the target state we make sure the timeout hasn't been reached.
    while ((digitalRead(pin)) != state) {
        if (loopCount++ == loopMax) {
            return 0;
        }
    }
    
    // When the pin *is* in the target state we bump the counter while still keeping track of the timeout.
    while ((digitalRead(pin)) == state) {
        if (loopCount++ == loopMax) {
            return 0;
        }
        pulseWidth++;
    }
    
    // Return the pulse time in microsecond!
    return pulseWidth * 2.36; // Calculated the pulseWidth++ loop to be about 2.36uS in length.
}
1 Like