===== Oak: using a photocell (photoresistor) =====
[[http://digistump.com/wiki/_media/oak/tutorials/photocell.png|{{http://digistump.com/wiki/_media/oak/tutorials/photocell.png?400}}]]
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.
===== Components =====
^ 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 [[http://digistump.com/wiki/oak/tutorials/serial_through_arduino|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 [[http://digistump.com/wiki/oak/tutorials/particle-variable|this tutorial]].
===== Concepts =====
=== Voltage divider ===
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 [[http://electronics.stackexchange.com/questions/70009/why-use-a-pull-down-resistor-with-a-ldr-and-microcontroller|here]]. An Adafruit [[https://learn.adafruit.com/photocells|tutorial]] also features a discussion on adjusting the resistor value to target different ranges of measurement in the section on [[https://learn.adafruit.com/photocells/using-a-photocell|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.
=== ADC ===
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.
=== analogRead() ===
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.
=== the if() statement ===
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); }
===== Circuit =====
To connect the photocell, we will use the following circuit:
[[http://digistump.com/wiki/_media/oak/tutorials/photocell.png|{{http://digistump.com/wiki/_media/oak/tutorials/photocell.png?500}}]]
To complete the circuit, follow these steps:
* Insert the photocell legs into two different rows
* Connect the 10k resistor from one photocell leg (either is fine) to a new row with a jumper wire
* Connect pin A0 of the Oak to the same row containing //both// leads from the resistor and photocell
* Connect a ground pin of the Oak to the free lead on the resistor
* Connect a Vcc pin on the Oak to the free lead of the photocell
For reference, here is the setup above in real life:
[[http://digistump.com/wiki/_media/oak/tutorials/photocell-wiring.jpg|{{http://digistump.com/wiki/_media/oak/tutorials/photocell-wiring.jpg?400}}]]
If you wish to read the photocell output via serial, please take this time to follow the instructions as described [[https://github.com/digistump/OakRestore|here for a UART]] and [[http://digistump.com/wiki/oak/tutorials/serial_through_arduino|here when using an Arduino]].
===== Code: reading the photocell =====
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
}
=== Code: turning on an LED when it's dark ===
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 [[http://digistump.com/wiki/oak/tutorials/blink|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:
[[http://digistump.com/wiki/_media/oak/tutorials/photocell-turn-on.gif|{{http://digistump.com/wiki/_media/oak/tutorials/photocell-turn-on.gif?500}}]]
===== Conclusion =====
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 [[https://learn.adafruit.com/tmp36-temperature-sensor/overview|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:
* an automated night light
* reminder to turn off your outside flood lights in the morning
* track the sunset/sunrise time each day
* auto close your curtains/blinds when it's bright