Introduction to the Nano 33 IoT

The Arduino Nano 33 IoT is a useful little microcontroller board. It can do the things that the Arduino Uno can, and it has a number of additional features for physical computing projects. In 2019, we started using it as the standard for Intro to Physical Computing. This page introduces some of the functions that this board supports.

Form Factor

The Nano 33 IoT is based on the original Arduino Nano pin layout, so if you’ve used the Nano in past projects, the layout is the same. It’s a dual-inline package (DIP) format, meaning it’s got two rows of pins spaced 0.1 inches apart, so it fits nicely on a solderless breadboard. You can get it with or without header pins, and it’s small enough that you can incorporate it in handheld projects as well.

The physical pin numbering for DIP devices goes in a U shape. Holding the micro USB connector at the top, the numbering starts with physical pin 1 on the upper left, counting down the left side to pin 14 on the lower left, then counting from pin 15 on the lower right, to pin 28 on the upper right. For the most part, the left side of the board is power and analog inputs, and the right side is digital I/O pins.

In brief, the Nano pins are as follows, counting from physical pin 1 (upper left) to pin 15 (lower left) across to pin 16 (lower right) to pin 30 (upper right):

  • Pin 1: Digital I/O 13
  • Pin 2: 3.3V output
  • Pin 3: Analog Reference
  • Pin 4-11: Analog in A0-A7; Digital I/O 14-21
    Pin 12: VUSB (not normally connected)
  • Pin 13: Reset
  • Pin 14: Ground
  • Pin 15:Vin
  • Pin 16: Digital I/O pin 1; Serial1 UART TX
  • Pin 17: Digital I/O pin 0; Serial1 UART RX
  • Pin 18: Reset
  • Pin 19: Ground
  • Pin 20-30: Digital I/O pins 2-12
Arduino Nano 33 IoT board with USB connector facing the top
Figure 1. Drawing of the Nano 33 IoT

The microcontroller pin functions page details the functions of each pin for the Nano and other Arduino boards. The full specifications of the Nano 33 IoT and an official pin diagram can be found on its Getting Started page.

Typical Breadboard Layout

Arduino Nano on a breadboard.
Figure 2. Breadboard view of an Arduino Nano connected to a breadboard.

In a typical breadboard layout, The +3.3 volts and ground pins of the Nano are connected by red and black wires, respectively, to the left side rows of the breadboard. +3.3 volts is connected to the left outer side row (the voltage bus) and ground is connected to the left inner side row (the ground bus). The side rows on the left are connected to the side rows on the right using red and black wires, respectively, creating a voltage bus and a ground bus on both sides of the board.Other board layouts can be found on the Breadboard Layouts page.

Handling the Board

You should be careful when handling the Nano 33 IoT as there are two delicate parts on it: the MicroUSB connector at the top, and the WiFi/Bluetooth antenna at the bottom.  Figure 2 shows a picture of the board.

Like many microcontrollers these days, the Nano 33 IoT uses a MicroUSB connector. This is a delicate connector, and you shouldn’t handle the board by the connector. If you are mounting the board in a project box or as a wearable and you are using the USB connection, make sure the cable and the board are mounted so that they won’t move relative to each other.

The WiFi/Bluetooth Antenna is the small rectangular part at the bottom center. If it is broken off, your WiFi and Bluetooth range will be significantly reduced. For more on caring for it, see the Care of your Nano 33 IoT video and Breadboard Basics.

Photo of an Arduino Nano 33 IoT module. The USB connector is at the top of the image, and the physical pins are numbered in a U-shape from top left to bottom left, then from bottom right to top right.
Figure 2. Arduino Nano 33 IoT

Power

The Nano 33’s first difference from the Uno is that it operates on 3.3 volts instead of 5 volts. This might be an issue for some older sensors or actuators, but most modern ones will operate on 3.3V. For most projects, you’ll supply 3.3V from the Nano’s +3V3 pin (physical pin 2) and ground from one of the ground pins (physical pins 13 or 18).

If you’re powering the Nano 33 IoT from USB, then the Vin pin (physical pin 14) will supply 5V from the USB connection. You can also supply power the Nano 33 IoT on this pin, up to 21V. If power is fed through this pin, the USB power source is disconnected. If you need 5V power when you’re powered via the Vin pin, you can solder the VUSB jumper on the back, behind pin 19. When you do this, then the VUSB pin will supply 5V whenever the board is powered via the Vin pin.

Processor

The Nano 33 IoT has an ARM Cortex-M0 32-bit SAMD21 processor. It’s considerably faster than the Uno’s processor (48MHz clock speed compared to the Uno’s 16MHz, and a 32-bit processor compared to the Uno’s 8-bit processor) and has more memory (32KB SRAM/256KB flash compared to the Uno’s 2KB/32KB). That makes for more programming space at a faster speed.

Uploading to the Nano 33 IoT

If you’ve used an Uno before, and are migrating to the Nano board, you may notice that the serial connection behaves differently. When you reset the MKR, Nano, or Leonardo boards,  or upload code to them, the serial port seems to disappear and re-appear. Here’s why:

There is a difference between the Uno and most of the newer boards like the MKR boards, the Nano 33 IoT and BLE, the Leonardo: the Uno has a USB-to-serial chip on the board which is separate from the microcontroller that you’re programming. The Uno’s processor, an ATMega328, cannot communicate natively via USB, so it needs the separate processor. That USB-to-serial chip is not reset when you upload a new sketch, so the port appears to be there all the time, even when your Uno is being reset.

The newer boards can communicate natively using USB. They don’t need a separate USB-to-serial chip. Because of this, they can be programmed to operate as a mouse, as a keyboard, or as a USB MIDI device.  Since they are USB-native, their USB connection gets reset when you upload new code or reset the processor. That’s normal behavior for them; it’s as if you turned off the device, then turned it back on. Once it’s reset, it will let your computer’s operating system know that it’s ready for action, and your serial port will reappear. This takes a few seconds. It means you can’t reset the board and then open the serial port in the next second. You have to wait those few seconds until the Arduino board has made itself visible to the computer’s operating system again.

If you’re doing MIDI or keyboard or mouse, the serial port number will also change when you add those functions. You’ll still be able to send and receive serial data as usual, but you’ll have to re-choose the port in the Boards -> Port submenu after you program your Nano to be a MIDI or HID device.

If you have trouble getting the Nano 33 IoT to appear in the Arduino IDE, double-tap the reset button at the top center of the board. This will put the board into bootloader mode, meaning that it will show up as a serial device, but not start running the sketch yet. This mode also makes it easier to recover your board if you write a sketch you can’t control, such as a runaway mouse sketch.

Input and Output (GPIO) Pins

The Nano 33 IoT’s got 14 digital I/O pins and 8 analog input pins. The analog in pins can also be used for digital in and out, for a total of 22 digital I/O pins. Of those, 11 can be used for PWM out (pseudo-analog out): digital pins 2, 3, 5, 6, 9, 10, 11, 12, A2, A3, and A5. One pin A0, can also be used as a true analog out, because it has a digital-to-analog converter (DAC) attached (here’s an example of how to use it). There are also more hardware interrupt pins than the Uno; pins 2, 3, 9, 10, 11, 13, A1, A5, and A7 can be used as hardware interrupts. Hardware interrupts make it possible to read very fast changes in digital input and output. For example, rotary encoders work best when attached to interrupt pins.

Serial and USB

The Nano 33 IoT is USB-native. That means it can operate as a few different USB devices: asynchronous serial, keyboard or mouse (also known as Human Interface Device, or HID), and USB MIDI. This is different than the Uno, which has a dedicated USB-to-serial chip on the board, but can only operate as a USB serial device.

There’s also a second asynchronous serial port on pins 0 and 1 that you can use for connecting to other serial devices while still connecting to your personal compuuter. The serial port on pins 0 and 1 is called Serial1, so you’d type Serial1.begin(9600) to initialize it, for example.

Synchronous Serial

Like the other Arduinos, the Nano 33 IoT can communicate via Synchronous serial communications using I2C or SPI. The SPI pins are:

  • SDI- 12
  • SDO – 11
  • SCK – 13
  • CS – 10

The I2C pins are:

  • SDA – A4
  • SCL – A5

Inertial Measurement Unit (IMU)

There is an Inertial Measurement Unit (IMU) on the board, combining a 3-axis accelerometer with a 3-axis gyrometer. This enables gesture-based sensing or tap sensing with no extra hardware. The Arduino_LSM6DS3 library supports this sensor. There are some notes at this link and a lab at this link introducing the IMU.

Real-Time Clock

The Nano 33 IoT also has a real-time clock module built into the processor, which is accessible using the RTCZero library. With this, you can keep track of hours, minutes and seconds much easier. As long as the board is powered, the realtime clock will keep time. Like all libraries, it comes with examples when you install it. You can find several additional examples in this gitHub repository.

WiFi and Bluetooth

WiFi and Bluetooth connectivity are available on the Nano 33 IoT via a low-power 2.4GHz radio. Secure communication is ensured through an on-board crypto chip as well. The WiFiNINA library supports the WiFi on this board, and it’s compatible with the WiFi101 library written for the MKR1000. Any examples written for WiFi101 should be able to run just by changing WiFi101.h to WiFiNINA.h. You can find additional WiFi examples at these links:

The ArduinoBLE library supports Bluetooth LE on this board, and with it you can run the board as a BLE peripheral or a central. Here’s an introduction to connecting ArduinoBLE and p5.ble. Here’s a pair of sketches that let you connect two Nano 33 IoTs to each other as a central and peripheral pair.

Scheduler

The Nano 33 IoT can run multiple loops at once, using the Scheduler library. When you’ve got an application that needs two or more independent loop functions, this can be a quick way to do it.

For more on using the Nano 33 IoT, see the various microcontroller Labs on this site, for example:

A few slightly more advanced examples:

Breadboard Layouts

We use a few different microcontroller boards in this class over the years, but for each one, there is a standard way we lay out the breadboard. This page details those layouts. In any lab exercise, you can assume the microcontroller and breadboard are laid out in this way, depending on the controller you are using. Figures 1, 2, and 3 show the layouts of an Arduino Nano 33 IoT, an Arduino Uno, an Arduino MKR.

Nano Layout

Arduino Nano on a breadboard.
Figure 1. Breadboard view of an Arduino Nano on a breadboard

Figure 1. An Arduino Nano mounted on a solderless breadboard. The Nano is mounted at the top of the breadboard, straddling the center divide, with its USB connector facing up. The top pins of the Nano are in row 1 of the breadboard.

The Nano, like all Dual-Inline Package (DIP) modules, has its physical pins numbered in a U shape, from top left to bottom left, to bottom right to top right. The Nano’s 3.3V pin (physical pin 2) is connected to the left side red column of the breadboard. The Nano’s GND pin (physical pin 14) is connected to the left side black column.

These columns on the side of a breadboard are commonly called the buses. The red line is the voltage bus, and the black or blue line is the ground bus. The blue columns (ground buses) are connected together at the bottom of the breadboard with a black wire. The red columns (voltage buses) are connected together at the bottom of the breadboard with a red wire.

Uno Layout

An Arduino Uno on the left connected to a solderless breadboard, right.
Figure 2. Breadboard drawing of an Arduino Uno on the left connected to a solderless breadboard on the right

Figure 2. An Arduino Uno on the left connected to a solderless breadboard, right. The Uno’s 5V output hole is connected to the red column of holes on the far left side of the breadboard. The Uno’s ground hole is connected to the blue column on the left of the board. The red and blue columns on the left of the breadboard are connected to the red and blue columns on the right side of the breadboard with red and black wires, respectively. These columns on the side of a breadboard are commonly called the buses. The red line is the voltage bus, and the black or blue line is the ground bus.


MKR Layout

An Arduino MKR series microcontroller mounted on a breadboard
Figure 3. Breadboard view of an Arduino MKR series microcontroller mounted on a breadboard

Figure 3. An Arduino MKR series board mounted on a solderless breadboard. The MKR is mounted at the top of the breadboard, straddling the center divide, with its USB connector facing up. The top pins of the MKR are in row 1 of the breadboard.

The Nano, like all Dual-Inline Package (DIP) modules, has its physical pins numbered in a U shape, from top left to bottom left, to bottom right to top right. The MKR’s Vcc pin (physical pin 26) is connnected to the right side red column of the breadboard. The MKR’s GND pin (physical pin 25) is connected to the right side black column. These columns on the side of a breadboard are commonly called the buses. The red line is the voltage bus, and the black or blue line is the ground bus.

The blue columns (ground buses) are connected together at the bottom of the breadboard with a black wire. The red columns (voltage buses) are connected together at the bottom of the breadboard with a red wire.


Microcontroller Pin Functions

Introduction

This page explains the basic pin functions that most microcontrollers share, and offers some tips for switching from one microcontroller to another. Since the tutorials on this site are all written with the Arduino Uno in mind, and students may be using other controllers, you may need to know how to “convert” a tutorial from the controller it’s written for to your own controller. In order to get the most out of it, you should know something about electrical circuits, and what a microcontroller is and what it can do. This video might help: Hardware functions in a microcontroller

What Do All These Pins Do?

A typical microcontroller can have between 6 and 60 pins on it, to which you’re expected to attach power connections, input and output connections, and communications connections. Every microcontroller has different configurations for its pins, and often one pin will have more than one function. This combining of functions on one pin is called pin multiplexing.

Every microcontroller has names for the pins specific to its hardware, but the Arduino  application programming interface (API) provides a set of names  for pins and their functions that should work across all microcontrollers that are programmable with the API. So, for example, A0 will always be the analog input pin 0, whether you’re on an Uno, 101, MKRZero, MKR1000, or other Arduino-compatible board. When you connect to the pin with the same function on another board, your code should operate the same, even though the physical layout of pins is different.

Every board has an operating voltage that affects its pins as well. The operating voltage, which is the same as the voltage of the GPIO pins, is labeled below. If you’re connecting a component to a board with a lower voltage than the component, you’ll need to do some level shifting.

Pin Diagrams

Microcontrollers typically come in a variety of physical forms, or packages. Sparkfun has a nice tutorial on integrated circuit package types if you want to know more. Pin numbering on any integrated circuit, including microcontrollers, starts at top left corner, which is usually marked with a dot. From there, you count around the chip counter-clockwise. For modules like the Arduino Uno, this numbering doesn’t hold up, since the board has several pin headers. The pin headers are usually numbered, and the pins of each header are counted. Unfortunately, header numbering does not always follow the same patterns as IC numbering.

Microcontroller pins are referred to by their physical pin (where they are physically on the board) and their functional pin names (what they do). For example, the Arduino Nano’s physical pin 20 is digital I/O pin 2.

Arduino Nano Series

Arduino Nano 33 IoT Pin diagram

The Arduino Nano boards, like the Nano Every, Nano 33 IoT, Nano 33 BLE, Nano 33 BLE Sense, and Nano RP2040 Connect have a number of similar features. The Nano 33 IoT is shown in Figure 1, but the other Nanos have the same pin layout. The pin numbering follows the U-shaped pattern of a typical integrated circuit as described above; pin 1 is on the top left, and pin 30 is on the top right. The pins, summarized, are as follows:

  • Physical pin 1: Digital I/O 13
  • Physical pin 2: 3.3V output
  • Physical pin 3: Analog Reference
  • Physical pin 4-11: Analog in A0-A7; Digital I/O 14-21
  • Physical pin 12: VUSB (not normally connected)
  • Physical pin 13: Reset
  • Physical pin 14: Ground
  • Physical pin 15:Vin
  • Physical pin 16: Digital I/O pin 1; Serial1 UART TX
  • Physical pin 17: Digital I/O pin 0; Serial1 UART RX
  • Physical pin 18: Reset
  • Physical pin 19: Ground
  • Physical pin 20-30: Digital I/O pins 2-12

PWM Pins: on the Nano 33 IoT, the following pins can be used as PWM pins: digital pins 2, 3, 5, 6, 9, 10, 11, 12, A2, A3, and A5. One pin A0, can also be used as a true analog out, because it has a digital-to-analog converter (DAC) attached. On the Nano Every, only pins  3, 5, 6, 9, and 10 can be used as PWM pins. On the Nano 33 BLE, all digital pins can be used as PWM pins.

  • SPI Pins:
    • SDI- digital pin 12 (physical pin 30)
    • SDO – digital pin 11 (physical pin 29)
    • SCK – digital pin 13 (physical pin 1)
    • CS – digital pin 10 (physical pin 28)
  • I2C Pins:
    • SDA – pin A4 (physical pin 8)
    • SCL – pin A5 (physical pin 9)
  • UART Pins:
    • Serial 1 TX: digital pin 1 (physical pin 16)
    • Serial1 RX: digital pin 0 (physical pin 17)

Notes on the Nano Series

  • The Nano Every operates on 5V. The Nano 33 IoT, 33 BLE, and RP2040 Connect operate on 3.3V.
  • The Nano 33 IoT is based on the SAMD21 processor, just like the MKR boards. It has a NINA W102 radio that can communicate using Bluetooth 4.0 or WiFi, just like the MKR 1010. The RP2040 Connect has the same radio. It also has a real-time clock and an IMU sensor. For more on this board, see the Introduction to the Nano 33 IoT.
  • The Nano 33 BLE is based on the nRF 52840 microcontroller. It can communicate using Bluetooth 5.0
  • The Nano Every is based on the ATMega4809 microcontroller. It is functionally most similar to the Uno’s Atmega328 processor.
  • The Nano RP2040 Connect is based on the Raspberry Pi RP2040 processor, a dual SAMD21 processor.
  • On the Nano Every, pins 16 and 17 (TX and RX)  are the serial port called Serial; they are also attached to the USB-Serial microcontroller on board. On  the 33 IoT and 33 BLE, they are the serial port called Serial1 and are not attached to the USB serial port.
  • On the Nano 33 IoT as opposed to other Arduino Nano boards, pins A4 and A5 have an internal pull-up resistor and default to the I2C functions.
  • On the Nano 33 IoT and Nano 33 BLE,  the VUSB pin does NOT supply voltage but is connected through a jumper, to the USB power input. You need to solder the jumper on the bottom of the board to use VUSB.
  • Interrupts: All the Nano 33 IoT’s, Nano 33 BLE’s, and Nano Every’s digital pins can be used as hardware interrupts. However, some repeat, so check the AttachInterrupt guide for the best pins to use as interrupts.

Arduino Uno Rev 3

Arduino Uno Rev 3 Pin diagram
Arduino Uno Rev 3 Pin diagram

The Arduino Uno Rev 3, shown in Figure 1, is the classic Arduino model. The pin numbering follows the U-shaped pattern of a typical integrated circuit as described above; pin 1 is on the top left, and pin 30 is on the top right. The pins, summarized, are as follows:

  • Physical pin 1: not connected
  • Physical pin 2: I/O reference voltage
  • Physical pin 3: Reset
  • Physical pin 4: 3.3V output
  • Physical pin 5: 5V output
  • Physical pin 6-7: Ground
  • Physical pin 8: Vin
  • Physical pin 9-14: Analog in A0-A5; Digital I/O 14-19
  • Physical pin 15-28: Digital I/O pin 0-13
  • Physical pin 29: Ground
  • Physical pin 30:Analog Reference
  • Physical pin 31: I2C SDA; Digital I/O pin 18; Analog in A4
  • Physical pin 32: I2C SCL; Digital I/O pin 19; Analog in A5

PWM Pins: on the Uno Rev 3, the following pins can be used as PWM pins: digital pins 3, 5, 6, 9, 10, 11.

  • SPI Pins:
    • SDI- digital pin 12 (physical pin 27; digital I/O pin 12)
    • SDO – digital pin 11 (physical pin 26; digital I/O pin 11)
    • SCK – digital pin 13 (physical pin 28; digital I/O pin 13)
    • CS – digital pin 10 (physical pin 25; digital I/O pin 10)
  • I2C Pins:
    • SDA – pin A4 (physical pin 13 or 31; Analog in pin A4)
    • SCL – pin A5 (physical pin 14 or 32; Analog in pin A5)
  • UART Pins:
    • Serial TX: digital pin 1 (physical pin 16)
    • Serial RX: digital pin 0 (physical pin 15)

Notes on the Uno Rev 3

At the bottom center of the Uno board is a six-pin connector called the In-Circuit Serial Programming connector (ICSP). It has two rows of pins, labeled as follows:

  • Top row (left to right): Reset, SCK, SDI
  • Bottom row (left to right): Ground, SDO, +5V

On the top right of the Uno is another six-pin connector. The Uno has a second microcontroller on board to handle USB-to-serial communications. This is the ICSP header for that microcontroller.

The Serial port called Serial is attached to pins 0 and 1, and to the USB-Serial micrcontroller on board.

Interrupts: on the Uno rev. 3, only digital pins 2 and 3 can be used as interrupts.

Arduino MKR Series

Mkr Zero Pin diagram
Mkr Zero Pin diagram

The Arduino MKR series are intended for advanced RF applications. They have the same SAMD Cortex M0+ as the Nano 33 IoT, and a built-in rechargeable battery connector and charging circuit. Like most of the Nanos, the MKRs are 3.3V boards. There are several boards in the MKR line for different connectivity needs:

  • The MKRZero has a built-in MicroSD card
  • The MKR1000 and MKR1010 are WiFi boards; the MKR1010 has Bluetooth as well
  • The MKR1300 and MKR1310 have LoRa and LoRaWAN connectivity
  • The MKR1400 has a GSM radio
  • The MKR1500 has a NB IoT 3G radio.

In addition, there are several special purpose shields for the MKR boards.

The pin numbering follows the U-shaped pattern of a typical integrated circuit as described above; pin 1 is on the top left, and pin 28 is on the top right. The pins, summarized, are as follows:

  • Physical pin 1: Analog Reference
  • Physical pin 2-8: Analog in A0-A6
  • Physical pin 9-14: Digital I/O pin 0-5
  • Physical pin 15-23: Digital I/O pin 6-14
  • Physical pin 24: Reset
  • Physical pin 25: Ground
  • Physical pin 26: 3.3V output
  • Physical pin 27: Vin
  • Physical pin 28: 5V output

PWM Pins: on the MKR series, the following pins can be used as PWM pins: digital pins 0 – 8, 10, 12, analog pins A3, A4.

  • SPI Pins:
    • SDI- digital pin 12 (physical pin 19; digital I/O pin 10)
    • SDO – digital pin 11 (physical pin 17; digital I/O pin 8)
    • SCK – digital pin 13 (physical pin 18; digital I/O pin 9)
    • CS – any other digital pin
  • I2C Pins:
    • SDA – Digital I/O pin 11 (physical pin 19)
    • SCL – Digital I/O pin 12 (physical pin 20 )
  • UART Pins:
    • Serial TX: digital pin 14 (physical pin 21)
    • Serial RX: digital pin 13 (physical pin 20)

Notes on the MKR Series

  • Serial: The MKR series boards have two hardware UARTs.The first one, UART0 (aka Serial in your sketches) is attached directly to the USB port not to any pins. GPIO pins 13 and 14 are Serial1
  • Battery in: LiPo, 3.7V, 700mAh min Recharging circuit on board.
  • Interrupts: On the MKR series, pins 0, 1, 4, 5, 6, 7, 8, 9, A1, and A2 can be used as interrupts.

Pin Functions Explained

In order to make sense of all of this, it helps to know the general functions of a microcontroller. There are a few common functions:

Power:  Every microcontroller will have connections for power (often labeled Vcc, Vdd, or Vin) and ground. A bare microcontroller will have only those, but modules like the Arduino, the Raspberry Pi, and others also have voltage regulators and other components on board. On these, it’s common to see an unregulated voltage input (Vin) and a regulated voltage output (5V and 3.3V on the Uno, for example).

Clock: Every microcontroller needs a clock. The bare microcontroller chip usually has two pins for this. On a module, the clock is usually built onto the board, and the pins are not exposed.

General Purpose Input and Output (GPIO): Most pins on a microcontroller can operate as either a digital input or digital output.

Hardware Interrupts: Many microcontrollers have a subset of their GPIO pins attached to hardware interrupt circuits. A hardware interrupt can interrupt the flow of a program when a given pin changes its state, so you can read it immediately. Some higher level functions like asynchronous serial and PWM sometimes use these interrupts. They’re also good for very responsive reading of digital inputs.

Analog Input (ADC): Not all microcontrollers have an analog-to-digital converter (ADC), but those that do have a number of pins connected to it and act as inputs to the ADC. If there are analog inputs, include analog reference pin as well, that tells the microcontroller what the default high voltage of the ADC is.

Pulse Width Modulation (PWM): Few microcontrollers have a true analog voltage output (though the MKR1000 does), but most have a set of pins connected to an internal oscillator that can produce a pseudo-analog voltage using PWM. This is how the analogWrite() function in Arduino works.

Communications:

Universal Asynchronous Receiver/Transmitter (UART): Asynchronous serial communication is managed by a Universal Asynchronous Receiver/Transmitter, or UART, inside the processor. The UART pins are usually attached to internal hardware interrupts that can interrupt the program flow when new serial data arrives, so you never miss a byte. It’s possible to manage serial communication in software alone, but at high speeds, you’ll see more errors.

Synchronous Serial: SPI and I2C: Most microcontrollers also have dedicated modules in the processor to handle the two most common forms of synchronous serial communication.

The Serial-Peripheral Interface (SPI) bus has four dedicated pins: Serial Data Out (SDO), also called Controller In, Peripheral Out (CIPO); Serial Data In (SDI), or Controller Out, Peripheral In (COPI); Serial Clock (SCK) and Chip Select (CS). Many miccrocontrollers are programmed via SPI through an In-Circuit Serial Programming header (ICSP) as well.

The Inter-Integrated Circuit (I2C) bus has two pins: Serial Data (SDA) and Serial Clock (SCL).

Reset: All microcontrollers have a pin which resets the program. Usually you take this pin low to reset the controller.

IORef: this is the operating voltage of the board. The Uno and 101 have this pin so that shields can read this voltage to adjust their own output voltages as needed. Not all shields have this functionality.

Lab: Sensor Change Detection

In this lab you’ll learn some methods for determining when a sensor’s reading changes significantly.

Introduction

Microcontrollers can sense what’s going on in the physical world using digital and analog sensors, but a single sensor reading doesn’t tell you much. In order to tell when something significant happens, you need to know when that reading changes. For example, when a digital input changes from LOW to HIGH or the reverse, you can tell that a person closed or opened  a switch. When a force-sensing resistor reaches a peak reading, you know that something has hit the sensor. In this lab, you’ll learn how to program your microcontroller to look for three common changes in sensor readings that give you information about events in the physical world: state change detection on digital sensors, and threshold crossing and peak detection on analog sensors. You’ll use these three techniques all the time when you’re designing to read users’ actions.

What You’ll Need to Know

To get the most out of this lab, you should be familiar with the following concepts. You can check how to do so in the links below:

Things You’ll Need

Understanding How Your Sensor Changes

Before you start trying to detect specific sensor change events, you should know what your sensor’s changes look like over time. You might want to start by viewing the change on an oscilloscope, or by using the Serial Plotter in the Arduino IDE Tools menu (command-shift-L), or a graphing program like the one shown in the WebSerial input to p5.js Lab or Serial Output From Arduino to Processing lab to understand how your sensors change. Figure 7 shows a typical sensor change graph.

Graphing a sensor in Processing. The drawing shows a graph in which the line is alternately rising and falling on a relatively smooth curve.
Figure 7. Graphing a sensor in Processing

Sensor changes are described in terms of the change in the sensor’s property, often a voltage output, over time. The most important cases to consider for sensor change are the rising and falling edges of a digital or binary sensor, and the rising and falling edges and the peak of an analog sensor. The graphs in Figures 8 and 9 of sensor voltage over time illustrate these conditions:

Graph of a digital sensor's rising and falling edge. The graph shows a flat line near zero, followed by a vertical rise to the top of the vertical axis. This change is labeled "Rising". Then there is another flat line for a short distance, then a vertical drop back to near zero. This change is labeled "Falling".
Figure 8. Digital sensors change from high voltage to low and vice versa. The change from low voltage to high is called the rising edge, and the change from high voltage to low is called the falling edge
Graph of an analog sensor. Graph depicts the sensor rising, peaking, and falling over time. It also depicts a threshold value below the rising, peak, and falling points.
Figure 9. The three general states of an analog sensor are when it’s rising (current state > previous state), when it’s falling (current state < previous state), and when it’s at a peak.

Prepare the breadboard

Connect power and ground on the breadboard to power and ground from the microcontroller. On the Arduino module, use the 5V or 3.3V (depending on your model) and any of the ground connections, as shown in Figures 10 and 11.

An Arduino Uno on the left connected to a solderless breadboard, right. The Uno's 5V output hole is connected to the red column of holes on the far left side of the breadboard. The Uno's ground hole is connected to the blue column on the left of the board. The red and blue columns on the left of the breadboard are connected to the red and blue columns on the right side of the breadboard with red and black wires, respectively. These columns on the side of a breadboard are commonly called the buses. The red line is the voltage bus, and the black or blue line is the ground bus.
Figure 10. Breadboard view of an Arduino Uno on the left connected to a solderless breadboard, right.

Figure 10 shows an Arduino Uno on the left connected to a solderless breadboard, right. The Uno’s 5V output hole is connected to the red column of holes on the far left side of the breadboard. The Uno’s ground hole is connected to the blue column on the left of the board. The red and blue columns on the left of the breadboard are connected to the red and blue columns on the right side of the breadboard with red and black wires, respectively. These columns on the side of a breadboard are commonly called the buses. The red line is the voltage bus, and the black or blue line is the ground bus.


Arduino Nano on a breadboard.
Figure 11. Breadboard view of Arduino Nano mounted on a breadboard.

Figure 11 shows an Arduino Nano mounted on a solderless breadboard. The Nano is mounted at the top of the breadboard, straddling the center divide, with its USB connector facing up. The top pins of the Nano are in row 1 of the breadboard.

The Nano, like all Dual-Inline Package (DIP) modules, has its physical pins numbered in a U shape, from top left to bottom left, to bottom right to top right. The Nano’s 3.3V pin (physical pin 2) is connected to the left side red column of the breadboard. The Nano’s GND pin (physical pin 14) is connected to the left side black column. These columns on the side of a breadboard are commonly called the buses. The red line is the voltage bus, and the black or blue line is the ground bus. The blue columns (ground buses) are connected together at the bottom of the breadboard with a black wire. The red columns (voltage buses) are connected together at the bottom of the breadboard with a red wire.


Images made with Fritzing

Add a pushbutton

Connect a pushbutton to digital input 2 on the Arduino. Figures 12 and 13 show the schematic and breadboard views of this for an Arduino Uno, and Figure 14 shows the breadboard view for an Arduino 33 IoT.

Schematic view of an Arduino connected to a pushbutton. One side of the pushbutton is connected to digital pin 2 of the Arduino. A 10-kilohm resistor is connected from digital pin 2 to ground as well. The other side of the pushbutton is attached to +5V.
Figure 12. Schematic view of an Arduino connected to a pushbutton.
Breadboard view of an Arduino connected to a pushbutton. The +5 volts and ground pins of the Arduino are connected by red and black wires, respectively, to the left side rows of the breadboard. +5 volts is connected to the left outer side row (the voltage bus) and ground is connected to the left inner side row (the ground bus). The side rows on the left are connected to the side rows on the right using red and black wires, respectively, creating a voltage bus and a ground bus on both sides of the board. The pushbutton is mounted across the middle divide of the solderless breadboard. A 10-kilohm resistor connects from the same row as pushbutton's bottom left pin to the ground bus on the breadboard. There is a wire connecting to digital pin 2 from the same row that connects the resistor and the pushbutton. The top left pin of the pushbutton is connected to +5V.
Figure 13. Breadboard view of an Arduino connected to a pushbutton.

Breadboard view of an Arduino Nano connected to a pushbutton. The +5 volts and ground pins of the Arduino are connected by red and black wires, respectively, to the left side rows of the breadboard. +5 volts is connected to the left outer side row (the voltage bus) and ground is connected to the left inner side row (the ground bus). The side rows on the left are connected to the side rows on the right using red and black wires, respectively, creating a voltage bus and a ground bus on both sides of the board. The pushbutton is mounted across the middle divide of the solderless breadboard. A 10-kilohm resistor connects from the same row as pushbutton's bottom left pin to the ground bus on the breadboard. There is a wire connecting to digital pin 2 from the same row that connects the resistor and the pushbutton. The top left pin of the pushbutton is connected to +3.3V.
Figure 14. Breadboard view of an Arduino Nano connected to a pushbutton

The +3.3 volts and ground pins of the Arduino are connected by red and black wires, respectively, to the left side rows of the breadboard. +3.3 volts is connected to the left outer side row (the voltage bus) and ground is connected to the left inner side row (the ground bus). The side rows on the left are connected to the side rows on the right using red and black wires, respectively, creating a voltage bus and a ground bus on both sides of the board. The pushbutton is mounted across the middle divide of the solderless breadboard. A 10-kilohm resistor connects from the same row as pushbutton’s bottom left pin to the ground bus on the breadboard. There is a wire connecting to digital pin 2 from the same row that connects the resistor and the pushbutton. The top left pin of the pushbutton is connected to +3.3V.


Program the Microcontroller to Read the Pushbutton’s State Change

In the Digital Lab you learned how to read a pushbutton using the digitalRead() command. To tell when a pushbutton is pushed, you need to determine when the button’s state changes from off to on. With the button wired as you have it here, the button’s state will change from 0 to 1. In order to know that, you need to know not only what the current state of the button is, but you also need to remember the state of the button the previous time you read it. This is called state change detection. To do this, set up a global variable to store the button’s previous state. Initialize the button in your program’s setup() function using the pinMode() command. Then, in the loop() function, write a block of code that reads the button and compares its state to the previous state variable. To do this, you need to read the button, check the current button state against the last state, then save the current state of the button in a variable for the next time through the loop like so:

int lastButtonState = LOW;    // state of the button last time you checked

void setup() {
  // make pin 2 an input:
  pinMode(2, INPUT);
}

void loop() {
  // read the pushbutton:
  int buttonState = digitalRead(2);

  // check if the current button state is different than the last state:
  if (buttonState != lastButtonState) {
     // do stuff if it is different here
  }

  // save button state for next comparison:
  lastButtonState = buttonState;
}

If buttonState is not equal to lastButtonState, then the button has changed. Then you want to check if the current state is HIGH. If it is, then you know the button has changed from LOW to HIGH. That means your user pressed it. Print out a message to that effect.

int lastButtonState = LOW;   // state of the button last time you checked

void setup() {
  // initialize serial communication:
  Serial.begin(9600);
  // make pin 2 an input:
  pinMode(2, INPUT);
}

void loop() {
  // read the pushbutton:
  int buttonState = digitalRead(2);

  // if it's changed and it's high, toggle the mouse state:
  if (buttonState != lastButtonState) {
    if (buttonState == HIGH) {
      Serial.println("Button was just pressed.");
    }
  }
  // save button state for next comparison:
  lastButtonState = buttonState;
}

Your code should only print out a message when the button changes state. For every button press, you should get one line of code. You can use this technique any time you need to tell when a digital input changes state.

Count Button Presses

One of the many things you can do with state change detection is to count the number of button presses. Each time the button changes from off to on, you know it’s been pressed once. By adding another global variable and incrementing it when you detect the button press, you can count the number of button presses.  Add a global variable at the top of your program like so:

int lastButtonState = LOW;   // state of the button last time you checked
int buttonPresses = 0;       // count of button presses

Then in the if statement that detects the button press, add one to the button press:

 if (buttonState == HIGH) {
      buttonPresses++;
      Serial.print("Button has been pressed ");
      Serial.print(buttonPresses);
      Serial.println(" times.");
    }

The key to detecting state change is the use of a variable to save the current state for comparison the next time through the loop. This is a pattern you’ll see below as well:

int lastSensorState = LOW;   // sensor's previous state
// other globals and the setup go here

void loop() {
  // read the sensor:
  int sensorState = digitalRead(2);

  // if it's changed:
  if (sensorState != lastSensorState) {
    // take action or run a more detailed check
  }
  // save sensor state for next comparison:
  lastSensorState = sensorState;
}

Long Press, Short Press

Sometimes you want to take a different action on a short button press than you do on a long button press. To do this, you need to know now only when the button changes, but also how long it stays in a pressed state after it changes. Here’s how you might do that.

Start with some global variables for the button pin number, and the length of a long press or a short press, in milliseconds. You also need a variable to track how long the button has been pressed, and as in the code above, you need a variable to track the last button state. Add another variable called pressTime, which will keep track of the last time the button went from LOW to HIGH:

// the input pin:
int buttonPin = 2;

// the length of the presses in ms:
int longPress = 750;
int shortPress = 250;
// variable for how long the user actually presses:
long pressTime = 0;

// previous state of the button:
int lastButtonState = LOW;

In the setup(), set the button pin mode and initialize serial as you did before:

void setup() {
  // initialize serial and I/O pin:
  Serial.begin(9600);
  pinMode(buttonPin, INPUT);
}

In the loop, look for the button to change state, and when it does, note the press time in the pressTime variable. When the button is released (goes from HIGH to LOW), calculate how ling it was pressed, and print it:

void loop() {
  // read the button:
  int buttonState = digitalRead(buttonPin);

  // if the button has changed:
  if (buttonState != lastButtonState) {
    // if the button is pressed, start a timer:
    if (buttonState == HIGH) {
      pressTime = millis();
    }
    // if it's released, stop the timer:
    if (buttonState == LOW) {
      long holdTime = millis() - pressTime;
      // take action for long press, short press, or tap:
      if (holdTime > longPress) {
        Serial.println("long press");
      } else if (holdTime > shortPress) {
        Serial.println("short press");
      } else {
        Serial.println("Tap");
      }
    }
  }
  // save button state for next time:
  lastButtonState = buttonState;
}

You can see from this that you’ve actually got three states now, long press (> 750ms), short press (250-750ms), and tap (>250ms). With this, you can make one button do three things.

Analog Sensor Threshold Detection

When you’re using analog sensors, binary state change detection like you saw above is not usually effective, because your sensors can have multiple states. Remember, an analog sensor on an Arduino can have up to 1024 possible states. The simplest form of analog state change detection is to look for the sensor to rise above a given threshold in order to take action. However, if you want the action be triggered only once when your sensor passes the threshold, you need to keep track of both its current state and previous state.

Change the Breadboard

To build this example, you’ll need an analog sensor attached to your microcontroller, as shown in the Analog Input lab. Figures 15-17 show how to connect it.

Schematic of Arduino connected to an FSR on pin 2. One leg of the FSR connects to +5V. The other leg simultaneously connects to the Arduino's digital pin 2 and one end of a 10-kilohm resistor. The other end of the resistor connects to ground.
Figure 15. Schematic of Arduino connected to an FSR on pin 2
Breadboard view of Arduino connected to an FSR on pin 2. One leg of the FSR connects to +5V. The other leg simultaneously connects to the Arduino's digital pin 2 and one end of a 10-kilohm resistor. The other end of the resistor connects to ground.
Figure 16. Breadboard view of Arduino connected to an FSR on pin 2. The FSR is connected to two rows in the left center section of the breadboard. One of its pins is wired to voltage. The other is connected to ground through a 10-kilohm resistor. The row connecting the two resistors is wired to analog input 0.
Breadboard view of Arduino Nano connected to an FSR on pin 2.
Figure 17. Breadboard view of Arduino Nano connected to an FSR on pin 2. The FSR is connected to two rows in the left center section of the breadboard, below the Nano. One of its pins is wired to voltage. The other is connected to ground through a 10-kilohm resistor. The row connecting the two resistors is wired to analog input 0.

Program the Microcontroller to Read a Sensor Threshold Crossing

This example is very similar to the one above:

int lastSensorState = LOW;   // sensor's previous state
int threshold = 512;   // an arbitrary threshold value

void setup() {
  Serial.begin(9600);
}

void loop() {
  // read the sensor:
  int sensorState = analogRead(A0);

  // if it's above the threshold:
  if (sensorState >= threshold) {
    // check that the previous value was below the threshold:
     if (lastSensorState < threshold) {
        // the sensor just crossed the threshold
        Serial.println("Sensor crossed the threshold");
     }
  }
  // save button state for next comparison:
  lastSensorState = sensorState;
}

This program will give you an alert only when the sensor value crosses the threshold when it’s rising. You won’t get any reading when it crosses the threshold when it’s falling, and you’ll only get one message when it crosses the threshold. It is possible to sense a threshold crossing when the sensor is falling, by reversing the greater than and less than signs in the example above. The threshold you set depends on your application. For example, if you’re using a light sensor to detect when it’s dark enough to turn on artificial lighting, you’d use the example above, and turn on the light when the threshold crossing happens. But you might also need to check for the falling threshold crossing to turn off the light.

Detecting a Peak

There are times when you need to know when an analog sensor reaches its highest value in a given time period. This is called a peak. To detect a peak, you first set an initial peak value at zero.  Pick a threshold below which you don’t care about peak values. Any time the sensor value rises above the peak value, you set the peak value equal to the sensor value. When the sensor value starts to fall, the peak will remain with the highest value:

int peakValue = 0;
int threshold = 50;   //set your own value based on your sensors

void setup() {
  Serial.begin(9600);
}

void loop() {
  //read sensor on pin A0:
  int sensorValue = analogRead(A0);
  // check if it's higher than the current peak:
  if (sensorValue > peakValue) {
    peakValue = sensorValue;
  }
}

You only really know you have a peak when you’ve passed it, however. When the current sensor value is less than the last reading you saved as the peak value, you know that last value was a peak. When the sensor value falls past below threshold after you have a peak, but your peak value is above the threshold, then you know you’ve got a significant peak value. after you use that peak value, you need to reset the variable to 0 to detect other peaks :

int peakValue = 0;
int threshold = 50;   //set your own value based on your sensors

void setup() {
  Serial.begin(9600);
}

void loop() {
  //read sensor on pin A0:
  int sensorValue = analogRead(A0);
  // check if it's higher than the current peak:
  if (sensorValue > peakValue) {
    peakValue = sensorValue;
  }
  if (sensorValue <= threshold) {
    if (peakValue > threshold) {
      // you have a peak value:
      Serial.println(peakValue);
      // reset the peak variable:
      peakValue = 0;
    }
  }
}

Dealing with Noise

Quite often, you get noise from sensor readings that can interfere with peak readings. Instead of a simple curve, you get a jagged rising edge filled with many local peaks, as shown in Figure 18:

Graph of a sensor rising above a constant threshold, peaking, falling below that peak but still above the threshold, then rising to its highest point and falling below the threshold
Figure 18. Graph of local peaks

You can smooth out the noise and ignore some of these local peaks by adding in a noise variable and checking to see if the sensor’s change is different than the previous reading and the noise combined, like so:

int peakValue = 0;
int threshold = 50;   //set your own value based on your sensors
int noise = 5;        //set a noise value based on your particular sensor

void setup() {
  Serial.begin(9600);
}

void loop() {
  //read sensor on pin A0:
  int sensorValue = analogRead(A0);
  // check if it's higher than the current peak:
  if (sensorValue > peakValue) {
    peakValue = sensorValue;
  }
  if (sensorValue <= threshold - noise ) {
    if (peakValue > threshold + noise) {
      // you have a peak value:
      Serial.println(peakValue);
      // reset the peak value:
      peakValue = 0;
    }
  }
}

Most sensor change cases can be described using a combination of state change detection, threshold crossing, and peak detection. When you start to write sensor change detection routines, make sure you understand these three basic techniques, and make sure you have a good idea what your sensor’s readings look like over time. With that combination, you should be able to detect most simple sensor change events.

Lab: Servo Motor Control with an Arduino

In this tutorial, you’ll learn how to control a servomotor’s position from a microcontroller using the value returned from an analog sensor.

In this tutorial, you’ll learn how to control a servomotor’s position from a microcontroller using the value returned from an analog sensor.

Introduction

Servos are the easiest way to start making motion with a microcontroller. Servos can turn through a range of 180 degrees and you can use them to create all sorts of periodic or reciprocating motions. Check out some of the mechanisms at Rob Ive’s site for ideas on how to make levers, cams, and other simple machines for making motion. The resources section of this site has links to other sites on construction, mechanics, and kinetics as well.

What You’ll Need to Know

To get the most out of this lab, you should be familiar with the following concepts. You can check how to do so in the links below:

Things You’ll Need

Prepare the breadboard

Connect power and ground on the breadboard to power and ground from the microcontroller. On the Arduino module, use the 5V or 3.3V (depending on your model) and any of the ground connections, as shown in Figures 9 and 10.

An Arduino Uno on the left connected to a solderless breadboard, right. The Uno's 5V output hole is connected to the red column of holes on the far left side of the breadboard. The Uno's ground hole is connected to the blue column on the left of the board. The red and blue columns on the left of the breadboard are connected to the red and blue columns on the right side of the breadboard with red and black wires, respectively. These columns on the side of a breadboard are commonly called the buses. The red line is the voltage bus, and the black or blue line is the ground bus.
Figure 9 Breadboard view of an Arduino Uno on the left connected to a solderless breadboard, right.

Figure 9. An Arduino Uno on the left connected to a solderless breadboard, right. The Uno’s 5V output hole is connected to the red column of holes on the far left side of the breadboard. The Uno’s ground hole is connected to the blue column on the left of the board. The red and blue columns on the left of the breadboard are connected to the red and blue columns on the right side of the breadboard with red and black wires, respectively. These columns on the side of a breadboard are commonly called the buses. The red line is the voltage bus, and the black or blue line is the ground bus.


Arduino Nano on a breadboard.
Figure 10. An Arduino Nano mounted on a solderless breadboard. The Nano is mounted at the top of the breadboard, straddling the center divide, with its USB connector facing up. The top pins of the Nano are in row 1 of the breadboard.

The Nano, like all Dual-Inline Package (DIP) modules, has its physical pins numbered in a U shape, from top left to bottom left, to bottom right to top right. The Nano’s 3.3V pin (physical pin 2) is connected to the left side red column of the breadboard. The Nano’s GND pin (physical pin 14) is connected to the left side black column. These columns on the side of a breadboard are commonly called the buses. The red line is the voltage bus, and the black or blue line is the ground bus. The blue columns (ground buses) are connected together at the bottom of the breadboard with a black wire. The red columns (voltage buses) are connected together at the bottom of the breadboard with a red wire.

Images made with Fritzing

Connect an Analog Input Sensor and a Servo

Connect an analog input to analog pin 0 as you did in the Analog Input Lab covered previously. A force-sensing resistor is shown in Figure 11-14 below, but you can also use a potentiometer, phototransistor, or any analog input you prefer. Then connect an RC servomotor to digital pin 9. The yellow wire of the servo goes to the pin, and the red and black wires go to +5V and ground, respectively.

Most RC servomotors are rated for 4-6 volt power input. When you’re using a 3.3V microcontroller like the Nano 33 IoT, you can use the Vin pin to power the motor if you’re running off USB power, or off a 5V source connected to the Vin.

Related video:Intro to Servo Motors

Safety Warning! Not all servos have the same wiring colors. For example, the Hextronik servos that come with Adafruit’s ARDX kit use red for +5V, brown for ground, and mustard yellow for control. Check the specifications on your particular servomotor to be sure.

Schematic view of an Arduino Uno connected to a voltage divider input circuit on analog in pin 0 and a servomotor on digital pin 9. On the left, a fixed 10-kilohm resistor is attached to analog in pin 0 and to ground on the Arduino. A variable resistor is attached to analog in pin 0 and to +5 volts. On the right, a servomotor's control wire is attached to digital pin D3. The motor's voltage input is attached to +5 volts, and its ground is attached to ground on the Arduino. A 10-microfarad capacitor is mounted across the +5V and ground buses close to where the motor voltage and ground wires are connected.
Figure 11. Schematic view of a servomotor and an analog input attached to an Arduino Uno.
Breadboard view of a servomotor and an analog input attached to an Arduino Uno. The +5 volts and ground pins of the Arduino are connected by red and black wires, respectively, to the left side rows of the breadboard. +5 volts is connected to the left outer side row (the voltage bus) and ground is connected to the left inner side row (the ground bus). The side rows on the left are connected to the side rows on the right using red and black wires, respectively, creating a voltage bus and a ground bus on both sides of the board. A force-sensing resistor, or FSR, is mounted in rows 18 and 19 of the left center section of the breadboard. a 10-kilohm resistor connects one leg of the FSR to the left side ground bus. A blue wire connects the row that connects these two to analog in 0 on the Arduino. A red wire connects the other pin to the left side voltage bus. A servomotor's voltage and ground connections are connected to the voltage and ground buses on the left side of the breadboard. the servomotor's control wire is connected to pin D9 of the Arduino. A 10-microfarad capacitor is mounted across the +5V and ground buses close to where the motor voltage and ground wires are connected.
Figure 12. Breadboard view of a servomotor and an analog input attached to an Arduino Uno.
Schematic view of an Arduino Nano 33 IoT connected to a voltage divider input circuit on analog in pin 0 and a servomotor on digital pin 9. On the left, a fixed 10-kilohm resistor is attached to analog in pin 0 and to ground on the Arduino. A variable resistor is attached to analog in pin 0 and to Vin pin (+5 volts). On the right, a servomotor's control wire is attached to digital pin D3. The motor's voltage input is attached to Vin, and its ground is attached to ground on the Arduino. A 10-microfarad capacitor is mounted across the 3.3V and ground buses.
Figure 13. Schematic view of a servomotor and an analog input attached to an Arduino Nano 33 IoT.
Breadboard view of an Arduino Nano 33 IoT connected to a voltage divider input circuit on analog in pin 0 and a servomotor on digital pin 9. A fixed 10-kilohm resistor is attached to analog in pin 0 and to ground on the Arduino. A variable resistor is attached to analog in pin 0 and to Vin pin (+5 volts). A servomotor's control wire is attached to digital pin D3. The motor's voltage input is attached to Vin, and its ground is attached to ground on the Arduino. A 10-microfarad capacitor is mounted across the 3.3V and ground buses.
Figure 14. Breadboard view of a servomotor and an analog input attached to an Arduino Nano 33 IoT.

When you attach the servo, you’ll need a row of three male headers to attach it to a breadboard. You may find that the pins don’t stay in the servo’s connector holes. Put the pins in the servo’s connector, then push them down on a table gently. They will slide up inside their plastic sheaths, and fit better in your servo’s connector.

Different RC servomotors will have different current requirements. The Tower SG5010 model servo sold by Adafruit draws more current than the HiTec HS311 and HS318 sold by ServoCity, for example. The Tower Pro servo draws 100-300 mA with no load attached, while the HiTec servos draw 160-180mA. The decoupling capacitor in the circuit will smooth out any voltage dips that occur when the servo turns on, but you will need an external 5V supply if you are using more than one servomotor.

Related video: Connect the Servo

Figures 15-17 show steps of this in action.

Photo of a servomotor connector with three header pins next to it. The header pins appear too short to connect properly to the servomotor connector.
Figure 15. Attaching header pins to a servomotor connector. If your header pins are too short, as shown here, you can lengthen them.
Photo of a hand holding a servomotor connector with header pins pushed partway into the holes. The pins are being braced against a tabletop.
Figure 16. Push the short ends of the header pins into the servomotor connector’s holes and then brace the long ends against a tabletop while you push down on the connector. Do this gently and the header pins will move in their plastic mount.
Photo of a servomotor connector with three header pins next to it. The header pins are now longer on top and shorter on bottom than they were in the first picture.
Figure 17. Now your header pins will be longer on top and shorter on bottom, and will stay firmly in the servomotor connector.

Program the Microcontroller

First, find out the range of your sensor by using analogRead() to read the sensor and printing out the results.

void setup() {
  Serial.begin(9600);       // initialize serial communications
} 

void loop()
{
  int analogValue = analogRead(A0); // read the analog input
  Serial.println(analogValue);      // print it
}

Now, map the result of the analog reading to a range from 0 to 179, which is the range of the sensor in degrees. Store the mapped value in a local variable called servoAngle.

void setup() {
  Serial.begin(9600);       // initialize serial communications
} 

void loop()
{
  int analogValue = analogRead(A0); // read the analog input
  Serial.println(analogValue);      // print it

  // if your sensor's range is less than 0 to 1023, you'll need to
  // modify the map() function to use the values you discovered:
  int servoAngle = map(analogValue, 0, 1023, 0, 179);
}

Finally, add the servo library at the beginning of your code, then make a variable to hold an instance of the library, and a variable for the servo’s output pin. In the setup(), initialize your servo using servo.attach(). Then in your main loop, use servoAngle to set the servo’s position.

#include "Servo.h"      // include the servo library

Servo servoMotor;       // creates an instance of the servo object to control a servo
int servoPin = 9;       // Control pin for servo motor
// time when the servo was last updated, in ms
long lastMoveTime = 0;  

void setup() {
  Serial.begin(9600);       // initialize serial communications
  servoMotor.attach(servoPin);  // attaches the servo on pin 9 to the servo object
} 

void loop() {
  int analogValue = analogRead(A0); // read the analog input
  Serial.println(analogValue);      // print it

  // if your sensor's range is less than 0 to 1023, you'll need to
  // modify the map() function to use the values you discovered:
  int servoAngle = map(analogValue, 0, 1023, 0, 179);

  // move the servo using the angle from the sensor every 20 ms:
  if (millis() - lastMoveTime > 20) {
    servoMotor.write(servoAngle);
    lastMoveTime = millis();
  }
}

Related video: Code for the Servo & Turn the Servo

Get Creative

Servo motors give you the power to do all kinds of things.

They can be used to push a remote control button, in a pinch, as shown in Figure 18.

Photo of a remote control mounted in a wooden cradle. A servomotor mounted on the side of the cradle is positioned such that when it moves, its horn presses down on the power button of the remote control.
Figure 18. A servomotor can press remote control buttons The remote control is mounted in a wooden frame, and the servo is mounted on the side of the frame. The servo horn moves down to press the power button.

You can play music with found objects like in this Project by Nick Yulman. You can build a frisking machine like in this project by Sam Lavigne and Fletcher Bach. If you’ve got 800 or so of them and a lot of time, you can build a wooden mirror like this Project by Daniel Rozin.

Lab: Analog In with an Arduino

In this lab, you’ll learn how to connect a variable resistor to a microcontroller and read it as an analog input. You’ll be able to read changing conditions from the physical world and convert them to changing variables in a program.

Introduction

In this lab, you’ll learn how to connect a variable resistor to a microcontroller and read it as an analog input. You’ll be able to read changing conditions from the physical world and convert them to changing variables in a program.

Many of the most useful sensors you might connect to a microcontroller are analog input sensors. They deliver a variable voltage, which you read on the analog input pins using the analogRead() command.

What You’ll Need to Know

To get the most out of this lab, you should be familiar with the following concepts and you should install the Arduino IDE on your computer. You can check how to do so in the links below:

Things You’ll Need

Figures 1-12 show the parts you’ll need for this exercise. Click on any image for a larger view.

Set Up the Breadboard

Connect power and ground on the breadboard to power and ground from the microcontroller. On the Arduino module, use the 5V or 3.3V (depending on your model) and any of the ground connections. Figures 13 and 14 show how to do this for an Arduino Uno and an Arduino Nano 33 IoT.

As shown in Figure 13, the Uno’s 5V output hole is connected to the red column of holes on the far left side of the breadboard. The Uno’s ground hole is connected to the blue column on the left of the board. The red and blue columns on the left of the breadboard are connected to the red and blue columns on the right side of the breadboard with red and black wires, respectively. These columns on the side of a breadboard are commonly called the buses. The red line is the voltage bus, and the black or blue line is the ground bus.


An Arduino Uno on the left connected to a solderless breadboard, right. The Uno's 5V output hole is connected to the red column of holes on the far left side of the breadboard. The Uno's ground hole is connected to the blue column on the left of the board. The red and blue columns on the left of the breadboard are connected to the red and blue columns on the right side of the breadboard with red and black wires, respectively. These columns on the side of a breadboard are commonly called the buses. The red line is the voltage bus, and the black or blue line is the ground bus.
Figure 13. An Arduino Uno on the left connected to a solderless breadboard, right.
Arduino Nano on a breadboard.
Figure 14. Breadboard view of an Arduino Nano mounted on a breadboard

Images made with Fritzing

In Figure 14, the Nano is mounted at the top of the breadboard, straddling the center divide, with its USB connector facing up. The top pins of the Nano are in row 1 of the breadboard.

The Nano, like all Dual-Inline Package (DIP) modules, has its physical pins numbered in a U shape, from top left to bottom left, to bottom right to top right. The Nano’s 3.3V pin (physical pin 2) is connected to the left side red column of the breadboard. The Nano’s GND pin (physical pin 14) is connected to the left side black column. These columns on the side of a breadboard are commonly called the buses. The red line is the voltage bus, and the black or blue line is the ground bus. The blue columns (ground buses) are connected together at the bottom of the breadboard with a black wire. The red columns (voltage buses) are connected together at the bottom of the breadboard with a red wire.

Add a Potentiometer and LED

Connect the wiper of a potentiometer to analog in pin 0 of the module and its outer connections to voltage and ground. Connect a 220-ohm resistor to digital pin 9. You can replace the LED with a speaker if you prefer audible output. Connect the anode of an LED to the other side of the resistor, and the cathode to ground as shown below. See Figure 15 and Figure 16 to learn how to do this with an Arduino Uno. Figure 17 shows a breadboard view of an Arduino Nano for the same circuit.

Related Video: Potentiometer schematic

Figure 15. Schematic view of a potentiometer connected to analog in 0 of an Arduino and an LED connected to digital pin 9. Connect the voltage lead of the potentiometer to 5V for Uno, 3.3V for Nano 33 IoT.
Breadboard drawing of a potentiometer connected to analog in 0 of an Arduino and an LED connected to digital pin 9. An Arduino Uno on the left connected to a solderless breadboard, right. The Uno's 5V output hole is connected to the red column of holes on the far left side of the breadboard. The Uno's ground hole is connected to the blue column on the left of the board. The red and blue columns on the left of the breadboard are connected to the red and blue columns on the right side of the breadboard with red and black wires, respectively. These columns on the side of a breadboard are commonly called the buses. The red line is the voltage bus, and the black or blue line is the ground bus. On the breadboard, a potentiometer is connected to pins 21 through 23 in the left center section of the board. A red wire connects row 21 in the left center section to the voltage bus on the left side. A black wire connects row 23 in the left center section to the ground bus on the left side. A blue wire connects row 22 to the Arduino's analog in pin 0. A 220-ohm resistor straddles the center divide of the breadboard, connecting to row 17 on both sides. In the left center section of the breadboard, a blue wire connects row 17 to pin D9 of the Arduino. In the right center section, the anode of an LED is connected to row 17. The cathode of the LED is in row 16. A black wire connects row 16 to the ground bus on the right side of the board.
Figure 16. Breadboard view of a potentiometer connected to analog in 0 of an Arduino and an LED connected to digital pin 9.

Breadboard view of Arduino Nano with an analog input and LED output.
Figure 17. Breadboard view of Arduino Nano with an analog input and LED output.

Figure 17 shows the breadboard view of an Arduino Nano connected to a potentiometer and an LED. The +3.3 volts and ground pins of the Arduino are connected by red and black wires, respectively, to the left side rows of the breadboard. +3.3 volts is connected to the left outer side row (the voltage bus) and ground is connected to the left inner side row (the ground bus). The side rows on the left are connected to the side rows on the right using red and black wires, respectively, creating a voltage bus and a ground bus on both sides of the board. The potentiometer is mounted  in the left center section of the solderless breadboard. Its outside pins are connected to the voltage and ground buses, respectively  There is a wire connecting to analog in 0 of the nano (physical  pin 4) to the the center pin of the potentiometer. An LED is mounted in the right center section of the board, with a 220-ohm resistor attached to its anode (long leg). The other end of the resistor connects to the Nano’s digital pin 9 (physical pin 27). The cathode of the LED (short leg) connects to ground. If you’re using a speaker instead of the LED, connect it to the same connections as the LED.


Program the Module

Now that you have the board wired correctly, program your Arduino as follows:

Related Video

First, establish some global variables: one to hold the value returned by the potentiometer, and another to hold the brightness value. Make a global constant to give the LED’s pin number a name.

const int ledPin = 9;       // pin that the LED is attached to
int analogValue = 0;        // value read from the pot
int brightness = 0;         // PWM pin that the LED is on.

In the setup() method, initialize serial communications at 9600 bits per second, and set the LED’s pin to be an output.

  // initialize serial communications at 9600 bps:
    Serial.begin(9600);
    // declare the led pin as an output:
    pinMode(ledPin, OUTPUT);
}

In the main loop, read the analog value using analogRead() and put the result into the variable that holds the analog value. Then divide the analog value by 4 to get it into a range from 0 to 255. Then use the analogWrite() command to face the LED. Then print out the brightness value. An alternate loop function for the speaker follows right after the first one.

void loop() {
    analogValue = analogRead(A0);    // read the pot value
    brightness = analogValue /4;       //divide by 4 to fit in a byte
    analogWrite(ledPin, brightness);   // PWM the LED with the brightness value
    Serial.println(brightness);        // print the brightness value back to the serial monitor
}

If you’re replacing the LED with a speaker, here’s an alternate loop function that will play a changing tone on the speaker:

void loop() {
    analogValue = analogRead(A0);      // read the pot value
    frequency = (analogValue /4) * 10; // divide by 4 to fit in a byte, multiply by 10 for a good tonal range
    tone(pinNumber, frequency);        // make a changing tone on the speaker
    Serial.println(brightness);        // print the brightness value back to the serial monitor
}

When you run this code, the LED should dim up and down as you turn the pot, and the brightness value should show up in the serial monitor.

Other variable resistors

You can use many different types of variable resistors for analog input. For example, the pink monkey in the photo below has his arms wired with flex sensors. These sensors change their resistance as they are flexed. When the monkey’s arms move up and down, the values of the flex sensors change the brightness of two LEDs. The same values could be used to control servo motors, change the frequency on a speaker, or move servo motors.

Related Video: Wiring an FSR (force sensitive resistor)
Related Video: Wiring a photocell to measure light

Photo of a stuffed pink monkey with flex sensors attached to its arms. The flex sensors are attached with tie-wraps at the shoulder and wrist of the monkey. The wired ends of the sensors are behind the monkey's neck. The wires lead away from the monkey's back discreetly.
Figure 18. A stuffed pink monkey with flex sensors attached

Note on Soldering Sensor Leads

Flex sensors and force-sensing resistors melt easily, so unless you are very quick with a soldering iron, it’s risky to solder directly to their leads. See Figure 19-21 to learn about three better solutions:

Photo of the metal ends of a force-sensing resistor with wire-wrapped wiring. Very thin single-strand wire is wrapped tightly around each of the two metal connections of the sensor, making a tight connection with no soldering.
Figure 19. Wire-wrapped connections of a force-sensing resistor
Photo of the metal ends of a force-sensing resistor mounted in a screw terminal. The screw terminal has three headers, and the force-sensing resistor is connected to two of them. a 10-kilohm resistor (with brown, black, orange, and gold bands) is connected to one of the two terminals with the FSR. The other end of the resistor is screwed into the third terminal.
Figure 20. Screw terminal connection for force sensing resistor
Photo of the metal ends of a force-sensing resistor mounted in breakaway socket headers. The socket headers, separated by 0.1 inches (2.5mm) have wires soldered to their metal ends. This way, the soldering happens to the socket pins. The socket headers are cheaper than the sensor, so the cost of damaging them by soldering is less than soldering the sensors.
Figure 21. Force sensing resistor connected to breakaway socket headers

Adafruit has a good FSR tutorial as well.

If you’d like to read a changing light level, you can use a phototransistor for the job. Phototransistors are not variable resistors like photoresistors (which are shown in this video), but they perform similarly are made from less toxic materials. They are actually transistors in which the light falling on the sensor acts as the transistor’s base. Like photoresistors, they are sensitive to changes in light, and they work well in the same voltage divider circuit. Figure 22 shows how to connect a phototransistor and a 10-kilohm resistor as an analog input:

Figure 22. Breadboard view of an Arduino Nano connected to a phototransistor as an analog input. The long leg of the phototransistor connects to voltage, and the long leg connects to the input pin. The 10-kilohm fixed resistor then connects from the input pin to ground.

Different phototransistors will have different sensitivities to light. For example, this model from Everlight, which has a clear top, is most sensitive to 390 – 700 nm light range, with a peak at 630nm (orange-red). This model from Excelitas has a colored top to block IR light, and has a range from 450 -700nm, with a peak at 585nm (yellow). For the frequencies of the visible light spectrum, see this chart from Wikipedia.


Figure 23 and 24 shows an example circuit much like the pink monkey circuit (Figure 18) above, but with force-sensing resistors instead of flex sensors.

On the breadboard, two force-sensing resistors are mounted in rows 16 and 17 and 24 and 25, respectively, in the left center section of the board. Two red wires connects rows 16 and 24 in the left center section to the voltage bus on the left side. Two 10-kilohm resistors (orange, black, brown, and gold bands) connect rows 17 and 25 to the ground bus on the left hand side. Two blue wires connect from rows 17 and 25 to analog in pins 0 and 1 of the Arduino, respectively. Two 220-ohm resistors straddle the center divide of the breadboard, connecting to row 7 on both sides and 11 on both sides, respectively. In the left center section of the breadboard, two blue wires connect rows 7 and 11 to pins D10 and D9 of the Arduino, respectively. In the right center section, the anodes of two LEDs are connected to rows 7 and 11, respectively. The cathodes of the LED are in rows 6 and 10, respectively. Two black wire connects row 6 and 10 to the ground bus on the right side of the board.

Schematic drawing of two force-sensing resistors and two LEDs attached to an Arduino. The Arduino is represented by a rectangle in the middle with lines on each side representing the pin connections. On the left side of the rectangle, two variable resistor are connected to analog in pins 0 and 1, respectively. The other ends of the variable resistors are connected to the 5-volt pin on the Arduino, shown at the top of the rectangle. Two fixed 10-kilohm resistors are connected to analog in pins 0 and 1 as well. The other ends of the fixed resistors are connected to ground, shown on the bottom of the rectangle. On the right side, two 220-ohm resistors are connected to pins D9 and D10, respectively. The other connections of the resistors are connected to the anodes of two LEDs. The cathodes of the LEDs are connected to the ground pin of the Arduino.
Figure 23. Schematic view of two force-sensing resistors and two LEDs attached to an Arduino.
On the breadboard, two force-sensing resistors are mounted in rows 16 and 17 and 24 and 25, respectively, in the left center section of the board. Two red wires connects rows 16 and 24 in the left center section to the voltage bus on the left side. Two 10-kilohm resistors (orange, black, brown, and gold bands) connect rows 17 and 25 to the ground bus on the left hand side. Two blue wires connect from rows 17 and 25 to analog in pins 0 and 1 of the Arduino, respectively. Two 220-ohm resistors straddle the center divide of the breadboard, connecting to row 7 on both sides and 11 on both sides, respectively. In the left center section of the breadboard, two blue wires connect rows 7 and 11 to pins D10 and D9 of the Arduino, respectively. In the right center section, the anodes of two LEDs are connected to rows 7 and 11, respectively. The cathodes of the LED are in rows 6 and 10, respectively. Two black wire connects row 6 and 10 to the ground bus on the right side of the board.
Figure 24. Breadboard view of two force-sensing resistors and two LEDs attached to an Arduino.

The circuit above works for any variable resistor. You could replace the force-sensing resistors with flex sensors to use the monkey toy above with this circuit. Two resistors placed in series like this are called a voltage divider. There are two voltage dividers in the circuit shown, one on analog in 0 and one on analog in 1. The fixed resistor in each circuit should have the same order of magnitude as the variable resistor’s range. For example, if you’re using a flex sensor with a range of 50 – 100 kilohms, you might use a 47-kilohm or a 100-kilohm fixed resistor. If you’re using a force sensing resistor that goes from infinity ohms to 10 ohms, but most of its range is between 10 kilohms and 10 ohms, you might use a 10-kilohm fixed resistor.

The code above assumed you were using a potentiometer, which always gives the full range of analog input, which is 0 to 1023. Dividing by 4 gives you a range of 0 to 255, which is the full output range of the analogWrite() command. The voltage divider circuit, on the other hand, can’t give you the full range. The fixed resistor in the circuit limits the range. You’ll need to modify the code or the resistor if you want a different range.

Finding Your Sensor Range

Related Video: Use map() to detect the sensor’s state

To find out your range, open the serial monitor and watch the printout as you press the FSR or flex the flex sensor. Note the maximum value and the minimum value. Then you can map the range that the sensor actually gives as input to the range that the LED needs as output.

For example, if your photocell gives a range from 400 to 900, you’d do this:

// map the sensor value from the input range (400 - 900, for example) to the output range (0-255):
int brightness = map(sensorValue, 400, 900, 0, 255);
analogWrite(ledPin, brightness);

You know that the maximum input range of any analog input is from 0 to 5 volts. So if you wanted to know the voltage on an analog input pin at any point, you could do some math to extrapolate it in your loop() like so:

void loop() {
  // read the sensor on analog pin 0:
  int sensorValue = analogRead(A0);
  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  float voltage = sensorValue * (5.0 / 1023.0);
  // for 0-3.3V use the line below:
  // voltage = sensorValue * (3.3 / 1023.0);
  // print out the value you read:
  Serial.println(voltage);
}

Now write a sketch to control the red LED with the first sensor (we’ll call it the right hand sensor) and the green LED with the second sensor (we’ll call it the left hand sensor). First, make two constants for the LED pin numbers, and two variables for the left and right sensor values.

const int redLED = 10;     // pin that the red LED is on
const int greenLED = 11;   // pin that the green LED is on
int rightSensorValue = 0;  // value read from the right analog sensor
int leftSensorValue = 0;   // value read from the left analog sensor

In the setup(), initialize serial communication at 9600 bits per second, and make the LED pins outputs.

void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600);
  // declare the led pins as outputs:
  pinMode(redLED, OUTPUT);
  pinMode(greenLED, OUTPUT);
}

Start the main loop by reading the right sensor using analogRead(). Map it to a range from 0 to 255. Then use analogWrite() to set the brightness of the LED from the mapped value. Print the sensor value out as well.

void loop() {
  rightSensorValue = analogRead(A0); // read the pot value
  // map the sensor value from the input range (400 - 900, for example)
  // to the output range (0-255). Change the values 400 and 900 below
  // to match the range your analog input gives:
  int brightness = map(rightSensorValue, 400, 900, 0, 255);
  analogWrite(redLED, brightness);  // set the LED brightness with the result
  Serial.println(rightSensorValue);   // print the sensor value back to the serial monitor

Finish the main loop by doing the same thing with the left sensor and the green LED.

 // now do the same for the other sensor and LED:
  leftSensorValue = analogRead(A1); // read the pot value
  // map the sensor value to the brightness again. No need to
  // declare the variable again, since you did so above:
  brightness = map(leftSensorValue, 400, 900, 0, 255);
  analogWrite(greenLED, brightness);  // set the LED brightness with the result
  Serial.println(leftSensorValue);   // print the sensor value back to the serial monitor
}

Mapping works for audible tones as well. Human hearing is in a range from 20Hz to 20 kHz, with 100 – 10000 Hz being a reasonable middle ground so if your input is in a range from 0 to 255, you can quickly get audible tones by mapping like so:

int pitch = map(input, 0, 255, 100, 10000);

When you run this, you should see the LEDs changing in brightness, or hear the speaker changing in pitch, as you press the sensors. This is the central function of analog sensors on a microcontroller: to allow for a variable range of input to control a variable range out output. Whether your sensor is read through an analog sensor like this, or through synchronous serial interfaces as you’ll see in the SPI and I2C labs, you always need to find out how the range of action from the user relates to the range of values that the sensor produces. Once you’re comfortable with this concept, get to know how to read the change in a sensor’s readings as well.

Lab: Digital Input and Output with an Arduino

In this lab, you’ll connect a digital input circuit and a digital output circuit to a microcontroller. Though this is written for the Arduino microcontroller module, the principles apply to any microcontroller.

Introduction

In this lab, you’ll connect a digital input circuit and a digital output circuit to a microcontroller. Though this is written for the Arduino microcontroller module, the principles apply to any microcontroller.

Digital input and output are the most fundamental physical connections for any microcontroller. The pins to which you connect the circuits shown here are called General Purpose Input-Output, or GPIO, pins. Even if a given project doesn’t use digital in and out, you’ll often use LEDs and pushbuttons or switches during the development for testing whether everything’s working.

What You’ll Need to Know

To get the most out of this lab, you should be familiar with the following concepts and you should install the Arduino IDE on your computer. You can check how to do so in the links below:

Things You’ll Need

Figures 1-8 show the parts you’ll need for this exercise. Click on any image for a larger view.

Photo of an Arduino Nano 33 IoT module. The USB connector is at the top of the image, and the physical pins are numbered in a U-shape from top left to bottom left, then from bottom right to top right.
Figure 1. Arduino Nano 33 IoT
Photo of flexible jumper wires
Figure 2. Jumper wires.  You can also use pre-cut solid-core jumper wires.
Photo of a solderless breadboard
Figure 3. A solderless breadboard
Photo of an 8 ohm speaker
Figure 4. An 8 ohm speaker (optional).This is a good alternate to the LED if you prefer audible output.

Photo of a handful of LEDs
Figure 5. LEDs. The long leg goes to voltage and the short leg goes to ground
Photo of a handful of 220-ohm resistors.
Figure 6. 220-ohm resistors. These ones are 4-band resistors. They are colored red, red, brown and gold, which signifies 2, 2 (red, red), times 10 (brown), with a 5% tolerance (gold).
Photo of a handful of 10-kilohm resistors
Figure 7. 10-kilohm resistors. These ones are 5-band resistors. They are colored brown, black, black, red, brown, which signifies 1 (brown), 0, 0 (black, black), times 100 (red), with a 1% tolerance (brown). Four-band 10-kilohm resistors are colored brown, black, orange (1, 0, times 1000), gold (5% tolerance).
Photo of four breadboard-mounted pushbuttons
Figure 8. A pushbutton. Any switch will do the job as well.

The video Video: Digital Output covers the material in this lab.

Prepare the breadboard

If you’re using a brand new breadboard, you might want to check out these videos before you get started, to prep your board and care for your microcontroller.

Connect power and ground on the breadboard to power and ground from the microcontroller. On the Arduino Uno, use the 5V or 3.3V (depending on your model) and any of the ground connections. Figures 9 and 10 show how to do this for an Arduino Uno and for an Arduino Nano 33 IoT.

An Arduino Uno on the left connected to a solderless breadboard, right. The Uno's 5V output hole is connected to the red column of holes on the far left side of the breadboard. The Uno's ground hole is connected to the blue column on the left of the board. The red and blue columns on the left of the breadboard are connected to the red and blue columns on the right side of the breadboard with red and black wires, respectively. These columns on the side of a breadboard are commonly called the buses. The red line is the voltage bus, and the black or blue line is the ground bus.
Figure 9. Breadboard view of an Arduino Uno on the left connected to a solderless breadboard, right.

As shown in Figure 9, the Uno’s 5V output hole is connected to the red column of holes on the far left side of the breadboard. The Uno’s ground hole is connected to the blue column on the left of the board. The red and blue columns on the left of the breadboard are connected to the red and blue columns on the right side of the breadboard with red and black wires, respectively. These columns on the side of a breadboard are commonly called the buses. The red line is the voltage bus, and the black or blue line is the ground bus.


Arduino Nano on a breadboard.
Figure 10 Breadboard view of an Arduino Nano mounted on a solderless breadboard.

As shown in Figure 10, the Nano is mounted at the top of the breadboard, straddling the center divide, with its USB connector facing up. The top pins of the Nano are in row 1 of the breadboard.

The Nano, like all Dual-Inline Package (DIP) modules, has its physical pins numbered in a U shape, from top left to bottom left, to bottom right to top right. The Nano’s 3.3V pin (physical pin 2) is connected to the left side red column of the breadboard. The Nano’s GND pin (physical pin 14) is connected to the left side black column. These columns on the side of a breadboard are commonly called the buses. The red line is the voltage bus, and the black or blue line is the ground bus. The blue columns (ground buses) are connected together at the bottom of the breadboard with a black wire. The red columns (voltage buses) are connected together at the bottom of the breadboard with a red wire.


Images made with Fritzing

Related video: Overview of the Arduino microcontroller

Related video: Connect Power and Ground using wires

Add a Digital Input (a Pushbutton)

Connect a pushbutton to digital input 2 on the Arduino. Figures 11 and 12 show the schematic and breadboard views of this for an Arduino Uno, and Figure 13 shows the breadboard view for an Arduino 33 IoT. The pushbutton shown below is a store-bought momentary pushbutton, but you can use any pushbutton. Try making your own with a couple of pieces of metal as shown in the Switches lab.

Related video: Connect a pushbutton to a digital pin

What Are The Input and Output Pins?

If you’re not sure what pins are the inputs and outputs of your board, check the Microcontroller Pin Functions page for more information. The reference page on the  standard breadboard layouts for the Uno, Nano series, and MKR series might be useful as well.

Schematic view of an Arduino connected to a pushbutton. One side of the pushbutton is connected to digital pin 2 of the Arduino. A 10-kilohm resistor is connected from digital pin 2 to ground as well. The other side of the pushbutton is attached to +5V.
Figure 11. Schematic view of an Arduino connected to a pushbutton.
Breadboard view of an Arduino connected to a pushbutton. The +5 volts and ground pins of the Arduino are connected by red and black wires, respectively, to the left side rows of the breadboard. +5 volts is connected to the left outer side row (the voltage bus) and ground is connected to the left inner side row (the ground bus). The side rows on the left are connected to the side rows on the right using red and black wires, respectively, creating a voltage bus and a ground bus on both sides of the board. The pushbutton is mounted across the middle divide of the solderless breadboard. A 10-kilohm resistor connects from the same row as pushbutton's bottom left pin to the ground bus on the breadboard. There is a wire connecting to digital pin 2 from the same row that connects the resistor and the pushbutton. The top left pin of the pushbutton is connected to +5V.
Figure 12. Breadboard view of an Arduino connected to a pushbutton.

Breadboard view of an Arduino Nano connected to a pushbutton. The +5 volts and ground pins of the Arduino are connected by red and black wires, respectively, to the left side rows of the breadboard. +5 volts is connected to the left outer side row (the voltage bus) and ground is connected to the left inner side row (the ground bus). The side rows on the left are connected to the side rows on the right using red and black wires, respectively, creating a voltage bus and a ground bus on both sides of the board. The pushbutton is mounted across the middle divide of the solderless breadboard. A 10-kilohm resistor connects from the same row as pushbutton's bottom left pin to the ground bus on the breadboard. There is a wire connecting to digital pin 2 from the same row that connects the resistor and the pushbutton. The top left pin of the pushbutton is connected to +3.3V.
Figure 13. Breadboard view of an Arduino Nano connected to a pushbutton.

Figure 13 shows the breadboard view of an Arduino Nano connected to a pushbutton. The +3.3 volts and ground pins of the Arduino are connected by red and black wires, respectively, to the left side rows of the breadboard. +3.3 volts is connected to the left outer side row (the voltage bus) and ground is connected to the left inner side row (the ground bus). The side rows on the left are connected to the side rows on the right using red and black wires, respectively, creating a voltage bus and a ground bus on both sides of the board. The pushbutton is mounted across the middle divide of the solderless breadboard. A 10-kilohm resistor connects from the same row as pushbutton’s bottom left pin to the ground bus on the breadboard. There is a wire connecting to digital pin 2 from the same row that connects the resistor and the pushbutton. The top left pin of the pushbutton is connected to +3.3V.


Note on The Pulldown Resistor

What happens if you don’t include the resistor connecting the pushbutton to ground? The resistor connecting the pushbutton is a pulldown resistor. It provides the digital input pin with a connection to ground. Without it, the input will behave unreliably.

If you don’t have a 10-kilohm resistor for the pushbutton, you can use any reasonably high value. 4.7K, 22K, and even 1 Megohm resistors have all been tested with this circuit and they work fine.  See the digital input and output notes for more about the digital input circuit.

If you’re not sure about the resistor color codes, use a multimeter to measure the resistance of your resistors in ohms, and check this resistor color code calculator.

Add Digital Outputs (LEDs)

Connect a 220-ohm resistor and an LED in series to digital pin 3 and another to digital pin 4 of the Arduino. Figures 14,  15, and 16 below show the schematic view as well as the breadboard view for both the Uno and the Nano. If you prefer an audible tone over a blinking LED, you can replace the LEDs with speakers or buzzers. The 220-ohm resistor will work with LED, speaker, or buzzer.

Arduino connected to pushbutton and two LEDs, Schematic view. The pushbutton is connected as described in the image above. Digital pins 3 and 4 are connected to 22-ohm resistors. The other sides of the resistors are connected to the anodes (long legs) of two LEDs. The cathodes of the LEDs are both connected to ground.
Figure 14. Arduino connected to pushbutton and two LEDs, Schematic view.
Arduino Nano connected to pushbutton and two LEDs, Breadboard view. The pushbutton is connected as described in the image above. Digital pins 3 and 4 are connected to 22-ohm resistors. The resistors are mounted across the center divide of the breadboard, each in its own row. The other sides of the resistors are connected to the anodes (long legs) of two LEDs. The cathodes of the LEDs are both connected to ground.
Figure 15. Arduino Uno connected to pushbutton and two LEDs, Breadboard view.

Arduino Nano connected to pushbutton and two LEDs, Breadboard view. The pushbutton is connected as described in the image above. Digital pins 3 and 4 are connected to 22-ohm resistors. The resistors are mounted across the center divide of the breadboard, each in its own row. The other sides of the resistors are connected to the anodes (long legs) of two LEDs. The cathodes of the LEDs are both connected to ground.
Figure 16. Arduino Nano connected to pushbutton and two LEDs, Breadboard view.

Note on LED Resistor Values

For the resistor on the LED, the higher the resistor value, the dimmer your LED will be. So 220-ohm resistors give you a nice bright LED, 1-kilohm will make it dimmer, and 10K or higher will likely make it too dim to see. Similarly, higher resistor values attenuate the sound on a speaker, so a resistor value above 220-ohm will make the sound from your speaker or buzzer quieter.

Related video: Resistors for an LED

Program the Arduino

Make sure you’re using the Arduino IDE version 1.8.19 or later. If you’ve never used the type of Arduino module that you’re using here (for example, a Nano 33 IoT), you may need to install the board definitions. Go to the Tools Menu –> Board submenu –> Board Manager. A new window will pop up. Search for your board’s name (for example, Nano 33 IoT), and the Boards manager will filter for the correct board. Click install and it will install the board definition.

Connect the microcontroller to your computer via USB. When you plug the Arduino into your computer, you’ll find a new serial port in the Tools–>Port menu (for details on installing the software, and USB-to-serial drivers for older Arduino models on Windows, see the Arduino Getting Started Guide). In the MacOS, the name look like this: /dev/tty.usbmodem-XXXX (Board Type) where XXXX are part of the board’s unique serial number and Board Type is the board type (for example, Arduino Uno, Nano 33 IoT, MKRZero, etc.)  In Windows it will be called COM and a number. Figure 17 shows the tools men and its Port submenu.

Screenshot of the Arduino Tools menu showing the Ports submenu
Figure 17. The Arduino Tools menu showing the Ports submenu

Now it’s time to write a program that reads the digital input on pin 2. When the pushbutton is pressed, turn the yellow LED on and the red one off. When the pushbutton is released, turn the red LED on and the yellow LED off.

In your setup() method, you need to set the three pins you’re using as inputs or outputs, appropriately.

 void setup() {
   pinMode(2, INPUT);    // set the pushbutton pin to be an input
   pinMode(3, OUTPUT);   // set the yellow LED pin to be an output
   pinMode(4, OUTPUT);   // set the red LED pin to be an output
 }

In the main loop, first you need an if-then-else statement to read the pushbutton. If you’re replacing the LED with a buzzer, the code below will work as is. If you’re using a speaker, there’s an alternative main loop just below the first one:

void loop() {
   // read the pushbutton input:
   if (digitalRead(2) == HIGH) {
     // if the pushbutton is closed:
     digitalWrite(3, HIGH);    // turn on the yellow LED
     digitalWrite(4, LOW);     // turn off the red LED
   }
   else {
     // if the switch is open:
     digitalWrite(3, LOW);     // turn off the yellow LED
     digitalWrite(4, HIGH);    // turn on the red LED
   }
 }

Here’s an alternate loop function for an audible output on two speakers. If you want to use only one speaker, try alternating the tone frequency from 440Hz (middle A) to 392Hz (middle G):

void loop() {
   // read the pushbutton input:
   if (digitalRead(2) == HIGH) {
     // if the pushbutton is closed:
     tone(3, 440);    // turn on the first speaker to 440 Hz
     noTone(4);     // turn off the second speaker
   }
   else {
     // if the switch is open:
     noTone(3);     // turn off the first speaker
     tone(4, 440);    // turn on the second speaker to 440 Hz
   }
 }

Once you’re done with that, you’re ready to compile your sketch and upload it. Click the Verify button to compile your code. Then click the Upload button to upload the program to the module. After a few seconds, the following message will appear in the message pane to tell you the program was uploaded successfully. Related video: Upload the code to the Arduino

Binary sketch size: 5522 bytes (of a 7168 byte maximum)

Press the pushbutton and watch the LEDs change until you get bored. That’s all there is to basic digital input and output!

The Uno vs Newer Boards

If you’ve used an Uno r3 board before (the “classic Uno”), and are migrating to the Nano or a newer board, you may notice that the serial connection behaves differently. When you reset the MKR, Nano, Uno R4, or Leonardo boards,  or upload code to them, the serial port seems to disappear and re-appear. Here’s why:

There is a difference between the Uno R3 and most of the newer boards like the MKR boards, the Nano 33 IoT and BLE, the Leonardo and the Uno R4: the Uno R3 has a USB-to-serial chip on the board which is separate from the microcontroller that you’re programming. The Uno R3’s processor, an ATMega328, cannot communicate natively via USB, so it needs the separate processor. That USB-to-serial chip is not reset when you upload a new sketch, so the port appears to be there all the time, even when your Uno R3 is being reset.

The newer boards can communicate natively using USB. They don’t need a separate USB-to-serial chip. Because of this, they can be programmed to operate as a mouse, as a keyboard, or as a USB MIDI device.  Since they are USB-native, their USB connection gets reset when you upload new code or reset the processor. That’s normal behavior for them; it’s as if you turned off the device, then turned it back on. Once it’s reset, it will let your computer’s operating system know that it’s ready for action, and your serial port will reappear. This takes a few seconds. It means you can’t reset the board, and then open the serial port in the next second. You have to wait those few seconds until the Arduino board has made itself visible to the computer’s operating system again.

If you have problems with the UBS-native boards’ serial connection, tap the reset button once, then wait a few seconds, then see if the port shows up again once the board has reset itself. You can also double-tap the reset on the MKR and Nano boards to cause the processor to reset and go into a sleep mode. In this mode, the USB connection will reset itself, but your sketch won’t start running. The built-in LED will glow softly. Then upload a blank sketch. From there, you can start as if your board was brand new.

Related video: Digital Output

Applications

Many projects can be made with just digital input and output. For example, a combination lock is just a series of pushbuttons that have been pushed in a particular sequence. Consider the cymbal-playing monkey in Figures 18-20:

A mechanical toy monkey that plays cymbals. The cymbals are covered with aluminum foil. The foil is connected to wires, and the wires are connected to an Arduino and breaboard. The two wires from the cymbals act as a switch when they are hit together.
Figure 18. A mechanical toy monkey that plays cymbals. The cymbals are covered with aluminum foil. The foil is connected to wires, and the wires are connected to an Arduino and breadboard. The two wires from the cymbals act as a switch when they are hit together.

The monkey’s cymbals can be turned into a switch by lining them with tin foil and screwing wires to them:

Detail of the cymbal monkey's cymbal. It is covered with tin foil, as described above.
Figure 19. Detail of the cymbal monkey’s cymbal. It is covered with aluminum foil, as described above.
Detail of the other cymbal. This one is also covered with aluminum foil.
Figure 20. Detail of the other cymbal. This one is also covered with aluminum foil.

Those wires can be run to a breadboard and used as a switch. Then the microcontroller could be programmed to listen for pattern of cymbal crashes, and if it sees that pattern, to open a lock by turning on a digital output.

Consider the project ideas from Project 1 for more applications you can do with simple input and output.

Lab: Tone Output Using An Arduino

In this tutorial you’ll learn how to generate simple tones on an Arduino

Introduction

This lab is an introduction to generating simple tones on an Arduino. In order to make the most of this lab, you should understand the basics of how to program digital input and output on an Arduino, and how to read a simple circuit diagram.

Video of this lab

What You’ll Need

Making Sound Electronically

The following is adapted from SoundExamples.

Sound is created by vibrations in air. When those vibrations get fast enough, above about 20 times a second, you hear them as an audible pitch. The number of vibrations per second is called the frequency and frequency is measured in Hertz (Hz). So 20 times a second is 20Hz. Humans can hear pitches from about 20Hz to about 20,000Hz, or 20 kiloHertz (kHz).

What vibrations are we talking about? A speaker can vibrate. The paper cone of the speaker moves forward, then backward, then back to its resting place many times a second. The length of time it takes to move from rest through one back-and-forth motion, is called the period of the vibration. For example, if a speaker is vibrating at 20Hz, then it moves forward, backward, and back to rest 2in 1/20 of a second, or 0.05 seconds. 0.05 seconds is the period of the sound. Period and frequency are related inversely: frequency = 1/period.

A microcontroller makes sound by sending pulses of electrical energy from an output pin through a wire that’s connected to the paper cone of a speaker. That wire is wrapped in a coil, and mounted inside a magnet. The electrical energy generates a magnetic field, and that field is either attracted to the magnet or repelled by it, depending on which direction the electrical energy is flowing. The magnetic energy moves the coil, and since the coil is attached to the cone, the speaker moves.

So in summary: how do you make sound from an Arduino? Attach a speaker to an output pin and turn it on and off at a set frequency. You can write this code yourself, or you can use the tone() command.

Pulsewidth Modulation vs. Frequency Modulation

When you use analogWrite() to create pulsewidth modulation (PWM) on an output pin, you’re also turning the pin on and off, so you might think, “why not use analogWrite() to make tones?” That command can change the on-off ratio of the output (also known as the duty cycle) but not the frequency. If you have a speaker connected to an output pin running analogWrite(), you’ll get a changing loudness, but a constant tone. To change the tone, you need to change the frequency. The tone() command does this for you.

Prepare the breadboard

Connect power and ground on the breadboard to the microcontroller. On the Arduino module, use the 5V or 3.3V (depending on your model) and any of the ground connections. Figures 8 and 9 show connections for an Arduino Uno and a Nano, respectively.

An Arduino Uno on the left connected to a solderless breadboard, right. The Uno's 5V output hole is connected to the red column of holes on the far left side of the breadboard. The Uno's ground hole is connected to the blue column on the left of the board. The red and blue columns on the left of the breadboard are connected to the red and blue columns on the right side of the breadboard with red and black wires, respectively. These columns on the side of a breadboard are commonly called the buses. The red line is the voltage bus, and the black or blue line is the ground bus.
Figure 8. Breadboard view of an Arduino Uno on the left connected to a solderless breadboard, right.

The Uno’s 5V output hole is connected to the red column of holes on the far left side of the breadboard (Figure 8). The Uno’s ground hole is connected to the blue column on the left of the board. The red and blue columns on the left of the breadboard are connected to the red and blue columns on the right side of the breadboard with red and black wires, respectively. These columns on the side of a breadboard are commonly called the buses. The red line is the voltage bus, and the black or blue line is the ground bus.


Arduino Nano on a breadboard.
Figure 9. Breadboard view of an Arduino Nano mounted on a solderless breadboard.

In Figure 9, the Nano is mounted at the top of the breadboard, straddling the center divide, with its USB connector facing up. The top pins of the Nano are in row 1 of the breadboard.

The Nano, like all Dual-Inline Package (DIP) modules, has its physical pins numbered in a U shape, from top left to bottom left, to bottom right to top right. The Nano’s 3.3V pin (physical pin 2) is connected to the left side red column of the breadboard. The Nano’s GND pin (physical pin 14) is connected to the left side black column. These columns on the side of a breadboard are commonly called the buses. The red line is the voltage bus, and the black or blue line is the ground bus. The blue columns (ground buses) are connected together at the bottom of the breadboard with a black wire. The red columns (voltage buses) are connected together at the bottom of the breadboard with a red wire.


Images made with Fritzing

Connect the Sensors and the Speaker

Connect a variable resistor such as a force-sensing resistor or photosensor to analog pin 0 in a voltage divider circuit as shown below. The 8-ohm speaker connects to pin 8 of the Arduino. You can use any digital I/O pin if you don’t like 8. The other end of the speaker connects to ground. Figures 10 through 12 show the schematic drawing and the breadboard layouts for an Uno and a Nano, respectively.

Note: Although the circuit shown in Figures 10-12 has a 100-ohm resistor with the speaker, you can use a larger resistor. The larger the resistor, the quieter the speaker. A 220-ohm resistor works reasonably well if you don’t have a 100-ohm resistor.

Figure 10. Schematic view of an Arduino connected to a force sensing resistor (FSR), a 10-kilohm resistor, and a speaker. One leg of the FSR is connected to voltage. The other leg is connected simultaneously to the first leg of a 10-kilohm resistor and the Arduino’s analog input pin A0. The second leg of the 10-kilohm resistor is connected to ground. The red positive wire of the speaker is connected to digital pin 8 of the Arduino. The black ground wire of the speaker is connected to one leg of a 100 ohm resistor. The other leg of the resistor connects to ground.
Figure 11. Breadboard view of an Arduino connected to a force-sensing resistor, a fixed resistor, and a speaker. The Arduino’s voltage out and ground pins are connected to the voltage and ground buses of the breadboard as usual. The FSR is mounted in the left center section of the breadboard. One leg of the FSR is connected to 5 volts. The other leg is connected simultaneously to the first leg of a 10-kilohm resistor and the Arduino’s analog input pin A0. The second leg of the 10-kilohm resistor is connected to ground. The red positive wire of the speaker is connected to digital pin 8 of the Arduino. The black ground wire of the speaker is connected to one leg of a 100 ohm resistor. The other leg of the resistor connects to ground.
Breadboard view of an Arduino Nano connected to two force sensing resistors (FSRs) and a speaker.
Figure 12. Breadboard view of an Arduino Nano connected to two force sensing resistors (FSRs) and a speaker. The Nano’s 3.3 Volts (physical pin 2) and ground (physical pin 14) are connected to the voltage and ground buses of the breadboard as usual. The FSR is mounted below the Nano in the left center section of the breadboard. One leg of the FSR is connected to voltage. The other leg is connected simultaneously to the first leg of a 10-kilohm resistor and the Arduino’s analog input pin A0. The second leg of the 10-kilohm resistor is connected to ground. The red positive wire of the speaker is connected to digital pin 8 of the Arduino. The black ground wire of the speaker is connected to one leg of a 100 ohm resistor. The other leg of the resistor connects to ground.

Check the sensor input range

Once you’ve got the circuit connected, check the range of the analog input and note the highest and lowest values you can reach.

void setup() {
  Serial.begin(9600);       // initialize serial communications
}

void loop() {
  int analogValue = analogRead(A0); // read the analog input
  Serial.println(analogValue);      // print it
}

Check that the Speaker Works

You can check that the speaker works by playing a single tone over and over. Here’s a short sketch to play middle A, 440Hz:

void setup() {
  // nothing to do here
}

void loop() {
  // play the tone for 1 second:
  tone(8, 440,1000);
  // do nothing else for the one second you're playing:
  delay(1000);
}

When you run this sketch, you should hear a tone of 44oHz, or middle A, continually. If you don’t, check to see that your speaker wiring is as shown above. If it’s too soft, try changing the 100 Ohm resistor to a smaller resistor.

Play Tones

Write a sketch to read the analog input and map the result to a range from 100 to 1000. The example below assumes your analog input circuit ranges from 200 to 900, so adjuct for your actual values.  Store the result in a local variable called frequency. This will be the frequency you play on the speaker Then use the tone() command to set the frequency of the speaker on pin 8.

void setup() {
  // nothing to do here
}

void loop() {
  // get a sensor reading:
  int sensorReading = analogRead(A0);
  // map the results from the sensor reading's range
  // to the desired pitch range:
  float frequency = map(sensorReading, 200, 900, 100, 1000);
  // change the pitch, play for 10 ms:
  tone(8, frequency, 10);
  delay(10);
}

Once you’ve uploaded this, move your hands over the photocells, and listen to the frequency change. It will change from 100 Hz to 1000 HZ, because that’s what you set in the map() command. If you want to change the frequency range, change those two numbers. See if you can get it to play a little tune.

If you want to know how to generate a tone without the tone() command, here’s the basic algorithm to play one wavelength:

void makeTone(float frequency) {
  // set the period in microseconds:
  int period = (1 / frequency) * 1000000;  
  // turn the speaker on:
  digitalWrite(speakerPin, HIGH);
  // delay half the period:
  delayMicroseconds(period / 2);
  // turn the speaker off:
  digitalWrite(speakerPin, LOW);
  // delay half the period:
  delayMicroseconds(period / 2);
}

Play it Loud

If you’d like to amplify the speaker, modify the speaker circuit by adding a transistor. Most any NPN transistor circuit or N-channel MOSFET will do. Figure 13 shows a speaker getting power from a transistor. This example uses a TIP120 transistor, but an NPN transistor or N-channel MOSFET should work. When using a transistor to amplify the power going to the speaker, you should definitely use a resistor to limit the current. A 100-ohm resistor is shown in this example.

Schematic view of a speaker connected to a transistor
Figure 13. Schematic view of a speaker connected to a transistor. The first leg of the speaker connects to the Arduino’s voltage supply (3.3V). The second leg of the speaker connects to a10-0-ohm resistor. The other side leg of the resistor connects to the collector pin of an NPN transistor (for a TIP120 transistor, this is the middle pin). The transistor’s base pin (the pin to the left when the transistor’s body is facing you) connects to the Arduino’s tone output pin (pin 8 in the examples above). The transistor’s collector pin (on the right when the transistor is facing you) connects to ground.
Figure 14. Breadboard view of a speaker connected to a transistor. The speaker and transistor are connected exactly as described in the schematic view caption in Figure 13.

Use Headphones

You can also connect the tone output of an Arduino to headphones. Using a standard 3.5mm audio jack, connect the center pin of the jack to ground through a 10-kilohm resistor. Then connect the two sides to each other and to your tone output pin. The 10-kilohm resistor here is important, because without it the audio signal will be too strong for your headphones, and could cause you ear damage. Figure 15 shows an audio jack connected to an Arduino Nano 33 IoT for the examples shown here.

Breadboard view of a 3.5mm Audio jack connected to an Arduino Nano 33 IoT.
Figure 15. Breadboard view of a 3.5mm Audio jack connected to an Arduino Nano 33 IoT. The center pin of the audio jack is connected to ground through a 10-kilohm resistor. The two sides are connected to the Nano 33’s tone output pin, which is pin 8 in this example.

A more complex example

There’s an example in the Arduino IDE examples that can play a melody for you. Look in the File Menu under Examples -> Digital -> ToneMelody. You can find the code online at this link. In this example, you’ll see a second tab of text called pitches.h. This file includes constants that give you the pitches for a standard western scale.

You can add your own extra tabs using the new Tab menu to the right of the IDE window. Figure 16 shows the new Tab dropdown menu. Tabs make it easier to separate frequently copied code from custom code for a sketch, as you see in this example.

A dropdown menu located in the upper right hand corner of the Arduino IDE. In order the options are "New Tab", "Rename", "Delete", "Previous Tab", "Next Tab", and the last option shows the name of the sketch
Figure 16. A dropdown menu located in the upper right hand corner of the Arduino IDE showing the tab options. You can also type cmmand-shift-N to get a new tab.

You’ll notice that pitches.h lists a number of note names and numbers. Those numbers are the frequency of each note. For example:

/*************************************************
* Public Constants
*************************************************/

#define NOTE_B0  31
#define NOTE_C1  33
#define NOTE_CS1 35
#define NOTE_D1  37
#define NOTE_DS1 39
#define NOTE_E1  41
#define NOTE_F1  44
#define NOTE_FS1 46
#define NOTE_G1  49
#define NOTE_GS1 52
#define NOTE_A1  55
#define NOTE_AS1 58
#define NOTE_B1  62
#define NOTE_C2  65
#define NOTE_CS2 69
#define NOTE_D2  73

This tells you that that first note in the list, B0 (which is the second lowest note on a piano keyboard, 4 octaves below middle A) has a frequency of 31 Hz. The values listed in pitches.h allow you to play notes from B0 to D#8.

For this sketch, you’ll play a simple melody. A melody consists of notes played in a sequence, and rests between the note. Each note and rest has its own particular duration. You’re going to play a seven note sequence, as shown in Figure 17 (in C Major):

Two measures of a musical notation in 4 / 4 time. The notes are C4, G3, G3, G#3, G3,rest, B3, C4 the respective durations are: quarter note, eighth note, eighth note, quarter note, quarter note, quarter rest, quarter note, quarter note
Figure 17. Two measures of a musical notation. The melody is “Shave and a haircut, two bits”

image from seventhstring.com

The sequence is: C4, G3, G3, G#3, G3, rest, B3, C4

the durations are:

quarter note, eighth note, eighth note, quarter note, quarter note, quarter rest, quarter note, quarter note.

The sketch starts with two global variables. Using pitches.h, make an array variable holding those notes. Make a second array to hold the note durations, marking quarter notes as 4 and eighth notes as 8.

// notes in the melody:
int melody[] = {
NOTE_C4, NOTE_G3,NOTE_G3, NOTE_GS3, NOTE_G3,0, NOTE_B3, NOTE_C4};

// note durations: 4 = quarter note, 8 = eighth note, etc.:
int noteDurations[] = {
4, 8, 8, 4,4,4,4,4 };

How can you use the durations to play notes? Well, imagine that a quarter note is one quarter of a second, and eighth note is one eighth of a second, and so forth. In that case, the actual duration for each note is 1000 milliseconds divided by the value for it in the durations array. For example, the first note is 1000/4, the second is 1000/8, and so forth.

Now, you only want to play the song once, so everything will happen in the setup(). You’ll make a for loop in the setup to iterate over the seven notes. For each time through the loop, use tone() to play the next note in the array. Use the formula in the last paragraph to determine how long each note should play for. After you start the note, delay for as long as the note plays, plus 30 milliseconds or so, to separate each note.

#include "pitches.h"

// notes in the melody:
int melody[] = {
NOTE_C4, NOTE_G3,NOTE_G3, NOTE_GS3, NOTE_G3,0, NOTE_B3, NOTE_C4};

// note durations: 4 = quarter note, 8 = eighth note, etc.:
int noteDurations[] = {4,8,8,4,4,4,4,4 };

void setup() {
  // iterate over the notes of the melody:
  for (int thisNote = 0; thisNote < 8; thisNote++) {
    // to calculate the note duration, take one second
    // divided by the note type.
    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
    int noteDuration = 1000/noteDurations[thisNote];
    tone(8, melody[thisNote],noteDuration);

    //pause for the note's duration plus 30 ms:
    delay(noteDuration +30);
  }
}

void loop() {
  // no need to repeat the melody.
}

That’s the whole tune!

The Relation Between Pitches

For those interested in a little music theory, here’s where those frequency values in pitches.h came from. If you’re not interested in the details, feel free to skip to the next section.

You may have noticed in pitches.h that the value of B1 was twice that of B0, and that C1 is twice C0, and so forth.  In European classical music tradition, the most common tuning system in the last few hundred years has been the 12-tone equal temperament system. This system divides an octave into twelve pitches, in which the frequency interval between every pair of adjacent notes has the same ratio. The pitches are arranged on a logarithmic scale, and the ratio between pitches is equal to to the 12th root of 2, or 21/12, or approximately 1.05946. The whole tuning system is based off a reference frequency, 440 Hz, or middle A (a in the 4th octave, or A4). The step between each adjacent note is called a semitone. Wikipedia’s page on equal temperament gives a longer explanation if you want to know more. Musictheory.net is also a great source of information.

You can use this information to dynamically generate notes in this scale:

frequency = 440 * 2^((noteValue - 69) / 12.0));

This formula, taken from the MIDI tuning standard, works for a range of notes. Using this formula, note 27 is A0, the lowest note on a piano, and note 108 is C8, the highest note on a piano. 440 is the reference frequency, middle A, and 69 is the note number of middle A in MIDI. With this formula, you can cover a wide range of human hearing with note values 0 to 127. And you could generate note frequencies without needing pitches.h. This formula can be handy if you decide to dive into building MIDI devices later on as well. The Arduino API includes a function called the pow() function that raises a number to a power. So that formula, expressed as a line of Arduino programming code, would look like this:

float frequency =  440 * pow(2, ((noteValue - 69) / 12.0));

And the “shave and a haircut” tune from above, would be:

int melody[] = {40, 35,35, 36, 35, 0, 39, 40};

Expressed in note values like this, it would be simple to convert a musical sketch from playing using tone() to playing using a MIDI synthesizer.

Next, try making a musical instrument.

A Musical Instrument

Playing a tune like you just doesn’t allow for much user interaction, so you might want to build more of a musical instrument.

Here’s an example of how to use the note constants to make a simple keyboard. Figures 18-20  show the circuit.

Schematic view of an Arduino connected to three force sensing resistors (FSR) and a speaker. Each of the three FSRs have one of their respective legs connected to +5 volts. Each of the other legs connect to one leg of a 10-kilohm resistor and simultaneously connect to one of the Arduino's analog input pins. In this case the pin connections are A0, A1, and A2. Each of the respective 10-kilohm resistors then connect to ground. The red positive wire of the speaker is connected to digital pin 8 of the Arduino. The black ground wire of the speaker is connected to one leg of a 100 ohm resistor. The other leg of the 100-ohm resistor connects to ground.
Figure 18. Schematic view of an Arduino connected to three force sensing resistors and a speaker.
Breadboard view of an Arduino connected to three force sensing resistors (FSR) and a speaker. Each of the three FSRs have one of their respective legs connected to +5 volts. Each of the other legs connect to one leg of a 10-kilohm resistor and simultaneously connect to one of the Arduino's analog input pins. In this case the pin connections are A0, A1, and A2. Each of the respective 10-kilohm resistors then connect to ground. The red positive wire of the speaker is connected to digital pin 8 of the Arduino. The black ground wire of the speaker is connected to one leg of a 100 ohm resistor. The other leg of the 100 ohm resistor then connects to ground.
Figure 19. Breadboard view of an Arduino connected to three force sensing resistors (FSR) and a speaker. Each of the three FSRs have one of their respective legs connected to +5 volts. Each of the other legs connect to one leg of a 10-kilohm resistor and simultaneously connect to one of the Arduino’s analog input pins. In this case the pin connections are A0, A1, and A2. Each of the respective 10-kilohm resistors then connect to ground. The red positive wire of the speaker is connected to digital pin 8 of the Arduino. The black ground wire of the speaker is connected to one leg of a 100 ohm resistor. The other leg of the 100 ohm resistor then connects to ground.

Figure 20. Breadboard view of an Arduino Nano connected to three force sensing resistors (FSR) and a speaker. Each of the three FSRs have one of their respective legs connected to the voltage bus of the breadboard. Each of the other legs connect to one leg of a 10-kilohm resistor and simultaneously connect to one of the Arduino’s analog input pins. In this case the pin connections are A0, A1, and A2. Each of the respective 10-kilohm resistors then connect to ground. The red positive wire of the speaker is connected to digital pin 8 of the Arduino. The black ground wire of the speaker is connected to one leg of a 100 ohm resistor. The other leg of the 100 ohm resistor then connects to ground.

Program it

Make a sketch that plays a note on each sensor when the sensor is above a given threshold.

Start with a few constants: one for the threshold, one for the speaker pin number, and one for the duration of each tone. To make this instrument work, you need to know what note corresponds to each sensor. Include pitches.h as you did above, then make an array that contains three notes, A4, B4, and C3 as well. Set all of this up at the beginning of your sketch, before setup().

#include "pitches.h"

const int threshold = 10;      // minimum reading of the sensors that generates a note
const int speakerPin = 8;      // pin number for the speaker
const int noteDuration = 20;   // play notes for 20 ms

// notes to play, corresponding to the 3 sensors:
int notes[] = {
NOTE_A4, NOTE_B4,NOTE_C3 };

You don’t need anything in your setup(), but in your loop, you need a for loop that iterates over the first three analog inputs, 0, 1, and 2. For each one, read the sensor, and if it’s above a threshold, play the corresponding note in the notes array for the note duration.

#include "pitches.h"

const int threshold = 10;      // minimum reading of the sensors that generates a note
const int speakerPin = 8;      // pin number for the speaker
const int noteDuration = 20;   // play notes for 20 ms

// notes to play, corresponding to the 3 sensors:
int notes[] = {
NOTE_A4, NOTE_B4,NOTE_C3 };

void setup() {

}

void loop() {
  for (int thisSensor = 0; thisSensor < 3; thisSensor++) {
    // get a sensor reading:
    int sensorReading = analogRead(thisSensor);

    // if the sensor is pressed hard enough:
    if (sensorReading > threshold) {
      // play the note corresponding to this sensor:
      tone(speakerPin, notes[thisSensor], noteDuration);
    }
  }
}

When you upload this sketch, you should have a three-key keyboard.

Get Creative

Now that you’ve got the basics, think about making an instrument for one of your projects. For more background on musical structure, see these notes on tone and generating a melody.

Doing More with Sound Output

If you’re interested going deeper into using sound outputs using speakers, take a look at the Mozzi Libary to produce more complex sound. In a future session, you’ll learn to play and control .wav files from Arduino, which is based on the I2S Library that connect digital audio devices together.

Analog Output

Introduction

This is an introduction to basic analog output on a microcontroller. In order to get the most out of it, you should know something about the following concepts.  You can check how to do so in the links below:

The following video links will help in understanding analog output:

Analog Output

Just as with input, there are times when you want greater control over  a microcontroller’s output than a digital output affords. You might want to control the brightness of a lamp, for example, or the turn of a pointer on a dial, or the speed of a motor. In these cases, you need  an analog output. The most likely things that you might want to vary directly from a microcontroller are lights, sound devices, or things controlled by motors. For many of these, there will be some other controller in between your microcontroller and the final output device. There are lighting dimmers, motor controllers, and so forth, most of which can be controlled using some form of serial digital communication. What’s covered here are simple electrical devices that can be controlled by a changing voltage. The Arduino and other digital microcontrollers generally can’t produce a varying voltage, they can only produce a high voltage or low voltage. Instead, you “fake” an analog voltage by producing a series of voltage pulses at regular intervals, and varying the width of the pulses. This is called pulse width modulation (PWM). The resulting average voltage is sometimes called a pseudo-analog voltage. The graph in Figure 1 shows how PWM works. You pulse the pin high for the same length of time that you pulse it low. The time the pin is high (called the pulsewidth) is about half the total time it takes to go from low to high to low again. This ratio is called the duty cycle and the total time from off through on to off again is the period. The duty cycle in this case 50%, and the effective voltage is half the total voltage.

Related video: Pseudo-Analog Explained

Graph of pulse-width-modulation (PWM) with a 50% duty cycle
Figure 1. PWM with a 50% duty cycle has an effective voltage of 50% of the maximum output voltage. Over time, the voltage is on half the time and off half the time.

If you make the duty cycle less than 50% by pulsing for a shorter amount of time than you pause, you get a lower effective voltage as shown in Figure 2:

Graph of pulse-width-modulation (PWM) with a 33% duty cycle. Effective voltage is a third of the maximum voltage
Figure 2. Graph of pulse-width-modulation (PWM) with a 33% duty cycle. Effective voltage is a third of the maximum voltage. Over time, the voltage is on one third the time and off two thirds of the time.

Related video: PWM graphed and see it on the scope

The period is usually a very small time, on the order of a few microseconds or milliseconds at most. The Arduino boards have a few pins which can generate a continuous PWM signal. On the Arduino Nano 33 IoT. they’re pins 2, 3, 5, 6, 9, 10, 11, 12, A2, A3, and A5. On the Arduino Uno, they’re pins 3, 5, 6, 9, 10, and 11. To control them, you use the analogWrite() command like so:

analogWrite(pin, duty);
  • pin refers to the pin you’re going to pulse
  • duty is a value from 0 – 255. 0 corresponds to 0 volts, and 255 corresponds to 5 volts. Every change of one point changes the pseudo-analog output voltage by 5/255, or  0.0196 volts.

Applications of Pulse Width Modulation

LED dimming

The simplest application of analogWrite() is to change the brightness of an LED. Connect the LED as you did for a digital output, as shown in Figure 3, then use analogWrite() to change its brightness. You’ll notice that it doesn’t change on a linear scale, however.

Related video: See the effect of PWM on the LED

Digital output schematic. A 220-ohm resistor is connected to an output from a microcontroller. The other end of the resistor is connected in series with the anode of an LED. The cathode of the LED is connected to ground.
Figure 3. You can dim an LED with the same circuit as you used for digital output. Just use analogWrite() on the pin to which the LED is connected.

DC Motor Speed Control

You can vary the speed of a DC motor using the analogWrite() command as well. The schematic is in Figure 4. You use the same transistor circuit as you would to turn on and off the motor, shown in Figure 4, but instead of setting the output pin of the microcontroller high or low, you use the analogWrite() on it. The transistor turns on and off at a rate faster than the motor can stop and start, so the result is that the motor appears to smoothly speed up and slow down.

For more on DC motor control, see the following links:

Schematic of motor control with an Arduino, using a MOSFET. One terminal of the motor is connected to +5 volts. The other side is connected to the source pin of a MOSFET transistor. The gate of the transistor is connected to a microcontroller's output pin. The drain pin of the MOSFEt is connected to ground. There is a diode connected in parallel with the transistor. its anode is connected to the drain, and its cathode is connected to the source.
Figure 4. Schematic of motor control with an Arduino, using a MOSFET. One terminal of the motor is connected to a high-current power supply and the other is connected to the MOSFET’s drain pin. The MOSFET’s source pin is connected to ground and its gate is connected to a microcontroller output pin. A protection diode’s cathode is attached to the source of the MOSFET, and the anode is connected to the drain.
Note: Filter circuits

Filter circuits are circuits which allow voltage changes of only a certain frequency range to pass. For example, a low-pass filter would block frequencies above a certain range. This means that if the voltage is changing more than a certain number of times per second, these changes would not make it past the filter, and only an average voltage would be seen. Imagine, for example, that your PWM is operating at 1000 cycles per second, or 1000 Hertz (Hz).  If you had a filter circuit that blocked frequencies above 1000 Hz, you would see only an average voltage on the other side of the filter, instead of the pulses. A basic low-pass filter consists of a resistor and a capacitor, connected as shown in Figure 5:

Schematic drawing of a low-pass filter for an LED. The LED's anode is connected to +5 volts. Its cathode connects to a resistor. The resistor's other end connects to the PWM output of a microcontroller. The junction where the cathode of the LED and the resistor meet is also connected to a capacitor. The other terminal of the capacitor is connected to ground.
Figure 5. Schematic: A basic low-pass filter. An LED’s anode is connected to voltage and its cathode is attached to one terminal of a capacitor. The capacitor’s other terminal is connected to ground. A resistor connects to the junction where the the LED and the capacitor meet. The other end of the resistor is connected to a microcontroller’s output pin.

The relationship between frequency blocked and the values of the capacitor and resistor is as follows:

frequency = 1/ (2π *resistance * capacitance)

A 1.5-kilohm resistor and a 0.1-microfarad capacitor will cut off frequencies above around 1061 Hz. If you’re interested in filters, experiment with different values from there to see what works best.

Servomotors

Perhaps the most exciting thing you can do as analog output is to control the movement of something. One simple way to do this is to use a servomotor. Servomotors are motors with a combination of gears and an embedded potentiometer (variable resistor) that allows you to set their position fairly precisely within a 180-degree range. They’re very common in toys and other small mechanical devices. They have three wires:

  • power (usually +5V)
  • ground
  • control

Connect the +5V directly to a 5V power source (the Arduino’s 5V or 3.3V output will work for one servo, but not for multiple servos). Ground it to the same ground as the microcontroller. Attach the control pin to any output pin on the microcontroller. Then you need to send a series of pulses to the control pin to set the angle. The longer the pulse, the greater the angle.

To pulse the servo, you generally give it a 5-volt, positive pulse between 1 and 2 milliseconds (ms) long, repeated about 50 times per second (i.e. 20 milliseconds between pulses). The width of the pulse determines the position of the servo. Since servos’ travel can vary, there isn’t a definite correspondence between a given pulse width and a particular servo angle, but most servos will move to the center of their travel when receiving 1.5-ms pulses. This is a special case of pulse width modulation, in that you’re modifying the pulse, but the period remains fixed at 20 milliseconds. You could write your own program to do this, but Arduino has a library for controlling servos. See the Servo lab for more on this.

Related video: Analog Output – Servo

Changing Frequency

Pulse width modulation can generate a pseudo-analog voltage for dimming and motor control, but can you use it to generate pitches on a speaker? Remember that you’re changing the duty cycle but not the period of the signal, so the frequency doesn’t change. If you were to connect a speaker to a pin that’s generating a PWM signal, you’d hear one steady pitch.

If you want to generate a changing tone on an Arduino microcontroller, however, there is a tone() command that will do this for you:

tone(pin, frequency);

This command turns the selected pin on and off at a frequency that you set. With this command, you can generate tones reasonably well. For more on this, see the Tone Output lab.

Related video: Analog Output – Tone

Ranges of Values

As a summary, Table 1 below shows the ranges of values for digital input/output and analog input/output, which have been discussed in Digital Input & Output, Analog Input, and this page.

DigitalInput (Digital Pins)0 [LOW] or 1 [HIGH] (2^0) 0V or 3.3V (newer microcontrollers) 0V or 5V (older microcontrollers)
Output (Digital Pins)0 [LOW] or 1 [HIGH] (2^0) 0V or 3.3V (newer microcontrollers) 0V or 5V (older microcontrollers)
AnalogInput (Analog Input Pins)0 ~ 1023 (<210)3.3 / 210
Output (Digital PWM Pins)0 ~ 255 (<28)3.3 / 28
Table 1. The Ranges of Values for Digital/Analog Input/Output