Ultrasonic sensor with pin change interrupt

Hi,

as I didn't find something to copy and paste for myself I wote a sketch to use my ultrasonic sensors with pin change interrups. I share it just in case someone else searches the forum for a copy and paste ready sketch.
The sketch uses one pin only per sensor. The Ping2cm function allows to include a temperature sensor.

I used some contributed libraries and the PING2cm function is from robtillaart.
This made the whole thing easy to code.

Usage:

  • Connect the echo pin of your sensor to analog 14 or 15 (both if you have two sensors).
  • (doesn't work with all sensors) Connect the trigger and echo pin of your sensor to eachother (easiest is to solder them together on the front of the sensor).

All suggestions to improve the sketch are welcome.

Robert

#include <digitalWriteFast.h>
#include <PinChangeInt.h>
#include <Streaming.h>

#define endl "\n"

long StartTime = micros();
long ReceiveTime = micros();
long roundtrip = 0;
unsigned long PingTimeout = millis();
boolean PingReceived = false;
boolean triggerRunning = false;

#define NO_PORTB_PINCHANGES
#define NO_PIN_STATE
#define NO_PIN_NUMBER 
#define DISABLE_PCINT_MULTI_SERVICE

#define SONAR_NUM 2
#define PingLPin  A14
#define PingRPin  A15
int PingLcm = -1;
int PingRcm = -1;
uint8_t PingCurrentSensor = 1;

#define temperature 22

void setup(){
	Serial.begin(115200);
	pinModeFast(PingLPin, INPUT); digitalWriteFast(PingLPin, HIGH);
	pinModeFast(PingRPin, INPUT); digitalWriteFast(PingRPin, HIGH);
	PCintPort::attachInterrupt(PingLPin, &echoEvent, CHANGE);
	PCintPort::attachInterrupt(PingRPin, &echoEvent, CHANGE);
}

void loop(){
	triggerEcho();
}

void triggerEcho(){
	if (IsTime(&PingTimeout,33)){
		int cm;

		if (PingReceived == false){cm = -1;}
		else {cm = PING2cm(roundtrip,temperature);}

		switch (PingCurrentSensor)
		{
		case 1:
			PingLcm = cm;
			break;
		case 2:
			PingRcm = cm;
			break;
		}

		//trigger new Ping
		if (PingCurrentSensor < SONAR_NUM){PingCurrentSensor++;}
		else {PingCurrentSensor = 1;}

		detachPingInterrupts();
		switch (PingCurrentSensor)
		{
		case 1:
			triggerPingLPin();
			PCintPort::attachInterrupt(PingLPin, &echoEvent, CHANGE);
			break;
		case 2:
			triggerPingRPin();
			PCintPort::attachInterrupt(PingRPin, &echoEvent, CHANGE);
			break;
		}
		PingReceived = false;
		triggerRunning = false;

		Serial << PingLcm << " - " << PingRcm << endl;
	}
}


void triggerPingLPin(){
	pinModeFast(PingLPin, OUTPUT);
	digitalWriteFast(PingLPin, HIGH);
	delayMicroseconds(8);
	digitalWriteFast(PingLPin, LOW);
	pinModeFast(PingLPin, INPUT); digitalWriteFast(PingLPin, HIGH);
}

void triggerPingRPin(){
	pinModeFast(PingRPin, OUTPUT);
	digitalWriteFast(PingRPin, HIGH);
	delayMicroseconds(8);
	digitalWriteFast(PingRPin, LOW);
	pinModeFast(PingRPin, INPUT); digitalWriteFast(PingRPin, HIGH);
}

void echoEvent(){
	if (triggerRunning == false){
		StartTime = micros();
		triggerRunning = true;
	}
	else{
		ReceiveTime = micros();
		roundtrip = ReceiveTime - StartTime;
		PingReceived = true;
	}
}

boolean IsTime(unsigned long *timeMark, unsigned long timeInterval) {
	if (millis() - *timeMark >= timeInterval) {
		*timeMark = millis();
		return true;
	}    
	return false;
}

uint32_t PING2cm(uint32_t duration, int t)
{
	uint32_t x = t+55;
	x = x + (x>>1) + (x>>2) + (x>>5); 
	x = x + 915;
	x = x * duration;
	x = (x >> 1) + (x >> 5) + (x >> 8) + (x >> 9); 
	x = x >> 15;
	return x;
}

void detachPingInterrupts(){
	PCintPort::detachInterrupt(PingLPin);
	PCintPort::detachInterrupt(PingRPin);
}