Physics 124 Week 1 Lab

Due Tue/Wed., Jan 12/13 dep. on section

Arduino Familiarization

We will make heavy use of the Arduino microcontroller environment as the brains behind our projects. This lab aims to familiarize you with the basic operation of Arduino boards, and their programming. We will add layers in the following weeks, but this week we'll at least get you running.

The Arduino Kit

Each lab station has a box with an Arduino Starter Kit in it. Please recognize that we want to keep these kits intact from year to year, so please be diligent about returning kit items to the kit box. In the kit, you should find:

Verifying Software

Make sure your machine has the Arduino software installed. Hopefully, the ACS-controlled computers in MHA 3544/3574 will be set up, and you just need to locate the program. If you want to install it on your own computer, the software can be found here, and should run on Mac, Windows, or Linux. For Macs, you may need to get a driver for operating the Arduino Nano, found here.

Plugging In

Go ahead and hook up the Arduino Uno to a USB port.

Starting Arduino

The first thing you should do after starting the Arduino software is open the Preferences dialog and pick a directory location for your sketches (programs). On ACS computers, pick a directory that you own and can access from any machine.

Next, select the appropriate board from the Tools menu. Pick the Arduino Uno until you have reason to do otherwise.

Now you need to locate the correct hardware port. On a windows machine, find the Device Manager (vista: Start: right-click Computer: Properties) (XP: Start: right-click My Computer: Hardware). Look for Arduino UNO in the list of devices, and note the COM port associated with it. From the Arduino software, go to Tools: Serial Port and select the matching COM port. On Mac, pick the device that starts with tty.usbmodem or cu.usbmodem (both work to my knowledge).

If you want help, look to the Guide for Windows or the Guide for Macs on the Arduino site. There is also a Linux Help Page. And it is worth checking out (at least being aware of) the collection of links on the Phys 124 site.

Sketches

Catering to the art community, Arduino has decided to call their programs "sketches," which is a bit odd, but okay. The sketch is written in C, but the Arduino IDE (integrated development environment) takes care of a lot of the nuts and bolts behind the scenes, wrapping your sketch into an encompassing code. Your code must necessarily contain the two structures below (the first, where declarations go, is optional depending on whether you need to define variables).


// Very useful to put a comment on the first line with program/sketch name!
// optional declarations and variable assignments, like:
const int LED = 13;

void setup()
{
  // put setup code here, configuring pins, etc.
}

void loop()
{
  //put action code here, to be repeated indefinitely
}

The Getting Started book guides you through many of the core examples we will pursue for the sake of familiarization (the second edition is available as PDF). There are also many examples online, as well as a Language Reference.

Exercise 1: Morse Code LED

Create a new sketch and type in the code to turn on the on-board LED on pin 13. Don't just grab a worked out code and paste it. How will you possibly learn like that? For now, you simply need to configure the appropriate pin for output via the pinMode command, then turn on the LED within the loop via digitalWrite. Once written, you can verify the code to make sure it compiles without error, then you can "upload" it to the Arduino board.

Once this works, modify the loop code to blink the LED, waiting a second between each cyclic ON/OFF action (via delay(1000), measured in milliseconds).

Now get yourself comfortable making custom subroutines. Shedding your fear of these will make future coding much cleaner and modular. Add the subroutine:


void blink(int on, int off)  // arguments are ON time in ms and OFF time in ms
{
  digitalWrite(LED,HIGH);    // turn LED ON
  delay(on);                 // hold ON for prescribed delay time
  digitalWrite(LED,LOW);     // turn LED OFF
  delay(off);                // hold OFF for prescribed time
}

Now in the main loop, the single line blink(1000,1000) will accomplish the continuous blink. But a more sophisticated sequence can be made with multiple calls to blink(), each with potentially different parameters.

So for turning in, make a code that says some word in Morse Code, waiting a bit before the next repetition. Refer to the Morse code link to get the timing right for dots, dashes, space between, inter-letter space, and inter-word space. Have a TA or professor verify visually that you have something working.

Exercise 2: Modulating LED brightness

Far more interesting than blinking an LED is to modulate its brightness. It turns out to be a similar process, just on a fast timescale. We will use PWM (Pulse Width Modulation) to control the LED brightness. By blinking the LED quickly, and controlling the fraction of the time (duty cycle) that the pulse is ON, we can change the effective brightness without noticing the fast blink.

Using the function analogWrite(), you can send a value to the LED between 0 and 255 to modulate brightness. For instance, sending 64 will result in approximately 25% brightness.

Only certain pins support PWM output (look for tilde by pin number). The on-board LED on pin 13 is not one of these, so you'll have to use an external LED rather than the on-board LED for this test. Start by hard-coding the program for a certain value, and re-uploading to the chip to see it work.

This becomes tiresome, so let's do something more interesting. Make a sinusoidal modulation of the brightness within the loop (use cos(((float) i)/100.0 where i is an integer variable you increment by one each time in the loop (via i += 1), and limiting to be no bigger than 628 (2π, once the division by 100.0 is considered) by saying i %= 628. I'll leave it to you to get the amplitudes right. And you'll probably also want to insert a delay to keep the thing from looping too fast and making a blink rather than a smooth, slow modulation.

Note that the cos() function expects radians, and returns a floating point value. In your declarations, you can declare a float and an integer, like: float fval and int ival so that the cos() can populate the fval variable, and then get converted to an integer via ival = (int) fval, then feeding this integer value to analogWrite().

Turn in the sinusoidal ramp code, and have a TA or professor verify visually that you have something working.

Exercise 3: LED dimmer

Note: You may want to do this exercise last, as it's the most time-consuming of the four.

Now that we can control the brightness of an LED, let's make a semi-functional light whose brightness the external user can control with a single pushbutton. The ultimate goal is an LED supplied by some PWM pin, and a pushbutton/switch that toggles the LED on and off, while the duration of the button press controls how bright the LED will be. For human feedback, the LED will get brighter and brighter, so the user can release when the light is a desirable brightness. You'll have to control the timing. As a bonus, you'll use the serial output to monitor the functions, which will introduce you to a powerful debugging tool that you will want to use frequently as project complexity increases. The serial communications are routed through the same USB cable used to connect to the Arduino.

First, a switched LED

As an intermediate step, hook up an LED to any pin (need not be PWM), and configure the pushbutton switch on another pin that will be configured for input. Figure out which pins on the switch are normally open with respect to each other, but closed when the button is depressed. Hook one of these pins to +5V (provided on an Arduino pin), and the other to a 10k resistor that goes to ground. The input to the Arduino connects to the node between the switch and the pull-down resistor.

Now arrange the code so that each press of the switch toggles the switch ON or OFF (meaning one press turns it on, the next press turnes it off). To facilitate this, declare three integer variables such as val, lastval, and state to read in the switch value, store what it was on the last read, and keep track of the ON/OFF state, respectively. In the loop, the switch value will be read in. Then if the value is HIGH and the last value was LOW, the button has just been pressed. So if LED is currently OFF (as judged by state), turn on the LED and set state to 1. Otherwise do the opposite. Now delay about 50 ms to wait out any bounces from the erratic connection of contacts (still may have some slip through). Before the end of the loop, store the lastval.

Note: It is highly instructive to hook up the oscilloscope to look at the switch bounce (on about 10 μs per division). If you're not sure how to do this, that's all the more reason why you should.

Dimmer Function and Serial

Save your switch code to a new file/sketch so you can start modifying it without losing your (functional, useful) starting place.

Add variables outval for the PWM output value (integer), plus some unsigned long variables tbut, tnow, and tdiff to keep track of time. In the setup(), add Serial.begin(9600) to activate serial monitoring (over the USB cable).

Now, if the button value is sensed to have gone HIGH from LOW (as compared to lastval), record tbut = millis(). If already ON, turn LED OFF, set state to 0, and report the time by something like:

Serial.print("Light off at ");
Serial.println(tbut,DEC);

Note the use of print and println to string things together on the same line: println terminates the line with a return, while print does not.

Otherwise set the state to 1 and report the times the LED came on via a similar serial sequence.

If the state is 1 (LED thought to be ON), and the button is still pressed (val is HIGH), compare tnow = millis() to tbut (make the difference tdiff), and create some outval to send to the LED based on how long the button has been down. You may need to do some division to make it slow enough to be user-friendly. You also need some code to handle holding the button down longer than the max time (probably want the light to stay on at max brightness in this case).

If the button has just been released (judging by comparison of val and lastval) and the LED is ON (judged by state), then report the button hold time (tdiff) and the associated outval to the Serial output. An example output sequence might look like:

Light on at 1789 ms, held for 382 ms, LED brightness 38
Light off at 3402 ms

Finally, add a bit of delay to keep things sane.

You can monitor the serial output using Tools: Serial Monitor.

Turn in your code, and get "official" verification that your dimmer circuit/program work properly.

Exercise 4: Analog Input

A final key function of the Arduino (and many microcontrollers) is the ability to measure an external voltage in digital terms. The Arduino Uno has six analog inputs, and can determine each voltage between zero and five volts to 10-bit precision (1024 levels), meaning 5 mV precision.

You'll use the photosensor from the kit, rigged in series with a 10k resistor so that one leg of the photosensor is at 5 V, the other is connected to the resistor, and the far leg of the resistor is at ground. Connect the node where the photosensor meets the resistor to one of the analog inputs.

Use the Serial capability to report the measured voltage and associated time once per second (roughly). The only thing in setup() is Serial.begin(9600). Use analogRead(#) to read the voltage on analog input # into a floating point variable (must declare the variable as float type).

As an option, you may decide to provide some way to report the measured light brightness without having to monitor a serial data transmission. For instance, you can blink an LED, with the blink rate proportional to the brightness, or some other means of indicating to an observer what is being recorded.

Turn in the code (with the external indicator stuff, if that was done), and show a TA or professor that your deal works.

What's Left?

This lab has actually gone quite far in familiarizing you with core functionality of the Arduino. You have performed digital input and output, analog input, PWM output, serial communications, and have even put together some mini-projects that adhere to the global project rubric for the course: something is sensed in the real world (button press; light level), and some action is taken (lighting or blinking an LED) in response.

In terms of the Arduino language set, please take some time to look over the Language Reference Page.

The left hand column, Structure, is basic C syntax, except for the setup() and loop() pieces, which you have already used. These exercises have exposed you to a good portion of the structural elements.

The middle column, Variables are also mostly C syntax. The only exception is in the first block, Constants, which includes some things defined by Arduino, like HIGH, LOW, INPUT, OUTPUT, etc.

The last column, Functions is largely Arduino-specific. You have now used all three Digital I/O functions, two of the three Analog I/O functions, two of the four Time functions, perhaps some of the math and trig (this is just the C math library), and you have used Serial. Not a bad bite in the first week.

To Turn In

Each group can submit a shared collection of program printouts from each exercise. Annotate as necessary to provide context. Comments in the code are highly appreciated and useful. Not overboard to have a short comment on each line providing context that is not self-evident in line (explain why, not what).

Indicate on each program which TA or prof checked off the demonstrated performance of your circuit. Take responsibility for making sure this happens. If it has not happened by the time you turn in the report, indicate as much and schedule a time to meet with a TA (or show up to office hours or nominal lab periods) to get it done soon.

Besides the joint submission, each team member should include a few paragraphs describing what role he/she played in the group effort.


Back to Phys 124 Lab Information Page