In this lesson, we will connect a photoresistor to the Oak. A photoresistor is like a potentiometer (a variable resistor) except light is acting instead of a knob. When there is a lot of light, the resistance drops; with low light, the resistance is higher. Using this property, we can send a voltage through a photoresistor, measure the resistance via a change in voltage, and obtain a value for how much light is shining on the photoresistor.
Part | Quantity | Identification |
---|---|---|
Oak with soldered headers | 1 | |
Breadboard | 1 | |
Photocell | 1 | |
Jumper wires | 7 | |
Resistor, 10k ohm | 1 | Brown-Black-Orange |
3.3V USB UART or an Arduino* | 1 |
Note: if using an Arduino to read serial, you will need to follow the instructions at the tutorial on serial with an Arduino. In contrast, you don't need either of these components if you learn how to use Particle.variable()
as described in this tutorial.
In the circuit we create below, electricity will flow from the Oak's Vcc
pin into one leg of the photocell. When electricity leaves the photocell, it will see two paths: one to pin 'A0
, and the other to ground through the 10k resistor. This creates what is known as a voltage divider, which is very helpful for measuring small changes in voltage. There's a great writeup of why this is required on the Electronics StackExchange Q&A site here. An Adafruit tutorial also features a discussion on adjusting the resistor value to target different ranges of measurement in the section on using a photoresistor.
The short version is that a voltage divider creates a ratio in the voltages in each path based on their individual resistances. The voltage going to A0
can be found as follows:
A0 voltage = 3.3V (Vcc) * 10k / (10k + photocell_resistance)
The ratio of the resistor going to ground divided by total resistance tells us how much will be measured at A0. If the photocell resistance is small, there will be very little difference between Vcc
and A0
with a direct connection. By using the ratio produced by a voltage divider, the A0
voltage will vary a lot more as the resistance of the photocell changes.
An analog sensor is one that produces a change in electrical properties in response to changes in the thing being measured. This is in contrast to digital sensors which use a communication protocol to report out an actual number. A photocell is an analog sensor in that it's resistance changes in response to light. We do not obtain a direct number from the photocell; instead, we need to measure the electricity going through it and convert that to a number of some form.
An Analog to Digital Converter (ADC) does this for us. It will read in a voltage and compare it to a reference voltage (Aref
), which serves as the maximum value it could read. The measured voltage is then converted into a number ranging from 0 (measured voltage = 0) to maximum (measured voltage = reference voltage), which depends on the microcontroller. The Arduino, for example, converts 0 - Aref
into 0-255. The Oak, converts to a range of 0-1023.
The analogRead()
function is how we access the ADC. When we call analogRead(A0)
, we are telling the Oak to convert the voltage it measures at A0
into a number between 0-1023 depending on how big it is. By using the delay()
function, we can adjust how often these readings are taken. We can also use an if()
statement to do something else based on the 0-1023 value.
For the second portion of this tutorial, the code will use an if()
statement. This is one of the fundamental ways to control the Oak's behavior. The format is:
if( some condition ) { do this; }
In our case, the condition we're checking for is whether or not the A0
light reading is above or below 250. If it's above 250, we do nothing. If it's below 250, we turn on the on-board LED. To compare the actual statements above to the actual code below, here are the lines. Can you see how they work?
if(light < 250) { digitalWrite(1, HIGH); } if(light >= 250) {digitalWrite(1, LOW); }
To connect the photocell, we will use the following circuit:
To complete the circuit, follow these steps:
For reference, here is the setup above in real life:
If you wish to read the photocell output via serial, please take this time to follow the instructions as described here for a UART and here when using an Arduino.
We will begin by simply reading the value produced by the photocell signal to A0
:
// variable to store our reading int light; // the setup() loop sets pinModes, starts things like Serial, // and is run once when the Oak powers on void setup() { // initialize the analog pin as an input pinMode(A0, INPUT); // start serial communication and create a variable for particle.io access Serial.begin(9600); Particle.variable("light", light); } // the loop() routine runs over and over again void loop() { // take a reading light = analogRead(A0); // print it out Serial.println(light); // a short delay as we don't need extremely fast readings delay(250); }
This code reads A0
, stores the number it obtain in the variable called light
, sends it ot the computer via serial, and then pauses for 0.25 seconds.
Using serial, the output will look like this as you cover and uncover the sensor:
764 737 620 421 313 246 200 153 157 165 408 630 491 235 153 163 763 765
If you are using Particle.variable()
, you would issue a call like this, substituting your device ID and access token in their appropriate locations:
curl https://api.particle.io/v1/devices/id_here/light?access_token=token_here
The result will look like this, where the value in “result” is the output of A0
{ "cmd": "VarReturn", "name": "button", "result": 529, "coreInfo": { "last_app": "", "last_heard": "2016-03-19T20:51:30.817Z", "connected": true, "last_handshake_at": "2016-03-19T20:32:30.268Z", "deviceID": "12345678", "product_id": 82 }
Now, we'll use these values to turn on and off the on-board LED at pin 1 based on how light or dark it is. Based on your readings, pick value 50-100 higher than your lowest reading. For the sensor above, 250 was chosen. If we add some code to our sketch, we can automatically turn on the on-board LED when the sensor is in low light. To do this, we add the LED functionality from the blink tutorial and use an if()
statement:
// variable to store our reading int light; void setup() { // enable the on-board LED as an output pinMode(1, OUTPUT); // initialize the analog pin as an input pinMode(A0, INPUT); // start serial communication and create a variable for particle.io access Serial.begin(9600); Particle.variable("light", light); } // the loop() routine runs over and over again void loop() { // take a reading light = analogRead(A0); // print it out Serial.println(light); // turn on/off the LED based on light reading if(light < 250) { digitalWrite(1, HIGH); } if(light >= 250) {digitalWrite(1, LOW); } // a short delay delay(250); }
Adjust the cutoff values as desired; with this code added, we get a nice effect like this:
Congratulations! You just connected to an analog sensor and read the values! Sensors are a crucial component to many projects, so this is an invaluable skill that will serve you well. For a next step, perhaps you could try connecting a different analog sensor? There are many Arduino tutorials for other types of sensors, such as Adafruit's on using the TMP36 temperature sensor.
Or perhaps you can think up some projects that might include a photocell? Now that you have this sensor in your toolbox for future project, here's some [perhaps silly] ideas to get you going: