- tutorial: title: Light Sensitive Alarm Clock image: /tutorial/tutorial-demo.gif description: When the sun rises, set off an alarm with sound and light. steps: - title: Introduction image: /tutorial/tutorial-demo.gif description: | In this tutorial, you will build a light-sensitive alarm clock. - title: Components Overview description: | ![parts](parts.jpg) Here are the components this tutorial requires: - Arduino Uno microcontroller - Neopixel LED Ring - Piezo Buzzer - Resistor - Button - Light Sensor - title: Firing up the Arduino description: | ![plug](plug.gif) First, connect the Arduino board to the USB port. To make sure it is connected ok, try uploading the starter code to it. The lights on the top of the board flash as it receives new code. tests: - title: Board Power Test description: Did the Arduino board light up after plugging it in? onerror: Make sure that the board is powered with the USB plug! form: manual - title: Simple Upload Test description: Press the button below to upload code to the board. onerror: Make sure that the board is plugged with the correctly labeled cable! form: upload - title: Breadboard Connection Overview image: /tutorial/breadboard.gif description: | The red and blue `(+/-)` columns along the sides of the breadboard are connected. The center rows are connected *horizontally*, as pictured above. - title: Connecting Power and Ground description: | ![power](power.jpg) From the Arduino to the breadboard, connect: - *GND* (ground) line to the blue rail - *5V* (power) line to the red rail ![power](power-crop.jpg) tests: - title: Breadboard Power Check description: | Measure the breadboard power with the testing device's two probes. Connect the white pin to *5V* (red/power), and the black pin to *0V / GND* (blue/ground). Then, press the button below to check the voltage. ![power](measure-power-crop.jpg) onerror: Make sure that you use the 5V pin; not the Vin or 3.3V pins! form: numeric output: '5.0' - title: Button Setup description: | ![button-in](button-in.jpg) Insert the button onto the breadboard, as pictured. Connect the one side of the button to *GND* (blue/ground) with a jumper wire. Connect the other side to *digital pin 2* on the Arduino board. ![button-in](button-in-crop.jpg) The button's legs are connected in pairs. When you press the button, you connect the pairs. ![button](button.jpg) tests: - title: Button Press Check description: | Measure the voltage across the button using the tester. Connect the *black wire to GND (ground)* and the *white wire to the Arduino-connected side*. The voltage should drop as you press the button down - *hold it down for AT LEAST 2 seconds*. ![piezo](measure-button-crop.jpg) form: numeric output: '0.0' - title: Voltage Knowledge Test description: What voltage difference exists between the power (red) and ground (blue) rails? jsondata: '["0 V", "10 V", "5 V", "3.3 V"]' output: 2 # 0-based form: multiple - title: Hardware Wiring Check description: | *REMOVE THE WHITE AND BLACK PROBES FROM THE CIRCUIT BEFORE DOING THIS TEST* The system will now check to see that you have wired up the board correctly. Does the Arduino light turn on as you push the button? Click the button below to begin the test. onerror: Check that the wire between the button and the board is in the right place. Also make sure that probe is no longer connected to the button. jsondata: '{"file":"1_button.ino"}' form: autoupload - title: Button Press Detection Code description: | Now that the button is connected, add code to detect when the button is pressed in software. At the top of the file, add this code to define which Arduino pin the button is connected to. ``` #define button 2 #define outLED 13 ``` Next, add this code in the `setup()` function body to add pin 2 (our button) as an input, using `pinMode`: ``` pinMode(button, INPUT_PULLUP); pinMode(outLED, OUTPUT); ``` Last, add this code to the `loop()` function to read the button's value. ``` int press = !digitalRead(button); digitalWrite(outLED, press); ``` We use a `!` to negate the reading, since when we press the button we pull the pin value to ground (0V). This code will also copy the inverted button state to the onboard Arduino LED, turning it on (high) when we press the button. ![onboard](internal-led.jpg) tests: - title: Voltage Knowledge Test description: What voltage exists across the button when it is not being pressed? jsondata: '["5 V", "0 V", "10 V", "3.3 V"]' output: 0 # 0-based form: multiple - title: Software Variable Check description: | The system will now check to see that you programmed the Arduino board correctly. Once loaded, press the button on the breadboard to set the `press` variable's value to `1`. Click below to begin the test. onerror: Make sure that you are saving the sensor value into `press` and that the pin is in the correction position. jsondata: '[{"name": "press", "value": 1}]' # name, value, line form: variable - title: Piezo Buzzer Wiring description: | ![pie](piezo.jpg) Insert the piezo so that its legs are on different rows, as pictured. Next, connect the piezo buzzer to the *digital pin 4* on the Arduino. With the resistor, connect the other end of the piezo to *GND* (the blue rail). The polarity does not matter, so you can plug it in either direction. ![pie](piezo-crop.jpg) tests: - title: Wiring Check description: | In this test, if the system is wired up according to the tutorial it will beep. Does the piezo beep after code is uploaded? onerror: Make the sure one end of the piezo is going to GND with the resistor, and the other end is going to pin 4! jsondata: '{"file":"2_sounds.ino"}' form: autoupload - title: Tone Generation Code description: | To stop the piezo's beeping, press the *Upload* button in the Arduino IDE. Next, in software, add code to set up the system to buzz whenever the button is pressed. Add these statements at the top of the file to define the buzzer pin and note frequency. ``` #define buzzer 4 #define freq 220 ``` Then, *just before the end* of `loop()` function, set the `tone` to play when the button is pressed: ``` if (press) { tone(buzzer, freq, 10); delay(10); } ``` tests: - title: Code Selection Test description: Highlight the part of your code which turns on the buzzer. onerror: Make sure to include the buzzer code line as described in the left pane. jsondata: '{"match": "tone", "flag": "i"}' form: code # regex - title: Code Check description: Check that your code compiles and uploads to the Arduino board. form: upload - title: Frequency Check description: | Next, the system will check that the piezo speaker is buzzing at the right frequency. Connect the tester's *black probe to ground (0V)* and the *white probe to the other piezo leg* (the one that is connected directly to the Arduino pin). The piezo will *only* play a tone when the button is pressed. Once the test starts, *press the button down for AT LEAST 2 seconds* to sample the frequency. Click below to start the test. ![piezo](measure-piezo-crop.jpg) ![piezo](measure-piezo.jpg) output: 220 # hz onerror: Make sure that the white probe is connected to the same end of the piezo as the Arduino. form: dynamic - title: Neopixel Ring Wiring description: | ![neopix](neopixel.jpg) Connect the *Power (red)* and *Ground (black)* ends of the Neopixel ring to the positive and ground rails. ![neopix](neopixel-crop1.jpg) Connect the *Data In* yellow LED pin to the *digital 7* on the Arduino. ![neopix](neopixel-crop2.jpg) tests: - title: Hardware Wiring Check description: | The system will now check to see that you have wired up the LED ring correctly. If the lights are wired up correctly, you will see a glowing pattern. Does the LED ring rotate though the rainbow? Click below to setup the test. ![neopix](rainbow.gif) onerror: Make the sure data pin is connected to pin 7, and the power/ground pins are connected to 5V and GND respectively. jsondata: '{"file":"3_lights.ino"}' form: autoupload - title: Neopixel Ring Code description: | ![rain](rainbow.gif) Include this library code for the LED ring *at the VERY top* of the file: ``` #include ``` Then, define the pin the Neopixel ring's data pin is connected to, and the number of "pixels" in the ring. ``` #define PIN 7 #define PIXELS 12 ``` *Before* the `setup()` function, create the strip of LEDs and a base white color. ``` int color = 0; Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXELS, PIN, NEO_GRB + NEO_KHZ800); uint32_t white = strip.Color(16, 16, 16); // dim white color ``` Initialize the LED strip *just before* the end of `setup()` function. ``` strip.begin(); // This initializes the NeoPixel library. strip.setBrightness(16); ``` *In between* the `setup()` and `loop()` functions, insert these two light helper functions. The first function, `Wheel`, takes in a number (specifically a byte, an 8-bit number), and returns a color that we can use to set the LED. The second function, `rainbow`, loops over all of the LEDs in the ring and updates their color, using the `Wheel` function. ``` uint32_t Wheel(byte WheelPos) { WheelPos = 255 - WheelPos; if (WheelPos < 85) { return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3); } if (WheelPos < 170) { WheelPos -= 85; return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3); } WheelPos -= 170; return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0); } void rainbow(int start, int wait) { int j = start; for (int q = 0; q < 3; q++) { for (int i = 0; i < strip.numPixels(); i = i + 3) { strip.setPixelColor(i + q, Wheel( (i + j) % 255)); //turn every third pixel on } strip.show(); delay(wait); for (int i = 0; i < strip.numPixels(); i = i + 5) { strip.setPixelColor(i + q, 0); //turn every third pixel off } } } ``` *Replace the* `loop()` function content with these lines. They make use of the helper functions to continuously glow the LED ring. ``` rainbow(color, 2); color = (color+2) % 255; ``` tests: - title: Code Selection Test - Library Inclusion description: Highlight the code which includes the *Neopixel LED* library. onerror: Include the Adafruit library at the top of the file. jsondata: '{"match": "include thresh_hi) { digital = 1; } else if (level < thresh_lo) { digital = 0; } // Write the digital value to the onboard LED. digitalWrite(outLED, digital); ``` Now, the *onboard Arduino LED* should turn on when you shine the light sensor. tests: - title: Code Selection Test - Sensor Reading description: Highlight the code which reads in the light sensor value. onerror: Include the sensor reading code from the left pane in the loop() function. jsondata: '{"match": "analogRead.*light", "flag": "i"}' form: code # regex - title: Software Trigger Check description: | The system will now check to see that you programmed the Arduino board correctly. Once loaded, shine the light sensor to raise the level above the threshold. onerror: Make sure that you are saving the sensor value into `level`. jsondata: '[{"name": "level", "value": 900, "op": "gt"}, {"name": "digital", "value": 1}]' # name, value, line form: variable - title: Hardware Integration description: | ![integration](integration.jpg) Now that each hardware component is working, we will test integrating the parts in software. The light sensor will trigger the alarm (lights and sound), and pressing button will reset it. tests: - title: Hardware Configuration Check description: | We will now check that your hardware is configured corrected. Try *flashing the light sensor* to turn on the alarm. Try *pressing the button* to turn off the alarm after it is activated. Did both of these functions work as expected? jsondata: '{"file":"5_complete.ino"}' onerror: Check that the sensor is connected and configured as `INPUT`, not `INPUT_PULLUP`. form: autoupload - title: Software Integration description: | Add this definition and this function *before* the `setup()` function: This code serves to keep track of the state whether the system is buzzing or not. ``` int buzzing; ``` This function provides a convenient way to reset the light ring when the alarm is deactivated. ``` void blankState() { for (int i = 0; i < PIXELS; i++) { strip.setPixelColor(i, white); } strip.show(); } ``` The variables will be used to control the whether the system is buzzing. The function will reset the LEDs back to a dim white. Add this code snippet *before* the `loop()` function: This function will activate the buzzer and flash the LED ring. ``` void buzz() { tone(buzzer, freq, 100); rainbow(color, 2); color = (color + 2) % 255; } ``` This helper function both buzzes the piezo and powers the LED. *Replace the* `loop()` function content with this snippet. This code is used to read from the button and the analog sensor. Depending on those values, it will either turn on the buzzer and lights, or reset it back to a waiting state. ``` int level = analogRead(light); int reset = !digitalRead(button); if (buzzing) { if (reset && level < thresh_lo) { blankState(); buzzing = 0; // reset } else { buzz(); } } else if (!buzzing && level > thresh_hi) { buzzing = 1; // begin buzzing } ``` tests: - title: Code Selection Test description: Highlight the function call in loop which resets the LEDs. onerror: Make sure to include replace the loop code with the new code! jsondata: '{"match": "blankState", "flag": "i"}' form: code # regex - title: Code Compile and Upload description: Compile and upload your code to the board. form: upload - title: Flashlight Trigger Test description: Do the lights and piezo buzzer turn on when you shine the light? onerror: Make sure that the code is setup to enable the lights when the system is `buzzing`! form: manual - title: Reset Button Test description: Does the alarm turn off when you press the reset button? onerror: Check that the code is setting the `buzzing` variable back to 0 when the button is pressed! form: manual - title: Task Complete! image: /tutorial/complete.gif description: # Well done! Congrats on successfully completing the tutorial! tests: - title: Congrats! description: You have successfully completed the tutorial! form: info info: true