Skip to content

Instantly share code, notes, and snippets.

@harrisonhjones
Forked from tomasero/ultrasound.ino
Last active August 29, 2015 14:23
Show Gist options
  • Save harrisonhjones/dd448010b905f60d3129 to your computer and use it in GitHub Desktop.
Save harrisonhjones/dd448010b905f60d3129 to your computer and use it in GitHub Desktop.
// -------------------------------------------- //
// Documentation
// ------------------
// -------------------------------------------- //
// Compiler Defines
// ------------------
#define APP_VERSION 1.2 // Keep track of what version this code is
#define NUM_MEASUREMENTS 20 // The number of measurements we want to take befoe averaging and publishing
// -------------------------------------------- //
// Includes (Libraries & Other Files)
// ------------------
#include "elapsedMillis/elapsedMillis.h" // ElapsedMillis Library for keeping track of timers/time
// -------------------------------------------- //
// Variables
// ------------------
const int trigPin = D0; // Define which pin we are using for the sensor trigger
const int echoPin = D1;
const int led = D7;
bool active = FALSE; // Define a boolean to keep track of our state (on or off)
bool prevActive = active;
int readingIndex = 0; // Define a variable to keep track of what reading we are on
double distances[NUM_MEASUREMENTS]; // Define an array of doubles to keep track of our measurements
double avgDistance = 0.0; // Define a variable to keep track of the average distance
unsigned long publishInterval = 4000; // Define a variable to pace how often we publishEvery 4000 ms (4 seconds)
unsigned long refractoryPeriod = 10000; // Define a variable to pace how often we refactor
elapsedMillis pTimeElapsed; // Define a timer to keep track of how often we publish
elapsedMillis rTimeElapsed; // Define a timer to keep track of how often we refactor
elapsedMillis tmrUpdate; // Define a timer to keep track of how often we take new measurements
unsigned long measurementInterval = 100; // Define a variable to pace how often we take new measurements every 100 miliseconds
// -------------------------------------------- //
// Function - setup - Runs once at boot
// ------------------
void setup() {
// Define a Spark Variable for grabbing the measured distance
Spark.variable("distance", &avgDistance, DOUBLE);
// Define a Spark function for ativating something
Spark.function("activation", activation);
// Define our pin mode so our pins in the correct state (input or output)
// Set the pin for the sensor trigger as an output
pinMode(trigPin, OUTPUT);
// pinMode(echoPin, INPUT);
// Set the pin for the status led (onboard) as an output
pinMode(led, OUTPUT);
// Let the world know we have started up and what version of the code we are running
Spark.publish("status", "{ status: \"started up! "+String(APP_VERSION)+"\"}", 60, PRIVATE );
// Reset the two timers
rTimeElapsed = 0;
pTimeElapsed = 0;
}
// -------------------------------------------- //
l// Funtion - Loop - Runs indefintely
// ------------------
void loop() {
if (active) {
// Externally indicate that we are in an active measurement mode
digitalWrite(led, HIGH);
// Only take new measurements every 100 ms
if(tmrUpdate > measurementInterval)
{
tmrUpdate = 0;
updateDistance();
}
} else {
digitalWrite(led, LOW);
}
}
// -------------------------------------------- //
// Function - activation - Runs when called by the Spark Function. Activates/deactivates measurement
// ------------------
// Turn on/off sensor measurement.
int activation(String state) {
// Let the world know the sensor is on/off
Spark.publish("status", "{ Sensor Activation: " + state +"}");
// Reset our variables to their default state
pTimeElapsed = 0;
rTimeElapsed = 0;
readingIndex = 0;
if (state == "on") {
active = TRUE;
} else {
active = FALSE;
}
return 1;
}
// -------------------------------------------- //
// Function - updateDistance - Takes distance measurements and sends them to be published when enough have been collected
// ------------------
void updateDistance() {
// If we are still taking new measurements then take a new measurement
if (readingIndex < NUM_MEASUREMENTS) {
// Define a local varible to keep track of the incoming reading
long echo = 0;
// Activate the sensor with a short series of pulses
pinMode(trigPin, OUTPUT);
digitalWrite(trigPin, LOW); // Send low pulse
delayMicroseconds(2); // Wait for 2 microseconds
digitalWrite(trigPin, HIGH); // Send high pulse
delayMicroseconds(5); // Wait for 5 microseconds
digitalWrite(trigPin, LOW); // Holdoff
// Switch our trigger pin to be a input so we can read the incoming data
// please note that pulseIn has a 1sec timeout, which may
// not be desirable. Depending on your sensor specs, you
// can likely bound the time like this -- marcmerlin
// echo = pulseIn(ultraSoundSignal, HIGH, 38000)
pinMode(trigPin, INPUT);
// Take a reading, convert it into centimeters, and save it to our data array
echo = pulseIn(trigPin, HIGH); //Listen for echo
distances[readingIndex++] = microsecondsToCentimeters(echo);
// If we have taken NUM_MEASUREMENTS measurements then publish the data and clear the index
} else {
publishDistance();
readingIndex = 0;
}
}
// -------------------------------------------- //
// Function - publishDistance - Publish the data to the world! The Particle cloud currently limits the publish rate to 1 Hz or 4 Hz in burst.
// ------------------
void publishDistance() {
// Calculate the average distance (use the global avgDistance)
for (int i=0; i<NUM_MEASUREMENTS; i++)
{
avgDistance += distances[i];
}
avgDistance = avgDistance / NUM_MEASUREMENTS;
if (pTimeElapsed > publishInterval) {
char publishBuffer[63];
// Publish the average distance (as "{avgDistance:#}")
sprintf(publishBuffer,"{avgDistance:%.1f}");
Spark.publish("status", publishBuffer);
// Publish the first 10 distances (as "{distances:#,#,#,#,#,#,#,#,#,#}")
sprintf(publishBuffer,"{distances:%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f}",distances[0],distances[1],distances[2],distances[3],distances[4],distances[5],distances[6],distances[7],distances[8],distances[9]);
Spark.publish("status", publishBuffer);
// Publish the next 10 distances (as "{distances:#,#,#,#,#,#,#,#,#,#}")
sprintf(publishBuffer,"{distances:%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f}",distances[10],distances[11],distances[12],distances[13],distances[14],distances[15],distances[16],distances[17],distances[18],distances[19]);
Spark.publish("status", publishBuffer);
// Publish the current distance state (far or near)
if (avgDistance < 100) {
Spark.publish("distance", "near");
} else {
Spark.publish("distance", "far");
}
// Reset out timer(s)
rTimeElapsed = 0;
pTimeElapsed = 0;
}
}
// -------------------------------------------- //
// Function - microsecondsToCentimeters - Convert our raw reading into a distance measurement
// ------------------
double microsecondsToCentimeters(long microseconds) {
// The speed of sound is 340 m/s or 29 microseconds per centimeter.
// The ping travels out and back, so to find the distance of the
// object we take half of the distance travelled.
return (double) microseconds / 29.0 / 2.0;
}
// -------------------------------------------- //
// Function - pulseIn - PulseIn function for the Spark Core
// ------------------
unsigned long pulseIn(uint16_t pin, uint8_t state) {
GPIO_TypeDef* portMask = (PIN_MAP[pin].gpio_peripheral); // Cache the target's peripheral mask to speed up the loops.
uint16_t pinMask = (PIN_MAP[pin].gpio_pin); // Cache the target's GPIO pin mask to speed up the loops.
unsigned long pulseCount = 0; // Initialize the pulseCount variable now to save time.
unsigned long loopCount = 0; // Initialize the loopCount variable now to save time.
unsigned long loopMax = 20000000; // Roughly just under 10 seconds timeout to maintain the Spark Cloud connection.
// Wait for the pin to enter target state while keeping track of the timeout.
while (GPIO_ReadInputDataBit(portMask, pinMask) != state) {
if (loopCount++ == loopMax) {
return 0;
}
}
// Iterate the pulseCount variable each time through the loop to measure the pulse length; we also still keep track of the timeout.
while (GPIO_ReadInputDataBit(portMask, pinMask) == state) {
if (loopCount++ == loopMax) {
return 0;
}
pulseCount++;
}
// Return the pulse time in microseconds by multiplying the pulseCount variable with the time it takes to run once through the loop.
return pulseCount * 0.405; // Calculated the pulseCount++ loop to be about 0.405uS in length.
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment