Lab 1: Introduction to Arduino programming

In this first lab you will gain experience with the Arduino development environment for writing programs. These programs are then loaded into the Arduino where they are run. You can use a physical Arduino Uno for this lab or you can make use of an online simulation environment called tinkercad.

Part 1 - Blink the LED on Pin 13

In this part you will create a see step-by-step how to build a blinking LED light. The speed with which the LED blinks can be controlled by the code running on an Arduino microprocessor. Before peforming the steps listed below you can also watch this video:


Create a new "Circuits" project on tinkercad.

Open the drop-down menu on the right-hand side and select "Arduino"

Click on the circuit "Breadboard" and place is somewhere on the workspace.

Click on the button "Code" to see the program loaded into the Arduino.

The program shown in written in Blocks. You can also switch to the native coding language by selecting the option "Text" from the dropdown menu.

You will see a warning like the one shown above. Just click "Continue" to proceed.

You can adapt the code for the blinking led by adjusting the timers. Note that the output is sent to pin 13 of the Arduino.

When you simulate the program you should see the onboard LED blink

Part 2 - Build a circuit with an external LED

Use the same program as Part 1, but now extend the circuit by connecting an external LED to pin 13. Note that you also need a resistor to prevent short circuiting the LED.

Not working?

  1. Make sure the program is uploaded properly.
  2. Make sure you have the proper wiring:
    1. Arduino 5 V to Left + on breadboard?
    2. Arduino GND to Left - (GND) on breadboard?
    3. Arduino Pin 13 to the breadboard row 1, left side of the division? (BB Left 01?)
    4. Make sure the LED is connected correctly. Long leg to + and short leg to the resistor.
    5. Resistor to row 2, left side of the breadboard and to the column of ground pins on the left side as well? (BB Left 2 to BB Left GND?)

In this circuit, there is a yellow wire connecting Arduino pin 13 to breadboard left pin 1 (BBL01). Breadboard left pin 2 (BBL02) is connected to the ground bus. The remainder of the circuit consists of a resistor and a light emitting diode (LED).

Resistor: The resistor has a color code on it that specifies the value of the resistor. (See resistor color code). In this case the code is Green Blue Brown, which means 560 Ω. The purpose of a resistor is to limit the amount of current that can flow in a part of a circuit.

Light Emitting Diode: The LED is the common replacement for the incandescent light bulb. (See LED). LEDs comes in various colors. There are two very important things to remember about LEDs.

  • The first is that a LED has a strongly preferred direction in which it will let current flow. If you do not connect the LED properly it will not work. The convention is that the anode which is the longer lead, or the lead that does not have the flat side of the case is the one that connects to the positive potential. The cathode is the shorter lead, or the lead on the flat side of the case is the one that connects to negative potential.
  • The second is that you must have a current limiting resistor in the LED circuit path. If not, the LED will burn out instantly.

Part 3 - The Potentiometer

The potentiometer is a variable reistsor. If we connect the middle pin of the potentiometer to an analog input pin on the Arduino, then we can read the voltage on the pin as an integer value that varies from 0 (at 0 V) to 1023 (at 5 V).

With the analogRead function, the program can read the voltage and convert it into an integer value that is then used to set the delay time on the flashing light of Part 1 and 2. Keep the same wiring as before. All we are doing is adding a potentiometer. See the images below the code.

// the external LED is attached to this pin.
// onboard LED is attached to pin 13, 
int ledPin = 13;

// slider of potentiometer attached to this analog input 
int analogInPin = 0;

// On and off time in milliseconds for the light
int delayTime = 300;
 
void setup() {
  // configure ledPin to be a digital output
  pinMode(ledPin, OUTPUT);
}
 
void loop() {
  // read the voltage on the analog input and convert
  // into an integer value in the range [0, 1023]
  delayTime = analogRead(analogInPin);

  digitalWrite(ledPin, HIGH);
  delay(delayTime);

  digitalWrite(ledPin, LOW);
  delay(delayTime);
}
Concept: A procedure invocation can return a result. This result can appear in a statement. For example, the statement
delayTime = analogRead(analogInPin);
invokes the analogRead procedure on the pin whose number is the value in variable analogInPin. It returns the result (an integer from 0 to 1023) and this is then stored in the variable delayTime.

Questions to Answer:

  1. When you turn the potentiometer in one direction the speed of the flasshing goes up, and in the opposite direction the speed goes down. How do the power (red) and ground (black) connections on the potentiometer relate to the direction necessary to increase the flashing rate?
  2. When you turn the potentiometer to speed up the flashing rate, the LED appears to stop flashing. Then it suddenly gets dim. What is happening?
  3. When you turn the potentiometer, the flashing speed does not change immediately. Why is this happening?

Part 4 - The Pushbutton

The last piece of hardware that we introduce in this lab is the pushbutton. The pushbutton is a simple switch. When it is not pushed, the circuit between the pins is open (not conducting). When pushed, the circuit between the pins is closed (conducting). The digital input pins on the Arduino convert a voltage on the pin into a HIGH or LOW signal. A voltage near 5 V is considered a HIGH input, and a voltage near 0 V is considered a LOW input. A value in the middle is ambiguous.

Concept: If a digital input pin is not connected to anything, it is said to be floating. Reading from a floating pin is very unreliable. It might be HIGH, but can be LOW. So to ensure that a proper voltage is always present on a digital input, a pullup circuit is used. The resistor attached to the pin is called a pull up resistor. It's job is to ensure that the digital input pin has 5V present when the switch is open. Then when the switch is closed it pulls down the voltage to 0V. You can install the pull up resistor yourself. But this is such a common issue that the Arduino processor has built in pull up resistors that can be turned on. This is done in the setup code of the program.

The switch is attached as in the circuit shown below. Just like before, simply add this circuit to the one you have already built that contains the external LED and the potentiometer.

Here is a simple program to turn the LED on or off when the switch is pushed and released.

// the LED is attached to this digital output pin
int ledPin = 13;
 
// the pushbutton is attached to this digital input pin
int buttonPin = 9;
 
// the value read by the pin.
int buttonValue;
 
void setup() {
  // set ledPin to OUTPUT
  pinMode(ledPin, OUTPUT);
 
  // set buttonPin to INPUT and 
  // turn on internal pull up resistor 
  pinMode(buttonPin, INPUT);
  digitalWrite(buttonPin, HIGH);
} 
 
void loop() {
  // read the pushbutton state
  buttonValue = digitalRead(buttonPin);
 
  // and set the light to be the same value
  digitalWrite(ledPin, buttonValue);
}

Not working?

  1. Make sure the proper program is uploaded properly.
  2. Make sure you have the proper wiring:
    1. The switch should have the pins coming out of the left and right sides, not the top and bottom when properly placed on the breadboard.
    2. A way to test this is to place the pushbutton on the breadboard just as shown in the wiring diagrams. Only when the pushbutton is placed correctly will it span over the gap easily between the division of the two halves of the breadboard.

Question: Why does pushing the button turn the light off?

There is a fix to that problem. This fix makes uses of a conditional statement (see code below).

// the LED is attached to this digital output pin
int ledPin = 13;
 
// the pushbutton is attached to this digital input pin
int buttonPin = 9;
 
// the value read by the pin.
int buttonValue;
 
// the value to be sent to the LED
int lightState;
 
void setup() {
  // set ledPin to OUTPUT
  pinMode(ledPin, OUTPUT);
 
  // set buttonPin to INPUT and 
  // turn on internal pull up resistor 
  pinMode(buttonPin, INPUT);
  digitalWrite(buttonPin, HIGH);
} 
 
void loop() {
  // read the pushbutton state
  buttonValue = digitalRead(buttonPin);
 
  // if you want the light on when the pushbutton is pushed
  if ( buttonValue == LOW ) {
    lightState = HIGH;
    }
  else {
    lightState = LOW;
    }
 
  // and set the light to be the same value
  digitalWrite(ledPin, lightState);
}
Reality Check: Because a switch is mechanical, it takes time to open or close. In addition, when it is making this transition it behaves in an unexpected way: the mechanical contacts bounce for a while very short (less than a microsecond) or long (fractions of a second). What this means is that we can't reliably trust a simple digital input from a switch. We have to wait long enough to assure ourselves that the switch really has changed state. For more details, see http://en.wikipedia.org/wiki/Contact_bounce.

Part 5 - Sending Morse Code With the Button

Morse code is a means for transmitting messages when all you can do is send or not send a signal (light or sound). It consists of gaps (no signal) and marks (signal present) of varying durations. The basic units of Morse code are

  • the dot (.) and
  • the dash (-) which is 3 times as long as a dot, and
  • the gap (of no signal). The gap comes in three lengths:
    • an inter-element gap between parts of a letter of duration same as a dot
    • a short gap between letters of 3 dot duration,
    • and a medium gap between words of 7 dot duration.

Each character is composed of a sequence of dots and dashes separated by inter-element gaps. A word consists of a sequence of characters separated by short gaps.

The most famous word in Morse code is SOS. It is represented as

. . . - - - . . .
Try sending this using the pushbutton.

For more details, see Morse code.

Part 6 - Sending SOS With a Program

You now have all of the tools to write a program that repeatedly sends SOS. The one thing you need to consider is how long the basic dot element should be. For now, you can run the code below and watch the O in SOS be transmitted. Take note of how dotTime is used. If you would like you can create the S (you will need to do so anyways) or move onto the next section to see how we can reuse code to make life easier.

// the external LED is attached to this pin.
// onboard LED is attached to pin 13, 
int ledPin = 13;

// slider of potentiometer attached to this analog input 
int analogInPin = 0;

// length of a dot
int dotTime = 300;

// even though we are not using it yet, make sure the
// pushbutton is set up correctly

// the pushbutton is attached to this digital input pin
int buttonPin = 9;
 
// the value read from the pushbutton
int buttonValue;

void setup() {
  // configure ledPin to be a digital output
  pinMode(ledPin, OUTPUT);

  // set buttonPin to INPUT and 
  // turn on internal pull up resistor 
  pinMode(buttonPin, INPUT);
  digitalWrite(buttonPin, HIGH);
}
 
void loop() {

  // send out an O: - - -

  // dash 1
  // a dash is 3 dots long
  digitalWrite(ledPin, HIGH);
  delay(3 * dotTime);

  // an inter-element gap is one dot
  digitalWrite(ledPin, LOW);
  delay(dotTime);

  // dash 2
  digitalWrite(ledPin, HIGH);
  delay(3 * dotTime);
  digitalWrite(ledPin, LOW);
  delay(dotTime);

  // dash 3
  digitalWrite(ledPin, HIGH);
  delay(3 * dotTime);
  digitalWrite(ledPin, LOW);
  delay(dotTime);

  // and a short gap between O and the next character
  delay(2 * dotTime);

}

Part 7 - Using Procedures to Reuse Code

In the program above there are repeated sequences of instructions to do the same thing. We can take these sequences and put them into a container, called a procedure that gives a name to the sequence of instructions, hides their details, and let's say more directly what it is that we want to do. For example, sendDash is a more obvious description of what we want to do than is a comment followed by the instructions that turn the pin on, delay, turn the pin off, and delay. This is an example of abstraction.

Procedures are in principle quite easy to define, we just need to give it a name, and then put a bunch of statements inside the body of the procedure. But there are a number of technical details that we have to worry about, such as how does the procedure know what variables are being talked about inside the procedure body? We will deal with this later. For the present, it is safe to follow the examples in the code below.

Here is a sample starting point. Complete the definitions of the various procedures and clean up the code to use the new procedures to send the S O S. Note that you could do an additional abstraction and write two new procedures sendS and sendO that are used to send the letters S and O.

// the external LED is attached to this pin.
// onboard LED is attached to pin 13, 
int ledPin = 13;

// slider of potentiometer attached to this analog input 
int analogInPin = 0;

// length of a dot
int dotTime = 300;

// even though we are not using it yet, make sure the
// pushbutton is set up correctly

// the pushbutton is attached to this digital input pin
int buttonPin = 9;
 
// the value read from the pushbutton
int buttonValue;

// we take the code for sending dot and dash and put them
// into two methods

void sendDot() {
  // a dot is one unit long
}

void sendDash() {
  // a dash is 3 dots long
  digitalWrite(ledPin, HIGH);
  delay(3 * dotTime);

  // an inter-element gap is one dot
  digitalWrite(ledPin, LOW);
  delay(dotTime);
}

void sendShortGap() {
  // we assume that we are preceeded by an inter-element gap.
  // so that we have 3 dots of gap
  delay(2 * dotTime);
}

void sendMediumGap() {
}

void setup() {
  // configure ledPin to be a digital output
  pinMode(ledPin, OUTPUT);

  // set buttonPin to INPUT and 
  // turn on internal pull up resistor 
  pinMode(buttonPin, INPUT);
  digitalWrite(buttonPin, HIGH);
}
 
void loop() {

  // send out an O: - - -
  sendDash();
  sendDash();
  sendDash();

  sendShortGap();
}

Modify your code so that it uses the analog input and potentiometer to control the length of the basic dot, thus making it possible to change the speed of the SOS transmission. Of course the speed will only change after a complete SOS signal has been sent, assuming that's you didn't change the length partway through the SOS transmission! You have now built an Emergency Beacon that sends out a distress signal.

Your tasks:

  • Complete the code for sendDot and sendMediumGap.
  • Complete the code to send out SOS. The code sample only sends an O.
  • Add code to read the potentiometer and set the dot length.

Questions:

  • Why doesn't the program read the button?
  • Why doesn't the second push of the button turn off the beacon?
  • Fix these problems!
  • Even when you fix the turn off problem, the pushbutton has to be held for some time, why?
  • How could you get around that problem. (One solution is called polling).

10. Other Things to Do

Was this too easy for you? Want a harder hardware challenge? Use the pushbutton as input for turning on and off the SOS signal. Turning off the signal is harder than it looks!

  • You will need a new variable to read the pushbutton. You can call it buttonValue and you can declare it at the beginning of the code along with the other variables like dotTime.
  • You will need to consider two states. One is when the SOS signal is being transmitted and one when it is not. Hint: You can use conditional statements to help.

Questions:

  • Why doesn't the program read the button?
  • Why doesn't the second push of the button turn off the beacon?
  • Fix these problems!
  • Even when you fix the turn off problem, the pushbutton has to be held for some time, why?
  • How could you get around that problem. (One solution is called polling).