Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Each part (such as LED, etc.) that you connect to your Photon device must have a complete electrical circuit. A circuit is a continuous path that conducts electricity from the positive (+) end of the power supply through a part (such as LED, etc.) back to the negative (-) end of the power supply. The Input/Output (I/O) pins, jumper wires, and breadboard are used to help make a separate circuit for each part.
This is why each part needs at least 2 wires (one for positive and one for negative). In many cases, an I/O pin acts as the voltage source (positive end) for a particular part's circuit. All parts will connect back (directly or indirectly) to one of the GND (-) pins on the Photon board. Parts that require more than 2 wires use the extra wires for power or data.
The Photon board has a number of I/O pins used for connecting inputs and outputs. Some of these are labeled as "analog" pins, while others are labeled as "digital" pins. However, in practice, the analog pins can act as digital pins, and some of the digital pins can act as analog pins.
The Photon board has 6 analog I/O pins labeled as: A0, A1, A2, A3, A4, A5.
Several of these analog pins are duplicated on the Photon board. A2, A3, A4, and A5 are each represented by two pins. The duplicate pins are located in the 10-pin digital header and labeled as: SS/A2, SCK/A3, MISO/A4, MOSI/A5. You can use either the primary analog pin or its duplicate. However, if you use one, then you should not use the other. For example, you could connect a part to either A2 or SS/A2 (choose one), but you cannot connect two different parts to these two pins and try to control them separately.
The Photon board has 8 digital I/O pins labeled as: D0, D1, D2, D3, D4, D5, D6, D7.
The D7 pin is also connected to a small, built-in blue LED light on the Photon board. Sending a digital output signal of HIGH to D7 will turn on the built-in D7 LED (and sending a signal of LOW turns it off). You can connect another part to the D7 pin, but just be aware that your Photon code might also turn the D7 LED on or off (only if you're using the D7 pin as a digital output for your other part).
The Photon board has several I/O pins with "special" labels, indicating they have special uses.
There are several analog and digital pins with special uses: SDA/D0, SCL/D1, SS/A2, SCK/A3, MISO/A4, MOSI/A5. However, all of these pins can be used as regular I/O pins. In your Photon code, you can just refer to these pins by their "regular" labels (D0, D1, A2, A3, A4, A5).
There are two pins labeled as RX and TX, which are normally used for receiving data (RX) or sending data (TX) data over a serial connection to a part. If needed, these pins can instead be used as regular I/O pins. In your Photon code, you would simply refer to these pins as RX and TX.
There are two pins labeled as WKP and DAC, which have special uses. If needed, these pins can instead be used as regular I/O pins. In your Photon code, you would refer to WKP as A6 and DAC as A7.
Some of the I/O pins are capable of PWM output. PWM stands for pulse-width modulation, which is how a digital output signal (which has only two values: HIGH or LOW) can act like an analog output signal (which has a range of values).
Certain parts (such as: speaker, servo motor, etc.) require a connection to a PWM output pin.
Only the following pins can act as PWM outputs: D0, D1, D2, D3, A4, A5, WKP, RX, TX.
The Photon board operates at 3.3 volts. Therefore, the voltage source from the I/O pins is 3.3 volts (regardless of whether the Photon is being powered by USB or battery). Again, many parts are powered directly from their I/O pin. However, some parts need a separate power source.
The 3.3V pin (+) on the Photon board can be used as a power source.
The V-USB pin (+) on the Photon board supplies 5 volts (which comes directly from the USB connection). This pin won't supply power if the USB is not connected.
The VIN pin (+) on the Photon board supplies power directly from the battery connected to the barrel jack. So connecting a 9V battery would provide 9 volts to the VIN pin (but still only supply 3.3V to the regular I/O pins). This pin won't supply power if a battery is not connected.
CAUTION: Some parts (such as OLED display, accelerometer, etc.) can only handle 3.3V and can be damaged if connected to a higher voltage. Check the power requirements of each part before connecting a part to either V-USB or VIN.
NOTE: Some parts (such as servo motor, motion sensor, etc.) require 5V in order to operate properly. These parts will have to be connected to either V-USB or VIN.
GROUND PINS
There are 3 separate ground pins on the Photon board, each labeled as GND. These act as the negative end of a circuit. All parts have to connect to a GND pin (either directly or through the breadboard).
The breadboard is an important part used to help make your circuits. The left and right halves of the breadboard are actually separate (which means they will not conduct electricity between each other). Within each half, the holes within the same row are connected to each other electrically, but each row is separate from the other rows. The rows are numbered (1-30), and holes within the same row are lettered (a-e for left-hand rows, f-j for right-hand rows).
In addition, each half of the breadboard has a power rail as its two outer columns (positive column and negative column). The power rails are not connected to the rows. The purpose of a power rail is to allow multiple parts (which will be attached to the breadboard rows) to share access to the positive and negative ends of your Photon device's power supply. Think of each power rail as a power strip.
The best way to try to understand how the breadboard conducts electricity is this image (on the right) that shows the metal strips embedded inside the breadboard:
When a jumper wire is inserted into a breadboard hole, it makes contact with the metal strip underneath. Any wires or parts that are connected to the same metal strip are therefore connected electrically to each other. As the picture above shows, there are separate rows of metal strips on the left side and the right side.
The red arrows in the image are pointing to the metal strips under the power rails. Again, think of these two power rails as two power strips. Once you plug a power rail into a power supply (by connecting it to the Photon board), you can plug other parts into the power rail.
In order to "plug in" a power rail, you have to connect a jumper wire from a voltage source (+) on the Photon board (such as the 3.3V pin) to any hole in the positive (+) column of the power rail. Then connect a second jumper wire from any hole in the negative (-) column of the power rail back to one of the GND (-) pins on the Photon board. Now if a part on the breadboard needs access to voltage (+) or GND (-), you can connect a jumper wire between a hole in that part's corresponding row and any hole in the appropriate power rail column (either + or -).
Depending on which parts are being connected, it may be necessary to only activate and use the negative (-) power rail. This is because every part needs to connect back to GND on the Photon board (and there are only 3 GND pins available). Since many parts use a digital or analog pin as their voltage source (+), sometimes it might not be necessary to activate and use a positive (+) power rail.
The fact that there are two power rails can be helpful if you have certain parts that need a lower voltage (such as 3.3V) while other parts need a higher voltage (such as 5V). You can supply these different parts with their appropriate voltage by connecting them to the correct power rail.
If necessary, you can even "plug in" one power rail to the Photon board, and then connect the second power rail to the first power rail.
Here's how you can determine whether you need to connect one or more power rails on the breadboard:
If you have only have 1-3 parts to connect, then you can choose to connect each part to a separate GND pin using a jumper wire. However, it's actually a good habit to instead connect the negative power rail because it makes it easier if you decide later to add more parts to your device.
Otherwise, use a jumper wire to connect one of the negative power rails on the breadboard to a GND pin on the Photon board. Then connect each part’s GND wire (or resistor) into this negative power rail.
If there is one (and only one) part requiring 3.3V, then connect that part directly to the 3.3V pin on the Photon board.
If there are multiple parts requiring 3.3V, then use a jumper wire to connect one of the positive power rails on the breadboard to the 3.3V pin on the Photon board. Then connect each part’s 3.3V wire into this positive power rail.
If there is one (and only one) part requiring 5V, then connect that part directly to the V-USB pin (5V) on the Photon board.
If there are multiple parts requiring 5V, then use a jumper wire to connect one of the positive power rails on the breadboard to the V-USB pin (5V) on the Photon board. (If you already connected one positive power rail to 3.3V, then connect the second positive power rail to V-USB). Then connect each part’s 5V wire into this positive power rail.
If there are no parts requiring 3.3V or 5V, then do not connect a positive power rail (because all the parts will receive power from their I/O pins). However, you will still use the negative power rail for the GND wires.
Parts have to be arranged so their pins are in their own breadboard rows (which are numbered):
Pins from different parts should not be in the same row. For example, a push button and LED would not share the same rows.
Different pins from the same part should not be in the same row. For example, the Micro OLED display has 8 pins, and each of these pins must be in a different row on the breadboard.
Resistors are the only exception to this rule: a resistor is supposed to share a row with a pin of another part (such as LED, etc.).
Parts should be arranged in a logical layout that makes it easy to understand and use the device:
Place as many of the jumper wires as possible on the side of the breadboard closest to the Photon board, so the wires don't block parts that need to be seen or interacted with.
UPDATE AVAILABLE: This section of the guidebook has been replaced with a new version (which is now a separate code guidebook). This older version will no longer be available after August 1, 2019.
The references in this section can help with:
connecting parts to create circuits using jumper wires, a breadboard, and the Photon I/O pins
coding Photon apps in the Wiring programming language that will run on the Photon device
coding web apps that interact with Photon apps through the Particle Cloud service
connecting and programming specific inputs and outputs for the Photon device
The defining feature of an IoT device is its ability to send and receive information through the Internet. This allows an IoT device to interact with other apps or with other IoT devices.
The Particle firmware (the operating system) on your Photon device has built-in functions to allow your device to send and receive data through the Particle Cloud service. This will allow your device to interact with web apps that you create.
Particle also has a JavaScript library that provides functions that will allow web apps to send and receive data through Particle Cloud. You can use these functions in your web app's JavaScript code, so that your web app can interact with your Photon device.
The three main ways your Photon device can interact with your web app through Particle Cloud are by:
sharing Photon variable: web app can read value of variable in Photon app
sharing Photon function: web app can send commands and data to Photon app
sharing Photon event: web app can receive event notifications and data from Photon app
You can also combine these Particle Cloud interactions in more complex ways. For example, your Photon app could send an event notification to your web app, which then triggers the web app to read the value of a variable in the Photon app.
This reference contains code examples for both your Photon app and your web app. Many of the code examples will need to be modified, in order to be used in your apps. For example, you may have to change the names of variables, add custom code, etc.
Particle API JS is a JavaScript library that contains functions that will allow a web app to interact with your Photon device by sending and receiving data through Particle Cloud.
A web app must load the Particle API JS file using a <script>
tag in the <head>
section of its HTML file.
If possible, you should load the Particle API JS file from a web service like jsDelivr:
Alternatively, you can download a copy of the Particle API JS file, and place the file into the same folder as your HTML file. In this case, your <script>
tag would load the file directly from the folder:
After loading the Particle API JS file (using one of the methods shown above), your web app also needs to load a JavaScript file containing your own code to interact with your Photon device. This will be loaded using another <script>
tag. The example below would load a JavaScript file (created by you) called: code.js
If a web app wants to interact with your Photon device through Particle Cloud, the web app has to know your Photon device ID and your Photo access token. These act like a username and password to help protect your Photon data.
Your Photon device ID is listed in the "Devices" section of your Particle Build account. Click the arrow to the right of your Photon device name to reveal the device ID. This device ID acts like a username to access your device's data in the Particle Cloud service.
Your Photon access token is listed in the "Settings" section of your Particle Build account. This access token acts as a password to access your device's data in the Particle Cloud service.
Your web app will need to include the device ID and access token in its own JavaScript file in order to interact with your Photon device. Usually these are stored in global variables to make it easier to use them repeatedly throughout your web app's JavaScript code.
Be sure to modify the code above to insert your actual Photon device ID and access token.
In order to use the Particle Cloud functions in the Particle API JS library, your web app's JavaScript file must declare a Particle object variable. This should be a global variable and is usually just called particle
.
Your JavaScript code will use this particle
object variable to run the Particle Cloud functions.
You can share the current values of variables in your Photon app through Particle Cloud, so a web app can read these variables.
For example, your Photon device could measure the air temperature using a sensor, store the measurement in a temperature variable, and then share this variable with a web app.
Particle Cloud will let your Photon device share up to 20 variables at one time. Each cloud variable has to be given a unique name (up to 12 characters in length).
NOTE: The only data types that are allowed to be shared as cloud variables are: int
(whole numbers), double
(decimal numbers), or String
(text, up to 622 characters).
A variable is shared through Particle Cloud by including a Particle.variable
statement in the setup()
function of your Photon app.
This Particle.variable
statement has to provide a name for your cloud variable (up to 12 characters) and identify the name of the variable in your Photon app. Usually, these two will have the same name (but they don't have to).
setup()
function of Photon AppIn the example above, the first name (in quotation marks) will become the name of your cloud variable. The second name identifies the variable in your Photon app that will be shared through the cloud. Modify this code to match your variable's name.
Your web app can read the current value of a cloud variable by using a particle.getVariable
statement in its JavaScript file.
This particle.getVariable
statement needs to provide your Photon device ID, the name of your cloud variable, and your Photon access token.
The value of your cloud variable gets temporarily stored in a local JS variable called data.body.result
that you can use in your JavaScript code.
For example, if you want to display the value in your web app, you could insert the value by using a JavaScript statement to find an HTML element with a specific id name and then changing its HTML content to include data.body.result
. In the code example below, assume that your web app HTML file contains a paragraph tag identified as: <p id="room-temp"></p>
Web apps are frequently updating their HTML through JavaScript statements that identify HTML elements using an id name or class name.
jQuery is a JavaScript library that makes it easier to update your HTML (and your CSS). jQuery statements start with $
and are usually shorter than using regular JavaScript. You can combine jQuery statements and regular JavaScript statements in the same code.
Here's an alternate example of the previous code that uses a jQuery statement instead.
If your web app needs to keep checking the current value of the variable, you can place the particle.getVariable
statement inside another custom function and then have your JavaScript code repeatedly run that custom function on a time interval (such as every 0.5 seconds, etc.).
If your web app needs to save the value of the Photon variable, you should create a global variable in your JavaScript that will be used to store the value. After getting the value of the Photon variable from the Particle Cloud, assign the data.body.result
to the JS global variable.
Your web app can get the values of several Photon variables from Particle Cloud. You just need to include a particle.getVariable
statement for each variable. However, you can put these statements inside the same custom function in your JavaScript. This next example runs a checkLocation()
function every 5 seconds to get the latitude and longitude values from Particle Cloud.
You can share a custom function in your Photon app through Particle Cloud, so a web app can call this function to make it run on your Photon device. The web app also sends data (as a text String up to 63 characters) when calling the function. This is how your web app can send commands and/or data to your Photon app.
For example, your Photon app could share a custom function to turn an LED light on or off. A web app would be able to call this function to make it run on the Photon device.
Particle Cloud will let your Photon device share up to 15 functions at one time. Each cloud function has to be given a unique name (up to 12 characters in length). You get to decide what to name your cloud function – but use a name that will make sense to someone reading your code. (Your web app will have to refer to this same cloud function name, in order to call the function.)
A custom function is shared through Particle Cloud by including a Particle.function
statement in the setup()
function of your Photon app.
This Particle.function
statement has to provide a name for your cloud function (up to 12 characters) and identify the name of the custom function in your Photon app. Usually, these two will have the same name (but they don't have to).
setup()
functionIn the example above, the first name (in quotation marks) will become the name of your cloud function. The second name identifies the custom function in your Photon app that will be shared through the cloud. Modify this code to match your function's name.
In order to share a custom function through Particle Cloud, the function must return an integer value and must accept a String value as an argument.
However, you do not necessarily have to do any with the function's return value. You also do not necessarily have to do anything inside the function with the String value. They just need to be present in the function for it to be shared with Particle Cloud.
When you want to use this custom function in your Photon app, you must pass a String value (text) to the function. Notice in the example below that we pass the text "switch"
when we call the ledToggle()
function, even though the ledToggle()
function above doesn't actually use this String data.
However, you can design your custom function to use the String data that is passed into it. The code examples below show a modified version of the ledToggle()
function for a device that has separate push buttons to turn the LED on and off. The String data passed into ledToggle()
function determines whether it will turn the light on, turn the light off, or do nothing.
If your Photon app needs to save the data sent by the web app when it calls the function, you should create a global variable in your Photon app that will be used to store the data. Then within the custom function called by the web app, assign the String data to the Photon global variable.
The Photon app receives data from the web app in the form of a String (text). However, if the data is actually a number (which was converted to a String by the web app), then you can convert the String data back into a number using either the .toInt()
or .toFloat()
method, depending on whether the number is supposed to be a whole number (integer) or a decimal number (float).
Your web app can call a cloud function to make it run on your Photon device by using a particle.callFunction
statement in its JavaScript file.
This particle.callFunction
statement needs to provide your Photon device ID, the name of your cloud function, an argument (text String) to pass to the function, and your Photon access token.
The argument
is the data that your web app sends to the Photon app. This argument data must be in the form of a text String. You can either list the String directly as text inside quotes, or you can use a String variable to store the text.
Often this particle.callFunction
statement will be included inside another JavaScript function. For example, your web app might have an onscreen button that can be clicked to toggle the LED light on or off.
For example, this code adds an onscreen button to your web app HTML that will run a JavaScript function called switchLight()
when the button is clicked:
This next code shows that the switchLight()
function in your JavaScript simply contains the particle.callFunction
statement.
You can also use a String variable to store the argument
data sent to your Photon app. For example, imagine our web app HTML had two different onscreen buttons: one to turn the light on, and a second to turn the light off.
In the JavaScript, you would declare a global variable to store the String data that will be sent to the Photon app as the argument
data. The example below creates a variable called myData
and sends either "off"
or "on"
to the Photon app depending on which onscreen button is clicked.
If the JavaScript data that you want to send is not already a String (text), then you need to convert the data into a String to send it. Numbers can be converted into a String using the .toString()
method. In this example, a variable containing a number is converted into a text string, in order to send it to the web app.
You can share an event condition that occurs in your Photon app through Particle Cloud, so a web app can be notified when the event occurs. You also have the option for the event notification to include data.
For example, if your Photon device detects movement using a motion sensor, it could send an event notification to a web app. The notification could also include data, such as which motion sensor was triggered.
Particle Cloud will let your Photon device send about one event notification per second. Sending more frequent event notifications can result in Particle Cloud temporarily slowing down your event notifications (which can make your web app become non-responsive).
TIP: To avoid a slowdown by Particle Cloud, you should add an intentional 1 second delay to your Photon code immediately after sending an event notification. (A one second delay in your Photon app is better than your web app becoming non-responsive.)
Each event notification is automatically cleared from Particle Cloud after 60 seconds (to prevent your web app from receiving outdated notifications).
An event notification is shared through Particle Cloud by including a Particle.publish
statement in your Photon app after the event condition occurs.
This Particle.publish
statement has to provide a name for your cloud event (up to 63 characters). You get to decide what to name your event – but use a name that will make sense to someone reading your code. (Your web app will have to use this same event name, in order to receive the notification.) The event can also send additional data as a String (text up to 255 characters), but this is optional.
loop()
or custom functionWhen publishing an event notification, you can also send additional data as a text String (up to 255 characters), but this is optional. The String data can either be sent directly as text inside quotes (as the example below shows) or through a String variable (as the next example shows).
This next example shows how a variable can be used to store the String data that will be sent through the event notification. In this example, the status of two magnetic switch sensors determines which text string is sent to the web app.
If the Photon data that you want to send is not already a String (text), then you need to convert the data into a String to send it. This can be done simply by listing the variable inside a String()
statement. In this example, a fingerprint ID number is converted to a text string, in order to send it to the web app.
Your web app can listen for a cloud event by using a particle.getEventStream
statement in its JavaScript file.
This particle.getEventStream
statement needs to provide your Photon device ID, the name of your cloud event, and your Photon access token. Be sure that your Photon app and web app are using the same name for the cloud event; otherwise, the web app will not receive the event notifications.
If an event notification includes optional String data, this gets temporarily stored in a local variable called feed.data
that you can use in your JavaScript.
This particle.getEventStream
statement can be placed directly after your JavaScript statements that declare the variables for your device ID, access token, and Particle object. (Do not place inside another function.)
The event stream will automatically keep listening for new event notifications. Every time an event notification occurs, it will automatically run the code inserted inside your particle.getEventStream
statement.
If your web app needs to save the data from Photon event notification, you should create a global variable in your JavaScript that will be used to store the data. After getting the event notification from the Particle Cloud, assign the feed.data
to the JavaScript global variable.
You can also combine these Particle Cloud interactions in more complex ways, depending on what is needed for your IoT system.
For example, your Photon app could send an event notification to your web app, which then triggers the web app to read the value of one or more variables in the Photon app.
Imagine a Photon device that is designed to act like a location tracker. Maybe the Photon device is installed in a vehicle, so you can track where the vehicle is parked.
In this example code, the Photon device uses a GPS receiver to determine the latitude and longitude of its location. The latitude and longitude are stored in variables, which are shared with a web app through Particle Cloud. The Photon device also has a push button. When the button is pushed, the Photon app notifies the web app to track the location of the Photon device. When the notification is received, the web app gets the updated values of the latitude and longitude variables from Particle Cloud. Then the web app displays the location on Google Maps using the latitude and longitude.
Apps that run on Photon devices are coded in a programming language called Wiring, which was specifically created for microcontrollers.
Wiring is based on another programming language called Processing. An app written in Wiring actually gets compiled (converted) into another programming language called C++ in order to run on your device.
You may have heard of another popular platform for building and programming electronic devices called Arduino. Arduino is a programming language based on Wiring. In fact, the languages are so similar that many apps created for Arduino devices will also work on Photon devices (or can be modified to work).
Apps for your Photon device are created in the Particle Build online code editor. An app is loaded onto your Photon device by "flashing" (downloading) the app over Wi-Fi (similar to updating an app on a smartphone). Here's a brief overview of navigating and using Particle Build.
You can only store and run one app at a time on your Photon device. However, you can create and save multiple apps in your Particle Build account, making it easy to "flash" a different app onto your device when needed.
Here is the official reference for the Wiring programming language:
Particle also has some custom functions built into the Photon device's firmware (its Operating System). For example, Particle has custom functions for sending and receiving data through the Particle cloud service, etc.
The basic syntax for Wiring code is similar to certain other programming languages (such as Java, C++, etc.). For example, each statement typically ends with a semi-colon, comment lines start with two forward slashes, etc.
Every Wiring app must contain a setup()
function and aloop()
function (but only one of each). In addition, an app can have custom functions. Most apps have global variables.
Here is the basic structure (in order) for the code of a Wiring app:
libraries (if needed for certain inputs or outputs)
global variables
setup()
function (required - can only have one)
loop()
function (required - can only have one)
custom functions (if needed - can have as many as needed)
It can also be helpful if you include some comments in your code.
Comments are just notes to yourself (or to anyone else reading your code) that help explain parts of your code. A comment can be inserted in your code whenever you think it will help. Any comments in your code are ignored by the device when your app runs.
A comment starts with two forward slashes. Everything after the slashes (until the end of the line) will be treated as part of the comment.
Certain inputs or outputs (such as the Micro OLED display, etc.) require that a specific code library is included in your app, so you have access to special functions to control these parts more easily. This is similar to how a webpage will include a JavaScript library, such as jQuery, in order to use special functions.
Particle Build has numerous libraries available and will automatically generate an #include
statement at the top of your code for each library that you add to your app.
Computer programs use variables to store and process data. The data might be numbers, text, etc.
Similar to variables in algebra, variables in computer programs are given names. Each variable should have a unique name. As the person coding the program, you get to decide the unique name for each variable. A variable name could be as simple as x
or y
– but it is better to use names that help describe what the variable represents, such as pushButton
or roomTemperature
. This will help your code make more sense to you and to anyone else reviewing your code.
Variable names cannot contain spaces. A common format used for variable names is to type them in "camelCase": type them in lowercase, but use a capital letter to start any new "word" within the name. (The capital letters in the middle of the name are like the humps on a camel's back.) For example, you cannot name a variable as red button
because it has a space. Instead, any of these names (or other variations) would work: redbutton
or REDBUTTON
or redButton
. The last example is in camelCase, which is easier to read than the first two examples (all lowercase, all uppercase).
Variable names cannot be the same as a keyword in the programming language. These keywords are reserved for your programming instructions. For example, pinMode
is a keyword used to set an I/O pin as an input or output. Therefore, you cannot use pinMode
as the name of a variable. Here is a list of keywords in the Wiring programming language.
Global variables are variables that will be used by multiple functions within your code, such as the setup()
, loop()
, and custom functions. Global variables are typically declared (created) at the top of the code, before the setup()
function. A variable has to be declared before it can be used.
Wiring requires that each variable is declared as a specific data type, such as int (integer numbers), float (decimal numbers), boolean (true or false), String (text), etc.
NOTE: Wiring treats pin names (D7, etc.) for inputs and outputs as int variables.
A variable can be assigned a value when it is first declared by using the "equals" sign. The value of a variable can also be assigned or changed later in the program. You can do other things with variables, such as compare the values of variables, assign the value of one variable to another variable, etc.
Variables that are only used within one function or within one statement (such as: if
statement, for
loop, etc.) can be declared inside that function or statement as a local variable. A local variable only exists inside that particular function or statement and won't be recognized by any outside functions or statements.
There is no difference in how you declare (create) a local variable versus a global variable. The difference is where you declare the variable. The simple rule is that if you declare the variable inside a function (or inside a statement), then it will be treated as a local variable. If you declare the variable outside of a function, then it will be treated as a global variable.
The setup()
function runs one time at the start of program when the device is powered on. The setup()
function typically contains statements that identify the input and output pins being used by the device.
A setup()
function must be included (even if it is simply empty inside), but only one setup()
function is allowed in an app.
After the setup()
function is finished, the loop()
function runs over and over in a repeating loop. The loop()
function usually contains statements that perform the main tasks of the device, such as reading data from inputs, processing the data to make decisions, and writing data to outputs.
A loop()
function must be included (even if it is simply empty inside), but only one loop()
function is allowed in an app.
Custom functions are typically listed at the bottom of the code, after the loop()
function. Custom functions can be run by "calling" their name within another function, such as within the setup()
, loop()
, or a different custom function.
Custom functions are useful for long or complex programs because it allows you to break up your code into smaller modules that perform specific tasks.
Similar to variables, each function must be given a unique name and must have a return data type declared. Some custom functions return a value (such as int, float, String, etc.) when they are run. If a function doesn't return any value, then void
is declared for the return data type. For example, the setup()
and loop()
functions always have void
declared for their return data type.
Custom functions can have values passed into the function as parameters when the function is called. These parameters are declared as local variables inside the parentheses following the function name.
Here is a simple app written in Wiring that has global variables, a setup()
function, a loop()
function, and also a custom function. What will this app do when it runs?
The push buttons included in your Photon kit are classified as momentary switches, which means they detect when they are being pressed or pushed. For example, the keys on a computer keyboard are momentary switches: they are only "on" when you press them (and they turn "off" when you release them).
This is different from maintained switches, which toggle between one state and another state. For example, a light switch is a maintained switch: pressing (or flipping) the switch will turn it on, and it will stay this way until pressed again (or flipped back).
The push button has 4 metal legs on its base (two legs on one side, and two legs on the opposite side). Unlike most other parts that connect to only one side of a breadboard, the push button has to connect to both sides of a breadboard.
Place the push button along the middle divider of the breadboard, so 2 of its legs will connect to the left side, while the other 2 legs will connect to right side. Carefully line up the legs with breadboard holes, and then firmly press the button down to "snap" its base into place. Then use jumper wires to connect 2 of the button legs to the Photon.
Experiment 2 of the online SparkFun Photon Experiment Guide shows how to connect a push button. Here is the connection diagram for Experiment 2 (ignore the wiring for the LED and resistor):
TIP: Be sure each jumper wire for the button is connected to the same row as one of the button legs. Both jumper wires should be placed on the same side of the breadboard (either the left or right side).
The push button does not require any special code library.
In the global variables, you should declare a variable to represent the specific pin on the Photon board that the push button is connected to. This will make it easier to understand your code (and easier to modify the code if you change which pin the button is connected to). The example below declares a variable called "button" (but you could use a different variable name).
If you are using multiple push buttons, then be sure to give each button a unique variable name. Use variable names that will make sense when someone reads your code.
Within the setup()
function, you have to include a statement to set the pin mode for the button pin variable:
If you are using multiple buttons, be sure to set the pin mode for each button's pin variable.
Code for checking the button would be placed within the loop()
function or within a custom function.
The current state of the push button can be detected by using a digitalRead()
statement.
If the button is currently being pressed, digitalRead()
will return a value of LOW
.
Often, a local variable is used to store the result of the digitalRead()
, so that your code can use this result to make decisions based on whether the button is being pressed.
Even though the push button is a momentary switch (which is only "on" when being pressed), you can modify your Photon code to make the button act like a maintained switch (which toggles between states with each press).
The key to doing this is to create a global variable that will store the current status of the part that you want the button to control (such as an LED light being "on" or "off"), so you can switch the status every time the button is pressed.
It will also help to include a delay()
statement before reading the button again because it takes a person a fraction of a second to physically press and release the button. This small delay will allow the code to detect each press as a single event (instead of as multiple presses).
The servo motor included in your Photon kit can rotate back or forth to any position between 0° and ~180° and hold its position. (In reality, this servo motor only physically rotates to about 160°, even if it is told to rotate to 180°.)
However, this type of servo motor is different from other motors that rotate continuously, like a motor used in a fan or an engine. If your device needs continuous rotation, then you need another type of motor, such as a gear motor or a continuous rotation servo motor.
The servo motor comes with 4 different plastic mounts (called "horns") that can be attached to the motor axis (the white part sticking out of the top of the motor – this is what actually rotates). There is a single-arm horn, a double-arm horn, a four-point horn, and a circular horn. Each horn just slips onto the motor axis (the horn and axis have matching "teeth"). Each horn has holes, which can allow you to attach something to the arm, using the included small screws.
The servo motor has a built-in 3-wire connector: just plug 3 jumper wires into the connector and then plug the other end of the jumper wires into a breadboard or directly to the Photon. To make it easier to remember which wire is which, use corresponding white, red, and black jumper wires to match the servo motor wires.
NOTE: The servo motor requires 5V of power, so connect it (directly or indirectly) to the V-USB pin.
IMPORTANT: The data wire must connect to an I/O pin that supports pulse-width modulation (PWM) output. Only the following pins on the Photon can act as PWM outputs: D0, D1, D2, D3, A4, A5, WKP, RX, TX.
TIP: Be sure to attach one of the horns to your servo motor. Otherwise, you won't be able to see the servo motor rotate (and it won't provide much use to your device). Later, once you test out your code to rotate the servo motor, you may need to remove and re-position the horn, so it's lined up where you want it to be. The easiest way to do this is to rotate the servo motor to 0° and then remove and re-position the horn how you want it to be pointed when it is at this angle.
Experiment 7 of the online SparkFun Photon Experiment Guide shows how to connect the servo motor. Here is the connection diagram for Experiment 7 (ignore the wiring for the push button):
The servo motor does need a code library with special functions that will allow you to control the servo motor. However, this library is already built-in to the Particle firmware on your Photon device.
In the global variables, you should declare which pin is being used as the servo motor data pin. The example below declares a variable called "servoPin" (but you could use a different variable name).
You also need to declare a Servo object variable that you will use to run the special functions in the built-in Servo library. The example below declares a variable called "servo" (but you could use a different variable name).
You may also want to declare a global variable to represent the current position (in degrees) of the servo motor. This isn't required, but it could make it easier to code the servo motor, especially if you create a custom function to rotate the motor. The example below declares a variable called "angle" (but you could use a different variable name).
There isn't any code that you need to include in the setup()
function. You don't have to set a pin mode for the servo.
However, you may want to rotate your servo motor to a particular starting position when your device first starts. If so, then include this code in the setup()
function.
Code for rotating the servo motor to a specific angle can be placed within the setup()
function (only runs once), within the loop()
function, or within a custom function.
Rotating the servo motor always takes four steps: (1) turn on the motor, (2) rotate the motor, (3) wait for a small time delay, and (4) turn off the motor.
Every time you want to rotate the servo motor, you first have to call a special function called servo.attach()
to turn on the motor.
Then you call a function called servo.write()
to rotate the servo motor to any angle from 0-180. For example, use servo.write(90);
to rotate the servo to the 90° position.
You have to include a small time delay()
before you turn off the motor. Otherwise, the servo motor might get turned off before it finishes rotating (because computer code runs much faster than the motor can physically rotate).
If you are rotating the motor by 180° (from 0° to 180° or from 180° to 0°), then delay(500);
(0.5 seconds) should be sufficient.
If you are rotating the motor by 90°, then delay(250);
should be sufficient.
If you are rotating the motor by only 1° at a time, then the delay can be just 15 milliseconds per degree: delay(15);
After rotating the servo motor, you should call a function called servo.detach()
to turn off the motor. Otherwise, the motor will be "jittery" as it tries to hold its position. After you turn off the motor, you may notice that it "debounces" (rotates backward slightly). This is normal.
Here's code that shows all 4 steps combined:
REMINDER: Once you've got your servo motor working, you may need to remove and re-position the horn, so it's lined up where you want it to be for your device. The easiest way to do this is to rotate the servo motor to 0° and then remove and re-position the horn how you want it to be pointed when it is at this angle.
IMPORTANT: You will notice that this servo motor can only physically rotate to about 160°, even if the code tells it to rotate to 180°. This is a minor limitation of this particular servo motor. You may need to try out different rotation angles in your code to make your device work the way you need it to.
It may be simpler to include a custom function in your Photon app that will rotate the servo motor to the current value of the angle
variable. This will allow you to change the value of angle
and then rotate the motor, without having to add code for the 4 steps (attach, write, delay, detach) every time you need to change the servo position.
Here's an example that shows the loop()
function calling a custom function called moveServo()
. This example simply rotates the servo motor back and forth between 0° and 180° every 5 seconds. (This extra 5-second delay between rotations is not necessary for your app.)
The Micro OLED display included in your Photon kit is a monochrome, blue-on-black screen that is 64 pixels in width and 48 pixels in height. It can be used to display text, graphics, or a combination.
The Micro OLED display requires using 7 jumper wires to connect specific OLED pins to specific pins on the Photon board.
The OLED pins are located along the top of the OLED display. Line up the pins with different numbered rows on a breadboard, and push down to insert the OLED display pins. Then use jumper wires to connect these rows to the Photon.
If the pins along the top of the display were numbered left to right as 1-8, the jumper wire connections would be:
NOTE: Several analog pins on the Photon board are duplicated. For example, there are two pins labeled as A2, two A3 pins, two A4 pins, and two A5 pins. However, the OLED only has to connect to a single A2 pin, not both (same goes for A3 and A5 pins). The only limitation is that you will not be able to connect another part (such as LED, etc.) to the other A2, A3, or A5 pins.
There are two experiments in the online SparkFun Photon Experiment Guide that show how to connect the Micro OLED display to the two different sets of analog pins. Either way works fine:
Experiment 10 shows how to connect the OLED to the analog pins on the lower left of the Photon board
Experiment 11 shows how to connect the OLED to the analog pins on the upper right of the Photon board.
Here is the connection diagram for Experiment 11 showing one way to connect the Micro OLED (ignore the wiring for the three buttons):
Your Photon app must include a code library with special functions that will allow you to control the OLED display.
In Particle Build, click on the bookmark icon to open the Libraries sidebar.
Type "oled" into the search field. Select the result called: SPARKFUNMICROOLED
Click the button to "Include in Project"
Select the name of your Photon app, and then click the "Confirm" button
Particle Build will automatically insert an #include
statement at the top of your app code
The following code should be included in your global variables to define certain pins that the OLED is using and to declare a MicroOLED object variable called "oled" that you will use to run the special functions in the OLED library.
You have to include a statement within the setup()
function to start the OLED display:
Code for displaying text could be placed within the setup()
function (only runs once), within the loop()
function, or within a custom function.
Code for displaying text on the OLED screen consists of at least 5 steps: (1) clear the screen, (2) set the cursor position on the screen, (3) set the font type (font size), (4) print text to the screen, and (5) display the updated screen.
If desired, steps 2-4 can be repeated to change the cursor position and/or font type for different text that you want to print on the screen.
To clear the screen:
The cursor (starting point for printing) can be set to any x-position and y-position. The OLED is 64 pixels wide by 48 pixels tall. The upper-left corner of the screen is (0,0).
There are 4 font types (sizes) available. The font type is set by referring to the font type number (0, 1, 2, or 3):
Here are the differences between the font types:
You can mix font types on the screen by printing something in one font type and then switching to a different font type to print something else.
Text and variable values (integer, float, or String) can be printed to the screen. Text that is longer than the screen column width will automatically wrap to the next line.
However, once the entire screen is filled with text, the screen will not scroll. Instead no more new text will be displayed. The screen will have to be cleared in order to display new text.
There are two different print commands: print()
and println()
print()
will print text to the screen, but the cursor will remain on the same line. So the next text printed to the screen starts where the last text ended.
println()
will print the text to the screen, and then move the cursor to the start of a new line. So the next text printed to the screen starts on the new line.
The print()
command is helpful for combining text and variables on the same line:
Text printed to the screen will not actually be shown until you specifically tell the OLED to display the updated screen.
Code for displaying graphics could be placed within the setup()
function (only runs once), within the loop()
function, or within a custom function.
More info coming...
The speaker included in the Photon kit can be used to produce tones or play simple music (note by note).
The speaker is a polarized part, meaning it has to be connected in a certain way to work properly. Specifically, the speaker has a positive pin and a negative pin. These can be identified by markings printed on the bottom of the speaker next to each pin.
Line up the speaker pins different numbered rows on the breadboard (be sure to remember which row has the positive pin), and push down to insert the speaker into the breadboard. Then plug jumper wires into the two rows with the speaker pins and connect them to the Photon.
IMPORTANT: The speaker's positive pin must connect to an I/O pin that supports pulse-width modulation (PWM) output. Only the following pins on the Photon can act as PWM outputs: D0, D1, D2, D3, A4, A5, WKP, RX, TX.
Experiment 5 in the online SparkFun Photon Experiment Guide shows how to connect the speaker. Here is the connection diagram from Experiment 5:
The speaker does not require any special code library.
In the global variables, you should declare which pin is being used as the speaker pin. The example below declares a variable called "speakerPin" (but you could use a different variable name).
Within the setup()
function, you have to include a statement to set the pin mode for the speaker pin variable:
Code for producing tones with the speaker could be placed within the setup()
function (runs only once), within the loop()
function, or within a custom function.
The speaker uses the tone()
function to produce a sound of a specific frequency for a specific duration of time.
The speaker can produce tones ranging in frequency from 20Hz (very low pitch) to 20KHz (very high pitch), which covers the full range of sounds that humans can hear.
NOTE: There is no built-in function to change the volume of the sound. However, you will notice that certain frequencies (in the mid-range) will naturally seem louder.
The tone()
function requires 3 values: speaker pin number, frequency, and duration. These values can be listed in the function as integer numbers or as integer variables.
The frequency should be an integer value ranging from 20-20000 (20Hz to 20KHz). Lower numbers will have a lower pitch (more bass). High numbers will have a higher pitch (more treble).
Note: The range of sounds that humans can hear naturally diminishes with age (starting as early as 18). As people get older, they become less able to hear high-frequency sounds. Everyone (regardless of age) should be able to hear sounds up to a frequency of 8000Hz. However, sounds above this frequency may not be heard by certain adults depending on their age range (so keep this in mind when building a product that uses sound).
The duration should be an integer value representing the number of milliseconds to play the tone (1000 milliseconds = 1 second). The Photon device will play the tone for the designated duration and then automatically turn the speaker off again.
Note: Using a duration of 0 (zero) will cause the speaker to produce a continuous tone.
You can use the notone()
function to turn the speaker off. This is not normally needed since a tone will automatically stop playing after the designated duration.
However, if you are playing a continuous tone (duration = 0) or simply want to turn off the speaker, use the notone()
function.
Try out this example app that plays a song. Do you recognize the song?
If you can figure out the notes and beats to a song, you can change the code below for songNotes
and songBeats
to play that song. Be sure to update the songLength
value, and adjust the tempo
value if necessary.
Did you figure out the song? 😎
LEDs (light-emitting diodes) are small, bright, power-efficient lights commonly used in electronic products.
An LED light is a part, meaning it has to be connected to a circuit in a certain way to work properly. Specifically, each LED has a positive leg and a negative leg. These can be identified visually by length: the negative leg has been made shorter.
To make it easier to insert the LED into a breadboard, you can carefully bend the positive leg as shown, so both legs become the same length. You can still identify them visually: the straight leg is negative, and the bent leg is positive.
The negative leg of the LED has to be connected to GND (-). The positive leg is connected to any I/O pin, which will serve as the voltage source (+).
In order to use a resistor, you will need to bend both ends into 90° angles, so the resistor can be inserted into the holes on a breadboard.
The resistor is typically used in place of a jumper wire to connect the negative leg of the LED to GND (-).
The LED does not require any special code library.
In the global variables, you should declare a variable to represent the specific pin on the Photon board that the LED is connected to. This will make it easier to understand your code (and easier to modify the code if you change which pin the LED is connected to). The example below declares a variable called "led" (but you could use a different variable name).
If you are using multiple LED lights, then be sure to give each LED a unique variable name. Use variable names that will make sense when someone reads your code.
Within the setup()
function, you have to include a statement to set the pin mode for the LED pin variable:
If you are using multiple LED lights, be sure to set the pin mode for each LED's pin variable.
IMPORTANT: If you want an LED light to be off when your device first starts, then be sure to include code to do this within the setup()
function (after setting the pin mode). Otherwise, the LED light might be on (at a low brightness) when the device starts, depending on which I/O pin the LED is connected to.
An LED can be turned on or off by using a digitalWrite()
statement. This can be included within the setup()
function (only runs once), within the loop()
function, or within a custom function.
To turn on an LED, set its LED pin variable to HIGH
:
To turn off an LED, set its LED pin variable to LOW
:
An LED can be turned on to a specific brightness by using a analogWrite()
statement, instead of using digitalWrite()
. However, the LED must be connected to a pin that is capable of PWM output.
Only the following pins on the Photon RedBoard can act as PWM outputs: D0, D1, D2, D3, A4, A5, WKP(A6), RX, TX.
To adjust the LED brightness, set the LED pin variable to any integer value between 0-255:
The in your Photon kit can measure the amount of moisture in soil or similar materials.
The moisture sensor has two gold-plated legs that you would insert into the soil. Moisture in the soil will allow electricity to conduct from one sensor leg to the other. More moisture allows more electricity to conduct. The sensor can indirectly measure the amount of moisture in the soil by measuring the the amount of electricity being conducted.
Your moisture sensor has an attached 3-pin terminal connector that you will use to attach 3 jumper wires (red, black, and yellow). The back of the sensor has labels for the 3 terminals: VCC, GND, SIG. Use a small flat-head screwdriver to slightly loosen each screw in the connector (turn counterclockwise to loosen – "lefty loosey"). Insert a red jumper wire into the connector opening for VCC. Then use the screwdriver to tighten that screw until the wire is firmly held in place (turn clockwise to tighten – "righty tighty"). Repeat to connect the black wire to GND and to connect the yellow wire to SIG.
Now you can plug the other end of the jumper wires directly into the Photon – or into a breadboard (and then use 3 more jumper wires to complete the connection to the Photon).
NOTE: The moisture sensor power wire (VCC) is being connected to a second I/O pin for power, instead of 3.3V or V-USB (5V). The reason is that your code should only supply power to the moisture sensor when you need to take a reading. After the reading, your code should turn the power off to the sensor. A constant flow of electricity across the sensor legs could cause them to corrode over time (because of natural salts and other minerals in the soil). The gold-plating on the legs resists corrosion, but it is still better to use your code to control when the sensor is actually powered.
IMPORTANT: The moisture sensor data wire (SIG) must connect to an analog I/O pin, such as: A0, A1, A2, A3, A4, A5.
of the online SparkFun Photon Experiment Guide shows how to connect the moisture sensor directly to the Photon (but you could also connect it to a breadboard and then use additional jumper wires to connect to the Photon). Here is the connection diagram for Experiment 3:
Once the moisture sensor is connected to the Photon, you can insert the sensor legs into the soil where you need to take measurements.
The moisture sensor does not require any special code library.
In the global variables, you should declare variables for the pins being used for the sensor power and sensor data. The example below declares variables called "moisturePower" and "moistureData" (but you could use a different variable name).
You will probably also want to declare an integer variable to store the reading from the moisture sensor. This will make it easier to do something based on the measurement. The example below declares a variable called "moistureReading" (but you could use a different variable name).
Within the setup()
function, you have to include a statement to set the pin mode for the moisture sensor power pin variable. You should also turn off the power to the moisture sensor when the device first starts.
IMPORTANT: Do not set a pin mode for the moisture sensor data variable.
Code for measuring the amount of moisture would be most likely placed within the loop()
function or within a custom function.
Measuring the amount of moisture always takes four steps: (1) turn on the power to the sensor, (2) wait for a small time delay (to allow electricity to conduct through the soil), (3) read the measurement, and (4) turn off the power to the sensor.
The measurement will be a value ranging from 0-4095.
When there is less moisture detected, the reading will be lower. When there is more moisture detected, the reading will be higher.
You will need to add code to do something with the moisture reading (such as: display it on the OLED screen, send the data to your web app, turn on LED if the reading is less than a certain value, etc.).
TIP: You can test out the moisture sensor by holding both of the sensor legs between your thumb and index finger. The moisture in your skin will conduct electricity across the sensor legs. Don't worry, the amount of electricity will be very small – you won't even feel it. The moisture reading will be low, but it should be detectable.
RECOMMENDATION: Depending on the specific purpose of your device, you may need to gather some data under different conditions to figure out which moisture values to use in your code to make decisions about what the device should do.
A is a variable resistor that can be adjusted by sliding, rotating, or another type of physical interaction.
Potentiometers are used in various electrical devices such as: joysticks and other game controllers, control knobs and sliders, dimmer switches for lights, etc.
The potentiometer included in your Photon kit is a "" that can be rotated and used as a dial. The dial can be rotated approximately 270° (it cannot be rotated all the way around). The position of the dial can be measured and used as an input to change something (such as: brightness of light, volume of sound, etc.) – or to make a selection from a range of values.
Your potentiometer has 3 metal legs. Line up the legs with different numbered rows on the breadboard, and push down to insert the potentiometer into the breadboard. Then use jumper wires to connect the 3 leg rows to the Photon.
IMPORTANT: The middle leg of the potentiometer must connect to an analog I/O pin, such as: A0, A1, A2, A3, A4, A5.
The potentiometer does not require any special code library.
In the global variables, you should declare which pin is being used as the potentiometer input pin (middle leg). The example below declares a variable called "dialPin" (but you could use a different variable name).
You will probably also want to declare an integer variable to store the reading from the dial. This will make it easier to do something based on the measurement. The example below declares a variable called "dialReading" (but you could use a different variable name).
There isn't any code that you need to include in the setup()
function for the potentiometer.
IMPORTANT: Do not set a pin mode for the potentiometer.
You can measure the position of the potentiometer dial using an analogRead()
statement. This code would be most likely placed within the loop()
function or within a custom function.
The measurement will be a value ranging from 0-4095.
When the dial is rotated all the way to the left (counterclockwise), the reading will be 0. When the dial is rotated all the way to the right (clockwise), the reading will be 4095.
IMPORTANT: Remember that the dial can only be rotated approximately 270° – it cannot be rotated all the way around.
In many cases, you don't want your dial to give you a number between 0-4095. Instead, you may want a dial that can be used to a select a value between a smaller custom range.
To do this, you can use a map()
function that converts a measurement from its original range (such as 0-4095) into a new range of your choice. You decide the minimum and maximum values for this new range.
To map the dial reading to your own custom range of values, it will help to declare global variables for the minimum value of your custom range, the maximum value of your custom range, as well as a variable to store your new dial value mapped within this custom range.
Here's the code to take a dial measurement and then map it to your custom range.
So now you can use your dial to turn it up to 11.
NOTE: The code rounds the mapped value to the nearest integer because the map()
function always returns a decimal value. Also, the code adds 1 to the maxValue because otherwise it is very difficult to select the maximum value even if the dial is turned all the way to the right.
The included in your Photon kit uses passive infrared (PIR) light to detect movement.
The motion sensor has a built-in 3-wire female JST connector. If necessary, attach a , and plug it into different numbered rows on a breadboard. Then use jumper wires to connect the rows to the Photon. To make it easier to remember which wire is which, use corresponding black, white, and red jumper wires to match the motion sensor wires.
NOTE: The motion sensor requires 5V of power, so connect it (directly or indirectly) to the V-USB pin.
The first part of Experiment 9 in the online SparkFun Photon Experiment Guide shows how to connect the motion sensor. Here is the connection diagram from Experiment 9:
The motion sensor does not require any special code library.
In the global variables, you should declare which pin is being used as the motion sensor data pin. The example below declares a variable called "motionPin" (but you could use a different variable name).
If you are using multiple motion sensors, then be sure to give each motion sensor a unique variable name. Use variable names that will make sense when someone reads your code.
Within the setup()
function, you have to include a statement to set the pin mode for the motion sensor data pin variable:
If you are using multiple motion sensors, be sure to set the pin mode for each motion sensor's data pin variable.
Code for checking the motion sensor would be placed within the loop()
function or within a custom function.
The motion sensor can be checked by using a digitalRead()
statement.
If the sensor is currently detecting motion, digitalRead()
will return a value of LOW
.
Often, a local variable is used to store the result of the digitalRead()
, so that your code can use this result to make decisions based on whether motion is detected.
Think about what your Photon app should do if motion is detected:
turn on a light
make a sound with the speaker (a tone with a frequency of 2000Hz works well)
send a notification to your web app
etc.
A is a sensor that measures the amount of light in the environment.
Some outdoor lights have photocells that are used to automatically turn the light on or off depending on whether it is dark or light outside.
Most smartphones and tablets have photocells that automatically change the brightness of their screens depending on the amount of ambient light detected.
The photocell has 2 metal legs. Line up the legs different numbered rows on the breadboard, and gently insert the photocell into the breadboard. (If you push too hard, you'll bend the legs. If that happens, just remove the photocell, carefully straighten the legs, and try again.) Then use 2 jumper wires and a resistor to connect the rows to the Photon.
NOTE: One of the photocell legs will have two connections: it should connect to an analog I/O pin through a jumper wire, and it should also connect to ground (GND) through a resistor. In the breadboard row, the jumper wire for the analog I/O pin should be placed between the photocell leg and the resistor leg. Look at the example wiring diagram below as a visual reference.
IMPORTANT: The photocell must connect to an analog I/O pin, such as: A0, A1, A2, A3, A4, A5.
The photocell does not require any special code library.
In the global variables, you should declare which pin is being used as the photocell analog input pin. The example below declares a variable called "lightPin" (but you could use a different variable name).
You will probably also want to declare an integer variable to store the reading from the photocell. This will make it easier to do something based on the measurement. The example below declares a variable called "lightReading" (but you could use a different variable name).
There isn't any code that you need to include in the setup()
function for the photocell.
IMPORTANT: Do not set a pin mode for the photocell.
You can measure the amount of light using an analogRead()
statement. This code would be most likely placed within the loop()
function or within a custom function.
The measurement will be a value ranging from 0-4095.
When there is less light detected, the reading will be lower. When there is more light detected, the reading will be higher.
You will need to add code to do something with the light reading (such as: display it on the OLED screen, send the data to your web app, turn on a LED light if the reading is less than a certain value, etc.).
RECOMMENDATION: Depending on the specific purpose of the photocell in your device, you may need to gather some data under different conditions to see how dark or how bright the environment will actually be where your device will be used. This will help you decide which values to use in your code to make decisions about what the device should do.
When learning a new coding language, many people first create what is called a "Hello World" program. Traditionally, this involves displaying the text "Hello World" on the screen. The purpose is to demonstrate that you can create a simple working program in the new coding language.
Creating a working device with an electronics kit involves both building the physical device and programming it. So if your device doesn't work as expected, the reason could be that some of the parts are connected incorrectly – or the program might have a mistake – or it could be both.
So you will create a different kind of "Hello World" app for your Photon device: an app that doesn't require connecting any additional parts to the Photon, so you can first focus on getting some code to work.
The Photon has a built-in blue LED light that is connected to its D7 pin. This "Hello World" app will turn this blue LED on and off in a repeating pattern. This will be your first app before you start to connect additional parts to program more complex devices.
This app – like all apps that run on Photon devices – is coded in a programming language called Wiring. Here's an overview of the .
Login to your account. If necessary, here's a .
Create a new app titled: hello-world
Delete the placeholder code that Particle Build inserted for your new app (the empty setup()
and loop()
functions).
Copy and paste the code below into your new app. Save the app in Particle Build, and then load ("flash") the app onto your Photon device. During "flashing", Particle Build transfers the app to your device over Wi-Fi. The RGB light on your Photon blinks magenta as the new app is being flashed, and then the Photon restarts. Be patient – sometimes it takes longer for your first app to flash because Particle may need to also update the firmware (OS) on your Photon device.
After the Photon has reconnected to Wi-Fi, the new app will automatically start running. If everything worked correctly, the blue D7 LED on your Photon device should blink on and off repeatedly. It may not seem like much, but you've just taken your first step in coding with the Wiring language.
Once you get the app working, try modifying the code to change the LED blinking pattern. Flash your modified app to your Photon to see what your changes do. Can you make the LED blink faster? Can you make it blink slower? Can you make it blink in a more complex pattern (maybe similar to Morse code)?
A couple of things to note about the code:
The lines that begin with two forward slashes are comments. Comments are just notes for people reading the code. The comments are ignored by the device when the app runs. Comments are optional, but it can be helpful to include comments to explain certain parts of the app.
Integers are supposed to be whole numbers, but the Wiring language treats input and output pin names (D7, etc.) as "integer" variables.
A can detect whether a door, window, drawer, etc. is open or closed.
The switch consists of two pieces, and it can detect whether these two pieces are close to each other. The two pieces have to be within 20 mm (about 0.75 inches) of each other – otherwise, the switch will detect that it is open.
The piece with the wires contains a special switch called a that moves in response to the presence (or absence) of a magnetic field. The other piece (without the wires) contains a small magnet, so it can activate the reed switch when the two pieces are close to each other.
For example, the piece with the wires (the reed switch) could be attached on a stationary door frame, and the piece without the wires (the magnet) would be attached on the door near its edge. The two pieces would be installed so they are very close together when the door is closed. When the door is opened, the reed switch detects that the magnet has moved away.
These magnetic switches are commonly used in security systems, but they are also used in many other products. For example, a doorbell uses a magnetic switch. Small magnetic switches are also used in many laptops and tablets to put the device to sleep when the laptop lid or tablet cover is closed.
The second part of Experiment 9 in the online SparkFun Photon Experiment Guide shows how to connect the motion sensor. Here is the connection diagram from Experiment 9:
The stationary piece of the magnetic switch (the piece with the wires) is connected to the Photon device. The other piece of the magnetic switch would be attached to the movable object (door, window, drawer, etc.) that can be opened.
The magnetic switch does not require any special code library.
In the global variables, you should declare which pin is being used as the magnetic switch pin. The example below declares a variable called "magnetPin" (but you could use a different variable name).
If you are using multiple magnetic switches, then be sure to give each magnetic switch a unique variable name. Use variable names that will make sense when someone reads your code.
Within the setup()
function, you have to include a statement to set the pin mode for the magnetic switch pin variable:
If you are using multiple magnetic switches, be sure to set the pin mode for each magnetic switch's pin variable.
Code for checking the magnetic switch would be placed within the loop()
function or within a custom function.
The magnetic switch can be checked by using a digitalRead()
statement.
If the magnetic switch is closed, digitalRead()
will return a value of LOW
.
If the magnetic switch is open, digitalRead()
will return a value of HIGH
.
Often, a local variable is used to store the result of the digitalRead()
, so that your code can use this result to make decisions based on whether the switch is open or closed.
Think about what your Photon app should do if the magnetic switch detects it is open:
turn on a light
make a sound with the speaker (a tone with a frequency of 2000Hz works well)
send a notification to your web app
etc.
The can measure the relative humidity and temperature of the air.
The front of the RHT03 sensor has openings to allow air in. Line up the sensor pins with different numbered rows on a breadboard, and push down to insert the sensor pins. Then use jumper wires to connect these rows to the Photon.
Looking at the front of the sensor, if these pins were numbered left to right as 1-4, the jumper wire connections would be:
The RHT03 sensor has 4 pins, but only 3 of them need to be connected.
Your Photon app must include a code library with special functions that will allow you to use the RHT03 sensor.
In Particle Build, click on the bookmark icon to open the Libraries sidebar.
Type "rht" into the search field. Select the result called: SPARKFUNRHT03
Click the button to "Include in Project"
Select the name of your Photon app, and then click the "Confirm" button
Particle Build will automatically insert an #include
statement at the top of your app code
In the global variables, you should declare which pin is being used as the RHT03 data pin. The example below declares a variable called "rhtPin" (but you could use a different variable name).
You also need to declare a RHT03 object variable that you will use to run the special functions in the RHT03 library. The example below declares an object variable called "rht" (but you could use a different variable name).
You will also want to declare a global variable for the temperature reading and/or humidity reading. The readings from the sensor are float
values (numbers with decimals), but you can convert these into an int
value (whole number) by rounding them after reading them (because people usually just want to know the temperature to the nearest degree, not to multiple decimal places).
TIP: If you aren't planning on using the humidity reading in your app, then don't create a global variable for it. (The same for the temperature variable if you only care about the humidity reading.)
You have to include this statement within the setup()
function to start the RHT03 sensor:
Code for reading the RHT03 sensor measurements would mostly likely be placed within the loop()
function or within a custom function.
Every time you want to get a new sensor reading, you first have to call a special function called rht.update()
. If the update is successful, the function will return a value of 1 (true). If so, then you can get the new measurement(s).
Each measurement is a float
value (number with decimals). In the code example below, we are rounding the readings to store them as global int
variables.
The humidity reading will be a value between 0-100 representing the relative humidity of the air (as a percentage). Higher numbers are more humid (more water vapor in air).
TIP: If you aren't planning on using the humidity reading in your app, then don't include the lines of code to take the humidity reading. (The same for the temperature reading if you only care about the humidity reading.)
An LED can be easily burned out if it receives too much power. Therefore, a must be used to help limit the amount of current flowing through the LED.
of the online SparkFun Photon Experiment Guide shows how to connect an LED. Here is the connection diagram for Experiment 1:
PWM stands for , which is how a digital output signal (which has only two values: HIGH or LOW) can act like an analog output signal (which has a range of values).
of the online SparkFun Photon Experiment Guide shows how to connect the potentiometer. Here is the connection diagram for Experiment 4 (ignore the wiring for the 3 push buttons):
For example, if you were using the dial as a volume control knob, you may want the dial to give you a value between 0-10 (with 0 representing volume off and 10 representing maximum volume). Even better, you may want a .
of the online SparkFun Photon Experiment Guide shows how to connect the photocell. Here is the connection diagram for Experiment 6 (ignore the wiring for the RHT03 humidity and temperature sensor):
of the online SparkFun Photon Experiment Guide shows how to connect the RHT03 sensor. Here is the connection diagram for Experiment 6 (ignore the wiring for the photocell and resistor):
Push Button
Photon Pin
Leg (any leg)
any I/O pin
Other Leg (on same side)
GND
Servo Motor
Photon Pin
White - Data
any I/O pin with PWM
Red - Power (5V)
V-USB (5V)
Black - Ground
GND
OLED Pin
Photon Pin
Pin 1 - CS
A2
Pin 2 - RST
D6
Pin 3 - D/C
D5
Pin 4 - SDO
(none)
Pin 5 - SCK
A3
Pin 6 - SDI
A5
Pin 7 - 3V3
3.3V
Pin 8 - GND
GND
Font Type
Font Size
Font Description
0
5x7 pixels, 10 columns by 6 rows
255 different characters
1
8x16 pixels, 6 columns by 3 rows
any character on keyboard
2
10x16 pixels, 5 columns by 3 rows
only numbers and period
3
12x48 pixels, 5 columns by 1 row
only numbers and colon
Speaker
Photon Pin
Positive (+) pin
any I/O pin with PWM
Negative (-) pin
GND
LED Light | Photon Pin |
Positive leg (long) = Power | any I/O pin |
Negative leg (short) = Ground | GND using resistor |
Potentiometer | Photon Pin |
Outer leg (either one) | 3.3V |
Middle leg | any analog I/O pin |
Outer leg (other one) | GND |
Photocell | Photon Pin |
First leg (either one) | 3.3V |
Second leg | (1) any analog I/O pin, (2) GND using resistor |
Magnetic Switch | Photon Pin |
Wire 1 (either one) | any I/O pin |
Wire 2 | GND |
RHT03 Pin | Photon Pin |
Pin 1 - Power | 3.3V or V-USB (5V) |
Pin 2 - Data | any I/O pin |
Pin 3 - Unused | (none) |
Pin 4 - Ground | GND |
Moisture Sensor | Photon Pin |
VCC (Red) - Power | any I/O pin |
GND (Black) - Ground | GND |
SIG (Yellow) - Data | any analog I/O pin |
Motion Sensor | Photon Pin |
Black - Data | any I/O pin |
White - Ground | GND |
Red - Power (5V) | V-USB (5V) |
The electret microphone can be used to detect sound levels in the nearby environment from 100Hz to 10KHz (which is most of the human hearing range).
IMPORTANT: The data wire must connect to an analog I/O pin, such as: A0, A1, A2, A3, A4, A5.
The microphone does not require any special code library.
In the global variables, you should declare which pin is being used as the microphone data pin. The example below declares a variable called "micPin" (but you could use a different variable name).
You will also want to declare an integer variable to store the sound level read by the microphone. This will make it easier to do something based on the data. The example below declares a variable called "soundLevel" (but you could use a different variable name).
There isn't any code that you need to include in the setup()
function for the microphone.
IMPORTANT: Do not set a pin mode for the microphone.
You can measure the amplitude of the sound in the environment using an analogRead()
statement.
The measurement will be a value ranging from 0-4095. Sounds with a higher amplitude (louder) will have a higher measurement.
However, sound waves have peaks and valleys, so a single measurement is not necessarily an accurate measurement of the sound environment. So it is better to take multiple measurements over a brief period of time (fraction of second) to get the "peak-to-peak" amplitude of the sound level.
The code below shows a custom function called listenMic()
that samples the sound over a window of 50 milliseconds. The custom function is called within the loop()
function. You would need to add code within the loop()
to do something based on the sound level.
The triple-axis accelerometer included in your Photon kit can be used to detect changes in motion or orientation in 3 dimensions (x, y, z).
Smartphones and tablets use accelerometers to sense the orientation of the device, in order to change the screen orientation to match. Fitness trackers use accelerometers to count steps and measure other activity. In fact, your accelerometer has built-in functions to detect portrait vs. landscape orientation (useful for device screens), as well as taps (useful for activity trackers).
Like the name implies, an accelerometer works by detecting acceleration – a change in motion. If a device with an accelerometer experiences a change in motion (i.e., speeding up, slowing down, or changing direction), the accelerometer can sense this change and measure the amount of acceleration in each of the 3 dimensions (x, y, z).
Even if a device with an accelerometer is not moving, the accelerometer can detect the orientation (tilt) of the device by measuring the acceleration due to Earth's gravity, which is a constant downward force acting on all objects. The accelerometer can determine if the object is parallel to the Earth's surface or if it is tilted – and can measure the amount of tilt for each of the 3 dimension (x, y, z).
Line up the accelerometer's pins with different numbered rows on a breadboard, and push down to insert the accelerometer pins. Then use jumper wires to connect these rows to the Photon.
The accelerometer has 6 pins, but only 4 of them need to be connected.
Experiment 8 of the online SparkFun Photon Experiment Guide shows how to connect the accelerometer. Here is the connection diagram for Experiment 8 (ignore the wiring for the push button):
Your Photon app must include a code library with special functions that will allow you to use the the accelerometer.
In Particle Build, click on the bookmark icon to open the Libraries sidebar.
Type "mma8452q" into the search field. Select the result called: SPARKFUNMMMA8452Q
Click the button to "Include in Project"
Select the name of your Photon app, and then click the "Confirm" button
Particle Build will automatically insert an #include
statement at the top of your app code
In your global variables, you need to declare a MMA8452Q object variable that you will use to run the special functions in the library. The example below declares an object variable called "accel" (but you could use a different variable name).
You will probably also want to declare global variables for the data from the accelerometer. You only need to include variables for the types of data that your Photon app will actually use. If you want, use can use different names for these variables.
You have to include an accel.begin()
statement within the setup()
function to initialize the accelerometer by setting its scale range (SCALE) and output data rate (ODR).
The accelerometer scale (SCALE) can be set to ± 2, 4, or 8 g (where g is a unit representing Earth's gravity, which is about 9.8 m/s2). The options for setting the scale are designated as: SCALE_2G
, SCALE_4G
, or SCALE_8G
. A higher scale can detect larger changes in acceleration but is less precise. A lower scale is more precise. For your application, using SCALE_2G
is the probably the best choice because it will be the most precise.
The accelerometer output data rate (ODR) determines how frequently it gathers new measurements. The ODR is set in Hz (number of times per second). The options for setting the ODR are designated as: ODR_1
, ODR_6
, ODR_12
, ODR_50
, ODR_100
, ODR_200
, ODR_400
, or ODR_800
. A higher ODR is faster (more frequent), while a lower ODR is slower (less frequent). For your application, using ODR_50
is probably a good choice because it's not too fast and not too slow.
Code for reading the accelerometer data would most likely be placed within the loop()
function or within a custom function.
Your accelerometer can provide three different types of data:
Acceleration Measurements (x, y, z)
Orientation Detection (portrait vs. landscape)
Tap Detection (good for activity tracking)
Every time you want to get new acceleration measurements, you first have to call a special function called accel.available()
. If new measurements are available (which depends on the ODR), the function will return a value of 1 (true). If so, then you can read the new measurements by using an accel.read()
statement.
You can detect the orientation (portrait vs. landscape) of your device by using an accel.readPL()
statement.
The possible values returned for accel.readPL()
are:
PORTRAIT_U
(Portrait Up)
PORTRAIT_D
(Portrait Down)
LANDSCAPE_R
(Landscape Right)
LANDSCAPE_L
(Landscape Left)
LOCKOUT
("Flat" - neither portrait or landscape)
NOTE: You may need to determine the proper physical arrangement of the accelerometer on your device, so that you can accurately read the device orientation.
If your app needed to do something different for each possible orientation value, the code below shows one way to accomplish this. (Another way is to use a switch()
statement instead of if-else statements.)
More info coming...
The LinkSprite JPEG Color Camera Serial Interface with Infrared can take pictures in JPEG format and transfer the picture data over a serial data connection. The camera can take pictures in 3 different sizes: 640×480 pixels, 320×240 pixels, or 160×120 pixels.
In normal lighting, the camera takes color pictures. When it's dark, a built-in ambient light sensor automatically turns on infrared LEDs to allow the camera to take black-and-white photos ("night vision").
The camera lens has a protective cover that you will need to remove before taking pictures. The camera board has holes in three of its corners, which could be used to help mount the camera to a surface.
The camera has a 4-wire connector. The ends of these wires are too wide to insert directly into a breadboard. However, you can connect additional wires to the camera wire ends, in order to connect to a breadboard or directly to the Photon. (In fact, you can simply plug a jumper wire into each camera wire end. To make it easier to keep track of the wires, use jumper wires with matching colors.)
The camera will communicate with the Photon board over a serial data connection using the Photon RX and TX pins.
NOTE: For serial data connections, the RX pin of one device connects to the TX pin of the other device. (RX = receive, TX = transmit)
You need to include a statement within the setup()
function to start a serial data connection (which will activate both the RX and TX pins on the Photon). This will allow the Photon and the camera to send and receive data between each other. The camera communicates at a default baud rate of 38400 bps.
A 12-button keypad can be used as an input for codes or commands. It has buttons for ten digits (0
-9
) and two symbols (*
,#
).
The keypad has 9 pinouts, but only the middle 7 are used. (The outer pinout on each side is not used.)
The keypad works by wiring the 12 buttons into 3 columns and 4 rows (thus 7 pinout wires). Pressing a button sends a signal through two wires representing the column and row of the key that was pressed. For example, key “8” is in column 2 and row 3 (which correspond to pinout wires 1 and 6).
Connect wires to each of the 7 pinouts, and then connect the other ends of the wires into different numbered rows in a breadboard. Then use jumper wires and resistors to connect the rows to the Photon.
NOTE: Keypad wires 3, 5, 6, and 7 each have two connections. They each connect to an I/O pin, and they each connect to 5V (V-USB) through a 10K resistor. Look at the example wiring diagram for the photocell as a visual reference, since it has similar wiring (except the resistor for the keypad will connect to 5V instead of GND).
FYI: Notice that this part does not connect to GND, which is unusual.
A code library for the keypad has to be included in your Photon app:
In Particle Build, click on the bookmark icon to open the Libraries sidebar.
Type "keypad" into the search field. Select the result called: KEYPAD_PARTICLE
Click the button to "Include in Project"
Select the name of your Photon app, and then click the "Confirm" button
Particle Build will automatically insert an #include
statement at the top of your app code
This code library contains special functions that allow you to interact with the keypad.
In the global variables, you will need to declare variables that will help set up the keypad buttons for the Keypad library functions. You will also need to declare a Keypad object variable that you will use to run the special functions in the library. The example below declares an object variable called "keypad" (but you could use a different variable name).
You will probably also want to declare variables for a secret PIN code or commands that can be entered to control the device.
NOTE: Be sure to use single quotes when listing key characters (not double quotes).
There isn't any code that you need to include in the setup()
function for the keypad.
You can read a key press by using a keypad.getKey()
statement that will identify which key is being pressed. (If no key is being pressed, the statement returns a value of false.)
If you want to check for a specific key, you can compare the value of key
to a specific keypad character.
RECOMMENDED: Connect the speaker to provide audio feedback whenever any key is pressed. Within the if (key)
statement, play a brief tone if a key is pressed.
Notice that delay(100);
was included at the end of the if(key)
statement. This is because it takes a person a fraction of a second to physically press and release a key. Including a small delay (0.1 seconds) before checking again for a key press will allow the code to detect each key press as a separate event (otherwise, it might detect it as multiple presses of the same key). You may need to fine-tune the delay value based on user testing, so the delay is not too fast and not too slow.
You can also use a series of if-else statements to compare the key pressed against multiple keys, in order to do something different based on which key is pressed.
NOTE: Be sure to use single quotes when listing key characters (not double quotes).
Here is an example of a custom function called checkPIN()
that will detect whether a secret PIN code has been correctly entered. You will need to add instructions to do something if the secret code is correctly entered.
RECOMMENDED: Connect the speaker to provide audio feedback whenever any key is pressed. Within the checkCode()
function, play a brief tone if any key is pressed.
A continuous rotation servo motor can rotate continuously, like a wheel. This type of servo motor can be made to rotate in either direction (clockwise or counterclockwise).
However, if your device needs to rotate to a precise angle and hold that position, then you need a regular servo motor, such as the one included in your Photon kit.
The continuous rotation servo motor comes with several different plastic mounts (called "horns") that can be attached to the motor axis (the white part sticking out of the top of the motor – this is what actually rotates). There are double-arm horns (2 sizes), a four-point horn, a six-point horn, and circular horns (2 sizes). Each horn just slips onto the motor axis (the horn and axis have matching "teeth"). Each horn has holes, which can allow you to attach something to the arm, using the included mounting hardware (screws, etc.).
This servo motor has a built-in 3-wire connector: just plug 3 jumper wires into the connector and then plug the other end of the jumper wires into a breadboard or directly to the Photon. To make it easier to remember which wire is which, use corresponding white, red, and black jumper wires to match the servo motor wires.
NOTE: This servo motor requires 5V of power, so connect it (directly or indirectly) to the V-USB pin.
IMPORTANT: The data wire must connect to an I/O pin that supports pulse-width modulation (PWM) output. Only the following pins on the Photon can act as PWM outputs: D0, D1, D2, D3, A4, A5, WKP, RX, TX.
TIP: Be sure to attach one of the horns to your servo motor. Otherwise, you won't be able to see the servo motor rotate (and it won't provide much use to your device).
Experiment 7 of the online SparkFun Photon Experiment Guide shows how to connect a servo motor. Here is the connection diagram for Experiment 7 (ignore the wiring for the push button):
The servo motor does need a code library with special functions that will allow you to control the servo motor. However, this library is already built-in to the Particle firmware on your Photon device.
In the global variables, you should declare which pin is being used as the servo motor data pin. The example below declares a variable called "servoPin" (but you could use a different variable name).
You also need to declare a Servo object variable that you will use to run the special functions in the built-in Servo library. The example below declares a variable called "servo" (but you could use a different variable name).
OPTIONAL: You may also want to declare a global variable to represent the direction of the servo motor rotation (counter-clockwise, stopped, or clockwise). This isn't required, but it could make it easier to code the servo motor, especially if the direction or speed of rotation will be changed by the user or are necessary to track. The example below declares a variable called "direction" (but you could use a different variable name).
There isn't any code that you need to include in the setup()
function. You don't have to set a pin mode for the servo.
However, if you want your servo motor to be turned on when your device first starts, then add the necessary code to do this within the setup()
function.
You have to call a special function called servo.attach()
to turn on the motor. For a continuous rotation servo motor, this typically only has to be done once, so this statement could be included within the setup()
function (which only runs once).
NOTE: You can stop the motor from rotating, while still keeping the motor turned on (so it's ready to rotate again when you need it to).
However, if you need to completely turn off the motor, then call the servo.detach()
function. This would be useful if the motor only needs to rotate for a specified period of time (to complete an action) and then might spend a long time unused.
If the servo motor is completely turned off (detached), then you will need to include a servo.attach()
statement before your code can rotate the motor again.
You can make the servo motor rotate clockwise, counter-clockwise, or stop.
Code for controlling the servo motor rotation can be placed within the setup()
function (only runs once), within the loop()
function, or within a custom function.
There are two different methods for controlling the rotation of a continuous rotation servo motor. Both work by changing the timing of the electrical pulses sent to the servo motor. You can use either method, but you should probably just use one, in order to keep your code simpler and avoid any issues.
servo.writeMicroseconds()
A continuous rotation servo motor can be controlled by calling the servo.writeMicroseconds()
function, which typically accepts values from 1000-2000. A value of 1000 should rotate the motor counter-clockwise at full speed. A value of 2000 should rotate the motor clockwise at full speed. A value of 1500 should cause the motor to stop rotating (and without any vibration). Intermediate values can be used to change the speed of the rotation.
If necessary, you can fine-tune the values listed above based on testing with your actual servo motor. You could go as low as 700 or as high as 2300.
CAUTION: If you adjust the endpoint values too far (too low or too high), you might damage the motor.
servo.write()
A continuous rotation servo motor can also be controlled by calling the servo.write()
function, which accepts a value from 0-180. A value of 0 should rotate the motor counter-clockwise at full speed. A value of 180 should rotate the motor clockwise at full speed. A value of 90 should cause the motor to stop rotating (and without any vibration). Intermediate values can be used to change the speed of the rotation.
If you need your device to only rotate for a specific period of time, then simply use a delay()
statement to wait for a specific amount of time in milliseconds (1000 milliseconds = 1 second) before stopping the motor.
You can declare constants (as part of your global variables) to represent the possible directions of the servo motor rotation. This isn't required, but in some cases, it might make it easier to write (and read) your code.
The example below declares 3 constants that can be used to control the direction of the servo rotation if you are using the servo.writeMicroseconds()
function. (If necessary, you can change the names or values of these constants based on what you need your device to do.)
If you were to declare these constant values as part of your global variables, then your commands to control your motor would be:
You could even create global variable constants for that represent different speeds of rotation (CLOCKWISE_SLOW
, CLOCKWISE_FAST
, etc.).
If you are using the servo.write()
function instead, you would change the values of the constants (so the values are between 0-180).
You may need to adjust the stop point for your continuous rotation servo motor. Normally, using servo.write(90);
or servo.writeMicroseconds(1500);
should cause the motor to stop rotating (and not vibrate). However, it's possible your servo motor still might be slowly rotating or vibrating at these values.
If necessary, you can adjust the stop point by:
manually turning an adjustment screw on the motor
adjusting values in your code
Either way, you first need a simple app that turns on your servo motor using servo.attach()
and instructs the motor to not rotate using either a servo.write(90);
or servo.writeMicroseconds(1500);
statement.
The continuous rotation servo motor has a built-in trimpot screw inset on one side (next to its wires). You can use a small screwdriver to turn this screw slightly clockwise or counterclockwise until your motor stops rotating (and does not vibrate) when it is running a servo.write(90);
or servo.writeMicroseconds(1500);
statement.
Another option is to try slightly different values in your code to see which value causes the servo motor to actually stop rotating.
If you are using the servo.write()
function to control your motor, you can set a trim value, so that your motor will actually be stopped whenever you use a servo.write(90)
statement. The trim value can be positive or negative – try different values to see what works.
If you are using the servo.writeMicroseconds()
function to control your motor, then you can change the value from 1500 to something slightly higher or lower until your motor completely stops.
A GPS receiver can be used to determine a device's location and velocity, as well as the date and time.
There are numerous GPS satellites in orbit around Earth. Each satellite broadcasts one-way radio signals that contain precise satellite location data and time data.
A GPS receiver uses the signals from at least 4 different satellites to calculate its own precise location (latitude and longitude, plus altitude). The GPS receiver can track changes in its location over time to calculate its velocity (speed and direction of motion). It can also verify the precise time and date using the satellite data.
Location data from GPS receivers are not perfectly accurate. Under ideal conditions, a GPS receiver's location data will be accurate to within about 15 feet of the actual location. The GPS accuracy can be affected by factors such as blocked signals, reflected signals, etc. For example, a GPS location is less accurate inside buildings and other structures (and GPS signals might even be blocked). Even outdoors, being near tall structures (buildings, trees, etc.) can reduce GPS accuracy.
The GP-20U7 GPS receiver has a built-in 3-wire female JST connector. If necessary, attach a male JST connector, and plug it into different numbered rows on a breadboard. Then use jumper wires to connect the rows to the Photon. To make it easier to remember which wire is which, use corresponding red, black, and white jumper wires to match the GPS receiver wires.
The GPS receiver will send the GPS data to the Photon board over a serial data connection using the Photon RX pin.
NOTE: For serial data connections, the RX pin of one device connects to the TX pin of the other device. (RX = receive, TX = transmit)
Your Photon app must include a code library with special functions that will allow you to use the GPS receiver. There are several possible libraries, but you're going to use one called TinyGPS++:
In Particle Build, click on the bookmark icon to open the Libraries sidebar.
Type "gps" into the search field. Select the result called: TINYGPS++
Click the button to "Include in Project"
Select the name of your Photon app, and then click the "Confirm" button
Particle Build will automatically insert an #include
statement at the top of your app code
This code library contains special functions that allow you to interact with the GPS receiver.
In your global variables, you need to declare a TinyGPSPlus object variable that you will use to run the special functions in the library. The example below declares an object variable called "gps" (but you could use a different variable name).
You may also want to declare global variables for the data from the GPS receiver. You only need to include variables for the types of data that your Photon app will actually use. If you want, use can use different names for these variables.
You need to include a statement within the setup()
function to start a serial data connection (which will activate both the RX and TX pins on the Photon). This will allow the Photon to receive data from the RFID reader. The GPS receiver communicates at a baud rate of 9600 bps.
Code for reading GPS measurements should probably be placed within its own custom function, which can then be called within the loop()
function.
Before reading new GPS measurements, you must first complete several checks: (1) check to see if new serial data is available, (2) if so, check to see if the serial data can be encoded by the GPS receiver, and (3) if so, does the GPS receiver have valid location data. If all these checks are okay, then the GPS measurements can be read.
The code below shows a custom function called checkGPS()
that performs these checks and then reads GPS data (including latitude, longitude, elevation, speed, and direction). The code can be modified to remove any GPS measurements that are not necessary for your Photon app.
Inside the loop()
function, you will have to insert additional code to do something with the GPS data after it has been read (such as display it on an OLED screen, send the data to your web app, etc.).
TIP: You can use the Google Maps JavaScript API to display a map in your web app using latitude and longitude data. W3Schools has a Google Maps JavaScript API tutorial.
NOTE: When you power on your GPS receiver, it may take a few minutes to establish a valid location, especially if the GPS receiver has traveled some distance or a long time has elapsed since its last use. Also remember that GPS signals can be scattered (or even blocked) inside buildings and other structures. However, under regular usage (and especially if outdoors), the GPS receiver will quickly establish a valid location.
Latitude measures position as an angle (0°-90°) north or south relative to the Equator, which is 0° latitude. The North Pole is 90° N latitude, and the South Pole is 90° S latitude. The GPS receiver will report latitudes north of the Equator as positive numbers, while positions south of the Equator are reported as negative numbers.
Longitude measures position as angle (0°-180°) east or west relative to the Prime Meridian (which was designated as running north-south through Greenwich, England). The GPS receiver will report latitudes east of the Prime Meridian as positive numbers, while positions west of the Prime Meridan are reported as negative numbers.
Locations in the United States will have a positive latitude (north of Equator) and negative longitude (west of Prime Meridian).
TIP: If you want to know the latitude and longitude of a location (so you can compare it to the readings from your GPS receiver), you can enter a specific address at this NASA website to obtain the precise latitude and longitude of that address.
Elevation (or altitude) measures distance above mean sea level.
The TinyGPS++ library offers the ability to read the elevation (altitude) in feet, miles, meters, or kilometers.
The GPS receiver can determine its speed and direction of travel by tracking changes in its location over time. If the location changes over time, it can determine the distance traveled and then calculate the speed as distance divided by time.
The TinyGPS++ library offers the ability to read the speed in miles per hour, meters per second, kilometers per hour, or knots (nautical miles per hour).
The GPS receiver can also determine the direction of travel (also called "course"). The direction is reported as an angle (0°-360°) measured clockwise relative to true north. For example, a direction of due north is 0°, a direction of due east is 90°, a direction of due south is 180°, a direction of due west is 270°, etc.
NOTE: Even a stationary GPS receiver will report a non-zero speed (usually less than 1 mph). Remember that the GPS receiver's location data is only accurate to within about 15 feet of the actual location. Each new GPS reading will be slightly different even if the GPS receiver is stationary. Because the location readings are "different", the GPS receiver acts as if it were "moving" (which means it has a non-zero speed). This is also why the GPS receiver will report a direction (course), even if it is actually stationary. So just keep in mind that speed calculations will have a small margin of error.
The distance between two GPS locations can be calculated using a haversine formula (used for calculating distance between two points on a sphere).
The example code below introduces a new custom function called getDistance()
that calculate the distance (in miles) between the current GPS location and another GPS location. Your code needs to provide the latitude and longitude of the other location.
TIP: For your other location, you can enter a specific address at this NASA website to obtain its precise latitude and longitude.
NOTE: The TinyGPS++ library does have a built-in function to calculate the distance (in kilometers) between two GPS locations. However, this library function does not return accurate values due to a mistake in its formula. Instead, use the custom function provided above.
GPS satellites broadcast date and time information in Coordinated Universal Time (abbreviated as UTC). If a device knows its local time zone (which you could figure out using your GPS location), then the UTC data could be converted into a precise local date and time. For example, Eastern Standard Time is 5 hours behind UTC (but Eastern Daylight Time is only 4 hours behind UTC).
If you need date and time information from the GPS receiver, you can declare additional global variables, as shown below.
Then, within the checkGPS()
custom function, you would add the following code to get the UTC date and time.
NOTE: The Particle firmware on your Photon device already has built-in functions to set the local time zone of your device and get the current date and time. It may be somewhat simpler to use those functions rather than converting the GPS data from UTC into local time.
A force sensitive resistor (FSR) can be used to measure applied force or pressure. This particular FSR can measure force from approximately 0.25 pounds to 22 pounds. (Higher forces can be applied to the FSR, but the measurement will reach a maximum value.) The measurement is proportional to the amount of force applied, but it isn't accurate enough to serve as a scale.
The force sensitive resistor has 2 pins. One option is to insert these pins directly into different numbered rows on a breadboard. If you need longer leads, another option is to take 2 wires, line them up side by side so each wire makes contact with one pin, and then wrap this connection in electrical tape to hold them securely together, and then insert the other end of the wires into a breadboard. Either way, you will need to use 2 jumper wires and a resistor to then connect the breadboard rows to the Photon.
NOTE: One of the FSR pins will have two connections: it should connect to an analog I/O pin through a jumper wire, and it should also connect to ground (GND) through a resistor. In the breadboard row, the jumper wire for the analog I/O pin should be placed between the FSR pin and the resistor leg. Look at the example wiring diagram for the photocell as a visual reference, since it has identical wiring.
IMPORTANT: The FSR must connect to an analog I/O pin, such as: A0, A1, A2, A3, A4, A5.
The FSR does not require any special code library.
In the global variables, you should declare which pin is being used as the FSR analog input pin. The example below declares a variable called "forcePin" (but you could use a different variable name).
You will probably also want to declare an integer variable to store the reading from the FSR. This will make it easier to do something based on the measurement. The example below declares a variable called "forceReading" (but you could use a different variable name).
There isn't any code that you need to include in the setup()
function for the FSR.
IMPORTANT: Do not set a pin mode for the FSR.
You can measure the amount of applied force using an analogRead()
statement. This code would be most likely placed within the loop()
function or within a custom function.
The measurement will be a value ranging from 0-4095.
When there is less force detected, the reading will be lower. When there is more force detected, the reading will be higher.
This FSR can measure from 0.25 pounds to 22 pounds of applied force. (Higher forces can be applied to the FSR, but the measurement will max out at 4095.) The measurement is proportional to the amount of force applied, but it isn't accurate enough to serve as a scale.
You will need to add code to do something with the force reading (such as: display it on the OLED screen, send the data to your web app, run a custom function if the reading is more than a certain value, etc.).
RECOMMENDATION: Depending on the specific purpose of the FSR in your device, you may need to gather some data under different conditions to see how much force will actually be applied when your device is used. This will help you decide which values to use in your code to make decisions about what the device should do.
An RFID reader can be used to read ID numbers (or other data) stored in RFID tags, labels, and chips. RFID stands for "radio-frequency identification" – radio waves of a specific frequency are used to read the data from a distance.
RFID is used extensively by industries and stores to keep track of inventory. Some companies give their employees RFID cards for access to buildings and other purposes. Some people have their pets embedded with a RFID microchip to help identify the pet if it gets lost and is found by someone.
Near-Field Communication (NFC) is a type of RFID. For example, the Apple Pay and Android Pay features in certain smartphones use NFC.
The RFID reader kit comes with an RFID reader (the black reader module has pins that plug into to the female pins on the reader board) plus two RFID cards, which look blank but actually have a tag embedded in them that stores a unique ID number.
When an RFID card is brought within about 2 inches of the reader, it will be automatically identified. The RFID reader has a buzzer that beeps and a small green LED that lights up to verify that the card has been identified.
The RFID reader board has 8 different pin holes, but only 3 of these have to be connected. The easiest way to connect the RFID reader is to use a 3-wire JST connector. Connect the 3 wires (black, red, blue) to the corresponding pin holes, and then plug the male JST connector into different numbered rows on a breadboard. Then use jumper wires to connect the rows to the Photon. To make it easier to remember which wire is which, use corresponding black, red, and blue jumper wires to match the JST wires.
The RFID reader will send the card ID data to the Photon board over a serial data connection using the Photon RX pin.
NOTE: For serial data connections, the RX pin of one device connects to the TX pin of the other device. (RX = receive, TX = transmit)
FYI: The RFID reader also has a Mini-USB port, which can be used to connect it directly to a computer (instead of wiring it to a Photon or other microcontroller device). However, you will not use this port. (Also this Mini-USB port is different from the Micro-USB cable included with your Photon kit.)
The RFID reader does not require any special code library. (It does use a serial data connection, but serial data functions are built-in to the Particle firmware on your Photon device.)
Each RFID card has a code consisting of 16 characters (combination of numbers and letters): 12-character unique ID code + 4 special characters (that are not unique). When we read the RFID card, we only want to keep the unique ID code.
In the global variables, you should declare an array variable of 13 characters, which will be used to store the unique ID code from the RFID card. (The array will include 1 extra character at the end, which will always be zero. This is needed for converting the character array to a String.) The example below declares an array variable called "RFID" (but you could use a different variable name).
You will probably want to also declare a String variable that will simply be a text version of the RFID (the array is separate pieces of data, while the String is the same data stored as one piece). This String variable will be easier to use for purposes such as comparing the ID to a set of known IDs, sending the ID to your web app, etc. The example below declares a String variable called "idCard" (but you could use a different variable name).
You need to include a statement within the setup()
function to start a serial data connection (which will activate both the RX and TX pins on the Photon). This will allow the Photon to receive data from the RFID reader. The RFID reader communicates at a baud rate of 9600 bps.
Code for reading an RFID card should probably be placed within its own custom function, which can then be called within the loop()
function.
Inside the readRFID()
function, you will have to insert additional code to do something with the ID after it has been read (such as compare the ID to a set of known IDs, send the ID to your web app as an event notification, etc.).
A fingerprint scanner can add encoded fingerprint images to a database and then read a fingerprint to compare it against the stored fingerprints for identification purposes.
The GT-511C3 fingerprint scanner can store up to 200 different fingerprints in its onboard database.
This fingerprint scanner comes with a 4-wire connector (1 black wire + 3 white wires). Insert the wires into different numbered rows on a breadboard. Then use jumper wires to connect these rows to the Photon.
If the fingerprint scanner wires were numbered left to right as 1-4 (with the black wire being Wire 1), the jumper wire connections would be:
The fingerprint scanner will transfer data with the Photon board over a serial data connection using the Photon RX and TX pins.
NOTE: For serial data connections, the RX pin of one device connects to the TX pin of the other device. (RX = receive, TX = transmit)
TIP: The fingerprint scanner has a small built-in green LED. If the Photon device is powered on and you have correctly wired the fingerprint scanner, this green LED should be on.
Your Photon app must include a code library with special functions that will allow you to control the fingerprint reader.
In Particle Build, click on the bookmark icon to open the Libraries sidebar.
Type "fingerprint" into the search field. Select the result called: FINGERPRINT_FPS_GT511C3
Click the button to "Include in Project"
Select the name of your Photon app, and then click the "Confirm" button
Particle Build will automatically insert an #include
statement at the top of your app code
In your global variables, you need to declare an FPS_GT511C3 object variable that you will use to run the special functions in the library. The example below declares an object variable called "fps" (but you could use a different variable name).
You will probably also want to declare an integer variable to store a fingerprint ID number (such as the ID of the detected fingerprint, etc.). This will make it easier to do something with this ID. The example below declares a variable called "fingerprintID" (but you could use a different variable name).
You need to include a statement within the setup()
function to start a serial data connection (which will activate both the RX and TX pins on the Photon). This will allow the Photon and the fingerprint scanner to send and receive data between each other. The fingerprint scanner communicates at a baud rate of 9600 bps.
You also need to include statements to start ("open") the fingerprint scanner and to turn on the LED inside the scanner.
You can use the following temporary code to test whether your fingerprint scanner is wired correctly and able to communicate with your Photon. It will simply turn the scanner's internal LED on and off in a blinking pattern. Once you've verified this works, you can remove this code from the loop()
function.
You can do the following tasks with the fingerprint scanner:
Check If Finger Pressed
Add Fingerprint
Delete Fingerprint
Verify Fingerprint Against Specific ID
Verify Fingerprint Against All Stored IDs
This code will most likely be placed within the loop()
function or within custom functions.
RECOMMENDATION: Use the speaker and/or LEDs to provide feedback on whether a fingerprint was verified or not. For example, if the fingerprint is verified, you could turn on a green LED and/or play a short medium-pitched sound. If the fingerprint is not recognized, you could turn on a red LED and/or play a longer low-pitched sound.
You can check whether a finger is being pressed against the scanner using a fps.IsPressFinger()
statement, which will return either true or false.
For example, if a finger is pressed against the scanner, you could have your code verify whether the fingerprint is already stored in the database, etc.
Before you can verify a fingerprint, you will obviously need to have at least one fingerprint added to the scanner database.
The fingerprint scanner can store up to 200 different fingerprints in its onboard database. Each fingerprint is given a unique ID number from 0-199. The fingerprints stored in the database will be retained even when the scanner is powered off.
Adding a new fingerprint is a process called "enrollment" which consists of capturing high-quality images of the same fingerprint 3 times in a row for comparison. This 3-step enrollment verifies the scanner is able to read and identify the fingerprint accurately and consistently.
During fingerprint enrollment, the person presses their finger on the scanner for the first capture, and then lifts the finger. The same finger is pressed down again for a second capture, and lifted again. Finally, the finger is pressed for a third capture, which will ideally complete the process. However, the enrollment process can fail at any of these 3 steps.
TIP: Be patient, as enrollment may take more than one try. However, once a fingerprint is successfully enrolled, verifying that fingerprint in the future is usually fast and accurate.
It is important to have some type of clear feedback during the enrollment process to know when to press and lift the finger, as well as to know whether the enrollment steps were successful or failed. This feedback could be provided through the OLED display screen, red & green LED lights, the web app, etc.
IMPORTANT: The code example below uses the Micro OLED display screen. You will need to wire the OLED screen to your Photon, and include other necessary code (library, global variables, etc.) for the OLED display.
You could use this code to enroll one or more fingerprints. Then you could remove the addFingerprint()
statement from the loop()
function, and replace it with your primary app code (to verify a fingerprint against the database and then do something with the result).
TIP: Once you are done enrolling fingerprints, you can still keep the code for the addFingerprint()
custom function in your app, even if you are no longer calling it in the loop()
. This will make it easier for you to add more fingerprints later, if necessary.
RECOMMENDATION: If you will need your Photon app (or web app) to know which fingerprint ID is assigned to which person, it may be easier to record this ID number immediately after successfully enrolling the finger. If a person (such as yourself) is going to register multiple fingers, then record the ID number for each specific finger (right index, left thumb, etc.) that you enroll. Then later, you can use this information to have your Photon app (or web app) make different decisions based on which specific fingerprint ID is detected by the scanner.
That's a lot of code compared to what's been needed for other parts. Luckily, the other fingerprint scanner tasks only require a few lines of code at most.
If necessary, you can delete a specific fingerprint from the scanner database by providing its ID (0-199) either as a number or as an integer variable.
If necessary, you can also delete all the fingerprint images from the scanner database. Be careful using this statement – there is no "undo" if you delete all the stored fingerprints.
You can use the fps.Verify1_1()
statement to verify whether a finger matches a specific fingerprint ID by providing the ID (0-199) to check against. The ID can be provided as a number or as an integer variable.
First, you need to capture an image of the finger being pressed. For faster identification, a lower-resolution image is captured.
If the captured fingerprint matches the specific fingerprint ID stored in the database, the fps.Verify1_1()
statement will return true. Otherwise, it will return false.
In most cases, you will want to use the fps.Identify1_N()
statement to verify whether a fingerprint matches any of the fingerprints stored in the database – and if so, identify which fingerprint ID matches.
First, you need to capture an image of the finger being pressed. For faster identification, a lower-resolution image is captured.
If the fingerprint matches an ID stored in the database, the fps.Identify1_N()
statement will return the matching ID number (0-199). Otherwise, it returns a value of 200 if the fingerprint isn't in the database.
Camera
Photon Pin
Red - RX
TX
Brown - TX
RX
Purple - GND
GND
Gray - Power (3.3V or 5V)
3.3V
Keypad
Photon Pin
Wire 1
D5
Wire 2
D3
Wire 3
D6, plus V-USB (5V) using 10K resistor
Wire 4
D0
Wire 5
D4, plus V-USB (5V) using 10K resistor
Wire 6
D1, plus V-USB (5V) using 10K resistor
Wire 7
D2, plus V-USB (5V) using 10K resistor
Servo Motor
Photon Pin
White - Data
any I/O pin with PWM
Red - Power (5V)
V-USB (5V)
Black - Ground
GND
GPS Receiver
Photon Pin
VCC (Red) - Power
3.3V
GND (Black) - Ground
GND
TX (White) - Data
RX
RFID Reader
Photon Pin
VCC - Power (Black)
3.3V
TX - Data (Red)
RX
GND - Ground (Blue)
GND
Microphone
Photon Pin
AUD - Data
any analog I/O pin
GND - Ground
GND
VCC - Power
3.3V
Accelerometer Pin
Photon Pin
3.3V
3.3V
SDA
SDA/D0
SCL
SCL/D1
I2
(none)
I1
(none)
GND
GND
Force Sensitive Resistor
Photon Pin
One FSR pin (either one)
3.3V
Other FSR pin
(1) any analog I/O pin, (2) GND using resistor
Fingerprint Scanner
Photon Pin
Wire 1 (Black) = TX
RX
Wire 2 (White) = RX
TX
Wire 3 (White) = GND
GND
Wire 4 (White) = VCC
V-USB (5V)