Quantcast
Channel: SparkFun Tutorials
Viewing all 1122 articles
Browse latest View live

Using the USB Logic Analyzer with sigrok PulseView

$
0
0

Using the USB Logic Analyzer with sigrok PulseView a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t793

Introduction

An 8-channel, 24MHz USB logic analyzer for under $20. What a deal!

USB Logic Analyzer - 25MHz/8-Channel

SPX-14789
$19.95

But a USB logic analyzer (LA) is only as useful as the software required to configure and monitor the tool. There are a few software options available for this USB logic analyzer; in this tutorial we aim to familiarize you with sigrok’s PulseView.

PulseView

sigrok is an open-source suite of software projects – all focused on supporting signal analysis tools. The project includes:

  • PulseView– A logic analyzer front end with a simple GUI.
  • sigrok-cli– A command line interface for sigrok – useful for scripting tests or running on a headless machine.
  • fx2grok– A collection of open-source hardware LA layouts, schematics, and BOM’s.

With an eye towards logic analyzers, this tutorial will focus mostly on PulseView.

Get the Software

Download the latest PulseView release from sigrok’s Downloads page. Here are direct links for the latest Windows, Mac, and Linux downloads:

Windows users can run the installer executable (pulseview-NIGHTLY-32bit-static-release-installer.exe) to install the software on your machine. The Mac installer is a binary disk image (DMG), which can be dragged into your Applications folder, for example.

Once installed open PulseView – the GUI frontend for sigrok.

Setting up the Software/Hardware

With PulseView open, plug in your USB Logic Analyzer. You should see faint red and green LEDs illuminate under the sticker.

Logic analyzer plugged in

If PulseView does not automatically detect your logic analyzer, you’ll need to set it manually:

  1. Click the “<No Device>” dropdown menu.
  2. Select fx2lafw (generic driver for FX2 based LAs) from the dropdown.
  3. Select USB for the interface
  4. Click Scan for devices using driver above
  5. Select “Saleae Logic with 8 channels” and click “OK”

Connecting to the USB logic analyzer

You’ll be greeted with a blank slate of eight colorful bands of logic channels, numbered D0 to D7 (these match the CH0-CH7 labels on the LA).

Click the Run button in the top-left of the window to beginning scanning.

Run button location

With the sampling parameters set as default – 1M samples, 20kHz – it’ll take almost a minute to gather all million samples. You can hit “Stop” to end the scan early.

Unless you’ve already connected a few channels and grounds, this first scan will probably not be that interesting.

Exploring the Capabilities

Here’s a fun, tormenting Arduino sketch you can load to help familiarize yourself with PulseView’s capabilities:

language:c
void setup() {
  // put your setup code here, to run once:
  randomSeed(analogRead(A0));
  Serial.begin(random(1, 115200)); // Set the baud rate to a random value between 1 and 115200 bps
}

void loop() {
  Serial.println(millis()); // Print the time
  delay(250);
}

Load that onto an Arduino, then connect the logic analyzers “CH0” to your Arduino’s TX pin (pin 1). Also connect on of the GND wires to GND.

Hardware connection

Before scanning, bump up the sample rate to 1MHz and change the sample quantity to 1 M samples. Depending on what you’re trying to analyze, these dropdowns may get a lot of use. With those values set, hit Run.

You should be greeted with a seconds worth of samples, and a few blips on the D0 channel every 250ms.

Results of our mystery baud scan

You can use your mouse’s scroll wheel to zoom in and out, or use the “+” and “-” buttons on the toolbar. Zoom into one of the blips. Now it’s your job to guess the baud rate!

The Show cursors (pair of blue flags icon) tool can be useful for measuring time. Click that, then try to place the cursors around one bit of the transmission. The measured frequency should be our mystery baud rate!

Mystery baud measurement

To decode the string, use the Add low-level, non-stacked protocol decoder tool (looks like yellow and green decoded signals). Then select UART– note that a huge list of protocols pops up here, including I2C, I2S, SDIO, and SPI.

Assortment of protocol analyzers

Click the green “UART” icon that appears towards the bottom-left and change the baud rate to your measured frequency. You can also change the data format to ascii to make the data easier to parse.

Decoding the UART traffic

Now if you zoom out you should see your serial prints decoded!

CLI and Going Further

If you’re connecting the logic analyzer to a headless machine, or want to automate a LA-based test, check out sigrok-cli– a command line interface for sigrok. With sigrok-cli installed, for example, you can use a command like:

sigrok-cli.exe -d fx2lafw --time 3000 --channels D0=RX --config samplerate=1m -P uart:baudrate=115200

To decode a UART connected to channel 0.

sigrok-cli output

The CLI has a lot of potential for automation, and the man page is super-helpful!

As you venture into this world of logic analyzing, be sure to try out all of PuseView’s protocol decoders and features. It’s a great software tool and has a powerful open-source community behind it.


learn.sparkfun.com | CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado


Atto84 Hookup Guide

$
0
0

Atto84 Hookup Guide a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t794

The Littlest 'Duino

Atto84 with Arduino Bootloader

SPX-14804
$5.95

Arduino and Arduino compatible dev boards are an awesome tool for developing an idea quickly but, being development boards, they’re often a little more bulky and full featured than you really need. Having a USB interface and a bootloader is so nice, though, so we put together the bare minimum Arduino compatible breakout for integration into your small projects. We call it the Atto84.

The Atto84 is essentially a breakout board for the absolutely minute WQFN ATtiny84, but we’ve done some work to make it easier to program. First off, we’ve added a micro-USB connector a firmware-based USB driver for the ATtiny that allows you to program the chip over USB. In addition, we’ve created an Arduino board profile that combines this bootloader with an extremely full-featured ATtiny Arduino core.

Simply install the USB drivers on your computer, select the board profile from Arduino’s Board Manager and upload code to this board like any other Arduino style development board.

In this hookup guide, you’ll learn how to do exactly that!

Installing USB Drivers

The Atto84 is emulating USB 1.1 using two of its pins and the V-USB driver. However, there are no common operating system drivers available that work with this custom USB class. As a result, we will need to install custom drivers in order to communicate with (and send our Arduino programs to) the Atto84. Choose your operating system below and follow the directions to install the driver.

Note: We did not write the USB firmware nor the driver. We simply packaged and modified them to work with the Atto84. The true geniuses are the fine folks who wrote micronucleus and libusb.

Windows

Insert a micro-USB cable into the Atto84. Your PC will probably make a happy “USB connected!” chime and then inform you that there is an unknown device connected.

Download the SparkFun ATtiny USB drivers by clicking on the link below.

Windows USB drivers

Unzip the file. Open the Windows Device Manager, and you should see an Unknown device. Right-click on Unknown device and select Update Driver Software.

Screeshot of the Device Manager window showing the right-click menu for a device called "unknown device". The "Update Driver Software..." option is highlighted.

In the pop-up window, click Browse my computer for driver software.

Screenshot of the "Update Driver Software" interface. The option labeled "Browse my computer for driver software" is highlighted.

Click Browse… and open the folder that contains the drivers you just unzipped. It will likely be the sparkfun_attiny_usb_driver folder.

Screenshot of the "Browse for driver software on your computer" interface. In the field labeled "Search for driver software in this location:" I've typed the filepath to my sparkfun_attiny_usb_driver folder.

Click Next. You may get a warning pop-up that says “Windows can’t verify the publisher of this driver software.” That’s OK. Just click Install the driver software anyway.

Windows Security prompt warning the user that the driver is unsigned. The "Install this driver software anyway" option is highlighted.

You should see a notification that the SparkFun ATtiny driver was installed successfully. Close that window, and verify that your Unknown device now shows up as SparkFun ATtiny in the Device Manager.

Screenshot of the Device Manager window again, this time showing a device enumerating under "libusb-win32 devices" as "SparkFun ATtiny"

MacOS

You’ll need to install Homebrew and use it to install libusb. Enter the following commands into a Terminal:

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew doctor
brew install libusb-compat

Linux

Good news! Linux doesn’t require special drivers. However, you will need to do one of the following to be able to program the Atto84 from Arduino:

1) When you download the Arduino IDE (next section), make sure you run it as root: sudo ./arduino

Very exciting screenshot of a terminal with "sudo ./arduino" typed in

2) Or, you can add some udev rules so that Linux enumerates your device with write permissions. Create a file in rules.d:

sudo edit /etc/udev/rules.d/49-micronucleus.rules

Copy the following contents into that file:

# UDEV Rules for Micronucleus boards including the Digispark.
# This file must be placed at:
#
# /etc/udev/rules.d/49-micronucleus.rules    (preferred location)
#   or
# /lib/udev/rules.d/49-micronucleus.rules    (req'd on some broken systems)
#
# After this file is copied, physically unplug and reconnect the board.
#
SUBSYSTEMS=="usb", ATTRS{idVendor}=="16d0", ATTRS{idProduct}=="0753", MODE:="0666"
KERNEL=="ttyACM*", ATTRS{idVendor}=="16d0", ATTRS{idProduct}=="0753", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1"
#
# If you share your linux system with other users, or just don't like the
# idea of write permission for everybody, you can replace MODE:="0666" with
# OWNER:="yourusername" to create the device owned by you, or with
# GROUP:="somegroupname" and mange access using standard unix groups.

Save and exit.

Installing the Board Package

If you don’t have the Arduino IDE on your computer, you’ll want to get that installed first.

Download Arduino IDE

If you need help installing Arduino for your operating system, you can follow this guide.

Important! Your Atto84 will only work with Arduino versions 1.6.10 and above.

Download and Install the Board Package

Because the Atto84 is not supported by the Arduino IDE by default, we need to add it manually. Open the Arduino program and go to File > Preferences. Then copy and paste the URL below into the Additional Board Manager URLs text box.

If you’re thinking “I already have the SparkFun Board Profiles and I don’t see any tiny boards!” notice that we’re specifically pointing to a branch of SparkFun’s Arduino Boards repository called “tiny,” not the main branch. If you copy/paste the URL below, you should have no troubles!

https://raw.githubusercontent.com/sparkfun/Arduino_Boards/tiny/IDE_Board_Manager/package_sparkfun_index.json

Screenshot of the Arduino IDE "Preferences" menu with the "Additional Board Manager URLs" field highlighted at the bottom of the window.

Then hit OK, and navigate to the Tools > Board > Boards Manager… tool. A search for “tiny” should turn up a SparkFun ATtiny Boards result. Select that and click Install.

Screenshot of the Boards Manager window with "tiny" typed into the search bar. A package called "SparkFun ATtiny Boards" is in the results pane

Once the installation is complete, go to Tools > Board and select SparkX Atto84 (ATtiny84, 3.3V, 8MHz) under the SparkFun ATtiny Boards section.

Screenshot of the Arduino IDE showing the location of the "SparkX Atto84" board profile under Tools>Board>SparkFun ATtiny Boards

Tiny Tricks and Gotchas

Because the Atto84 is the bare-minimum of hardware that can be USB programmed, it does have a few quirks that you should be aware of. But first, let’s talk about a few of the cool features that it inherits from SpenceKonde’s ATTiny Core.

A diagram showing the pinout of the Atto84. Looking at the board from the top down, with the micro USB port in the 12 o'clock position, the pin assignments are as follows: From top to bottom on the right-hand side: VCC, which is 5 volts maximum. Pin 0, which is also A0. Pin 1, which is also A1. Pin 2, which is also A2, Pin 3, which is also A3, Pin 8, which is also the built-in LED. On the left-hand side, from top to bottom the pins are as follows: GND. Pin 4, which is also A4, SCL and SCK. Pin 5, which is also A5, MISO and DO. Pin 7, which is also A7. Pin 6, which is also A6, MOSI, DI and SDA. Pin 11, which is the Reset Pin.

I²C Support

The ATTiny Core includes a special version of the Wire library that leverages the tiny84’s hardware USI for I²C communication. This means that it will run any Wire-based code that you’ve written for ATmega platforms like the Arduino Uno or the SparkFun RedBoard.

SPI Support

The ATtiny actually has hardware SPI support, so the Atto84 will work identically to the Uno in that respect.

Servos?

Yeah, why not? The tiny84 has plenty of timers and you’ll find a copy of the Servo library included with the core!

The “Gotchas”

Sounds great, right? It is, but there are a few catches that you should be aware of.

Power

There is no power regulator on the Atto84, so the input to VCC must be between 3.3V and 5V. Powering your project through the USB connector is a good, too.

Serial

The ATtiny doesn’t have a hardware UART, so serial doesn’t work the way you might expect. There is a custom library built in to the ATTiny Core called “Serial” which is actually an implementation of Software Serial. This works quite well but you do need to know its limitations. For instance, it’s not full duplex, so sending and receiving at the same time will produce gibberish. Also, it does not implement V_USB, so if you want to do Serial debugging, you’ll need to connect a separate USB-Serial adapter.

Uploading Code

Most USB Arduino boards can be forced into bootloader mode by the Arduino IDE during programming, but due to the limitations of V-USB, the Atto84 needs to me manually reset during programming. Every time the Atto84 restarts, it goes into bootloader mode for about 5 seconds. During this time, your computer will recognize it as a USB device. After 5 seconds, the Atto84 begins running user code. Unless your code also happens to be implementing V-USB, the computer will stop recognizing the device.

In order to get code onto the board, simply click the upload button in the Arduino IDE and wait for the “uploading…” message to show. When the IDE says “uploading,” press the reset button on your Atto84. Don’t worry, the timing isn’t critical, the Micronucleus upload program gives you 30 seconds to press reset. After the board has reset and shows up as a USB device, your code will upload like normal!

Note: If you get an error message while uploading, it could be caused by a variety of reasons. The way we're uploading programs to Roshamglo is actually hacked together, as we're emulating USB on the badge, which many computers do not like. Here are some things to try if you do get an error:
  • Try a different USB port
  • Unplug other USB devices
  • Close other programs that might be running
  • Reinstall the Roshamglo USB driver
  • Try a different computer

This image is an invisible square but it's here so that I can ask you a favor if you're enjoying this tutorial using a screen reader. I'm trying to improve our site's accessibility, so I would love to hear your feedback about the image alt tags in this article. You can email me at nick.poole@sparkfun.com and please put the phrase "image tags" in the subject line. Thank you so much. Happy Hacking!


learn.sparkfun.com | CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

Python Programming Tutorial: Getting Started with the Raspberry Pi

$
0
0

Python Programming Tutorial: Getting Started with the Raspberry Pi a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t783

Introduction

The Raspberry Pi is an amazing single board computer (SBC) capable of running Linux and a whole host of applications. Python is a beginner-friendly programming language that is used in schools, web development, scientific research, and in many other industries. This guide will walk you through writing your own programs with Python to blink lights, respond to button pushes, read sensors, and log data on the Raspberry Pi.

Speaker, button, and LED connected to a Raspberry Pi

Notice: This tutorial was written with Raspbian version "April 2018" and Python version 3.5.3. Other versions may affect how some of the steps in this guide are performed.

Required Materials

To work through the activities in this tutorial, you will need a few pieces of hardware:

Optional Materials

You have several options when it comes to working with the Raspberry Pi. Most commonly, the Pi is used as a standalone computer, which requires a monitor, keyboard, and mouse (listed below). To save on costs, the Pi can also be used as a headless computer (without a monitor, keyboard, and mouse). This setup has a slightly more difficult learning curve, as you will need to use the command-line interface (CLI) from another computer.

SmartiPi Touch

PRT-14059
$24.95
8
Raspberry Pi LCD - 7" Touchscreen

LCD-13733
$64.95
35
Multimedia Wireless Keyboard

WIG-14271
$29.95
2
Please note: If you have trouble seeing any of the images throughout this tutorial, feel free to click on it to get a better look!

Open Source!

This guide is licensed under the Creative Commons Attribution Share-Alike 4.0 International License.

Python Logo

Install the OS

You have a few options when it comes to interacting with the Raspberry Pi. The first and most common is to use it like you would a full desktop computer (just smaller). This involves connecting a keyboard, mouse, and monitor. With this setup, you are likely best served by installing Raspbian with Desktop, which gives you a full graphical user interface (GUI) to work with. This is the best option if you want an experience similar to working with other operating systems (OS), such as Windows, macOS, or other popular Linux flavors, like Ubuntu.

Raspberry Pi full desktop setup with monitor, keyboard, and mouse

Option 1: Use the Raspberry Pi like a full computer with keyboard, mouse, and monitor

The other option is to create a headless setup, which means you can skip the monitor, keyboard, and mouse. While this is the cheaper way to go, it means you’ll need to be open to performing all your actions in the command line interface. For this, you will want either Raspbian with Desktop or Raspbian Lite operating systems.

Raspberry Pi connected to laptop over Serial

Option 2: Configure the Raspberry Pi for “headless” operation where you interact with it from another computer

This guide will show you how to write and run Python programs that will work in both configurations.

Option 1: Full Desktop Setup

The Raspberry Pi 3 Starter Kit Hookup Guide offers a great walkthrough to setting up your Raspberry Pi with NOOBS (Raspberry Pi’s easy-to-use graphical OS installer).

From here on out, all instructions that are unique to the full desktop setup will be highlighted in blue.

Raspberry Pi 3 Starter Kit Hookup Guide

April 11, 2016

Guide for getting going with the Raspberry Pi 3 Model B and Raspberry Pi 3 Model B+ starter kit.

Option 2: Headless Pi

If you want to skip the keyboard, mouse, and monitor, you can install Raspbian Lite. This will allow you to get a terminal into your Pi using SSH or Serial on another computer. The Headless Raspberry Pi Setup walks you through setting up your Raspberry Pi without a graphical interface.

Instructions in this tutorial that are unique to the headless setup will be highlighted in yellow.

Headless Raspberry Pi Setup

April 23, 2018

Configure a Raspberry Pi without a keyboard, mouse, or monitor.

If you have the Raspberry Pi Starter Kit, you can attach the Pi Wedge to the Pi over the provided ribbon cable, and connect the FTDI Breakout board to the Pi Wedge. From here, connect a USB cable between your computer and the FTDI Breakout board. This will allow you to open a Serial terminal to your Raspberry Pi, as covered in the Serial Terminal section of the Headless Pi tutorial.

Fully assembled Raspberry Pi Starter kit with FTDI serial-to-USB breakout

Configure Your Pi

Regardless of whether you are using the full desktop or a headless setup, you will need to perform some basic configuration steps on your new Raspberry Pi installation. These steps can be easily performs from a terminal (a text input/output environment).

Full Desktop: You should be automatically logged into the X windows manager (otherwise known as the desktop). To open a terminal, simply click on the Terminal icon on the top left of the desktop. You should be immediately presented with a command prompt in a terminal window.

Raspbian desktop

Headless: With a headless setup, everything you do will be through a terminal. When you connect to your Pi through Serial or SSH, you will be presented with a login prompt on the terminal. Enter the default credentials:

  • Username: pi
  • Password: raspberry

You will be presented with a command prompt.

Serial terminal showing command prompt for Raspberry Pi

Run the Config Tool

From your command prompt, enter the command:

sudo raspi-config

If asked to enter a password, type out the default password: raspberry.

You will be given several options on how to configure your Raspberry Pi.

Raspberry Pi raspi-config tool

  • Use the arrow keys to select 1 Change User Password and follow the on-screen prompts to change your default password.
Warning: It is strongly recommended that you change your password. If you connect your Pi to a network and leave the password as 'raspberry', anyone with access to that network will be able to easily get into your Pi.
  • Next, select 2 Network Options
  • In the following screen, select N2 Wi-fi, and follow the prompts to connect your Pi to a local WiFi network (assuming you have one available).

Raspberry Pi network options

Select 4 Localisation Options to bring up the keyboard and time zone options.

Raspberry Pi raspi-config screen

  • Select I1 Change Local
  • Scroll down to highlight en_GB.UTF-8 UTF-8, and press the spacebar to deselect it (the asterisk ‘*’ will disappear)
  • Scroll to find your language/country and press space to select it (an asterisk ‘*’ will appear next to your selection)
  • If you live in Great Britain, you can just leave en_GB.UTF-8 UTF-8 selected
  • If you live in the United States, you will probably want to select en_US.UTF-8 UTF-8.

Raspberry Pi raspi-config screen

  • Press enter to save the changes
  • On the next screen, highlight your chosen localization option (e.g. en_US.UTF-8 if you’re in the United States) and press enter.

Raspberry Pi raspi-config screen

  • Go back into the 4 Localisations Options, and select I2 Change Timezone
  • Follow the prompts to select your timezone.
  • Back in 4 Localisations Options, select I3 Change Keyboard Layout
  • Choose your preferred layout (the default Generic 105-key (Intl) PC seems to work well in most situations)
  • On the next screen, select the layout for your language/country
  • If you live in Great Britain, you can leave English (UK) selected. Otherwise, select Other, press enter, and follow the prompts to select your language/country. If you live in the United States, select English (US), and on the next screen, scroll up to highlight English (US). Press enter.

Raspberry Pi raspi-config screen

  • Leave The default for the keyboard layout selected, and press enter
  • Once again, leave the default No compose key selected, and press enter
  • Leave No selected when asked about using Control+Alt+Backspace, and press enter
  • After a few moments, you will be dropped back into the main Configuration Tool menu.

Select 5 Interfacing Options.

Raspberry Pi raspi-config screen

  • Feel free to enable the Camera interface and SSH if you think you’ll need them
  • Select SPI, select yes on the following screen, press enter
  • Repeat for I2C
  • Repeat for Serial

Back in the main screen, select 7 Advanced Options.

Raspberry Pi raspi-config screen

  • Select A1 Expand Filesystem, and press enter
  • Go back into 7 Advanced Options, select A4 Audio, highlight 1 Force 3.5mm (‘headphone’) jack, and press enter
  • Use the right arrow key to select Finish, and press enter. If asked to reboot, select Yes and press enter. Wait while your Raspberry Pi restarts.

If you are using a Serial or SSH terminal, log back in using the username pi and the password you created earlier.

Use Python 3

By default, Raspbian (Stretch version April 2018 and earlier) uses Python 2. However, versions 2 and 3 come installed by default. We just have to make 1 minor change so that the Pi uses Python 3 whenever we type python into a terminal.

In a terminal window, enter the following command:

python --version

You should see which version is being used by default. For example, you might see Python 2.7.13. If you see that your OS is using Python 2 by default, you’ll need to change it to use the Python 3 installation. We want to this so that Python 3 is used every time we log in.

Enter the command:

nano ~/.bashrc

.bashrc is a file that resides in the user’s home directory (the user pi in this case). The file acts as a shell script that is run each time that specific user opens a terminal (or logs in over SSH, Serial, etc.). It can help to customize the user environment, and you will likely see a number of other commands already in there.

Scroll down to the bottom, and add the following command to the file:

alias python='/usr/bin/python3'

Modifying .bashrc to use Python 3 by default

Exit out of nano by pressing ctrl+x, press the y key when prompted if you want to save the file, and press the enter key.

Instead of logging out and logging back in again to run the new command, you can simply run the contents of the .bashrc script by entering:

source ~/.bashrc

Now, check the version of Python again:

python --version

You should see some version of Python 3 being used.

Checking Python version on the Raspberry Pi

Install pip

Full Desktop: If you are using the full desktop version of Raspbian, you should have pip already installed.

Headless: If you are using Raspbian Lite, the Python package manager, pip, does not come pre-installed. As a reult, you will need to install it with the commands:

sudo apt-get update
sudo apt-get install python3-pip

Press y when prompted.

Note that to use pip for Python 3, you will need to use the command pip3. However, we can modify the .bashrc file to use pip instead of pip3, as the rest of the tutorial will show examples using pip:

nano ~/.bashrc

Scroll down to the bottom, and add the following command to the file:

alias pip=pip3

Modify .bashrc to use the pip command

Exit out of nano with ctrl+x, press y and enter. Run the .bashrc script with:

source ~/.bashrc

You should now be able to install Python packages using the pip command.

Hello, World!

One of the coolest features of Python is that it is an interpreted language (OK, in reality, Python scripts are first compiled to some bytecode, and that bytecode is interpreted). This means that we don’t need to run a separate compile step (i.e. translate our program into machine code) in order to run our program. In fact, we can even run the interpreter in what’s known as interactive mode. This will allow us to test out commands one line at a time!

To start, we’ll tell Python to print the phrase, “Hello, World!” to the terminal. We’ll do this first from the interpreter and then we’ll create a file and run it as a program. This will show you two of the main ways to interact with Python.

If you are curious about where the phrase “Hello, World!” comes from, this Wikipedia article gives a brief yet fascinating history.

Getting Started with the Interpreter

From a terminal, enter the following commend to start the Python interpreter:

python

You should be presented with a different command prompt, consisting of 3 greater-than signs >>>.

Type the following command:

print("Hello, World!")

Once you press enter, you should see the phrase Hello, World! repeated back to you.

Running Python on a Raspberry Pi from a serial terminal

And that’s it! You just ran your first Python program!

Exit out of the interpreter by entering:

exit()

Running a Python Program from a File

You can individually enter and run commands one line at a time in the Python interpreter, which is incredibly useful for trying out different commands (or using it as a calculator!). Often, you will want to save your commands together in one or more files so that you can run them all at once.

The simplest way to do this is to create a file from the terminal, although you are welcome to use the Raspbian graphical editor, Leafpad, as well (found under Accessories > Text Editor when you click on the Raspberry Pi icon in the top left).

Still in a terminal, enter the command:

nano hello.py

This creates a file named hello.py in your home directory (/home/pi) and starts editing it with the nano program.

In this file, enter the following on the first line:

print("Hello, World!")

Writing a Python program on a Raspberry Pi

Save and exit (ctrl+x followed by y and then enter). Back in the Linux command prompt, enter the command:

python hello.py

This should run the code found in the file hello.py. In our case, you should see the iconic phrase Hello, World! printed out in the console.

Running a Python program on a Raspberry Pi

Note: In case you were wondering, I am clearing my terminal between screenshots with the clear command.

To summarize what we just did, you can use the python command on its own to begin an interactive interpreter session that allows you to type commands in real time. If you specify a file, such as python <FILE>.py, the Python interpreter will run the commands found in the file without giving you an interactive session.

Note that the filename suffix .py is not required for the interpreter to run the code found inside. However, it can be very helpful to keep your files organized so that when you see a file ending in .py, you will know that it contains Python code. The .py suffix is also necessary when making modules, which we’ll cover later.

Development Environments

The simplest way to create Python programs is to write your code in a text editor (e.g. nano, vim, emacs, Midnight Commander, Leafpad, etc.), save it, and then run it from the terminal with the command python <FILE>.py. You are welcome to continue working through this guide using a text editor and command line.

Some users prefer to use an integrated development environment (IDE) when developing code. IDEs offer a number of benefits including syntax highlighting, code completion, one-click running, debugging hints, etc. However, most IDEs require a graphical interface to use, which means you will need to be on the full desktop version of Raspbian.

Note: Out of the box, Raspbian comes with three Python IDEs: IDLE, Geany, and Thonny. I show a brief introduction to each below, and you are welcome to use them or any other text editor or IDE you so choose.

IDLE

IDLE is the default Python editor that has been available on Raspbian for many generations. The good news is that it has a built-in interpreter, which allows you to run commands one at a time to test code. The bad news is that it doesn’t show line numbers, and it only works with Python (but you’re only here for Python anyway, right?).

Open IDLE by selecting the Raspberry Pi logo in the top-left, and click Programming > Python 3 (IDLE). You should be presented with the Python interactive interpreter.

IDLE Python command prompt

To write a program, go to File > New File. Enter in your code.

Writing a Python program in IDLE

Click File > Save As… to save your code to a Python file (don’t forget the .py suffix!). Click Run > Run Module to run your program.

Running a Python program in IDLE

Geany

Geany is a great, beginner-friendly IDE that works with many different languages. However, it does not start up with a Python interactive interpreter. You can open Geany up by click on the Raspberry Pi logo in the top-left, and selecting Programming > Geany. Write your code in the file editor pane.

Writing a Python program in Geany

Save your code, making sure the filename ends with .py.

By default, Geany will attempt to open a new window to show the output of your code, which may or may not work on the Raspberry Pi. We can change it to run in the Terminal pane. Click Edit > Preferences. Select the Terminal tab and click to enable Execute programs in the VTE. Press enter to save and close the Preferences window.

Execute programs in the terminal in Geany

Click Build > Execute (or click the paper airplane icon) to run your code. You should see the output of your program appear in the Terminal pane of Geany.

Running a program in Geany

Thonny

Finally, Thonny is another great, easy-to-use IDE that comes pre-loaded on Raspbian. It focuses on Python and has an interactive environment when you load the program. Start Thonny by clicking on the Raspberry Pi icon followed by Programming > Thonny Python IDE.

Thonny IDE on the Raspberry Pi

Write your program in the top pane, click File > Save as… to save it, and click Run > Run current script to execute the program. Output will appear in the bottom interpreter pane.

Running a Python program on Thonny

Opinion: If you are just starting your journey in programming, we recommend Thonny for a graphical IDE and using nano if you are using a headless Raspberry Pi setup.

Programming in Python

The bulk of this tutorial focuses on controlling hardware connected to the Raspberry Pi. To accomplish that, we will be using the Python programming language. As such, you should be familiar with some of the basics of Python, including literals, variables, operators, control flow, scope, and data structures. Depending on your comfort level with Python, we recommend the following:

  • Not familiar: Read the recommended documentation and attempt the challenges
  • Somewhat familiar: Attempt the challenges and refer to the documentation when you run into trouble
  • Very familiar: Feel free to skip this whole section!

Since we don’t want to reinvent the wheel (there are many great tutorials and books out there on Python!), we will be referencing two texts:

  • A Byte of Python - A free, well-written introduction to the Python language. Concepts are covered briefly and succinctly with examples. Paper copies can be found here for purchase (besides, it helps support the author!).
  • The Python Documentation - A more technical and in-depth look at the Python language, which consists of a set of tutorials and reference guides. Refer to this if you need additional help understanding a concept.
Note: Some of the links for "A Byte of Python" might not open to the correct location on the page for some browsers. If this happens, just refresh the page to take you there.
Try it! Each of the code examples given can be run as separate programs. Try typing them out into the interpreter or copying them into a file (one example at a time) and running them with Python!

If you would like additional help with programming in Python (more examples and exercises) than what’s provided here, check out the following free sites: Non-Programmer’s Tutorial for Python 3, learnpython.org, and Google’s Python Class. After covering the basics of the Python language in this section, we’re going to dive into flashing lights, reading sensors, and controlling motors!

Comments

A comment is any text to the right of the pound (or hash) symbol #. The Python interpreter ignores this text, and it can be useful for writing notes to yourself or other programmers about what’s going on in the code.

Example:

# This is a comment and is not seen by the interpreter
print("Hello, World!")

Recommended reading:

Literals

Literals, also known as literal constants, are fixed values and include integers (e.g. 42), floating-point numbers (e.g. 6.23), and strings (e.g. “Hello, World!”). Note that strings need to be in between single quotation marks (‘ ’) or in between double quotation marks (“ ”).

Example:

print(42)
print("hi")

Recommended reading:

Challenge: Change the print("Hello, World!") program we wrote earlier so that it prints out your name.

Variables

Variables are containers whose values can change. We can store a number or string in a variable and then retrieve that value later.

Example:

number = 42
print(number)

Recommended reading:

Challenge: Store your name in a variable and then print that variable’s value to the terminal.

Logical Lines

So far, we’ve been writing one expression per line in our program. For example:

message = "hello!"
print(message)

You can combine these two lines into one line by separating them with a semicolon ;:

message = "hello"; print(message)

These two programs will execute in exactly the same fashion. That being said, it’s often recommended that you write programs with one logical line per physical line to make your code easier to read.

Recommended reading:

User Input

You can ask a user to enter information into the terminal by using the input() function. This will prompt the user to type out some text (including numbers) and then press enter to submit the text. Upon submission, the input() function will read the text and then return it as a string, which can be stored in a variable.

Whatever is in between the parentheses (known as arguments) will be printed to the screen prior to accepting user input.

Functions are sections of code that can be called by name. For example, print() is a function that takes the arguments and prints it out to the terminal. Notice in the example below that we separated two different arguments in print() by a comma. In this case, print() will print the different strings (or variables) in order on one line.

Note that you can use the int() function to turn a string into an integer (assuming the string is an integer).

Examples:

message = input("Type a message to yourself: ")
print("You said:", message)


number = int(input("Type a number:"))
print("You entered:", number)

Recommended reading:

Challenge: Write a program that asks for the user’s first name and last name (two separate input() calls) and then prints the user’s first and last name on one line. An example of this program running should look like:

User input in Python

Indentation

White space (number of spaces) at the beginning of a line is important in Python. Statements that form a group together must have the same level of indentation (amount of white space in front of the line). This will be important when we get into control flow statements (e.g. if, for) and functions.

If you have written programs in other languages before, you might be familiar with curly braces {}. In other languages, code in between these curly braces would form a group (or block) of code. In Python, a group (or block) of code is designated by the level of indentation of the individual lines of code.

Example:

answer = "yes"
guess = input("Is the sky blue? ")
if guess == answer:
    print("Correct!")
else:
    print("Try again")

if statements will be covered later, but note how the print() functions are indented, and thus form separate code groups underneath if and else statements.

Recommended reading:

Operators

An operator is a symbol that tells the interpreter to perform some mathematical, relational, or logical operation on one or more pieces of data and return the result.

Mathematical operators perform basic math operations on numbers:

OperatorDescriptionExample
+Adds two numbers2 + 3 returns 5
-Subtracts one number from another8 - 5 returns 3
*Multiplies two numbers together4 * 6 returns 24
**Raises the first number to the power of the second number2 ** 4 returns 16
/Divides the first number by the second number5 / 4 returns 1.25
//Divides the two numbers and rounds down to the nearest integer (divide and floor)5 / 4 returns 1
%Divides the first number by the second number and gives the remainder (modulo)19 % 8 returns 3

Logical operators compare two numbers and returns one of the Boolean values: True or False.

OperatorDescriptionExample
<True if the first number is less than the second, False otherwise5 < 3 returns False
>True if the first number is greater than the second, False otherwise5 > 3 returns True
<=True if the first number is equal to or less than the second, False otherwise2 <= 8 returns True
>=True if the first number is equal to or greater than the second, False otherwise2 >= returns False
==True if the first number is equal to the second, False otherwise6 == 6 returns True
!=True if the first number is not equal to the second, False otherwise (not equal)6 != 6 returns False

Compound logical operators require Boolean inputs and give a Boolean answer.

OperatorDescriptionExample
notGives the opposite (True becomes False and vice versa)x = False; not x returns True
andReturns True if both operands are True, False otherwisex = True; y = False; x and y returns False
orReturns True if either of the operands are True, False otherwisex = True; y = False; c or y returns True

Bitwise operators perform binary operations on the bits (1s and 0s) of the given numbers. This tutorial talks more about binary and bitwise operations.

OperatorDescriptionExample
&Returns a 1 in each bit position for which the corresponding bits of both operands are 1 (bitwise AND)3 & 5 returns 1
|Returns a 1 in each bit position for wich the corresponding bits of either or both operands are 1 (bitwise OR)3 | 5 returns 8
^Returns a 1 in each bit position for which the corresponding bits of either but not both operands are 1 (bitwise XOR)3 ^ 5 returns 6
~Inverts the bits in the given number (bitwise NOT)~5 returns -6
<<Shifts the bits of the first number to the left by the number of bits specified by the second number5 << 2 returns 20
>>Shifts the bits of the first number to the right by the number of bits specified by the second number5 >> 2 returns 1

Recommended reading:

Challenge: Ask the user for two integers, and print the addition, subtraction, multiplication, division, and modulo of those numbers. For example, if you enter the numbers 6 and 7, the output should look like:

First number: 6
Second number: 7
13
-1
42
0.8571428571428571
6

Control Flow

The Python interpreter executes statements in your code from the top to the bottom of the file, in sequential order. That is unless, of course, we employ some time of control flow statements to break this normal sequential flow.

We introduce the range(x, y) function in the examples below, which generates a list of numbers between the first number, x (inclusive), and the second number, y (exclusive).

StatementDescriptionExample
ifelifelseIf a condition is true, execute the block of code underneath the if statement. If not, see if the condition is true in one or more else if (elif) statements. If one of those is true, execute the code block under that. Otherwise, execute the code block underneath the else statement. elif and else statements are optional.
number = 42
guess = int(input("Guess a number between 1-100: "))
if guess == number:
    print("You win!")
elif guess < number:
    print("Nope")
    print("Too low")
else:
    print("Nope")
    print("Too high")
print("Run the program to try again")
whileA while loop executes the block of code underneath it repeatedly as long as the condition is true.
counter = 15
while counter >= 5:
    print(counter)
    counter = counter - 1
for..inIterate over a sequence of numbers or objects. The variable declared in a for loop assumes the value of one of the numbers (or objects) during each iteration of the loop.
for i in range(1, 11):
    print(i)
breakUse the break statement to exit out of a loop.
while True:
    message = input("Tell me when to stop: ")
    if message == "stop":
        break
    print("OK")
continueThe continue statement works similar to break, but instead of exiting the loop, it stops the current iteration and returns to the top of the loop.
for i in range(1, 6):
    if i == 3:
        continue
    print(i)

Recommended reading:

Challenge: Write a program that prints integers counting up from 1 to 20, except that for every multiple of 3 (3, 6, 9, etc.), the word “fizz” is printed instead. The output should look like the following:

Counting and replacing numbers in Python

Functions

Functions allow you to name a block of code and then reuse that code by calling its name. You can pass data to a function through variables known as parameters (note that the variables in the function definition are called parameters whereas the actual data itself being passed are known as arguments). Data can also be passed back to the calling statement using the return statement.

An example of a function definition would look like:

def functionName(parameter1, parameter2):
    # Code goes here

You can call this function elsewhere in your code with functionName(argument1, argument2).

Note that variables declared inside the function definition are known as having local scope. This means that they cannot be accessed outside of that function. Variables declared at the top level of the program (i.e. outside any functions, loops, or classes) are known as having global scope and can be accessed anywhere in the program (including inside functions).

Important: Any functions you create must be defined before you use them! If you try to call a function higher up in the code (before its def definition), you’ll likely get an error such as:

NameError: name 'FUNCTION_NAME' is not defined

Python has a number of built-in functions that can help you (we’ve already seen three: print(), int(), and range()). A list of these functions can be found in the Python Tutorial.

Example:

def add(x, y):
    sum = x + y
    return sum

print(add(2, 3))

Recommended reading:

Challenge: Starting with the code below, implement the sumTo() function that takes an integer as a parameter (n), sums all the whole numbers from 1 to n (including n), and returns the sum. You may assume that the input, n, will always be a positive whole number (do not worry about handling negative numbers).

def sumTo(n):
    # YOUR CODE GOES HERE

# Should be 1
print(sumTo(1))

# Should be 45
print(sumTo(9))

# Should be 5050
print(sumTo(100))

Objects

We have not talked about objects yet, but in reality, you’ve been using them all along. The secret to Python is that everything is an object. That’s right: everything, including functions and integers.

An object is simply a collection of data stored somewhere in your computer’s memory. What makes an object special in a programming language is the ability for it to store information and perform actions. We’ve already seen an object’s ability to store data (for example, a = 3 means that a is an integer object and stores the information 3). But how do we get an object to perform an action?

Objects are given a set of functions as defined by their class, which acts as a blueprint–telling the objects what they can and can’t do or information it can and can’t hold. When we talk about functions within a class (or objects), we call them methods.

For example, we can test if a floating point number is an integer by using the built-in is_integer() method. Note that this method is only accessible from float objects! We can’t call is_integer() on its own, so we use the dot-notation (.) to have the float object call the is_integer() method from within itself.

Example:

a = 3.0
b = 7.32

print(a.is_integer())
print(b.is_integer())

Note that we can’t use an integer as a float! For example, if we said c = 8, then c is an integer, not a float! If c is an integer, there is no .is_integer() method in integers, so calling c.is_intger() would fail (and throw an interpreter error). Try it! To force an integer value to be a floating point number, we simply add .0 after it (just like we did with a = 3.0).

Recommended reading:

Challenge: Modify the code below so that the phrase stored in my_string is converted to all lower case letters and printed to the terminal. Hint: review the String Methods in the Python Reference Guide to find a built-in method to do this for you.

my_string = "THiS iS A TEst!"

# Should print "this is a test!"
# YOUR CODE GOES HERE

Data Structures

In addition to variables and objects, Python has four other ways to store data: list, tuple, dictionary, set. These structures hold a collection of related data, and each of them has a slightly different way of interacting with it.

StructureDescriptionExample
ListA list is a sequence of ordered items. You can access items in a list using brackets [] and an index (e.g. list[2]). Note that indeces are 0-based, which means list[0] will access the first item in the list. Because lists can be modified, they are known as mutable.
my_list = [1, 5, 73, -3]
my_list[2] = -42

# Get third item in list
print(my_list[2])

# Get all but first item in list
print(my_list[1:])
TupleA tuple works just like a list (an ordered set). The difference is that a tuple is immutable, which means you cannot change the values once they are set. A tuple is usually specified by parentheses (). While the parentheses are not necessary, they are highly recommended to make your code easier to read.
my_tuple = ("bird", "plane", 5, "train")

# Get one item from the tuple
print(my_tuple[0])

# Get a tuple of second and third items
print(my_tuple[1:3])

# Can't do this because tuples are immutable!
my_tuple[1] = "skyscraper"
DictionaryA dictionary is a collection of assciated key and value pairs. Similar to how a phonebook works: you look up someone's name (key) and you find their phone number (value). Dictionaries are defined by curly braces {}, and key/value pairs are separated by a colon :. Dictionaries are mutable.
my_dictionary = {"name": "Bruce", "aka": "The Hulk"}
my_dictionary["name"] = "Banner"
print(my_dictionary["name"])
SetA set is a mutable, unordered collection with no duplicate elements. Sets are optimized for determining if an item is in the set (and you don't care about the order of items). Sets are great if you want to implement any sort of set theory in Python.
my_set_1 = set(["orange", "banana"])
my_set_2 = set(["apple"])
my_set_2.add("orange")

print(my_set_1)
print(my_set_2)
print("apple" in my_set_2)
print("strawberry" in my_set_2)
print(my_set_1.union(my_set_2))
print(my_set_1.intersection(my_set_2))

Recommended reading:

Challenge: Starting with the code below, implement the average() function to compute the average of the numbers given to it in list form. Hint: you will probably want to use the len() function.

def average(num_list):
    # YOUR CODE GOES HERE

# Should print 5.0
list_1 = [4, 7, 9, 0]
print(average(list_1))

# Should print 4.406333333333
list_2 = [-3.2, 6.419, 10]
print(average(list_2))

# Should print 42.0
list_3 = [42]
print(average(list_3))

Modules

Modules are another way to reuse code and help you organize your program. They are simply files that are imported into your main program. After importing a module, you can use a module in much the same way you would an object: access constants and functions using the dot-notation.

Example:

Save the following file as stringmod.py:

a = 42

def string_to_list(s):
    c_list = []
    for c in s:
        c_list.append(c)
    return c_list

In the same folder as stringmod.py, run the following code (either in the interpreter or saved as a file):

import stringmod

s = "Hello!"
print(stringmod.a)
print(stringmod.string_to_list(s))

Recommended reading:

Challenge: Python comes with several standard modules that you can import into your program. One of them is the math module, which you can use with import math. Use the constants and functions found in the math module to perform the following actions:

  • Print the ceiling of 3.456 (should be 4)
  • Print the square root of 9216 (should be 96.0)
  • Calculate and print the area of a circle whose radius is 2 (should be 12.566370614359172)

Finding and Fixing Bugs

Programs almost never work right away, so don’t sweat it! The art and science of finding and fixing problems in your code is known as debugging. The most helpful debugging tool is the standard Python output. If there is a problem with your code, it will likely tell you where the error is and what’s wrong with it.

For example, let’s take the following code snippet. In it, we forget to indent our code underneath our for loop.

a = [1, 2, 3, 4]

for n in a:
print(n)

If you run this code, you’ll see that the Python interpreter is super helpful by saying it was looking for an indented piece of code around line 4.

  File "test_01.py", line 4
    print(n)
        ^
IndentationError: expected an indented block

Here’s another example. Can you spot the error?

a = [1, 2, 3, 4]

for n in a
    print(n)

We forgot the colon after the for loop! The interpreter will let us know by telling us:

  File "test_01.py", line 3
    for n in a
             ^
SyntaxError: invalid syntax

“Invalid syntax” is a little vague, but it tells you to look around line 3 for something that might be wrong, such as a missing colon, too many parentheses, a single quote instead of a double quote, etc.

What happens if your code runs, but it doesn’t output the value(s) you expect? This is on you, the programmer, to find and fix! Adding print() statements throughout your code can help you identify where something might have went wrong.

Try running this code:

for i in range(1, 10):
    if i == 10:
        print("end")

Why don’t you see “end” appear in the terminal? To help diagnose this problem, we can add a print() statement to see what’s going on:

for i in range(1, 10):
    print(i)
    if i == 10:
        print("end")

When we run this, we see the values of i printed in order.

Using print() to debug in Python

A-ha! It turns out that i never reaches 10. That’s because the second number in the range() function is exclusive. If we need it to count to 10, then we should change it to:

for i in range(1, 11):
    if i == 10:
        print("end")

Thanks for the help, print()!

Recommended reading:

Challenge: Find the 7 errors in the program below. When you fix the errors and run it, it should print numbers from 1 to the first argument, replacing multiples of the second argument with the word “buzz”.

print("Count to 7, buzz on 2's")            
buzz(7, 2)

print('Count to 10, buzz on 5's")
buzz(10, 5)

def buzz(n):
    for i in range(1, n):
        if i % z = 0:
            print("buzz")
        else
            print(n)

Here is the program running successfully:

Output of counting with replace in Python

Experiment 1: Digital Input and Output

In the embedded world, the first thing many developers like to do is blink an LED. In a sense, it is the “Hello, World!” of embedded electronics. It proves that we can run code and control some hardware (with immediate, and often amusing, results). In this section, we’ll start by blinking an LED, and we’ll take it a step further by also responding to a push button.

Recommended Reading

Raspberry Pi Pinout

One of the things that makes the Raspberry Pi better for learning electronics than most other computers is its ability to control the voltage on several of its easily accessible pins. If you hold your Pi facing up in portrait mode (as shown in the photo below), on the right side, you will see a header with 40 pins. This header contains outputs for 3.3V, 5V, Ground, and lots of General Purpose Input/Output (GPIO) pins!

Raspberry Pi GPIO Header

Note that pin 1 is on the top left of the header, as shown in the photo. With pin 1 in this position, we can see what each of the pins is used for:

Raspberry Pi 3 GPIO pinout

Hardware Connections

You can connect the Raspberry Pi to the LED and button directly, or you can go through the SparkFun Pi Wedge to make the connections easier on a breadboard. The important thing is to note that we are using the GPIO numbers in our code (listed as Gx on the Pi Wedge, where x is the GPIO number). These GPIO numbers are shown in the yellow boxes in the GPIO Pinout diagram above.

  • Connect GPIO12 (pin 32) to the 330Ω resistor, and the resistor to the LED
  • Connect GPIO4 (pin 7) to the button
  • Make the power (3.3 V) and ground (GND) connections as shown in the Fritzing diagram
Having trouble seeing the diagrams? Click on them to see the full-size version!

If you have a Pi Wedge, it can make connecting to external hardware on a breadboard easier. If you don’t, you can still connect directly to the Raspberry Pi with jumper wires.

Connecting through a Pi Wedge:

Pi Wedge Fritzing diagram to connect LED and button

Connecting directly to the Raspberry Pi:

Raspberry Pi Fritzing diagram to connect LED and button

Note: It matters how you plug in your LED! Current can only flow in one direction through an LED, so pay careful attention to the leads. The long lead on the LED should be connected on the same row as the 330Ω resistor.

LED polarity diagram

Note: Buttons can be a little weird, if it's the first time you've used them. The pins across from each other are always connected, whereas the pins on the same side are only connected when you push the button.

How a push button is configured on the inside

Note: If you are using the full-size breadboard, the power rails are divided in the middle. This means that to get power to the whole power row, you will need to connect the two halves. See the picture below to see how to use jumper wires to connect the halves of the power rows.

Connect power rows on a full-size breadboard

Code Part 1: Blinking an LED

Depending on your version of Raspbian, you may or may not have to install the RPi.GPIO package (e.g. Raspbian Lite does not come with some Python packages pre-installed). In a terminal, enter the following:

pip install rpi.gpio

In a new file, enter the following code:

import time
import RPi.GPIO as GPIO

# Pin definitions
led_pin = 12

# Suppress warnings
GPIO.setwarnings(False)

# Use "GPIO" pin numbering
GPIO.setmode(GPIO.BCM)

# Set LED pin as output
GPIO.setup(led_pin, GPIO.OUT)

# Blink forever
while True:
    GPIO.output(led_pin, GPIO.HIGH) # Turn LED on
    time.sleep(1)                   # Delay for 1 second
    GPIO.output(led_pin, GPIO.LOW)  # Turn LED off
    time.sleep(1)                   # Delay for 1 second

Save the file (I named my file blink.py). Run the code from the terminal by entering:

python blink.py

You should see your LED begin to blink on and off every second:

LED connected to Raspberry Pi blinking

Once you’ve gotten bored of watching the LED, end the program by pressing ctrl + c.

Troubleshooting: If you see the message “ModuleNotFoundError: No module named ‘rpi’” you will need to install the RPi.GPIO package by entering pip install RPi.GPIO in a terminal.

Code to Note:

To control hardware from the Raspberry Pi, we rely on the RPi.GPIO module. This module (likely known as a “library” in other languages) is specifically designed to help us toggle pins and talk to other pieces of hardware. Lucky for us, it comes pre-packaged with Raspbian!

In the first two lines, you see that we imported modules, but we added a few things onto those imports. First up, we used the keyword as:

import RPi.GPIO as GPIO

RPi.GPIO is the name of the module. By saying as GPIO, we change how we want to refer to that module in the rest of the program. This allows us to type

GPIO.output(led_pin, GPIO.HIGH)

instead of the much longer

RPi.GPIO.output(led_pin, RPi.GPIO.HIGH)

While it’s generally not a good idea to disable warnings while coding, we added the following line:

GPIO.setwarnings(False)

Without it, you’ll get a warning from the interpreter when you try to run the blink program again:

blink.py:14: RuntimeWarning: This channel is already in use, continuing anyway.  Use GPIO.setwarnings(False) to disable warnings.
  GPIO.setup(led_pin, GPIO.OUT)

This is because we did not shut down the GPIO 12 pin nicely when we exited the program. To do this, we would want to add a GPIO.cleanup() line at the end of our program. However, because we wrote our program to run forever, we have to interrupt the program to stop it (and a call to cleanup() would never occur). For the time being, it’s enough to just ignore the warnings.

Challenge: Change the program to make the LED blink like a heartbeat: 2 quick flashes in succession and then a longer delay.

Code Part 2: Fading an LED with PWM

We’ve seen how to turn an LED on and off, but how do we control its brightness levels? An LED’s brightness is determined by controlling the amount of current flowing through it, but that requires a lot more hardware components. A simple trick we can do is to flash the LED faster than the eye can see!

By controlling the amount of time the LED is on versus off, we can change its perceived brightness. This is known as pulse width modulation (PWM). We have two separate PWM channels for our use: PWM0 and PWM1. We can output a PWM signal on PWM0, which will show up on GPIO12 and GPIO18. Additionally, PWM1 controls the signal for GPIO13 and GPIO19.

Copy the following code into a file (e.g. pwm.py):

import time
import RPi.GPIO as GPIO

# Pin definitions
led_pin = 12

# Use "GPIO" pin numbering
GPIO.setmode(GPIO.BCM)

# Set LED pin as output
GPIO.setup(led_pin, GPIO.OUT)

# Initialize pwm object with 50 Hz and 0% duty cycle
pwm = GPIO.PWM(led_pin, 50)
pwm.start(0)

# Set PWM duty cycle to 50%, wait, then to 90%
pwm.ChangeDutyCycle(50)
time.sleep(2)
pwm.ChangeDutyCycle(90)
time.sleep(2)

# Stop, cleanup, and exit
pwm.stop()
GPIO.cleanup()

Run it (e.g. python pwm.py), and you should see the LED start dim, wait 2 seconds, grow brighter, wait another 2 seconds, and then turn off before exiting the program.

Dim LED connected to Raspberry Pi

Code to Note:

In the first part, we use the .output() function of the GPIO module to toggle the LED. Here, we create PWM object and store it in the variable pwm. We do this with the line:

pwm = GPIO.PWM(led_pin, 50)

From there, we can control the PWM by calling methods within that object. For example, we change the brightness by calling:

pwm.ChangeDutyCycle(t)

where t is some number between 0-100 (0 being off and 100 being always on). Putting in the number 50 would mean that the LED is on half the time and off the other half the time (it’s just toggling so fast that you can’t see it!).

Also, we left out the GPIO.setwarnings() call, since we can actually call GPIO.cleanup() at the end of our program! If you try to run the PWM code twice, you should not see any warnings.

Challenge: Make the LED slowly fade from off to fully bright over the course of about 2 seconds. Once it has reached maximum brightness, the LED should turn off and repeat the fading process again. Have the LED fade on over and over again forever.

Code Part 3: Button Input

Let’s add some user input! Save the following to a file (such as button.py).

import time
import RPi.GPIO as GPIO

# Pins definitions
btn_pin = 4
led_pin = 12

# Set up pins
GPIO.setmode(GPIO.BCM)
GPIO.setup(btn_pin, GPIO.IN)
GPIO.setup(led_pin, GPIO.OUT)

# If button is pushed, light up LED
try:
    while True:
        if GPIO.input(btn_pin):
            GPIO.output(led_pin, GPIO.LOW)
        else:
            GPIO.output(led_pin, GPIO.HIGH)

# When you press ctrl+c, this will be called
finally:
    GPIO.cleanup()

Run it the code (python button.py). Now, when you press the button, the LED should turn on.

Pushing button to turn on LED connected to Raspberry Pi

Code to Note:

The first odd thing you might notice is the try: and finally: statements. These are part of the error and exception handling abilities in Python (you can read more about them in the Exceptions chapter in Byte of Python).

If we press ctrl + x while the program is inside the while True: loop, an exception will be thrown. We don’t care to do anything with that exception (hence why you don’t see an except block, like you might have read about in “exception handling”). Regardless of whatever the exception is, we do want to call our GPIO.cleaup() function. That way, we can close down the GPIO and not have to worry about any more errors!

The other odd thing you might see is that if GPIO.input(btn_pin) is True (which means the pin is logic high, or 3.3V), we turn the LED off. Wait, what?

In our circuit, our button has a pull-up resistor connecting one of the pins to a constant 3.3V. This means that in its default state (not pressed), the pin connected to the button is 3.3V. When we press the button, the pin is connected to ground (through the button’s internal contacts), and the pin becomes logic low (0V).

As a result, when the button is not pressed, we get logic high (GPIO.input() returns True), and when the button is pressed, we get logic low (GPIO.input() returns False).

Challenge: Write a program so that whenever you press the button, a variable is incremented by one and is printed to the screen. This should work as a simple button counter. Start at 0, and each time you press the button, it counts up on the screen.

Incrementing a counter whenever a button is pressed

Experiment 2: Play Sounds

Downloading audio clips and playing them on a Raspberry Pi is quite simple. We will use the command line to download a .wav file, adjust the audio, and test playing the file. Then, we’ll write a Python script to play that file whenever we press a button!

Recommended Reading

  • amixer - We will be using the amixer Linux tool to adjust the volume on our Raspberry Pi
  • Pygame - Pygame is a framework that is used for making simple games in Python. Raspbian comes pre-loaded with Pygame, which means we can use it to play sounds.

Hardware Connections

Good news, everyone! We will be using the same circuit from the previous experiment.

  • Connect GPIO12 (pin 32) to the 330Ω resistor, and the resistor to the LED
  • Connect GPIO4 (pin 7) to the button
  • Make the power (3.3 V) and ground (GND) connections as shown in the Fritzing diagram

Connecting through a Pi Wedge:

Pi Wedge Fritzing diagram to connect LED and button

Connecting directly to the Raspberry Pi:

Raspberry Pi Fritzing diagram to connect LED and button

You will also need to plug an external speaker (or a set of headphones) into the Pi’s headphone jack. If you are using the Hamburger Mini Speaker, make sure it is charged and turned on.

Speaker plugged into Raspberry Pi

Configure Audio

Before we write code, we need to configure the audio from the command line. Open a terminal (if you are using Raspbian with a desktop).

Note: Make sure you have selected the 3.5mm ('headphone') jack as your output audio device from the sudo rasp-config advanced options. Refer to the Configure Your Pi section to see how to do this.

From a terminal, enter the following commands:

amixer set PCM unmute
amixer set PCM 100%

Verify that your audio is on and up by entering the command:

amixer

At the end of the printout, you should see Mono: Playback 400 [100%] [4.00dB] [on].

Configure audio output on Raspberry Pi

Download a free sound clip (we’ll go with some applause, because we’re awesome):

wget http://www.pacdv.com/sounds/people_sound_effects/applause-1.wav

Test playing this sound with:

aplay applause-1.wav

You should hear some nice cheering and clapping out of your speaker (or headphones).

Code: Push Button, Get Sound

Depending on your version of Raspbian, you may or may not have to install the pygame package (e.g. Raspbian Lite does not come with some Python packages pre-installed). In a terminal, enter the following:

sudo apt-get update
sudo apt-get install python3-pygame

In a new file, enter the following code:

import time
import RPi.GPIO as GPIO
from pygame import mixer

# Pins definitions
btn_pin = 4

# Set up pins
GPIO.setmode(GPIO.BCM)
GPIO.setup(btn_pin, GPIO.IN)

# Initialize pygame mixer
mixer.init()

# Remember the current and previous button states
current_state = True
prev_state = True

# Load the sounds
sound = mixer.Sound('applause-1.wav')

# If button is pushed, light up LED
try:
    while True:
        current_state = GPIO.input(btn_pin)
        if (current_state == False) and (prev_state == True):
            sound.play()
        prev_state = current_state

# When you press ctrl+c, this will be called
finally:
    GPIO.cleanup()

Save the file (e.g. applause.py), and start the program with python applause.py. Push the button, and you should hear some congratulatory sounds!

Pushing button to play sound

Troubleshooting: If you see the message “ModuleNotFoundError: No module named ‘pygame’” you will need to install the pygame package by entering pip install pygame in a terminal.

Code to Note:

To play sounds, we are using the pygame package. A package in Python is a collection of modules grouped together. Lucky for us, pygame comes pre-installed with Python on Raspbian. To use it, we just need to use from pygame in our code, and we can specify which module we want to use by saying import after it. For example, we might say:

from pygame import mixer

This says that we want to import the mixer module from the pygame package. Later in our code, we can use the mixer module to create a Sound object with:

sound = mixer.Sound('applause-1.wav`)

Our downloaded file, applause-1.wav is used to create a Sound object, which we store in the sound variable. We can call the .play() method in our Sound object to start playing the .wav file.

sound.play()

Challenge: You might have noticed that if you press the button again while the sound is playing, an new sound will start that overlaps the first clip. Let’s fix this! Change the code so that when you press the button while the sound is playing, the sound stops. When you press it again, the sound clip starts over again. Also, because we can, have the LED light up while the sound is playing. Hint: it might help to look at the pygame.mixer methods for determining if sound is being played (or “mixed”) and how to stop a sound.

Experiment 3: SPI and Analog Input

Many sensors out there use an analog voltage to convey their measurement data. For example, photocells change their resistance depending on how much light is falling on the sensor. By using a voltage divider in our circuit, we can effectively measure the amount of ambient light by measuring a voltage.

The bad news is that our Raspberry Pi does not come with any way to measure an analog voltage. To do that, we’ll need to rely on a separate piece of circuitry: an analog-to-digital converter (ADC). Specifically, we’ll be using the Microchip MCP3002, which is a niftly little chip that can measure up to 2 analog voltages on separate channels and report their values over the Serial Peripheral Interface (SPI) interface.

We’ll use the built-in spidev module in Python to send commands and read replies on the SPI bus.

Recommended Reading

Hardware Connections

Refer to the Raspberry Pi Pinout section in the previous example if you would like to see what pins and GPIO labels belong to each of these connections.

  • Connect MOSI (GPIO10, pin 19) to Din on the MCP3002
  • Connect MISO (GPIO9, pin 21) to Dout on the MCP3002
  • Connect SCLK (GPIO11, pin 21) to CLK on the MCP3002
  • Connect CE0 (GPIO8, pin 24) to CS/SHDN on the MCP3002
  • Connect the photocell voltage divider to CH0 on the MCP3002
  • Connect the potentiometer’s middle pin to CH1 on the MCP3002
  • Make the power (3.3 V) and ground (GND) connections as shown in the Fritzing diagram

Connecting through a Pi Wedge:

Pi Wedge Fritzing diagram to connect an MCP3002

Connecting directly to the Raspberry Pi:

Raspberry Pi with MCP3002 Fritzing diagram

Note: Pay close attention to how the MCP3002 is oriented. You should see a notch in the top surface of the chip. With the notch oriented up, pin 1 is down and to the left of the notch.

MCP3002 DIP pinout

Pinout from the MCP3002 datasheet

Code: Reading Analog Voltage

Depending on your version of Raspbian, you may or may not have to install the spidev package (e.g. Raspbian Lite does not come with some Python packages pre-installed). In a terminal, enter the following:

pip install spidev

In a new file, enter the following code:

import time
import spidev

spi_ch = 0

# Enable SPI
spi = spidev.SpiDev(0, spi_ch)
spi.max_speed_hz = 1200000

def read_adc(adc_ch, vref = 3.3):

    # Make sure ADC channel is 0 or 1
    if adc_ch != 0:
        adc_ch = 1

    # Construct SPI message
    #  First bit (Start): Logic high (1)
    #  Second bit (SGL/DIFF): 1 to select single mode
    #  Third bit (ODD/SIGN): Select channel (0 or 1)
    #  Fourth bit (MSFB): 0 for LSB first
    #  Next 12 bits: 0 (don't care)
    msg = 0b11
    msg = ((msg << 1) + adc_ch) << 5
    msg = [msg, 0b00000000]
    reply = spi.xfer2(msg)

    # Construct single integer out of the reply (2 bytes)
    adc = 0
    for n in reply:
        adc = (adc << 8) + n

    # Last bit (0) is not part of ADC value, shift to remove it
    adc = adc >> 1

    # Calculate voltage form ADC value
    voltage = (vref * adc) / 1024

    return voltage

# Report the channel 0 and channel 1 voltages to the terminal
try:
    while True:
        adc_0 = read_adc(0)
        adc_1 = read_adc(1)
        print("Ch 0:", round(adc_0, 2), "V Ch 1:", round(adc_1, 2), "V")
        time.sleep(0.2)

finally:
    GPIO.cleanup()

Save the file (e.g. adc.py), and run it with Python:

python adc.py

You should be able to cover the photocell and see the Ch 0 voltage change. Adjust the knob on the potentiometer to see the Ch 1 voltage change.

Reading analog voltages with Python on a Raspberry Pi

Code to Note:

We are using SPI channel 0 on the Raspberry Pi when we initialize the SpiDev object:

spi_ch = 0
spi = spidev.SpiDev(0, spi_ch)

Channel 0 corresponds to using CE0 (chip enable 0) on the Pi’s pins. If you wanted to use another device on the SPI bus, you would need to connect it to CE1 and use SpiDev channel 1 as well.

We construct our SPI message by manipulating individual bits. We start with binary 11 (which is the decimal number 3) by using the prefix ‘0b’:

msg = 0b11

If you look at section 5 in the MCP3002 datasheet, you will see that we need to send a 1 to start transmission, followed by another 1 to denote that we want “single ended mode.” After that, we select our channel with a 0 (for channel 0) or a 1 (for channel 1). Then, we send a 0 to show that we want data returned to us with the least significant bit (LSB) sent first.

msg = ((msg << 1) + adc_ch) << 5

Finally, we send another twelve 0s. What we send here really doesn’t matter, as we just need to send clock pulses to the MCP3002 so that it sends data back to us over the Dout (MISO) line. This data (4 setup bits followed by twelve 0s) is stored in a list.

msg = [msg, 0b00000000]

We store the data returned to us in the reply variable, and it comes to us as a list of 2 bytes (stored as 2 integers). Note that we send out data and read the reply at the same time when using SPI:

reply = spi.xfer2(msg)

From there, we construct a single integer out of the two bytes (8 bits) by shifting the first over to the left by 8 bits and then adding the second byte to it. The last bit we read in is extraneous (not part of the ADC’s return value) so we shift the answer to the right by one bit.

adc = 0
for n in reply:
    adc = (adc << 8) + n

adc = adc >> 1

The ADC value is given as a percentage of the maximum voltage (whatever the voltage is on the Vdd/Vref pin). That percentage is calculated by dividing the reply value by 1024. We get 1024 because we know that the MCP3002 is a 10-bit ADC, which means the maximum value of 10 bits (0b1111111111) is 1023. Many ADCs have some error, so we round up to 1024 to make the math easier (here’s a discussion on max ADC values, if you’re curious).

Once we get the percentage of Vref with val / 1024, we multiply that percentage by our Vref, which we know is 3.3V in the case of our Raspberry Pi.

voltage = (vref * adc) / 1024

And that’s how we get our analog voltage reading! If all this is confusing, you can simple copy the Enable SPI portion and read_adc() function into your own code. Then, just call read_adc(0) to get the voltage at CH0 on the MCP3002.

One last interesting bit of code is the idea of default parameters. If you take a look at the read_adc() definition:

def read_adc(adc_ch, vref = 3.3):

You’ll see that there are actually two parameters: adc_ch and vref. When you call this function, you are required to give it a channel number (0 or 1). However, you can optionally send it an argument with the Vref value. On most cases with the Raspberry Pi, the voltage will be 3.3V. If you use another voltage (e.g. 5V), then you can change the math so that the ADC gives you a more accurate reading.

You have the option of calling this function with another Vref (e.g. 5) using either read_adc(0, 5) or by explicitly naming the vref parameter read_adc(0, vref=5). However, because we know that we’ve connected 3.3V to the MCP3002, we can simply call read_adc(0) and know that the function will rely on its default parameter of vref=3.3 when doing its calculations.

Challenge: Add an LED to your circuitry. Write a program to act as a variable nightlight. That is, the LED should turn on whenever the photocell sees dark (little ambient light) and should turn off whenever the photocell sees light (lots of ambient light). Have the potentiometer control the brightness of the LED when it is on. Hint: you might want to take some measurements to determine the threshold of light vs. dark. What is the voltage when you cover the photocell with your hand?

Raspberry Pi nightlight created in Python

Experiment 4: I2C Temperature Sensor

In addition to analog sensors and SPI chips, you’ll often find sensors (and other devices) that rely on the Inter-Integrated Chip (IIC or I2C) protocol. This is a 2-wire bus that contains a clock and data channel. The master (Raspberry Pi) and device (sensor) can communicate on the same data wire.

To see this protocol in action, we’ll write a program to talk to a TMP102 Temperature Sensor. We’ll use the smbus Python module to handle the low-level communication for us. Note that “SMBus” stands for “System Management Bus” and is another protocol layer built on top of the I2C protocol. By using smbus, we lose out on a few I2C abilities (e.g. clock stretching), but we can still talk to many I2C sensors.

Recommended Reading

  • I2C - A detailed look at how the I2C protocol works

Hardware Connections

Refer back to Experiment 1 to look at the Pinout chart.

  • Connect SDA1 (GPIO2, pin 3) to SDA on the TMP102
  • Connect SCL1 (GPIO3, pin 5) to SCL on the TMP102
  • Connect power (3.3 V) to VCC on the TMP102
  • Connect ground (GND) to GND on the TMP102

Connecting through a Pi Wedge:

Fritzing diagram of using a Pi Wedge to connect to a TMP102 temperature sensor

Connecting directly to the Raspberry Pi:

Fritzing diagram of Raspberry Pi connected to a TMP102 temperature sensor

Code: Read and Calculate Temperature

Depending on your version of Raspbian, you may or may not have to install the smbus package (e.g. Raspbian Lite does not come with some Python packages pre-installed). In a terminal, enter the following:

sudo apt-get install python3-smbus

In a new file, copy in the following code:

import time
import smbus

i2c_ch = 1

# TMP102 address on the I2C bus
i2c_address = 0x48

# Register addresses
reg_temp = 0x00
reg_config = 0x01

# Calculate the 2's complement of a number
def twos_comp(val, bits):
    if (val & (1 << (bits - 1))) != 0:
        val = val - (1 << bits)
    return val

# Read temperature registers and calculate Celsius
def read_temp():

    # Read temperature registers
    val = bus.read_i2c_block_data(i2c_address, reg_temp, 2)
    temp_c = (val[0] << 4) | (val[1] >> 5)

    # Convert to 2s complement (temperatures can be negative)
    temp_c = twos_comp(temp_c, 12)

    # Convert registers value to temperature (C)
    temp_c = temp_c * 0.0625

    return temp_c

# Initialize I2C (SMBus)
bus = smbus.SMBus(i2c_ch)

# Read the CONFIG register (2 bytes)
val = bus.read_i2c_block_data(i2c_address, reg_config, 2)
print("Old CONFIG:", val)

# Set to 4 Hz sampling (CR1, CR0 = 0b10)
val[1] = val[1] & 0b00111111
val[1] = val[1] | (0b10 << 6)

# Write 4 Hz sampling back to CONFIG
bus.write_i2c_block_data(i2c_address, reg_config, val)

# Read CONFIG to verify that we changed it
val = bus.read_i2c_block_data(i2c_address, reg_config, 2)
print("New CONFIG:", val)

# Print out temperature every second
while True:
    temperature = read_temp()
    print(round(temperature, 2), "C")
    time.sleep(1)

Save the file (e.g. tmp102.py), and run it with Python:

python tmp102.py

You should see the 2 bytes in the CONFIG register be updated and then the temperature is printed to the screen every second.

Reading temperature using Python and I2C

Code to Note:

Unlike SPI, I2C relies on a set of addresses and registers. This is because SPI is configured to talk to one chip at a time while I2C can share many devices on one bus. To avoid conflicts, addresses are assigned to devices (by the manufacturer) so that each one knows when the host (the Pi) is trying to talk to it. The address for our TMP102 is 0x48.

Each time we want to talk to the TMP102, we must send out its address (0x48) on the bus. Only then can we send the memory location (or address) of the register that we want to read from or write to on the TMP102. Note that for most I2C devices, a register is a location in the device’s memory that stores 8 bits (1 byte) of data. Sometimes, this data controls the function of the device (as in the case of the CONFIG register). Other times, the registers hold the sensor reading data (as in the case of the temperature register).

We use the following command to read 2 bytes from the temperature register in the TMP102:

val = bus.read_i2c_block_data(i2c_address, reg_temp, 2)

These values are stored as a list [x, y] in the val variable. By looking at the TMP102 datasheet, we see that temperature is 12 bits. When we read the two bytes that contain this reading, we need to remove the last 4 bits from the second byte. We also move the first byte over 4 bits:

temp_c = (val[0] << 4) | (val[1] >> 5)

In order to display negative numbers for the temperature, values from the TMP102 can come in the form of Two’s Complement. In this, the first bit of the 12-bit number determines if the value is positive or negative (0 for positive, 1 for negative). See this article to learn more about Two’s Complement.

To convert a Two’s Complement number to a negative number in Python, we check to see if the first bit is 0 or 1. If it is 0, then we just use the number as is (it’s positive!). If it’s a 1, we subtract the max negative number of the Two’s Complement (212=4096 in this case) from our number.

if (val & (1 << (bits - 1))) != 0:
    val = val - (1 << bits)

Challenge: Change the CONFIG register so that the TMP102 updates its temperature reading 8 times per second (instead of 8). Additionally, print out the temperature in degrees Fahrenheit. Hint: see page 7 of the TMP102 datasheet to see which bits need to be changed in the CONFIG register.

Experiment 5: File Reading and Writing

Let’s take our previous example (taking measurements from an I2C device) and log them to a file! This can be incredibly useful if you are trying to measure the temperature (light, humidity, wind speed, air pressure, people entering your room, or really anything) and want to see how it changes over the course of minutes, hours, or days.

Recommended Reading

Hardware Connections

We’ll use the same circuit as last time.

  • Connect SDA1 (GPIO2, pin 3) to SDA on the TMP102
  • Connect SCL1 (GPIO3, pin 5) to SCL on the TMP102
  • Connect power (3.3 V) to VCC on the TMP102
  • Connect ground (GND) to GND on the TMP102

Connecting through a Pi Wedge:

Fritzing diagram of using a Pi Wedge to connect to a TMP102 temperature sensor

Connecting directly to the Raspberry Pi:

Fritzing diagram of Raspberry Pi connected to a TMP102 temperature sensor

Code: Measure and Log Temperature to a File

We’ll turn our previous code into a module for use to use. Change the code in tmp102.py to the following:

tmp102.py

import smbus

# Module variables
i2c_ch = 1
bus = None

# TMP102 address on the I2C bus
i2c_address = 0x48

# Register addresses
reg_temp = 0x00
reg_config = 0x01

# Calculate the 2's complement of a number
def twos_comp(val, bits):
    if (val & (1 << (bits - 1))) != 0:
        val = val - (1 << bits)
    return val

# Read temperature registers and calculate Celsius
def read_temp():

    global bus

    # Read temperature registers
    val = bus.read_i2c_block_data(i2c_address, reg_temp, 2)
    temp_c = (val[0] << 4) | (val[1] >> 5)

    # Convert to 2s complement (temperatures can be negative)
    temp_c = twos_comp(temp_c, 12)

    # Convert registers value to temperature (C)
    temp_c = temp_c * 0.0625

    return temp_c

# Initialize communications with the TMP102
def init():

    global bus

    # Initialize I2C (SMBus)
    bus = smbus.SMBus(i2c_ch)

    # Read the CONFIG register (2 bytes)
    val = bus.read_i2c_block_data(i2c_address, reg_config, 2)

    # Set to 4 Hz sampling (CR1, CR0 = 0b10)
    val[1] = val[1] & 0b00111111
    val[1] = val[1] | (0b10 << 6)

    # Write 4 Hz sampling back to CONFIG
    bus.write_i2c_block_data(i2c_address, reg_config, val)

    # Read CONFIG to verify that we changed it
    val = bus.read_i2c_block_data(i2c_address, reg_config, 2)

Create a new file and enter the following code. Give the file a name such as templogger.py.

templogger.py

import time
import datetime
import tmp102

filename = "temp_log.csv"

# Create header row in new CSV file
csv = open(filename, 'w')
csv.write("Timestamp,Temperature\n")
csv.close

# Initialize communication with TMP102
tmp102.init()

# Sample temperature every second for 10 seconds
for t in range(0, 10):

    # Construct CSV entry from timestamp and temperature
    temp_c = str(round(tmp102.read_temp(), 2))
    entry = str(datetime.datetime.now())
    entry = entry + "," + temp_c + "\n"

    # Log (append) entry into file
    csv = open(filename, 'a')
    try:
        csv.write(entry)
    finally:
        csv.close()

    # Wait 1 second before sampling temperature again
    time.sleep(1)

# When all the writing has been completed, print the CSV contents
csv = open(filename, 'r')
print(csv.read())
csv.close()

Run the temperature logger with python templogger.py. You should see nothing happen for 10 seconds as the program reads the temperature once every second. For fun, try breathing on the temperature sensor to affect the data! After those 10 seconds, the collection should be complete, and the contents of temp_log.csv will be printed to the screen.

You can view the contents of the log by entering cat temp_log.csv into the console.

Logging temperature and displaying it on a Raspberry Pi

Code to Note:

If you remember from our Programming in Python section, we covered how to create modules. Modules let you reuse code that exist in other files. In our case, we put the “measure temperature” section of the tmp102.py code into a function definition so that we may call it from another file.

In our main program (templogger.py), we imported our own module with import tmp102. Notice that we left out the .py suffix–Python knows to look for a .py file.

You’ll also notice that whenever we open a file for reading or writing, we close it as soon as we can. It’s generally not good practice to open a file and leave it open. If your program or operating system crashes while the file is open, you could potentially corrupt the file (or worse, the whole filesystem).

For extra protection, we add the writing section in a try block:

try:
    csv.write(entry)
finally:
    csv.close()

Now, if something crashes while the program is trying to write to the file, an exception will be thrown and Python will automatically close the file before exiting.

You can also see that how we access a file is given by the second parameter in the open() function:

  • ‘r’ - Read
  • ‘w’ - Write (this will erase the original contents of the file)
  • ‘a’ - Append (this will keep the original contents and add your additions at the end)

datetime.datetime.now() returns a datetime object, which we convert into a string with str(). Note that this is based on the local time of your Raspberry Pi. You can get a Coordinated Universal Time (UTC) date and timestamp with datetime.datetime.utcnow().

Challenge: Open the temperature log in a spreadsheet program and create a graph showing how the temperature changed over those 10 seconds (for extra credit, change the program to measure temperature over a longer period of time). Hint: Raspbian comes with LibreOffice Calc, a free spreadsheet program. If you use Calc, the Data > Text to Columns function might help you convert your date/timestamps into something usable.

Temperature data logged and displayed as a graph

Headless: If you are using the Raspberry Pi as a headless device, you may want to print the contents of the CSV to the screen, and copy-and-paste them into a spreadsheet program on your host computer.

Solution: There’s not really an “answer” to this. Get creative and show off your graphing skills!

Resources and Going Further

Hopefully, this tutorial has given you a starting point for your adventures with Python (and more specifically, how to control hardware with Python). If you would like to dig deeper into the Python language, here are some resources for you:

Python Logo

Looking for even more inspiration? Check out these other Raspberry Pi projects:

Building Large LED Installations

Learn what it takes to build large LED installations from planning to power requirements to execution.

Bark Back Interactive Pet Monitor

Monitor and interact with pets through this dog bark detector project based on the Raspberry Pi!

Raspberry Pi Zero Helmet Impact Force Monitor

How much impact can the human body handle? This tutorial will teach you how to build your very own impact force monitor using a helmet, Raspberry Pi Zero, and accelerometer!

Using Flask to Send Data to a Raspberry Pi

In this tutorial, we'll show you how to use the Flask framework for Python to send data from ESP8266 WiFi nodes to a Raspberry Pi over an internal WiFi network.

learn.sparkfun.com | CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

Light Up Your 3D Printer's Bed

$
0
0

Light Up Your 3D Printer's Bed a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t790

Introduction

Are you 3D printing in a room at night with barely any light? That’s the problem that I came across when inspecting prints at SparkFun during odd hours. The light source behind me created a shadow over the print bed making it hard to see what was going on. In this tutorial, we will be using a LED strip to light up the print bed on a LulzBot 3D printer!

Non Addressable LEDs on Illuminating a 3D Printer's Bed

Required Materials

To follow along with this tutorial, you will need the following materials. You may not need everything though depending on what you have. Add it to your cart, read through the guide, and adjust the cart as necessary.

Tools

You will need a screw driver, wire strippers, and diagonal cutters.

You Will Also Need

In addition to the materials listed above, you will need:

  • Electrical Tape
  • Hot Glue Gun and Glue Sticks

Hardware Hookup

The wiring is simple between the female barrel jack adapter and the non-addressable LED strip. Simply insert the black wire connecting the “12V”“ pin to the ”+“” of the barrel jack adapter’s screw terminal. Then insert the rest of the wires to the “” screw terminal.

Fritzing Diagram for Adapter and LED Strip

Click the image for a closer look.

Hookup Table

Below is a hookup table that shows the connection between the female barrel jack adapter and non-addressable RGB LED strip.

Nonaddressable RGB LED Strip Pinout Female DC Barrel Jack Adapter
+12V
-G
-R
-B

Connecting and Modifying the LED Strip

We will be attaching the LEDs to the top of the frame. Make sure that the LEDs and wires are not in the way of any moving parts. Determine the length that you need by holding the LED strip up against the 3D printer's frame. The length depends on the size of your printer’s frame. For the Lulzbot TAZ 3D printers, about 16x segments of the LED strip was used. For the Lulzbot Mini, about 12x segments seemed to be sufficient. Each segment consists of 3x LEDs between the exposed copper pads.

LED Strip Segment

Click the image for a closer look.

Cut 4x segments off one end of the 1M non-addressable LED using the diagonal cutter. Relative to the 3D printer that I was using, I decided to remove the 4x segments from the right side of the LED strip.

Cut Between Segments

Carefully strip extra wire insulation to expose more wire for the screw terminal. You may need to tin the tips of the wires by adding more solder. Then, insert the wires for R, G, and B, into barrel jack adapter's screw terminal labeled as “”. Then tighten the screw with a Phillips head screw driver. Repeat for the black wire labeled as 12V on the “+” side.

Tighten Screw Terminal

Pull gently to verify that the wires are secure in the socket.

Pull Wires to Check If Secure

Insulate the exposed end of the LED strip with hot glue.

Insulate with Hot Glue

Connect a barrel jack power switch between barrel jack adapter and power supply.

Connected Hardware

Testing

Now would be a good time to check if the hardware was wired properly. Connect the power supply to a wall outlet. If the LEDs do not light up, flip the switch to the other side to see if the LED strip lights up.

Powering the LED Strip to Test

Secure the LEDs

Attach the LED strip flush against the top of the 3D printer's frame and ensure that the wires are not in the way of the printable area. Since we want to illuminate the print bed, aim the LEDs toward the printer. While we could use the 3M adhesive that is on the back of the LED strip's clear jacket, I wanted to ensure that the adhesive did not fail during a print. Instead, the wires were secured by using electrical tape and wrapping the strip against the frame. Depending on the width of the tape, you may want to cut it down to prevent the LEDs from being blocked. You could use zip ties as well.

Mount the LED Strip with Tape

Tape was added as necessary on the enclosure; left, top, and right side of the frame as shown in the image below. Feel free to mount the power switch to another location so that you do not accidentally turn the power off to your 3D printer.

Highlighted Areas with Electrical TapeLED STrip Mounted to 3D Printer
Hightlighted Areas with Electrical TapeLED Strip Mounted to 3D Printer

Enjoy 3D Printing in the Light!

Insert the power supply into a wall outlet and flip the switch to power the lights when you need to check on your print!

3D Printer Lit Up

Making It Better

Like all projects, you can always make it better and build upon the design. Here are few ideas to make it even more impressive by adding effects or interactive!

Resources and Going Further

Need some inspiration for your next project? Check out some of these related tutorials for ideas:

The Great Big Guide to Paper Circuits

Let's take a look at different materials we can use to combine paper crafting and electronics.

Large Digit Driver Hookup Guide

Getting started guide for the Large Digit display driver board. This tutorial explains how to solder the module (backpack) onto the back of the large 7-segment LED display and run example code from an Arduino.

LED PomPom Headbands

Follow this tutorial to make your own light up PomPom headband! Try the beginner version if you are new to electronics or the advanced version if you have some more experience!

LilyPad Tri-Color LED Hookup Guide

Learn how to hook up the LilyPad Tri-Color LED and use a common cathode RGB LED in e-textile projects.

learn.sparkfun.com | CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

Mean Well LED Switching Power Supply Hookup Guide

$
0
0

Mean Well LED Switching Power Supply Hookup Guide a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t779

Introduction

In this tutorial, we will be connecting a Mean Well LED switching power supply (5V/25W or 5V/40W) to an addressable LED strip controlled by an Arduino.

Mean Well LED Switching Power Supply - 5VDC, 5A

TOL-14601
$14.95
Mean Well LED Switching Power Supply - 5VDC, 8A

TOL-14602
$19.95

Required Materials

To follow along with this tutorial, you will need the following materials with the Mean Well 5V power supply. This is assuming that you are using the wall adapter cable for 120VAC. For the load, we will be using an addressable LED strip. You may not need everything though depending on what you have. Add it to your cart, read through the guide, and adjust the cart as necessary.

Skinny LED RGB Strip - Addressable, 1m, 60LEDs (SK6812)

COM-14730
$14.95
Terminal Block - 6 Position (15A, 600V)

PRT-13061
$2.95
2
Terminal Block - 3 Position (15A, 600V)

PRT-13060
$1.95
1
iPixel Wall Adapter Cable - Two Terminal (NA)

CAB-14603
$3.95

Suggested Tools

Depending on your setup, you may need a soldering iron, solder, and general soldering accessories. Otherwise, a screw terminal block and a screw driver is sufficient.

Digital Multimeter - Basic

TOL-12966
$14.95
19
Solder Lead Free - 100-gram Spool

TOL-09325
$7.95
7
Weller WLC100 Soldering Station

TOL-14228
$44.95
SparkFun Mini Screwdriver

TOL-09146
$0.95
3

You will also need:

  • Electrical Tape
  • Surge Protector

Suggested Reading

If you aren’t familiar with the following concepts, we recommend checking out these tutorials before continuing.

Voltage, Current, Resistance, and Ohm's Law

Learn about Ohm's Law, one of the most fundamental equations in all electrical engineering.

How to Power a Project

A tutorial to help figure out the power requirements of your project.

Working with Wire

How to strip, crimp and work with wire.

Electric Power

An overview of electric power, the rate of energy transfer. We'll talk definition of power, watts, equations, and power ratings. 1.21 gigawatts of tutorial fun!

WS2812 Breakout Hookup Guide

How to create a pixel string with the WS2812 and WS2812B LEDs!

How to Use a Multimeter

Learn the basics of using a multimeter to measure continuity, voltage, resistance and current.

Hardware Overview

The Mean Well APV-35 and LPV-60 series power supplies were designed to power LEDs. They include wire pairs for the input (brown and blue) and output (red and black). The input voltage requires an AC power cable to be connected that is not included with the power supply. The APV-35-5 provides 5V with up to 5.0A. The LPV-60-5 provides 5V with up to 8.0A.

APV-35 Series 5V/5ALPV-60 Series 5V/8A
APV-35 SeriesLPV-60 Series

Pinout

Mean Well Power Supply Notes
ACL (Brown)Input AC Voltage, Live/Hot wire
ACN (Blue)Input AC Voltage, Neutral Wire, Wider Blade on Wall Outlet Side
V+ (Red)Output Voltage (DC)
V- (GND, Black)Output Ground (DC)

Hardware Assembly

Hookup Table

The following is the hookup table for connecting a wall adapter cable to a Mean Well power supply and then to your load. Ensure that the cable is not connected to a wall outlet when making the following connections between the cable and Mean Well power supply!

120VAC Outlet (North American Standard) Mean Well Power Supply Load (i.e. LED Strips) Notes
LIVE/HOT Wire (Black) ACL (Brown)Input AC Voltage, Live/Hot wire
NEUTRAL Wire (White) ACN (Blue)Input AC Voltage, Neutral Wire, Wider Blade on Wall Outlet Side
V+ (Red)5V Output Voltage (DC)
V- (GND, Black)GND Output Ground (DC)

Connecting the AC Input Voltage w/ Screw Terminals

Before beginning, make sure the power cable is unplugged from the wall outlet. Carefully remove the plastic cover on the terminal block by wiggling it back and forth from the black housing.

Remove Plastic Cover

Insert the hot wire's spade connector into a terminal block between the metal plates.

Insert Spade Connector Between Metal PlatesInserted Spade Connector Between Metal Plates

Tighten the screw. Pull wire gently to see if it is secure.

Tighten Screws on Terminal Blocks

Repeat for the neutral wire's spade connector.

Insert Mean Well Power Supply's Neutral Wire

Connect the hot wire to the Mean Well's hot wire by inserting the wire between the metal plates and tightening the screw.

Insert Mean Well Power Supply's Hot Wire

Remember to pull the wire gently to see if the connection is secure.

Pull Wire to Check If Secure

Repeat for the input neutral wire.

Repeat for Neutral Wire

Connecting the DC Output Voltage w/ Screw Terminals

Connect your Mean Well power supply's output ground wire to one side of the terminal block.

Connect DC Output Ground

Connect the output voltage's wire to another screw terminal.

Connect DC Output Voltage

Connect your load wires to the other side of the Mean Well output voltage.

Connect Load

Other Methods of Connecting to the Mean Well Power Supply

You can also splice the wires or use spade connectors depending on your preference. If you decide to connect with a spade connector, make sure that you are using the correct tool to properly crimp the connection. Needle nose pliers may not provide sufficient force to clamp the spade connector against the wires. Ensure that the power cable is unplugged from the wall outlet.

Connect Spade Connectors

Remember to insulate your connections with electrical tape or heat shrink so that the connections are not exposed.

Insulate Wires for VAC

Once connected, make sure to test it out with a multimeter and surge protector before installing.

Testing the Output

Let's test the power supply using a multimeter to see if we connected everything properly! To safely test, we will be using alligator clips, probes, and a breadboard to measure the output voltage to see if we get our expected voltage. If you are confident in your connections, you can also connect a multimeter's alligator clips directly to the output. Insert the two prong cable into a surge protector that is turned OFF. When ready, flip the switch on your surge protector to the ON position to provide power.

Testing the APV-35 Series Output voltageTesting the LPV-60 Series Output Voltage
Testing the APV-35 Series Output VoltageTesting the LPV-60 Series Output Voltage

If you are measuring a voltage that is close to your Mean Well power supply's output voltage rating, you are good to go!

Adding a Load

Remove power and connect your load to the output. In this case, I decided to power an addressable LED strip using an Arduino and custom built shield.

Adding an LED Strip as a LoadPowered LED Strip

For safety and installation, make sure to add electrical tape around the exposed input voltage side and mount the electronics securely in an enclosure.

Big Red Box - Enclosure

PRT-11366
$8.95
8

Power Large Loads and Daisy Chained LED Strips

When daisy chaining your addressable LED strips, there may be a voltage drop depending on the:

  • amount of LEDs connected
  • length of LED strip
  • how bright the LEDs are set

Below is an image of addressable LED strips daisy chained together and controlled by Arduino. The Arduino was programmed to turn on all the LEDs at full brightness using one 5V/25W power supply as an extreme case.

Daisy Chained LED Strips

As you can see from the image below, the LEDs are not able to fully turn on after a certain distance due to the voltage drop. This is due to the increased resistance as you move further away from the power supply. You may notice that not all the colors are turned on or the strip becomes dim.

Voltage Drops with Daisy Chained LED Strips with RGB Colors Turnned on at Full Brightness

If you see voltage drops and the LED strip not properly turning on, you will need to connect the Mean Well's output between each LED strip's Vcc and GND after about 1 or 2 meters.

Power Injection Between LED Strips

As you can see from the image below, the LEDs throughout the strip are able to fully turn on when connecting power between each LED strip.

LEDs Fully Turned On at Full Brightness as Expected

Again, turning on all the LEDs at full brightness is an extreme case. You may be able get away with injecting power after more than a few meters if your setup uses a lower brightness setting and sequencing the LEDs.

LED Strips with Lower Brightness and Animated

Resources and Going Further

Now that you’ve successfully got your Mean Well power supply up and running, it’s time to incorporate it into your own project!

For more information, check out the resources below:

Need some inspiration for your next project? Check out some of these related tutorials:

RGB Panel Hookup Guide

Make bright, colorful displays using the 32x16, 32x32, and 32x64 RGB LED matrix panels. This hookup guide shows how to hook up these panels and control them with an Arduino.

Large Digit Driver Hookup Guide

Getting started guide for the Large Digit display driver board. This tutorial explains how to solder the module (backpack) onto the back of the large 7-segment LED display and run example code from an Arduino.

How to Build a Remote Kill Switch

Learn how to build a wireless controller to kill power when things go... sentient.

Building a Safe Cracking Robot

How to crack an unknown safe in under an hour.

Or check out some of these blog posts about power supplies


learn.sparkfun.com | CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

LoRaWAN with ProRF and The Things Network

$
0
0

LoRaWAN with ProRF and The Things Network a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t796

What is LoRaWAN?

TL;DR: LoRaWAN™ is like cellphone towers for IoT that allow battery powered things to talk to the internet.

If you’re interested in the Internet of Things, you’ve probably heard of LoRa™ radios. LoRa™ is a fancy new kind of FSK (Frequency-shift keying) modulation that was developed by Semtech Corporation, it’s short for Long Range and it lives up to the name.

Because LoRa™ is just a modulation scheme, it can be used anywhere that you would use other types of packet radio. In fact, one of our favorite LoRa™ modules — the HopeRF RFM95W — is a direct drop-in replacement for their standard FSK radio module — the RFM69HCW— which makes it easy to upgrade your existing packet radio projects to take advantage of Semtech’s long-range, low-power technology.

One particular use of LoRa™ is uniquely exciting, though: LoRaWAN™

LoRaWAN™ is a network standard developed and maintained by the LoRa Alliance: an open association of collaborating members — mostly large tech companies — that’s designed to allow low-power devices to connect to each other and the internet using public gateways. The standard dictates that devices can move freely between gateways. Essentially, it’s like cellphone towers for IoT. The difference is that anyone can inexpensively own and operate a LoRaWAN™ gateway, so building the network is easy. And because anyone could theoretically operate a network server, it’s relatively resistant to monopoly.

The LoRa Alliance has laid out a template for LoRaWAN™ networks and this template consists of 4 parts: Nodes, Gateways, Network Servers and Application Servers.

Nodes

A LoRaWAN™ node is an endpoint device, such as a sensor or an actuator of some kind. A node can be up to 10km (6 miles!) away from a gateway in ideal conditions with the right radio modules. The connection between a node and a gateway is very low bandwidth — between 0.3 and 50 kbps — but it is bi-directional. Nodes need to be smart enough to encrypt and decrypt packets, handle network authentication and respect the duty cycle (we’ll talk about that in a minute) but these are tasks that can be easily achieved on super low-cost microcontroller hardware. The only other thing that a node needs to have is a LoRa™ radio and some kind of antenna.

Gateways

A LoRaWAN™ gateway— sometimes called a concentrator— is kind of like a cross between a cell tower and a WiFi router. It’s the bridge between the nodes and the internet. Because of the long range capabilities of LoRa™, a single gateway can theoretically service entire cities or hundreds of square kilometers. Ideally, however, a given node will be “heard” by multiple gateways to ensure the best network fidelity. Nodes don’t intrinsically know when they’ve been “heard” they just scream into the void, so it’s always good to have multiple gateways within range. If multiple gateways happen to get copies of the same packet, that will be taken care of upstream at the network server. Besides range, another limitation to any LoRaWAN™ gateway is the number of channels it has. The number of channels that a gateway has is the number of nodes that it can talk to at once. At first, this seems extremely limiting since many consumer gateways are around 8 channels, but then we introduce the concept of duty-cycle.

Nodes agree to adhere to a duty cycle limitation. This limitation is actually enforced by government regulation in many parts of the world in an effort to keep the airwaves open for everyone to use. A duty cycle is a measure of the fraction of time that a resource is in use. For instance, if you’re transmitting on a particular frequency for 2 seconds straight every 10 seconds, you’re operating at a 20% duty cycle. So what’s the duty cycle limitation for a LoRaWAN™ node? It depends on your local laws, but it’s probably 1%. For certain applications it may be as low as 0.1%, but this isn’t as low as it sounds. A 1% duty cycle represents almost 15 minutes of combined airtime per day, which far exceeds the fair usage policy of most free networks. And when you consider that a packet takes tens of milliseconds of airtime, these restrictions feel a lot more permissive. Also, by adhering to this duty cycle, we increase the number of nodes that can be serviced by a single gateway by a hundred times!

Network Servers

LoRaWAN™ nodes don’t know anything about the internet so the gateway can’t just turn LoRaWAN™ packets loose on the web and hope for the best, there needs to be a particular server that expects those packets and knows how to deal with them. This is the network server and — as the control center of the network — it has a lot of jobs to do. Its primary job is to direct packets between gateways and application servers. Since LoRaWAN™ allows for uplinks (messages to a server from a node) and downlinks (messages to a node from a server) and because the network server controls all gateways on the network there are a lot of packets to juggle.

Another thing that the network server does is to de-duplicate packets coming in from multiple gateways. Since any node might be within range of multiple gateways and there’s no hand-off when moving between them, the packets just get duplicated as each gateway sends its copy to the network server. The network server compares them and throws out identical packets. Finally, depending on the capabilities advertised by the network operator, a network server might be doing all kinds of other things like monitoring airtime usage and managing subscriptions. Some networks even offer localization for all nodes, triangulating them using Differential Time of Arrival techniques with multiple gateways.

The big thing to remember about the network server is that it does all of the behind-the-scenes work that makes a LoRaWAN™ network operate. Just like in the early days of cellular networks, not all gateways talk to the same network. LoRaWAN™ is only a network standard, not a network in and of itself. On top of this, the network server probably isn’t going to run any application-specific code to talk to your devices, but it will know where to send your packets so that your application-specific code can see them…

Application Servers

An application server is a server that’s connected to the network server (usually somewhere on the internet) that know specifically what to do with packets from a given node or type of node. For instance, if you have a website that shows the current weather conditions at a certain LoRaWAN™ weather station, the weather station is sending packets which are being relayed to the network server by one or more gateways but the network server isn’t interpreting that weather data or serving you the website… that stuff is happening on an application server. The application server and the node are both registered with the network server, so it knows to send packets from the weather station node to the weather station application server. Application servers can be anything from an IFTTT Webhook to a Raspberry Pi somewhere on the web. Sometimes an application server makes data available to browsers, sometimes it simply manipulates data and sends it back out to nodes over the network server.

“Okay, so how do I get in on this?”

There are a lot of LoRaWAN™ networks all over the world, some free to use and some paid. The largest free network today seems to be The Things Network, and it’s growing every day. Even if you’re not currently covered, you can set up your own gateway and join the network to help it grow!

The Things Network

The Things Network logo. A blue cloud radiating blue half circles.

“Building A Global Internet of Things Network Together.”

The Things Network is essentially the free, community-based, open source arm of The Things Industries— an integrated chain of products and services for developing enterprise IoT solutions. While The Things Industries makes their money selling hardware, software, services and consulting, they maintain The Things Network as a sort of tech demo and a tool for gaining market share. I know this is a cynical way to discuss a free open source network, but I like to put it in these terms because their service is so convenient and well maintained that it’s natural to wonder “what’s the catch?”

The Things Network (TTN) is a LoRaWAN™ network server with some extra bells and whistles. Registering a node or an application to the network is free and so is the network traffic — as long as you follow the fair use guidelines. Services are based on best effort, so there’s no guarantee on uptime or latency, but it’s free! The Things Network also encourages members to grow the network by making it incredibly easy to register a gateway. Simply connect your gateway hardware to the internet, open the TTN console, and follow the prompts. They sell their own branded gateway hardware, but they also provide documentation for registering your homebrew gateway. When you register a gateway, you also provide your gateway’s physical location and antenna placement so The Things Network can estimate network coverage and map that coverage for potential users.

To help grow the network, The Things Network even provides resources for finding, joining and starting regional “communities,” organizations dedicated to providing an entire city or area with network coverage. You can see a map of existing communities here, many large cities around the world already have total coverage!

Needless to say, we think The Things Network is a pretty cool idea. Also, since it’s free, it’s a great way to get started with LoRaWAN™. We’ll be using The Things Network to complete this tutorial, so if your city doesn’t have TTN coverage, you’ll need to set up a gateway of your own. You can buy one from The Things Network Marketplace or [make your own with an ESP8266 or a Raspberry Pi!

Heads up! I'll assume for the purposes of this tutorial that you're within range of a functioning gateway. If you're not, you'll need to set up one of your own and register it to The Things Network before continuing.

Registering your Node

Before you can program your first node, you’ll need to register a device on The Things Network. Registering allows the network to generate the necessary keys which you’ll then place in your code so that the network recognizes your device.

Heads up! From here on out, I’m going to assume that you have singed up for The Things Network and have access to the The Things Network Console. It’s free, to sign up you’ll just need an email address.

Once you’ve logged into the console, you’ll be presented with a screen like this:

Screenshot of the front page of the TTN Console. A welcome message is at the top center, below it are two large buttons: one labeled Applications and one labeled Gateways

You’ll notice that there’s no option to just add a node, that’s because The Things Network needs to know what application to associate with your device. Therefor, you’ll need to start by creating an application. Clicking on the Applications button will take you to a page that looks like this:

Screenshot of the Applications menu with a message in the center reading "You do not have any applications." and a link below it that reads "Get started by adding one!", there is a small link in the top right-hand corner of the menu that reads "add application" with a small green circle-with-a-plus-sign icon next to it.

This would usually be a list of all your applications, but The Things Network very helpfully recognizes that you don’t have any applications yet and suggests that you add one. You can add an application either by clicking that link or clicking on “add application” in the upper right corner. Both of those links will take you to this page:

Screenshot of the Add Application menu showing the various form fields described below.

Give your application an Application ID, this is the name that The Things Network will use to distinguish it from the other applications. It can only contain lowercase letters, numbers, and dashes. The description field is for humans, so take a moment to write a sentence about what your app does. In this case, I’ve just written that it’s an example application. The EUI will be issued by the network, so there’s no need to type anything there. Finally, select the handler that you want your application to be registered to. Essentially, these are instances of the network server in different physical locations around the world. All applications will talk to all network servers, but to minimize latency, it’s best to select the handler closest to your gateway. I’m in Colorado, so I chose “ttn-handler-us-west,” which I assume is in California somewhere. Click the Add Application button and you’ll be taken to your freshly generated application console.

Screenshot of the Devices menu with a message in the center reading "0 registered devices", there is a small link in the top right-hand corner of the menu that reads "register device" with a small green circle-with-a-plus-sign icon next to it, as well as a link that reads "manage devices" with a small gear icon next to it.

Now that you’ve created an application, you can register a device to it. Scroll down to the Devices section of the application page and you will see your current device count (which is none) as well as options to register a device and to manage devices. Click on register device.

Screenshot of the Register Device menu showing the various form fields described below.

This form is pretty similar to the Register an Application page, but you have a little less to do. Give your device a Device ID, the same rules apply as did with the Application ID. Then click the little crossed arrows beside the Device EUI field, this lets TTN know that you want them to generate an EUI for you. Now just click on the Register button at the bottom of the form.

Screenshot of the Device Overview menu showing the various form fields described below.

And now you’ve been taken to your brand new device console. Under the section labeled Device Overview you’ll notice the Application ID and Device ID that you set earlier. Under Activation Method it will likely say “OTAA,” which stands for Over The Air Activation. This is a secure, transportable method of activating LoRaWAN devices, whereby the device uses a known application key to request new session keys whenever it wants to join the network. This is the preferred method for activating a production device, but for prototyping it’s usually easier to hard code the session keys into your device. In order to do this, we’ll need to set the activation method to “ABP” or Activation By Personalization. To do this, click on the Settings tab in the upper right-hand corner of the device page and you’ll be taken to the device settings menu. Partway down the page you should find an option to change the activation method.

Screenshot illustrating the Activation Method selection switch

Click on “ABP,” and then save your settings. When you return to the Overview page, you should now see some extra fields in the Device Overview:

Screenshot of the Device Overview menu showing the new form fields added.

We’ll need these numbers to program your Pro RF so leave this page up on your browser and let’s open up the Arduino IDE. It’s time to program the node!

Programming your Node

SparkX Pro RF - LoRa®-enabled 915MHz

SPX-14785
$24.95

We developed the SparkX Pro RF to be a small, lightweight LoRaWAN node. All you need to do is close two solder jumpers on the bottom of the board (labeled LoRaWAN) to connect the extra GPIO required by the LoRaWAN library. With that done, let’s get started!

Important! You'll need the Arduino IDE as well as SparkFun's Board Profiles in order to proceed. If this is your first time using Arduino, please review our tutorial on installing the Arduino IDE.

Get the LMIC-Arduino Library

For this example, we’re going to use a library written by Matthijs Kooijman which is a modified version of IBM’s LMIC (LoraMAC-in-C) library. You can download the library and install it manually from the GitHub Repository, or download it through the Arduino Library Manager. It’s currently called “IBM LMIC Framework” in the Arduino Library Manager, but that may change to “LMIC-Arduino” in the next release.

Once you have the library installed, you may need to edit the LMIC configuration file. Find your Arduino libraries folder and navigate to IBM_LMIC_framework/src/lmic/, you should find a file called config.h here, open it in any text editor and find the lines where CFG_us915 is defined. It should look like this:

language:c
//#define CFG_eu868 1
#define CFG_us915 1
// This is the SX1272/SX1273 radio, which is also used on the HopeRF
// RFM92 boards.
//#define CFG_sx1272_radio 1
// This is the SX1276/SX1277/SX1278/SX1279 radio, which is also used on
// the HopeRF RFM95 boards.
#define CFG_sx1276_radio 1

Since we’re using the 915MHz radio module, you need to make sure that the line #define CFG_us915 1 is not commented out and that the line #define CFG_eu868 1 is, by prepending // as shown above. Same goes for the radio type, we want #define CFG_sx1276_radio 1 and not #define CFG_sx1272_radio 1. with those changes made, save the config.h file and return to the Arduino IDE.

Edit the Example Code

With the library installed, you should now have the example code in your Examples menu. Let’s start with File>Examples>IBM LMIC framework>ttn-abp, this is the “ABP” or “Activation By Personalization” example code. In order to make it work with your application you’ll need to copy in some keys from the Device Overview page on your TTN Console, so flip back to the browser tab with the Device Overview page loaded up.

You’ll notice that, by default, the Network Session Key and App Session Key fields are obscured for security reasons. You can click the eye icon to show the code before copying it. Also, it will be easier to copy this into the example code if you click the <> button to show the codes in “C style”.

You will need to copy three separate numbers into your example code from this page: the Network Session Key, the App Session Key, and the Device Address. Here’s a diagram explaining which field on this page corresponds to which constant in the example code:

Screenshot of the Device Address, Network Session Key, and App Session Key fields from the Device Overview page with red arrows and text pointing out several labels and icons. An icon with a stylized eye on it un-obscures the Key fields which are obscured by default for security reasons. An icon with angle brackets on it expands the Key fields into "c style," adding hex prefixes to each value, separating them with commas, and enclosing them in curly brackets. The Device Address field is labeled DEVADDR. The Network Session Key field is labeled NWKSKEY. The App Session Key field is labeled "APPSKEY".

With these constants replaced in your example code, you can upload it to your Pro RF and watch for data to come pouring in!

Watch for Data

The example code is designed to send the string “Hello, World!” once every minute. This is actually a pretty large string for LoRaWAN and you shouldn’t allow the example code to run all day because it will eventually violate TTN’s Fair Usage Policy. But don’t worry too much about it, you can send a string the size of “Hello, World!” over 600 times in 24 hours before violating the policy.

To see the data arriving from your device, click on the Data tab in your device console. You should see a field labeled Application Data and after a minute or so, you’ll hopefully see your first packet come through:

Screenshot of the Application Data page showing a single packet received. The Payload is listed as "48 65 6C 6C 6F 2C 20 77 6F 72 6C 64 21"

Congratulations! You just sent your first LoRaWAN packet to The Things Network, your node device is working!

Decoding your Data

You may have noticed in the Application Data window that your payload is shown in raw bytes. In order to see “Hello, World!” encoded in ASCII, the way you sent it, you’ll need to decode the payload. The Things Network includes tools for doing this right in the console! Navigate to the Application Overview page for your application and click on the Payload Formats tab. This menu allows you to write functions which will be applied to all incoming packets for this application.

Screenshot of the Payload Formats page, showing a field labeled "decoder" where code can be typed. Some example code is in the field by default. It doesn't appear to return anything.

So let’s write our own decoder. We need to take the raw byte data and return a string that contains all of the characters corresponding to each byte. Take a look at this solution and then we’ll walk through it:

language:js
function Decoder(bytes, port) {

return {
    ASCII: String.fromCharCode.apply(null, bytes)
};

}

Decoder is a Javascript function that The Things Network has already set up for us, it takes two arguments called bytes, an array containing our payload, and port, the LoRaWAN “FPort” of the packet. FPort identifies the end application or service that the packet is intended for. Port 0 is reserved for MAC messages. We don’t need to know anything about the port number for our example.

We can return any value that we want from the Decoder function and it will appear alongside our payload in the Application Data window. In the example above, I’ve created a new property called “ASCII” which is equal to String.fromCharCode.apply(null, bytes). To break this down a little more, we’re returning a new String object called “ASCII,” and we’re using the Javascript apply() method to call fromCharCode() with the argument bytes and stuff the result into our new String. The fromCharCode() method simply steps through each byte in the array bytes (which, remember, contains our payload) and returns the ASCII character represented by that character code.

After copying the above code into your decoder function, scroll down and click the save payload functions button. Now return to the Application Data window and you should see that all packets received after the decoder function was changed now have a new property:

Another screenshot of the Application Data page, this time showing several packets received. The latest packet at the top of the list has a new field beside payload labeled "ASCII" with the value "Hello, world!"

Our packet has been decoded! Excellent!

Using your Data

Okay, so now you have data coming in to your TTN application but what do you do with it now? Well, you have a few options:

APIs

The most basic endpoints for interacting with The Things Network programmatically are the TTN Handler APIs or “application programming interfaces”. There are two APIs, the Data API and the Application Manager API. The Data API allows you to send and receive messages, making it the most useful for most applications. You can interact with this API using the MQTT protocol. The Application Manager API is available directly through HTTP and lets you manage applications, gateways, and devices. It’s much more powerful than the Data API and is mostly intended to allow endpoint applications to perform device management.

SDKs

The Things Network has also created several Software Developer Kits (SDKs) which allow you to program your application without having to interact directly with the low level APIs. SDKs are available for several popular languages.

Integrations

Finally, the easiest way to access your data and put it to work is with The Things Network’s various platform integrations. Integrations allow you to pass your application data directly to another platform such as AWS IoT, Cayenne, EVRYTHNG, or IFTTT. From there, you can use those platforms to interact with your data.

Example: IFTTT Integration

IFTTT Logo. The letters IFTTT drawn from apparently translucent rectangles. rectangles aligned vertically are blue and rectangles aligned horizontally are orange. Where they overlap, the colors combine to form dark purple squares.

As an example of how to use Integrations, let’s set up an IFTTT integration with our example application. If you’ve never used IFTTT, go ahead and create an account. IFTTT is a pretty cool platform that allows you to combine services from around the web to automate all kinds of tasks. These combinations of services are called “recipes” and they take the form of “If This happens, then make That happen,” and in our case, the This will be new data arriving in our application. First, head over to your TTN Application Console and click on the Integrations tab and then click “add integration”.

Find the “IFTTT Maker” integration in the list. It looks like this:

Screenshot of the IFTTT Maker integration icon on The Things Network. It contains a combination of the IFTTT and TTN icons and is labeled "IFTTT Maker v2.6.0 TheThingsInductries B.V."

Clicking on that block will take you to the “Add Integration” form for this integration. The form has 6 fields:

Screenshot of the Add Integration form. The fields in this form are described below.

Process ID

This is a name that TTN will use to keep track of this integration. You can name it whatever you want, I’m calling mine “my-new-integration”.

Event Name

This is the name of the IFTTT “recipe” that you want to trigger whenever the application receives new data. Go ahead and name this something, just remember what you named it so we can call your IFTTT recipe the same thing.

Key

This is your IFTTT Key. You can find this by going to the Maker Webhooks page on IFTTT and clicking on the Documentation button.

Value 1, Value 2, and Value 3

IFTTT Webhooks allow you to pass up to 3 values to your IFTTT recipe. In this case, let’s pass our decoded payload to IFTTT. To do this, we put the name of the property that we want to pass into the Value field, so type “ASCII” into Value 1.

Alright, take note of the Event Name that you set, click the Add integration button and let’s hop over to IFTTT. Get to the New Applet page and click on the +This in If +This Then That. You should now be looking at a list of all the services that IFTTT has triggers for… it’s a lot. Click the “Webhooks” service and choose the Receive a Web Request trigger. This is where you’ll enter the Event Name that we chose earlier when setting up the integration on TTN.

Screenshot of the "Receive a Web Request" trigger on IFTTT. It explains the way this trigger works as follows "This trigger fires every time the Maker service receives a web request to notify it of an event. For information on triggering events, go to your Maker service settings and then the listed URL (web) or tap your username (mobile)." Underneath, there is a field named "Event Name" in which I've typed "LoRaWAN". Underneath this field is a large button labeled "Create trigger"

Click on Create Trigger and you’ll be brought back to the Make an Applet page. Now click on +That to add an action for the trigger we just created. There are all kinds of triggers available for IFTTT, but let’s do something simple for the purpose of this tutorial. Click on the Email service and select the Send Me an Email action. This will send you an email at the address that you used to sign up for IFTTT every time that new data comes in on your TTN application. You can even edit the body of the email. Notice that Value 1, Value 2, and Value 3 are ingredients in the email. Wherever you see that ingredient, it will be replaced with the appropriate value. In our case, Value 1 will be replaced with the value of ASCII. Click on Create Action and then Finish to start your new applet running.

Now open up your email and plug in your Pro RF. After a few minutes, you should get an email from IFTTT!

Screenshot of an email with the subject line "The event named "LoRaWAN" occurred on the Maker Webhooks service". The body of the email reads "What: LoRaWAN When: July 5,1028 at 3:44PM Extra Data: Hello, world!"

Pretty. Darn. Cool.

This image is an invisible square but it's here so that I can ask you a favor if you're enjoying this tutorial using a screen reader. I'm trying to improve our site's accessibility, so I would love to hear your feedback about the image alt tags in this article. You can email me at nick.poole@sparkfun.com and please put the phrase "image tags" in the subject line. Thank you so much. Happy Hacking!


learn.sparkfun.com | CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

SparkFun Paper Circuit Kits

$
0
0

SparkFun Paper Circuit Kits a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t775

Introduction

Welcome to the world of paper circuits - creating electronic projects directly on paper using simple components. This guide will walk you through building a simple circuit using copper tape, a 5mm LED, and a 3V coin cell battery.

Design and build time: 5-10 minutes

SparkFun offers two kits designed specifically for this paper circuit project. The main difference between the two kits is that the Classroom Pack includes batteries, four LED color options, and some spare parts. If using the SparkFun Paper Circuits Kit, you will need to provide or purchase your own 3V CR2032 20mm coin cell battery to follow along and complete the project.

SparkFun Paper Circuits Kit

KIT-14655
$14.95
SparkFun Paper Circuits Classroom Pack

KIT-14715
$49.95

Materials and Tools

In your paper circuits kit, you will find a plastic bag that includes:

  • Printed paper circuit template
  • 12" piece of copper tape
  • Yellow 5mm LED
  • Binder Clip

You Will Also Need:

  • 3V CR2032 Coin Cell Battery (included in the Classroom pack)
  • Scissors
  • Hole Punch
  • Clear Tape
  • Decorating supplies (markers, pens, crayons) if you’d like to color in the finished project

Downloadable Templates

Your kit includes a printed template. If you would like to choose a different template or make more projects, you can also download and print a PDF.

Inside and outside of the included robot paper circuit template

Download Robot Template

Right-click the link or images below, and choose “Save Link As” to download the templates to your computer. Each file has the circuit template on one side and a design on the other. Print on 8 ½” x 11” cardstock paper and cut out individual template (6 total). You will only need one to make the project.

Underwater Template Preview

Download Underwater Template

Blank Template Preview

Download Blank Template

Suggested Reading

If you are brand new to working with electronics, here’s some helpful reading to check out:

What is a Circuit?

Every electrical project starts with a circuit. Don't know what a circuit is? We're here to help.

Light-Emitting Diodes (LEDs)

Learn the basics about LEDs as well as some more advanced topics to help you calculate requirements for projects containing many LEDs.

The Great Big Guide to Paper Circuits

Let's take a look at different materials we can use to combine paper crafting and electronics.

Create Copper Traces

Time to create a path for our electricity to flow through our circuit. In this project we will use copper tape wiring that connects each part of the circuit. Each template has numbered icons to help guide you in constructing the different parts of the circuit.

Take a look at the template and find the circle marked 1. Peel away a few inches of the paper backing from the copper tape and stick down along the shaded line to cover it.

Backing peeled away from copper tape

Pressing copper tape down onto line marked 1

This template includes a few turns - to keep a solid connection of copper around corners, we’ll be using a folding technique to press the tape into shape. Start by sticking the copper tape down until you reach the corner, then fold the tape backward on itself. Use a fingernail or pen to give it a good crease at the edge.

Bending copper tape backward at corner to create a crease

Then carefully move the tape down around the corner - you should see the fold forming - and press down flat against the paper. The neatness of the fold doesn’t matter that much, it will be covered by your pop up in the end.

Folding copper tape around corner

Corners got you confused? Watch how it is done here (watch full screen to see the process a little better):

Finally, cut the tape when you reach the end of the printed line.

Cutting copper tape

Repeat this process starting at the line marked 2.

Template will all copper tape placed

Now we are done creating our copper tape paths. If you have extra tape, you can discard or save for another project.

Prepare and Place LED

Now that we’ve created the path for electricity to follow in the circuit, it’s time to add a light-emitting diode (LED) that will turn on when we power the project. Look for the circle marked 3 and the yellow LED illustration for where to place it on the template.

LEDs

The template has an LED symbol on it which shows its wires - let’s check it out. LEDs are polarized, which means they need to be connected in a certain orientation to function. The LED has two wires coming out of its colored bulb - notice one is longer than the other - this is the positive (+) side of the LED. The shorter side is the negative (-). We will connect these on the + and - sides of our copper tape paths. There is also a flat side on the bulb itself; this is the negative side.

Image showing the two legs of an LED

Read more about LED polarity in our Light-Emitting Diodes (LEDs) Tutorial.

Light-Emitting Diodes (LEDs)

Learn the basics about LEDs as well as some more advanced topics to help you calculate requirements for projects containing many LEDs.

Bending the LED

We will need to do a little preparation in order for the LED to lay flat in our circuit. Using your fingers (or pliers), bend the longer wire (also known as its ‘leg’) of the LED flat. Be careful not to break the wire by bending back and forth over the same joint too many times.

Bending positive leg of LED

Bent postive leg of LED

Next, bend the shorter (-) leg of the LED flat as shown.

Bending negative leg of LED

Once all bending is complete, place the LED on a table or flat surface to make sure it sits flat and upright. If not, make any adjustments now.

LED with both legs bent outward and sitting flat on a table

Tape Down LED

Next, line up the positive leg of the LED with the copper tape marked + and the negative with -. Use clear tape over the leads to hold down to the copper. If you have trouble telling the sides apart, check the base of the LED bulb - the flat edge is the negative (-) side.

Taping clear tape over LED wire placed on copper tape on negative side

Taping clear tape over LED wire placed on copper tape on positive side

Close up photo of LED taped down onto copper tape

Punch Hole

Before finishing the project, punch a hole for the LED to go through. You can use a hole punch or carefully cut with scissors.

Using a hole punch on the template

Depending on how centered you placed the LED over the gap in the copper tape, you may need to slide or slightly move it. Simply peel up the clear tape and adjust to center the LED in the hole, then secure with some new tape. Fold the card over for a preview of where the LED will shine through on the template’s design.

Folding template over LED to check placement

Insert Battery

Once all the components are installed, it’s time to test our circuit by adding a battery. Place the battery inside the circle marked - with the labeled (marked + or with the battery name) facing up.

Placing battery with labeled side up on the template

Carefully fold along the dotted line so that the copper tape inside the + circle rests on top of your battery, making a connection. You should see your LED light up once the copper tape touches the battery. Flip your project over and push the LED through the hole you punched to see it shine through the design.

Folding top of template over battery

LED lighting up when folded template makes contact with the battery and completes the circuit

Secure the battery in the project using a binder clip. If you don’t have a binder clip, a large paper clip can also work.

Attaching binder clip to fold to hold battery in place

Finished project lighting up

Troubleshooting

  • If your LED isn’t lighting up - check the tape connections. Use your nails or a pencil to make sure the LED’s wires are being held down to the copper tape and making contact.
  • Check the wires of the LED - double check that they weren’t accidentally broken while bending them or if the LED is installed with the + side to - side.
  • Check the battery - make sure it is sandwiched firmly between the top and bottom copper tape lines and that the top copper is not accidentally touching the bottom of the battery.

Decorate and Customize

Decorate your project by coloring in the design or adding stickers. You can also make it a wearable badge by adding an adhesive pin to the back of the design. To make it easier to color on the paper, unclip the binder clip and remove the battery so the paper will lay flat on a table.

Coloring design on template with marker

If you have a spare binder clip, attach one to the other edge of the paper to create a stand for your artwork.

Using a second binder clip to create a standing artwork

You can also attach a magnet to create a fridge decoration or a pin pack to wear your project around.

Resources and Going Further

Here are some other paper circuit projects to try out:

Light-Up Valentine Cards

Light up your love with paper circuits - no soldering required!

The Great Big Guide to Paper Circuits

Let's take a look at different materials we can use to combine paper crafting and electronics.

LED Butterfly Pop Up Card

Craft an illuminated butterfly pop up card with copper tape, two LEDs, and a battery.
New!

SparkFun Paper Circuit Kits

Learn how to build a simple circuit using copper tape, a 5mm LED, and a 3V coin cell battery.

learn.sparkfun.com | CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

How to Use Remote Desktop on the Raspberry Pi with VNC

$
0
0

How to Use Remote Desktop on the Raspberry Pi with VNC a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t795

Introduction

If you like the idea of a headless computer setup for your Raspberry Pi (i.e. one without a keyboard, mouse, or monitor) but want access to the full graphical desktop, then you’re in luck! By using a Virtual Network Computing (VNC) program, you can access a remote desktop over the network!

For schools and individuals that need to use the full desktop for certain applications (Scratch, creating your own graphical interface, etc.), using a VNC client to access your Raspberry Pi might be the way to go.

Using VNC to remotely access the Raspberry Pi desktop

Using RealVNC to access the Raspberry Pi’s graphical desktop

The good news is that Raspbian (the recommended Raspberry Pi operating system) comes with RealVNC installed by default. The bad news is that we need to enable it using some other means.

Required Materials

To follow along with this tutorial, you will need a Raspberry Pi, power supply, and micro SD card. Note that no monitor, keyboard, or mouse is required!

Note: The Raspberry Pi Zero W should also work with this tutorial, if you want a smaller option for your project.

Optional Materials

All that being said, you can also use a keyboard, mouse, and monitor to enable the VNC server. Once you have enabled it, you will not need these accessories any more (unless you really want them).

SmartiPi Touch

PRT-14059
$24.95
8
Raspberry Pi LCD - 7" Touchscreen

LCD-13733
$64.95
35
Multimedia Wireless Keyboard

WIG-14271
$29.95
2

Suggested Reading

If you aren’t familiar with the following concepts, we recommend checking out these tutorials before continuing.

Serial Terminal Basics

This tutorial will show you how to communicate with your serial devices using a variety of terminal emulator applications.

Raspberry Pi 3 Starter Kit Hookup Guide

Guide for getting going with the Raspberry Pi 3 Model B and Raspberry Pi 3 Model B+ starter kit.

Getting Started with the Raspberry Pi Zero Wireless

Learn how to setup, configure and use the smallest Raspberry Pi yet, the Raspberry Pi Zero - Wireless.
Please note: If you have trouble seeing any of the images throughout this tutorial, feel free to click on it to get a better look!

Flashing the OS

The Raspberry Pi has several operating systems available for use, and beginners are often encouraged to use NOOBS to install the default Raspbian image. This guide will show you how to configure a headless version of Raspbian to be used with VNC. To do so, we’ll be following along with parts of the Headless Raspberry Pi Setup tutorial, but note that we’ll be using full Raspbian instead of Raspbian Lite, as we need the Linux X server that comes installed on the full version.

To start, download the latest version of Raspbian.

Download Latest Version of Raspbian

Note: This tutorial was created with Raspbian Stretch (version: June 2018). Using a different version may require performing different steps than what's shown in this tutorial. If you would like to download the June 2018 version of Raspbian, it can be found below.

Raspbian Stretch (version: June 2018) Download (ZIP)

To flash the image to your SD card, we recommend the program Etcher. Download and install it. Plug your SD card into your computer (using a microSD USB Reader if necessary), and run Etcher. Select your OS image file (no need to unzip it! just select your downloaded .zip file in Etcher), select your SD card reader, and click the Flash! button.

Using Etcher to flash an SD card

Enable VNC

You will need to interact with your Pi in order to turn on the VNC server. To do this, you have several options:

(Optional) Install RealVNC

By default, Raspbian should come with a VNC server (RealVNC) installed. If you are using another operating system, you might need to install RealVNC. With most flavors of Debian (e.g. Raspbian is built on top of Debian), you should be able to use apt-get to install RealVNC. In a terminal, enter the following:

language:shell
sudo apt-get update
sudo apt-get install real-vnc-server
sudo apt-get install real-vnc-client

Enable the VNC Server

You will need to go into the Raspberry Pi configuration tool to turn on the VNC server:

language:shell
sudo raspi-config

Select Interfacing Option, and then select VNC. On the next screen, select Yes, and press enter to save the changes.

Enable VNC on the Raspberry Pi

Feel free to make any other changes you might like, including setting a new password and changing the keyboard layout.

Back in the raspi-config homescreen, press right arrow twice to select Finish and press enter.

Use VNC Over a Local Network

If your host computer is on the same local network (e.g. connected to the same WiFi or Ethernet network), then you can make a direct VNC connection to your Raspberry Pi. This method has several up sides: it’s the easier option, does not require signing up for a RealVNC account, and can be done on a closed network (i.e. one not connected to the Internet). The down side is that you must be on the same network to access your Pi (i.e. physically connected or through a VPN). This is a known as a direct connection.

If you want to to access your Raspberry Pi over the Internet, then see the next section.

Still in your Raspberry Pi’s terminal, enter the following command:

language:shell
ifconfig

Copy down the Raspberry Pi’s IP address, which is given as a series of 4 numbers next to inet. If you are connected over WiFi, this will appear under the wlan0 settings. If you are connected over Ethernet, this will appear under the eth0 settings.

Find your Raspberry Pi's IP address

On your host computer, head to the RealVNC Viewer downloads page to download the VNC client (known as VNC Viewer) for your operating system. Install it, accepting all the defaults.

Open VNC Viewer. At the top address bar, enter the IP address of the Raspberry Pi (once again, make sure your host computer and Pi are on the same network!).

Connect to your Raspberry Pi from within the RealVNC VNC Viewer

Press enter, and click Continue when warned that “VNC Server not recognized.” You should be prompted with an Authentication window. If you did not change the login username and password for your Pi, your default login credentials are:

  • Username: pi
  • Password: raspberry
Heads up: it's highly recommended that you change your password! Anyone with access to your network could easily gain access to your Pi by trying the default username and password.

Once you successfully authenticate, you should be presented with your Raspberry Pi’s graphical desktop. Now, you can do everything remotely as if you were sitting in front of your Pi with a keyboard, mouse, and monitor! If you hover your mouse over the top part of the window, you should see a drop-down box appear, giving you access to the various RealVNC settings, including closing the session.

Raspberry Pi desktop in the VNC viewer

Use VNC Over the Internet

Using remote desktop on a local network is likely to offer a much faster and smoother experience, however, you can’t necessarily guarantee you will have access to that network directly. Luckily, RealVNC allows us to log in to our computer over the Internet!

The other good news is that we don’t have to go through the process of finding our Pi’s IP address.

Sign Up for a RealVNC Account

Note: Using RealVNC's cloud service means that we'll need to sign up for an account on their site. Also note that the cloud connection service is free for only non-commercial and educational purposes. See RealVNC's pricing guide for more details.

To start, sign up for an account (or sign in, if you already have one) on RealVNC’s site here. Head to your Account page, and click Activate under the Home version of VNC Connect.

Signing up for a RealVNC account

Enable VNC Cloud Connection on the Pi

Note: You will need to have access to the graphical desktop for your Raspberry Pi for this next step. This can include using a keyboard, mouse, and monitor, or it can mean directly connecting with VNC over a local network. Only the Enterprise edition of RealVNC will allow you to enable the VNC cloud connection via command line.

Assuming you have VNC enabled on the Pi, click on the VNC logo in the top-right portion of the desktop. This will open the RealVNC settings window. In the top-right part of that window, click on the properties button, and select Licensing….

Enabling cloud connection for a Raspberry Pi

Leave Sign in to your RealVNC account selected, and click Next.

Signing in to a RealVNC account on a Raspberry Pi

Enter your RealVNC email and password, and click Sign In. On the next screen, change the connectivity method to Direct and cloud connectivity.

Assigning the Raspberry Pi to be part of a RealVNC team

Click Next. Review the settings and click Apply. If you get a pop-up warning you that permissions were granted without asking for a password, click Close. On the next screen, click Done.

Remotely Control the Raspberry Pi

On your host machine, download and install the RealVNC viewer. Open the application, and click the Sign in button in the top-right. Enter your email and password, and click Sign in.

On the right side, you should see an address book (previously used connections) and something showing your “Team” (computers available for a VNC cloud connection). Click on your Team, and you should see your VNC-ready Raspberry Pi listed.

Finding your Raspberry Pi on the RealVNC Cloud

Double-click on your Raspberry Pi to connect to it. You should see a pop-up window explaining that the VNC server on your Raspberry Pi has been verified. Click Continue. You should be prompted with an Authentication window. If you did not change the login username and password for your Pi, your default login credentials are:

  • Username: pi
  • Password: raspberry
Heads up: it's highly recommended that you change your password! Anyone with access to your network could easily gain access to your Pi by trying the default username and password.

Once you have been authenticated, you should be presented with your Raspberry Pi’s desktop. If you hover of the top part of the window, a drop-down should appear, giving you access to various settings for RealVNC, including a button to close the session.

Raspberry Pi desktop in the VNC viewer

Another slick feature is the ability to control your Raspberry Pi from your smartphone or tablet! Download the VNC Viewer app from the iTunes store or Google Play. Open the app, sign in, and connect to your Raspberry Pi!

Remote desktop into a Raspberry Pi from a smartphone

Resources and Going Further

If you would like to dig deeper into the details of RealVNC, we recommend looking at its docs page.

While RealVNC comes pre-installed on Raspbian, there are other Linux-based VNC applications out there that you could try. Here are some alternatives:

If you don’t have any sort of network access for your Raspberry Pi, you can have your Pi host its own network by becoming a WiFi access point! This will allow you to connect to your Pi from another computer via SSH, VNC, etc. without relying on other networking equipment (e.g. routers).

Setting up a Raspberry Pi 3 as an Access Point

April 23, 2018

This guide will show you how to configure a Raspberry Pi as an access point and connect it to your local Ethernet network to share Internet to other WiFi devices.

Ready to develop some Python programs on your Pi? Our Getting Started guide will walk you through writing your own Python code to control hardware:

New!

Python Programming Tutorial: Getting Started with the Raspberry Pi

June 27, 2018

This guide will show you how to write programs on your Raspberry Pi using Python to control hardware.

Looking for some inspiring Raspberry Pi projects? We recommend checking out these tutorials:

Raspberry Pi Twitter Monitor

How to use a Raspberry Pi to monitor Twitter for hashtags and blink an LED.

Raspberry gPIo

How to use either Python or C++ to drive the I/O lines on a Raspberry Pi.

Raspberry Pi Zero Helmet Impact Force Monitor

How much impact can the human body handle? This tutorial will teach you how to build your very own impact force monitor using a helmet, Raspberry Pi Zero, and accelerometer!

Setting Up the Pi Zero Wireless Pan-Tilt Camera

This tutorial will show you how to assemble, program, and access the Raspberry Pi Zero as a headless wireless pan-tilt camera.

Using Flask to Send Data to a Raspberry Pi

In this tutorial, we'll show you how to use the Flask framework for Python to send data from ESP8266 WiFi nodes to a Raspberry Pi over an internal WiFi network.

Raspberry Pi Stand-Alone Programmer

This tutorial will show you how to use a headless Raspberry Pi to flash hex files onto AVR microcontrollers as a stand-alone programmer. It also tells the story about production programming challenges, how SparkFun came to this solution, and all the lessons learned along the way.

learn.sparkfun.com | CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado


Getting Started with Electroluminescent (EL) Wire

$
0
0

Getting Started with Electroluminescent (EL) Wire a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t355

Introduction

When it comes to creating projects that glow, nothing beats Electroluminescent wire (or EL wire for short). LEDs are fun and all, but EL wire is what all the hip kids are using. Whether you just want to light up your bicycle for an evening cruise or you’re creating an entire light up costume for Burning Man, EL wire is a great solution.

White EL Wire Glowing

In this tutorial, we will show you how to get started with EL wire. With the right parts, EL wire can be very easy to implement into any project!

Suggested Reading

If you aren’t familiar with the following concepts, we recommend checking out these tutorials before continuing. A general understanding of electricity is necessary to understand the theory behind EL Wire operation. EL Wire is powered with AC power. It’s not as dangerous as the electricity coming from you home outlets, but it does deserve the same respect. Depending on your setup, you will need to understand how a circuit works.

What is a Circuit?

Every electrical project starts with a circuit. Don't know what a circuit is? We're here to help.

What is Electricity?

We can see electricity in action on our computers, lighting our houses, as lightning strikes in thunderstorms, but what is it? This is not an easy question, but this tutorial will shed some light on it!

Series and Parallel Circuits

An introduction into series and parallel circuits.

Suggested Videos

Having a hard time seeing the videos? Try viewing them in a full screen mode.

How EL Works

EL wire (short for electroluminescent wire) is particularly useful for many reasons. Nevertheless, there are a few characteristics to keep in mind.

EL Wire, Tape, Panel, Chasing Wire, Bendable Wire Forms

It comes in many different, shapes, and sizes. You can get it in wire (the most typical shape), tape, panels, and bendable form. All of these can be cut to any shape or size to achieve the desired effect. Just be sure to reseal the ends that have been cut.

EL Panel - Red (10x10cm)

COM-10801
$14.95
1
EL Wire - Red 3m

COM-10191
$9.95
1
EL Tape - Red (1m)

COM-10796
$8.95
EL Wire - Red 3m (Chasing)

COM-12931
$9.95
1
Bendable EL Wire - Red 3m

COM-14703
$10.95

Colors

EL also comes in many different colors. Below are a few options for standard EL wire.

EL Wire - Blue 3m

COM-10195
$9.95
EL Wire - Red 3m

COM-10191
$9.95
1
EL Wire - White 3m

COM-10197
$9.95
EL Wire - Purple 3m

COM-10196
$9.95
EL Wire - Green 3m

COM-10194
$9.95
2
EL Wire - Yellow 3m

COM-10192
$9.95
2
EL Wire - Orange 3m

COM-10193
$9.95
1
EL Wire - Fluorescent-Green 3m

COM-10200
$9.95
EL Wire - Blue-Green 3m

COM-10199
$9.95
1

There are other options available for EL tape, panel, chasing wire, and bendable wire.

Click to Browse More Colors Options for Different EL Materials

Flexible

EL wire is flexible to a point. It allows you to sew it into clothing, attach it to moving parts, and bend it into any shape you desire. EL wire is more flexible than using LED strips but you will want to avoid sharp bends.

EL Wire Bending

EL Wire Bends on a DIY Neon Sign

EL tape and panels can also be used in e-textile projects. However,they are not as flexible as EL wire. They are better in projects when there is reinforced fabric to support the material.

EL Tape and Panels on ShirtsEL Panel Patches on a hat, bag, and jacket
EL Tape and Panels on ShirtsEL Panel Patches on a Hat, Bag, and Jacket

Low Power Consumption

EL requires less power to operate compared to using several LEDs for a project. EL is also great because it is cool to the touch, even after being on for hours. Hence why it is often seen in clothing applications. The EL does not heat up because, rather than heating an element to achieve an optical phenomenon, the glowing in EL comes from sending an electrical current through the material, which is comprised of semiconducting mixtures. The electrons flowing through the material create photons, which create the glowing that we see as a result.

White EL Wire Powered and Glowing

Let It Glow… In a Dark Room

While EL has a nice glowing effect, it can be hard to see in the daylight or when there is light in a room. It would be better to use EL in low light conditions for the best effect.

EL in Bright RoomEL in Low Lighting
EL in Bright RoomEL in Low Lighting

AC Power

Many people ask, “Can’t I just hook up EL wire to a battery?” The answer is, no! In order to operate EL wire properly, you must use AC (alternating current) power. This is similar to the power that comes out of your wall outlets at home, though outlets provide much more current than needed for EL wire. That’s where the inverter comes in!

EL Inverter - 12v

COM-10469
$14.95
3
EL Inverter - 3v

COM-10201
$9.95
5
EL Inverter - Battery Pack

COM-11222
$4.95
3
EL Inverter - 3v (Chasing)

COM-12933
$6.95
4

The battery pack included in the EL starter kit and the chasing inverter are not just a battery holder. It houses an inverter as well. This inverter takes the DC (direct current) power produced by the batteries and turns it into AC. If you listen very closely to the inverter battery pack while it’s on, you will hear a slight hum, similar to what you would hear if you stand under power lines or close to transformer boxes. Compared to the battery pack however, the 3V and 12V inverters do not have a battery holder build in.

With that, it’s important to mention that the AC power coming from the inverter is not enough to hurt or kill you. However, it is enough to give you a good shock. Be careful when handling EL products and any exposed circuits that are powered on the AC side. You can cut EL to any length or shape, but you must reseal the ends you cut. If you do not have an end cap for the EL wire, you can still seal the ends with hot glue or epoxy to seal cut wire. If you don’t reseal, you could end up getting a good jolt.

Anatomy of EL

EL consists of a few layers. Let's take a look at the anatomy of standard EL wire.

  • Colored, Clear PVC Sleeve– On the outside is a colored PVC sleeve. Depending on the manufacturer and color, this may be clear or translucent.
  • Clear PVC Sleeve– A second layer is yet another PVC sleeve. This sleeve is not as thick as the outer layer and is also clear.
  • Corona Wires– There are two thin wires that wrap around and extend to the end of the EL wire. These are very fine and can sometimes be referred to as angle wires. The wire pair is isolated from the center core.
  • Phosphor Coating– Applying AC power around the coating creates that nice glowing effect from the phosphor being excited. It also separates the corona wires and core.
  • Core Wire– At the center of EL wire is another wire.

On the left is a physical diagram of EL wire. On the right is a close up of white EL wire opened up. Regardless of the labels in the images, each component functions the same.

Anatomy of EL WireCloseup of Standard EL Wire
Image courtesy of LogiNevermore from Wikipedia: Electroluminescent WireCloseup of Standard EL Wire

Hardware Hookup - EL

Recommended Materials

At a minimum, you'll need the following to power EL. We will be using the following components to get started. You may not need everything though depending on what you have. Add it to your cart, read through the guide, and adjust the cart as necessary.

Depending on your setup, you may also need the following depending on the inverter:

  • Wires(Optional)– Depending on your setup and inverter being used, you will need wires.
  • Insulation(Optional)– Electrical tape, heat shrink, hot glue, or epoxy to seal the exposed pins and wires connected to the AC side.

EL Inverter - Battery Pack

Using the EL is about as simple as it gets when using the EL inverter battery pack.

EL Inverter - Battery Pack

COM-11222
$4.95
3

Take the battery cover off by sliding in the direction indicated on the pack. Place your two AA batteries in the battery pack inverter, and put the cover back on. Plug in the male JST connector from your EL wire into one of the two female JST connectors on the inverter battery pack. Make sure there is a solid connection between the two.

Inserting JST Connector into Socket

Press the button on the case and your EL wire should illuminate. Press it again for a slow blinking effect, and press it once more for a fast blink. This inverter pack allows you to connect two EL products of your choice at a time. You can mix and match colors as well as shapes. You could have a red panel with blue wire, green tape with a pink wire, or two yellow and purple wires. The possibilities are endless!

EL Wire Powered

EL Inverter - 3V

We also have a 3V inverter. The wires are terminated at the end with JST PH connectors. These require a little bit more work to get started since they are designed to plug directly into our EL Escudo Dos or EL Sequencer. They are ideal for small EL displays.

EL Inverter - 3v

COM-10201
$9.95
5

This particular EL inverter accepts an input (on the red/black pair of wires for +Vcc and GND, respectively) anywhere from 2.5V-4.2V, so you can use them with batteries. Once powered, it can output up to 110VAC (on the black/black pair of wires) to drive EL wire.

You can drive EL wires with them directly without using an EL Escudo Dos and EL Sequencer. However, you may need to re-terminate them, make an adapter, or possibly regulate the voltage down from your power supply. Below is a simple connection if you are just powering one strand for an installation using a 5V USB power supply, 3.3V FTDI to regulate the voltage down, M/M jumper wires, and one strand EL wire. The pins of the JST connector are small enough to be inserted into a JST connector.

Lighting Up One Strand with a 3V Inverter

Having a hard time seeing the circuit? Click on the image for a closer look.

You can even connect two strands together by making a parallel connection. For testing purposes, the circuit was placed on a breadboard. It should not matter what color of wire is connecting on the inverter's output since it is AC. The wire colors were connected together for consistency.

Lighting Up Two Strands in Parallel with a 3V Inverter

Having a hard time seeing the circuit? Click on the image for a closer look.

When you are done testing and integrating the EL wire in a project, make sure to seal any exposed EL wire or connections on the AC side. Electrical tape is a good option to secure the connection and insulate any exposed pins should you decide to continue using M/M jumper wire between an inverter and EL wire.

Insulating Exposed Pins on the AC Side with Electrical Tape

EL Inverter - 12V

When using several strands of EL, you may want to consider using the 12V inverter. The inverter consists of a barrel jack connector and a pair of wires terminated with a JST PH connector. These are ideal for the biggest, brightest display possible!

EL Inverter - 12v

COM-10469
$14.95
3

This particular EL inverter accepts an input via the 5.5mm x 2.1mm barrel jack connector. Simply connect a power source with a center positive barrel jack connector. The output (red/black pair or wires) was designed to connect to a mating JST connector on the EL Escudo Dos or EL Sequencer board. There is also a small switch on the side which allows you to switch between “on”, “blink”, and “off” settings.

Similar to the 3V inverter. You can drive EL wires with the 12V inverter directly. However, you may need to re-terminate them or make an adapter. Below is a simple connection if you are just powering one strand for an installation using a 12V power supply, M/M jumper wires, and one strand EL wire.

Lighting Up One Strand with the 12V Inverter

Having a hard time seeing the circuit? Click on the image for a closer look.

Again, you can connect two strands together by making a parallel connection. For testing purposes, the circuit was placed on a breadboard. It should not matter what color of wire is connecting on the inverter’s output since it is AC. The wire colors were connected together for consistency.

Lighting Up Two Strands with 12V Inverter

Having a hard time seeing the circuit? Click on the image for a closer look.

Remember to seal any exposed EL wire or connections on the AC side when you are done.

Insulating Exposed Pins on the AC Side with Electrical Tape

How EL Chasing Wire Works

EL chasing wires work in a similar fashion to standard EL wire. Instead of one core wire, there are three thin wires coated in phosphor. Basically, you can think of three strands of standard EL wire smashed into one EL chasing wire. As a result, EL chasing wire requires 4x connections: three for each strand and one for common ground. By sequencing each strand inside by turning them on and off, we have a cascading or “chasing” effect.

EL Chasing Wire Lit Up

Let's take a look at the anatomy of EL chasing wire.

  • Colored, Clear PVC Sleeve– On the outside is a colored PVC sleeve. Depending on the manufacturer and color, this may be clear or translucent.
  • Clear PVC Sleeve– A second layer is yet another PVC sleeve. This sleeve is not as thick as the outer layer and is also clear.
  • Corona Wires– There are two thin wires that wrap around and extend to the end of the EL wire. These are very fine and can sometimes be referred to as angle wires. The wire pair is isolated from the center core wires.
  • Phosphor Coating– Applying AC power around the coating creates that nice glowing effect from the phosphor being excited. It also separates the corona wires and core wires.
  • Core Wires– At the center of EL chasing wire are three thin wires coated and twisted at the center.

Labeled EL Chasing Wire Close Up

If you compare the size of EL standard wire and chasing wire, you will not notice the difference until you are modifying and repairing the core wire. As you can see, EL chasing wire uses three thin wires at the core.

Comparison of Standard EL Wire and EL Chasing Wire

Hardware Hookup - EL Chasing

EL Inverter - 3v (Chasing)

The EL chasing inverter works similar to the 3V EL inverter battery pack.

EL Inverter - 3v (Chasing)

COM-12933
$6.95
4

Simply take the battery cover off by sliding it off, insert two AA batteries for power, slide the cover back on, and connect one EL chasing wire to the 4 pin mating connector. Press the button to turn on and begin sequencing the three strands of EL wire in one. Continue pressing the button to cycle through the three modes: slow, fast, and super-duper fast chase!

EL Chasing Wire Lit Up

EL Wire Extension Cables

Need just a little more length in between your JST connector and EL? There are few methods to extend the wires to your EL. One method is splicing the wires leading to the EL material. Below is an example of extending the wires to an EL panel but it can be used for wires leading to any EL. For more information about how to extend the wires, head over to the Pokémon Go Patches with EL Panels: Adding EL Extension Cables tutorial.

Spliced Wires to Extend Wires to EL

Spliced Wires to Extend Wires to EL

Controlling and Sequencing EL

It’s as simple as that. However, if you are looking for more of a challenge, fear not. EL projects can become very complex, very quickly. You may have noticed that the effects are somewhat limited on the inverter, and both products hooked up behave the same when plugged into it.

Let’s say you want one color to blink while the other stays solid. You could purchase another inverter battery pack, or you could get one of the many boards out there that are specifically designed to work with EL products. SparkFun carries two such boards, the EL Sequencer and the EL Escudo Dos. Both of these boards are designed to handle many EL products hooked up to them at once, and there are many different effects you can create with both.

SparkFun Animated Flame with EL Wire

SparkFun Animated Flame from Setting Up an EL Display with the EL Escudo Dos Tutorial

For more information, check out the hookup guide on those products.

EL Sequencer/Escudo Dos Hookup Guide

December 3, 2015

A basic guide to getting started with the SparkFun EL Sequencer and Escudo Dos to control electroluminescence (EL) wire, panels, and strips.

Resources and Going Further

Thanks for checking out our tutorial! Now that you’ve successfully got your EL wire/panel/strip up and running, it’s time to incorporate it into your own project! For more information, check out the resources below:

Need some inspiration for your next project? Check out some of these related tutorials:

ELasto-Nightlight

Fear the dark no longer with this ELastoLite nightlight.

EL Sequencer/Escudo Dos Hookup Guide

A basic guide to getting started with the SparkFun EL Sequencer and Escudo Dos to control electroluminescence (EL) wire, panels, and strips.

Heartbeat Straight Jacket

An EL project that displays one person's heartbeat on another person's costume.

Prototype Wearable LED Dance Harness

A project tutorial to add an extra effect for dancers performing a choreographed piece. The harness can be added quickly under a costume.

Looking for more ideas, check out these related blog posts:

Or check out this additional project tutorials for more information.


learn.sparkfun.com | CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

Qwiic MUX Hookup Guide

$
0
0

Qwiic MUX Hookup Guide a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t787

Introduction

PCA9548A and TCA9548A? The SparkX version of the Qwiic Mux breakout used the PCA9548A. The SparkFun red version uses the TCA9548A. Overall, both should be functionally the same with a few minor differences.

The Qwiic Mux - TCA9548A enables communication with multiple I2C devices that have the same address. The IC is simple to interface with and also has 8 configurable addresses of its own, this allows you to put 64 I2C buses on a single bus!

SparkFun Qwiic Mux Breakout - 8 Channel (TCA9548A)

BOB-14685
$9.95

In this tutorial we’ll go over how to talk to sensors on different channels of your MUX. The application of this is pretty straightforward so things won’t get too fancy.

Required Materials

To get started, you’ll need a microcontroller to, well, control everything.

SparkFun RedBoard - Programmed with Arduino

DEV-13975
$19.95
34
SparkFun ESP32 Thing

DEV-13907
$19.95
55
Raspberry Pi 3

DEV-13825
$39.95
92
Particle Photon (Headers)

WRL-13774
$19.00
28

Now to get into the Qwiic ecosystem, the key will be one of the following Qwiic shields to match your preference of microcontroller:

SparkFun Qwiic Shield for Arduino

DEV-14352
$5.95
SparkFun Qwiic HAT for Raspberry Pi

DEV-14459
$4.95
1
SparkFun Qwiic Shield for Photon

DEV-14477
$4.95

You will also need a Qwiic cable to connect the shield to your MUX, choose a length that suits your needs.

Qwiic Cable - 100mm

PRT-14427
$1.50
Qwiic Cable - 200mm

PRT-14428
$1.50
Qwiic Cable - 500mm

PRT-14429
$1.95
Qwiic Cable - 50mm

PRT-14426
$0.95

Tools

Depending on your setup, you may need a soldering iron, solder, and general soldering accessories.

Solder Lead Free - 100-gram Spool

TOL-09325
$7.95
7
Weller WLC100 Soldering Station

TOL-14228
$44.95

Suggested Reading

If you aren’t familiar with our new Qwiic system, we recommend reading here for an overview. We would also recommend taking a look at the following tutorials if you aren’t familiar with them.

I2C

An introduction to I2C, one of the main embedded communications protocols in use today.

Qwiic Shield for Arduino & Photon Hookup Guide

Get started with our Qwiic ecosystem with the Qwiic shield for Arduino or Photon.

Hardware Overview

What is the difference between the PCA9548A and TCA9548A? Very little. PCA is made by NXP, TCA is made by TI. PCA can operate from 2.3 to 5.5V, TCA can operate from 1.65 to 5.5V. Everything else is identical.

Let’s look over a few characteristics of the TCA9548A so we know a bit more about how it behaves.

CharacteristicRange
Operating Voltage1.65V - 5.5V
Operating Temperature-40 - 85&deg C
I2C Address0x70 (default) up to 0x77 (see below table)

The Qwiic input for the Mux is located at the top-center of the board, labeled Main, highlighted in the image below. The outputs are then located on the left and right sides of the board and are numbered accordingly.

Main Qwiic Port

The onboard reset pin, highlighted below, is an active low input. Pulling reset low for at least 6 ns will restart the multiplexer.

Reset Pin

The Qwiic Mux also allows you to change the last 3 bits of the address byte, allowing for 8 jumper selectable addresses if you happen to need to put more than one Mux on the same I2C port. The address can be changed by adding solder to any of the three ADR jumpers, shown in the image below.

Address Jumpers

The below table shows which jumpers must be soldered together to change to the corresponding address.

I2C AddressADR2ADR1ADR0
0x70OpenOpenOpen
0x71OpenOpenClosed
0x72OpenClosedOpen
0x73OpenClosedClosed
0x74ClosedOpenOpen
0x75ClosedOpenClosed
0x76ClosedClosedOpen
0x77ClosedClosedClosed

If you want to remove the pullup resistors from the I2C bus, simply remove the solder from the jumper highlighted in the below image.

Pullup Jumper

Hardware Assembly

If you haven’t yet assembled your Qwiic Shield, now would be the time to head on over to that tutorial.

Qwiic Shield for Arduino Photon Hookup Guide

With the shield assembled, SparkFun’s new Qwiic environment means that connecting the mux could not be easier. Just plug one end of the Qwiic cable into the Qwiic multiplexer breakout, the other into the Qwiic Shield of your choice and you’ll be ready to upload a sketch and figure out just how all those address sharing sensors are behaving. It seems like it’s too easy to use, but that’s why we made it that way!

Mux Connected to Shield

Example Code

Note: This example assumes you are using the latest version of the Arduino IDE on your desktop. If this is your first time using Arduino, please review our tutorial on installing the Arduino IDE. If you have not previously installed an Arduino library, please check out our installation guide.

SparkFun has written some example code to enable and disable ports on the Qwiic Mux. Go ahead and download this example code here.

Qwiic Mux Example (ZIP)

Additionally, you will need to install the MMA8452Q Arduino library if you are using two MMA8452Q accelerometers. First, you’ll need the Sparkfun MMA8452Q Arduino library. You can obtain these libraries through the Arduino Library Manager. Search for Sparkfun MMA8452Q Accelerometer by Jim@SparkFun Electronics to install the latest version. If you prefer downloading the libraries from the GitHub repository and manually installing it, you can grab them here:

Download Sparkfun MMA8452Q Accelerometer (ZIP)

Arduino Example Example1-BasicReadings.ino

Opening Example1-BasicReadings will open two tabs in the Arduino IDE, the first example, and also Mux_Control. Let’s take a look under the hood of Mux_Control to get an idea of what’s going on. There are two functions here, boolean enableMuxPort(byte portNumber) and boolean disableMuxPort(byte portNumber) which is pretty much all we need to specify which channels we’d like to talk to on the Mux. If we have a sensor on channel 0, we simply call enableMuxPort(0) to open that channel on the multiplexer. Then we’ll take whatever reads and perform whatever actions we’d like to the sensor on that channel. Once finished, we have to call disableMuxPort(0) to close communication on that channel so we don’t accidentally perform actions on the sensor on that channel. The below example code shows how to read from two MMA8452Q accelerometers.

language:c
#include <Wire.h>
#include <SFE_MMA8452Q.h> //From: https://github.com/sparkfun/SparkFun_MMA8452Q_Arduino_Library

MMA8452Q accel;

#define NUMBER_OF_SENSORS 2

void setup()
{
  Serial.begin(9600);
  Serial.println("Qwiic Mux Shield Read Example");

  Wire.begin();

  //Initialize all the sensors
  for (byte x = 0 ; x < NUMBER_OF_SENSORS ; x++)
  {
    enableMuxPort(x); //Tell mux to connect to port X
    accel.init(); //Init the sensor connected to this port
    disableMuxPort(x);
  }

  Serial.println("Mux Shield online");
}

void loop()
{
  for (byte x = 0 ; x < NUMBER_OF_SENSORS ; x++)
  {
    enableMuxPort(x); //Tell mux to connect to this port, and this port only

    if (accel.available())
    {
      accel.read();

      Serial.print("Accel ");
      Serial.print(x);
      Serial.print(": ");
      Serial.print(accel.cx, 2);
      Serial.print("");
      Serial.print(accel.cy, 2);
      Serial.print("");
      Serial.print(accel.cz, 2);
      Serial.print("");

      Serial.println(); // Print new line every time.
    }

    disableMuxPort(x); //Tell mux to disconnect from this port
  }

  delay(1); //Wait for next reading
}

With the example provided, you should be able to read two I2C sensors with the same address on the same bus! Try opening up the Arduino Serial Monitor set to 9600 baud in order to read the sensor values.

Resources and Going Further

Now that you’ve successfully got your Qwiic mux listening to all of those concurrent addresses, it’s time to incorporate it into your own project!

For more information, check out the resources below:

Need even more inspiration for your next project? Check out some of these related tutorials:

CCS811/BME280 (Qwiic) Environmental Combo Breakout Hookup Guide

Sense various environmental conditions such as temperature, humidity, barometric pressure, eCO2 and tVOCs with the CCS811 and BME280 combo breakout board.

Qwiic HAT for Raspberry Pi Hookup Guide

Get started interfacing your Qwiic enabled boards with your Raspberry Pi. This Qwiic connects the I2C bus (GND, 3.3V, SDA, and SCL) on your Raspberry Pi to an array of Qwiic connectors.

Qwiic GRID-Eye Infrared Array (AMG88xx) Hookup Guide

The Panasonic GRID-Eye (AMG88xx) 8x8 thermopile array serves as a functional low-resolution infrared camera. This means you have a square array of 64 pixels each capable of independent temperature detection. It’s like having thermal camera (or Predator’s vision), just in really low resolution.
New!

Qwiic Flex Glove Controller Hookup Guide

Is your finger bent? is your finger straight? The Qwiic Flex Glove controller board will answer this age old question for you.

learn.sparkfun.com | CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

Qwiic Flex Glove Controller Hookup Guide

$
0
0

Qwiic Flex Glove Controller Hookup Guide a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t785

Introduction

Flex sensors are great for telling how bent something is in a project, but we’ve been running into issues with durability when using them in wearable applications like gloves. The Qwiic Flex Glove Controller isolates the weak point to allow for more permanent flex sensor applications. The board has an onboard ADS1015 ADC to I2C so we can get a whole bunch of analog inputs without touching our microcontroller’s ADC pins.

SparkFun Qwiic Flex Glove Controller

SEN-14666
$39.95

In this hookup guide, we’ll figure out how to pull values from our fingers as well as calibrate the sensor for our range of motion. We’ll also cover recommended placement and installation to implement these into gloves.

Required Materials

To get started, you’ll need a microcontroller to, well, control everything.

SparkFun RedBoard - Programmed with Arduino

DEV-13975
$19.95
34
SparkFun ESP32 Thing

DEV-13907
$19.95
55
Raspberry Pi 3

DEV-13825
$39.95
92
Particle Photon (Headers)

WRL-13774
$19.00
28

Now to get into the Qwiic ecosystem, the key will be one of the following Qwiic shields to match your preference of microcontroller:

SparkFun Qwiic Shield for Arduino

DEV-14352
$5.95
SparkFun Qwiic HAT for Raspberry Pi

DEV-14459
$4.95
1
SparkFun Qwiic Shield for Photon

DEV-14477
$4.95

You will also need a Qwiic cable to connect the shield to your sensor, choose a length that suits your needs.

Qwiic Cable - 100mm

PRT-14427
$1.50
Qwiic Cable - 200mm

PRT-14428
$1.50
Qwiic Cable - 500mm

PRT-14429
$1.95
Qwiic Cable - 50mm

PRT-14426
$0.95

If you don’t have a sewing needle, we’d recommend grabbing one if you’re trying to add these flex sensors to some gloves.

Needle Set

TOL-10405
$1.95

Suggested Reading

If you aren’t familiar with our new Qwiic system, we recommend checking out our overview:

WHAT IS QWIIC?

We would also recommend taking a look at the hookup guide for the Qwiic Shield if you haven’t already. Brushing up on your skills in I2C is also recommended, as all Qwiic sensors are I2C.

I2C

An introduction to I2C, one of the main embedded communications protocols in use today.

Serial Terminal Basics

This tutorial will show you how to communicate with your serial devices using a variety of terminal emulator applications.

Qwiic Shield for Arduino & Photon Hookup Guide

Get started with our Qwiic ecosystem with the Qwiic shield for Arduino or Photon.

You’ll also most likely want to sew these boards into a wearable project, so if you’ve never picked up a needle and thread before, we’d recommend checking out a how-to on hand sewing.

Hardware Overview

Let’s look over a few characteristics of the ADS1015 so we know a bit more about how our glove controller behaves.

CharacteristicRange
Operating Voltage2.0V - 5.5V
Operating Temperature-40&degC - 125&degC
Resolution12 bit
Sample Rate128 Hz - 3.3 kHz
Current Consumption150 &microA (Typ.)
I2C Address0x48 (default), 0x49, 0x4A, 0x4B

Pins

The characteristics of the available pins on the magnetometer are outlined in the table below.

Pin LabelPin FunctionInput/OutputNotes
3.3VPower SupplyInputShould be between 2.2V - 3.6V
GNDGroundInput0V/common voltage.
SDAI2C Data SignalBi-directionalBi-directional data line. Voltage should not exceed power supply (e.g. 3.3V).
SCLI2C Clock SignalInputMaster-controlled clock signal. Voltage should not exceed power supply (e.g. 3.3V).

Optional Features

The Qwiic Flex Glove controller has onboard I2C pull up resistors, which can be removed by removing the solder from the jumper highlighted below. Only remove this solder if you are using your own pullups on the I2C lines.

I2C Pullup

The I2C address of the board can be changed using the jumpers on the back of the board. The address selection pin is connected to the center pad of each jumper, the below table shows the addresses available when the address selection pin is tied to each of the 4 available pads.

PinAddress
GND0x48 (Default)
VCC0x49
SDA0x4A
SCL0x4B

The location of the jumpers is shown in the below image.

Address Jumpers

The holes in the bottom corners of the board are used for sewing the board into the gloves of your choice.

Sewing holes

Make sure you don’t crease the flex sensors as this will break the sensor!

Hardware Assembly

If you haven’t yet assembled your Qwiic Shield, now would be the time to head on over to that tutorial.

Qwiic Shield for Arduino Photon Hookup Guide

With the shield assembled, SparkFun’s new Qwiic environment means that connecting the sensor could not be easier. Just plug one end of the Qwiic cable into the Flex Glove Controller breakout, the other into the Qwiic Shield of your choice and you’ll be ready to upload a sketch and figure out how bent your fingers are. It seems like it’s too easy to use, but that’s why we made it that way!

Connected Flex Sensor

You may want to integrate this board into some gloves, after all, that’s what it was originally designed for. If you’re looking to get sensors on 8 fingers, you’ll need 4 glove boards, and if you have 4 boards on the same IsC bus, you’ll need to use every address available to the ADS1015. So get started by changing the addresses of your boards so no two boards share the same address.

Now we want to attach our boards to our gloves. We’ve found it best to sandwich the board between two layers of gloves to keep the sensor flush with the finger. To accomplish this, we’ll sew the board to the outer layer of the inner glove. First, lay the glove out flat and place the board on the glove so that the ends of the flex sensors reach the tips of the fingers.

Sensor Laid on Glove

Once you have the sensor laid out on the glove, take a marker and mark the point where the sewing hole touches the glove.

Mark Sewing Points

Now simply sew the points to the available mounting holes on the sensor, The finished product should look like the below glove.

Glove put together

Now it’s time to hide the circuitry under a second glove. Go ahead and put the just the fingers of the second glove on, then slip the flex sensor down the gap between the the two layers of fabric. Sensors are shown at various states of this process in the image below.

Adding glove

Now just plug Qwiic cables to connect both boards together, then plug one board into your microcontroller so we can get readings from the glove.

Library Overview

Note: This example assumes you are using the latest version of the Arduino IDE on your desktop. If this is your first time using Arduino, please review our tutorial on installing the Arduino IDE. If you have not previously installed an Arduino library, please check out our installation guide.

Before we get into getting data from our flex sensors, let’s look at the available functions in the library. We’ve written a library to control the flex sensors. You can snag this library through the Arduino Library Manager. Search for SparkFun ADS1015 Arduino Library and you should be able to install the latest version. If you prefer manually downloading the libraries from the GitHub repository, you can grab them here:

Download the SparkFun ADS1015 Arduino Library (ZIP)

Let’s get started by looking at the functions that set up the flex controller.

Setup and Settings

  • boolean begin(uint8_t deviceAddress = BNO080_DEFAULT_ADDRESS, TwoWire &wirePort = Wire);— By default use the default I2C address and use Wire port. Otherwise, pass in a custom I2C address and wire port.

  • uint16_t getAnalogData(uint8_t channel);— Returns the uncalibrated analog value from the sensor.

  • float getScaledAnalogData(uint8_t channel);— Returns a value between 0 and 1 based on calibration. Won’t work properly without first running calibrate()
  • void calibrate();— Used to calibrate the sensor and map the flexible range to values given by the user. While running calibration, simply flex each sensor to the minimum and maximum that it will be used in your project.

  • void setMode(uint16_t mode);— Set mode of the sensor. Mode 0 is continuous read mode, mode 1 is single-shot

  • uint16_t getMode();— Get’s the read mode of the ADS1015.
  • getCalibration(uint8_t channel, bool hiLo)— Get the high or low calibration value for a certain channel. if hiLo is true, getCalibration() will return the high calibration for the given channel.
  • setCalibration(uint8_t channel, bool hiLo, uint16_t value)— Sets the high or low calibration value of a channel without using the automatic calibration function. Allows for manual calibration.
  • resetCalibration()— Resets the calibration to 0.

  • void setGain(uint16_t gain);— Pass in different values for different gains

  • uint16_t getGain();— Get’s the gain of the ADS1015. This will return 16-bit hex value. The values and their corresponding gains are listed below.

    • 0x0E00: &pm; 0.256V
    • 0X0000: &pm; 6.144V
    • 0X0200: &pm; 4.096V
    • 0X0400: &pm; 2.048V
    • 0X0600: &pm; 1.024V
    • 0X0800: &pm; 0.512V
    • 0X0A00: &pm; 0.256V
  • void setSampleRate(uint16_t sampleRate);— Sets the sample rate for the ADS1015, pass in the below 16-bit values to change to the corresponding sample rate.

    • 0X0000: 128 Hz
    • 0X0020: 250 Hz
    • 0X0040: 490 Hz
    • 0X0060: 920 Hz
    • 0X0080: 1600 Hz
    • 0X00A0: 2400 Hz
    • 0X00C0: 3300 Hz
  • uint16_t getSampleRate();— Returns the sample rate according to the above list of sample rates.

Example Code

Now that we know how our library works, let’s go ahead and get started pulling values from our flex sensors.

Example 1 - Basic Readings

To get started with the first example, open up File>Examples>SparkFun ADS1015 Arduino Library>Example1_BasicReadings. In this example, we begin by creating an ADS1015 object called fingerSensor and then initializing our sensor object in the setup() loop. We then get the values from each finger by looping through and reading each channel on the ADS1015. The code for this is shown below.

language:c
#include <SparkFun_ADS1015_Arduino_Library.h>

ADS1015 fingerSensor;

void setup() {

  Wire.begin();
  Serial.begin(115200);

  if (fingerSensor.begin(Wire, 100000, ADS1015_ADDRESS_GND) == false) {
     Serial.println("Device not found. Check wiring.");
     while (1);
  }

}

void loop() {  
  uint16_t data;
  for (int finger = 0; finger < 2; finger++) {
    data = fingerSensor.getAnalogData(finger);
    Serial.print(finger);
    Serial.print(": ");
    Serial.print(data);
    Serial.print(",");
  }
  Serial.println();
}

Uploading this sketch and opening the Serial Monitor to 115200 bps will yield an output somewhat like the below image.

Example 1 Output

Single Sensor Output - click the image for a closer look

Example 2 - Setup hand

In this example, we’ll see how to setup an entire hand of flex sensors. To get started with this example, open up File>Examples>SparkFun ADS1015 Arduino Library>Example2_SetupHand. In this example, we create two ADS1015 objects, naming them indexSensor and pinkySensor to correspond with their locations on the glove. We also create an array with 4 spots to hold the data for the hand called hand. We then populate hand with values from each sensor. The code that accomplishes this is shown below.

language:c
#include <SparkFun_ADS1015_Arduino_Library.h>

ADS1015 pinkySensor;
ADS1015 indexSensor;
uint16_t hand[4] = {0, 0, 0, 0};

void setup() { 
  Wire.begin();
  Serial.begin(115200);

  if (pinkySensor.begin(Wire, 100000, ADS1015_ADDRESS_SDA) == false) {
     Serial.println("Pinky not found. Check wiring.");
     while (1);
  }
  if (indexSensor.begin(Wire, 100000, ADS1015_ADDRESS_GND) == false) {
     Serial.println("Index not found. Check wiring.");
     while (1);
  }  
}

void loop() {  
  uint16_t data;
  for (int finger = 0; finger < 2; finger++) {
    hand[finger] = indexSensor.getAnalogData(finger);
    hand[finger + 2] = pinkySensor.getAnalogData(finger);
  }
  for (int finger = 0; finger < 4; finger++)
  {
    Serial.print(finger);
    Serial.print(": ");
    Serial.print(hand[finger]);
    Serial.print("");
  }
  Serial.println();
}

Uploading this sketch and opening the Serial Monitor to 115200 bps will yield an output somewhat like the below image.

Serial monitor output for full glove

Full Glove Output - click the image for a closer look

Example 3 - Calibration

The second example will show us how to calibrate our flex sensor so we get 0 when our finger is closed and 1 when it is open. To get started, open up File>Examples>SparkFun ADS1015 Arduino Library>Example3_Calibration. In this example we will calibrate our sensor’s maximum and minimum values in order to find the range for our sensor.

language:c
#include <SparkFun_ADS1015_Arduino_Library.h>
#include <Wire.h>

ADS1015 fingerSensor;

void setup() {

  Wire.begin();
  Serial.begin(115200);

  if (fingerSensor.begin(Wire, 100000, ADS1015_ADDRESS_GND) == false) {
     Serial.println("Device not found. Check wiring.");
     while (1);
  }
  Serial.println("Calibrating, send 'e' when finished");
}

void loop() {
  uint8_t incoming;
  do
  {
    fingerSensor.calibrate();

    if(Serial.available())
    {
       incoming = Serial.read();
    }
  } while (incoming != 'e');
  Serial.println("Calibrated");

  for (int channel; channel < 2; channel++)
  {
    Serial.print("Channel ");
    Serial.print(channel);
    Serial.print(": ");
    for (int hiLo = 0; hiLo < 2; hiLo++)
    {
      switch (hiLo)
      {
        case 0:
        Serial.print("Low: ");
        Serial.print(fingerSensor.getCalibration(channel, hiLo));
        break;
        case 1:
        Serial.print(" High: ");
        Serial.print(fingerSensor.getCalibration(channel, hiLo));
        break;
      }
    }
    Serial.println();
  }
}

The sensor is initialized in the same manner as the first example, then our loop() begins calibrating the sensors. To calibrate the sensors, simply flex them to their maximum and minimum bend radii, then send an e over the Serial Monitor when you’re finished. This will save the current calibration and show you the values that have been saved. Uploading this sketch and opening the Serial Monitor to 115200 bps will yield an output somewhat like the below image once you’ve sent e and saved the calibration.

Example 3 - Calibration

Calibration Output - click the image for a closer look

Example 4 - Calibrated Hand

You don’t necessarily want to calibrate your hand every single time you put on a glove with the flex controllers built in, so let’s figure out how to manually set our calibration if we know it already. To get started, open up File>Examples>SparkFun ADS1015 Arduino Library>Example4_ManualCalibration. We can see in the preamble to our code that we have an array of all of our calibration values, which were obtained using the previous example sketch. We then use a loop in the setup function along with our setCalibration() function to set the individual calibration values. The code for this is shown below.

language:c
#include <SparkFun_ADS1015_Arduino_Library.h>
#include <Wire.h>

ADS1015 pinkySensor;
ADS1015 indexSensor;
float hand[4] = {0, 0, 0, 0};
uint16_t handCalibration[4][2] = {
//{hi , low}
  {722, 1080},//index
  {600, 980},//middle
  {680, 900},//ring
  {736, 907} //pinky
};

void setup() {

  Wire.begin();
  Serial.begin(115200);

  //Begin our finger sensors, change addresses as needed.
  if (pinkySensor.begin(Wire, 100000, ADS1015_ADDRESS_SDA) == false) 
  {
     Serial.println("Pinky not found. Check wiring.");
     while (1);
  }
  if (indexSensor.begin(Wire, 100000, ADS1015_ADDRESS_GND) == false) 
  {
     Serial.println("Index not found. Check wiring.");
     while (1);
  }

  //Set the calibration values for the hand.
  for (int channel; channel < 2; channel++)
  {
    for (int hiLo = 0; hiLo < 2; hiLo++)
    {
      indexSensor.setCalibration(channel, hiLo, handCalibration[channel][hiLo]);
      pinkySensor.setCalibration(channel, hiLo, handCalibration[channel + 2][hiLo]);
    }
    Serial.println();
  }
}

void loop() {
  for (int channel = 0; channel < 2; channel++)
  {
    //Keep in mind that getScaledAnalogData returns a float
    hand[channel] = indexSensor.getScaledAnalogData(channel);
    hand[channel + 2] = pinkySensor.getScaledAnalogData(channel);
  }
  for (int finger = 0; finger < 4; finger++)
  {
    Serial.print(finger);
    Serial.print(": ");
    Serial.print(hand[finger]);
    Serial.print("");
  }
  Serial.println();
}

Uploading this sketch and opening the serial monitor will show a stream of calibrated values. Use these to scale any other variable you’d like in your project.

Serial monitor output showing calibrated values

Calibrated Hand Output - click the image for a closer look

Resources and Going Further

Now that you’ve successfully got your Qwiic Flex Glove Controller up and running, it’s time to incorporate it into your own project!

For more information, check out the resources below:

Need even more inspiration for your next project? Check out some of these related tutorials:

AS726X NIR/VIS Spectral Sensor Hookup Guide

It's now easier than ever to measure and characterize how different materials absorb and reflect different wavelengths of light. The AS726X spectral sensors allow you to detect wavelengths in the visible range (VIS) and near infrared range (NIR)!

CCS811/BME280 (Qwiic) Environmental Combo Breakout Hookup Guide

Sense various environmental conditions such as temperature, humidity, barometric pressure, eCO2 and tVOCs with the CCS811 and BME280 combo breakout board.

Qwiic Real Time Clock Module (RV-1805) Hookup Guide

Find out what time it is, even after the power's been out on your project for a while with the Qwiic Real Time Clock (RTC) module.

IoT Power Relay

Using the ESP32 to make a web-configured timed relay.

learn.sparkfun.com | CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

LilyPad Buttons and Switches

$
0
0

LilyPad Buttons and Switches a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t740

Introduction

Buttons, slide switches, and reed switches are electronic components you can use to control a project, turn it on or off, or trigger behaviors in the code of a program. This guide will provide an overview of the options available in the LilyPad sewable electronics line and some examples of using them in a project.

LilyPad Button Board

DEV-08776
$1.50
10
LilyPad Slide Switch

DEV-09350
$1.50
1
LilyPad Reed Switch

DEV-13343
$2.95

You can also explore buttons and switches in a pre-wired circuit using the E-Sewing ProtoSnap or with Arduino in the LilyPad ProtoSnap Plus.

LilyPad E-Sewing ProtoSnap

DEV-14546
$4.95
1
LilyPad ProtoSnap Plus

DEV-14346
$39.95

Suggested Reading

Here are some additional resources to check out before you begin:

Switch Basics

A tutorial on electronics' most overlooked and underappreciated component: the switch! Here we explain the difference between momentary and maintained switches and what all those acronyms (NO, NC, SPDT, SPST, ...) stand for.

LilyPad Basics: E-Sewing

Learn how to use conductive thread with LilyPad components.

Getting Started with LilyPad

An introduction to the LilyPad ecosystem - a set of sewable electronic pieces designed to help you build soft, sewable, interactive e-textile projects.

What are Buttons and Switches?

Buttons and switches are electronic components that control the flow of current in a circuit. They can act as a simple gateway to light up an LED or as inputs for a microcontroller. Buttons are considered a type of switch, often with a momentary push actuation. We’ll refer to both as switches in this section.

Switch States

To change a switch from one state to another requires a physical action, often a flip, slide, or push. This is called actuating the switch. Different types of switches have different actuation methods. In the LilyPad line you can activate switches by sliding, pushing, and even using a magnet to trigger.

Maintained vs Momentary Switches

Switches that stay in one state until changed are called maintained switches. Examples of some common maintained switches are light switches, on/off switches on devices, and toggle switches. The LilyPad Slide Switch is an example of a maintained switch.

A momentary switch is only active when being actuated. Push buttons are a common example of a momentary switch. Other momentary switches you may find around you are the keys on your keyboard - a letter is only typed when the key is pressed. The LilyPad Button is an example of a momentary switch.

LilyPad Slide Switch

The LilyPad Slide Switch has a small switch labeled ON/OFF. When moved to the OFF position, parts inside the switch move away from each other and open the circuit (disconnecting it). No current will flow through the switch to the components connected to its sew tabs. When the toggle switch is moved to the ON position, the two sew tabs on the switch are connected, allowing current to flow through and close the circuit.

Detail of using LilyPad Switch

Using a LilyPad Slide Switch on the LilyPad ProtoSnap Plus

Examples

Slide switches can be used to control individual LEDs in an e-sewing project. Here’s an example of using three slide switches connnected with conductive thread to control each color channel on a LilyPad TriColor LED.

Tri-Color LED stitched with conductive thread to three LilyPad Switches and a LilyPad Battery Holder

Simple color mixing circuit using LilyPad Switches connected to each color tab of the tri-color LED.

A slide switch can also be used to turn off an element in a project, such as a buzzer or indicator while debugging or when you want a bit of peace and quiet. The example below shows a slide switch sewn in a LilyPad Buzzer. This allows the other features of the project to still function while disconnecting power to the buzzer.

Piezo buzzer sewn into a circuit with a slide switch

You can also connect the slide switch to a LilyPad Arduino and read its state in your programs. Here’s an example of using a LilyPad Button and LilyPad Switch in a project on the LilyPad ProtoSnap Plus to control LEDs.

This wearable dice project tutorial utilizes seven slide switches to select from a 4, 6, 8, 10, 12, 20, and 100 side virtual dice for gaming.

Dungeons and Dragons Dice Gauntlet

August 13, 2013

A playful, geeky tutorial for a leather bracer that uses a LilyPad Arduino, LilyPad accelerometer, and seven segment display to roll virtual 4, 6, 8, 10, 12, 20, and 100 side dice for gaming.

LilyPad Reed Switch

The LilyPad Reed Switch is another kind of switch available in the LilyPad line. Unlike the other LilyPad switch offerings, the reed switch does not require you to touch the board to activate it. Inside the reed switch are two thin pieces of metal that are pulled in contact with each other when exposed to a magnetic field.

Read more about how to use it in the full hookup guide.

LilyPad Reed Switch Hookup Guide

November 5, 2015

A guide to using the LilyPad Reed Switch breakout in your projects.

Examples

In this episode of Electricute, Dia and Nick build an interactive Krampus stocking using the LilyPad Reed Switch and a magnet.

LilyPad Button

The LilyPad Button Board is also a type of switch. When you press the button in the middle of the board, it connects the two sew tabs and allows current to flow through. When you let go of the button, the connection is opened again, and the button springs back into place. This button is an example of a momentary switch.

Pressing LilyPad button on E-Sewing ProtoSnap

Pressing the LilyPad Button on the E-Sewing ProtoSnap

Examples

This stuffed creature uses both a slide switch and button to control LEDs embedded in it.

Light-Up Plush

December 16, 2016

Craft a light-up plush with LilyPad LEDs controlled by pressing a button and sliding a switch in the creature's hands.

Here’s an example of a button being used as an input connected to the LilyMini microcontroller to switch LED modes.

Resources and Going Further

In addition to using LilyPad pieces to add interactivity to your projects, you can also create your own custom buttons and switches. Check out these blog posts for more:

Ready to add some interactivity to a project using LilyPad Arduino? Check out the ProtoSnap Plus Activity Guide for code examples to follow along with.

LilyPad ProtoSnap Plus Activity Guide

December 7, 2017

Learn how to program in Arduino with the LilyPad ProtoSnap Plus. This guide includes 10 example activities that use the pre-wired LilyPad boards on the LilyPad ProtoSnap Plus.

For inspiration, have a look at some of the following projects!

My Drunk Kitchen Apron

A fun project that uses the LilyPad MP3 trigger. This apron will dispense helpful kitchen advice and humor from the host of My Drunk Kitchen, Hannah Harto!

ProtoSnap LilyPad Development Simple Hookup Guide

Interested in getting into LilyPad? Or maybe it's Arduino that tickles your fancy? Just want to add a little white-blinky-LED zest to your vest? All of the above? The ProtoSnap LilyPad Simple is a great tool to explore any of these subjects.

21st Century Fashion Kit: Inflation

Learn how to use a blower and thin sheet plastic to create designs that change shape and volume!

Powering LilyPad LED Projects

Learn how to calculate how many LEDs your LilyPad project can power and how long it will last.

learn.sparkfun.com | CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

Graph Sensor Data with Python and Matplotlib

$
0
0

Graph Sensor Data with Python and Matplotlib a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t798

Introduction

Python is a wonderful high-level programming language that lets us quickly capture data, perform calculations, and even make simple drawings, such as graphs. Several graphical libraries are available for us to use, but we will be focusing on matplotlib in this guide. Matplotlib was created as a plotting tool to rival those found in other software packages, such as MATLAB. Creating 2D graphs to demonstrate mathematical concepts, visualize statistics, or monitor sensor data can be accomplished in just a few lines of code with matplotlib.

Graphing temperature data with Python and matplotlib

The Raspberry Pi is a great platform for connecting sensors (thanks to the exposed GPIO pins), collecting data via Python, and displaying live plots on a monitor.

Notice: This tutorial was written with Raspbian version "June 2018" and Python version 3.5.3. Other versions may affect how some of the steps in this guide are performed.

Required Materials

To work through the activities in this tutorial, you will need a few pieces of hardware:

Optional Materials

You have several options when it comes to working with the Raspberry Pi. Most commonly, the Pi is used as a standalone computer, which requires a monitor, keyboard, and mouse (listed below). To save on costs, the Pi can also be used as a headless computer (without a monitor, keyboard, and mouse).

Note that for this tutorial, you will need access to the Raspbian (or other Linux) graphical interface (known as the desktop). As a result, the two recommended ways to interact with your Pi is through a monitor, keyboard, and mouse or by using Virtual Network Computing (VNC).

SmartiPi Touch

PRT-14059
$24.95
8
Raspberry Pi LCD - 7" Touchscreen

LCD-13733
$64.95
35
Multimedia Wireless Keyboard

WIG-14271
$29.95
2

At the bare minimum, you need a breadboard and some jumper wires to connect the Pi to the TMP102 sensor. However, the Pi Wedge and some M/M jumper wires may make prototyping easier.

Jumper Wires Standard 7" M/M - 30 AWG (30 Pack)

PRT-11026
$1.95
20
SparkFun Pi Wedge

BOB-13717
$9.95
10

Suggested Reading

If you aren’t familiar with the following concepts, we recommend checking out these tutorials before continuing:

Serial Terminal Basics

This tutorial will show you how to communicate with your serial devices using a variety of terminal emulator applications.

Raspberry Pi 3 Starter Kit Hookup Guide

Guide for getting going with the Raspberry Pi 3 Model B and Raspberry Pi 3 Model B+ starter kit.

Getting Started with the Raspberry Pi Zero Wireless

Learn how to setup, configure and use the smallest Raspberry Pi yet, the Raspberry Pi Zero - Wireless.
New!

Python Programming Tutorial: Getting Started with the Raspberry Pi

This guide will show you how to write programs on your Raspberry Pi using Python to control hardware.
Please note: If you have trouble seeing any of the images throughout this tutorial, feel free to click on it to get a better look!
Python Logo

Prepare Your Pi

To begin, you will need to flash an image of the Raspbian operating system (OS) onto an SD card (if you have not done so already). You have a couple of options:

  • In the Python Programming Tutorial, follow the Install the OS section, making sure to go with the Full Desktop Setup

OR

Once you have installed the OS for your Raspberry Pi, follow the steps in Configure Your Pi. If given the choice, choose the steps that relate to the Full Desktop setup.

Alias Python and Pip

We will be using Python 3 in this tutorial. At the time of writing, Python 2 was still the default version with Raspbian, which means that we will need to tell Linux that the command python should execute Python version 3.

Note: If you have already performed these steps in the Configure Your Pi portion previously, feel free to skip this part.

Open a terminal and enter the following command to edit the .bashrc file:

language:shell
nano ~/.bashrc

Scroll down to the bottom of the file, and add the following (if they are not already present):

language:shell
alias python='/usr/bin/python3'
alias pip=pip3

Aliasing Python and Pip

Exit out of nano with ctrl+x, press y, and press enter. Run the .bashrc script with:

language:shell
source ~/.bashrc

You can check the versions of Python and pip with:

language:shell
python --version
pip --version

Both should tell you the they are using a version of Python 3 (e.g. 3.5.3).

Enable I2C

By default, Raspbian disables the I2C port, which we’ll need to talk to the TMP102.

Note: If you have already performed these steps in the Configure Your Pi portion previously, feel free to skip this part.

Bring up the Raspberry Pi configuration menu:

language:shell
sudo raspi-config

If asked to enter a password, type in the password you set for your Raspberry Pi. If you did not change it, the default password is raspberry.

Raspberry Pi config tool

Select 5 Interfacing Options.

Enable I2C on the Raspberry Pi

Select P5 I2C, select yes on the following screen, and press enter to enable the I2C port.

Back on the main screen, highlight Finish and press enter. A reboot is not necessary if you did not change any other options.

Install Dependencies

Like any good Linux project, we need to install a number of dependencies and libraries in order to get matplotlib to run properly. Make sure you have an Internet connection and in a terminal, enter the following commands. You may need to wait several minutes while the various packages are downloaded and installed.

language:shell
sudo apt-get update
sudo apt-get install libatlas3-base libffi-dev at-spi2-core python3-gi-cairo
pip install cairocffi
pip install matplotlib

You are now ready to build your circuit and make some graphs!

Hardware Assembly

In this guide, we will read temperature data from a TMP102 temperature sensor and plot it in various ways using matplotlib. After a brief introduction to matplotlib, we will capture data before plotting it, then we’ll plot temperature in real time as it is read, and finally, we’ll show you how to speed up the plotting animation if you want to show faster trends.

To begin, you’ll need to connect the TMP102 to the Raspberry Pi, either directly or through a Pi Wedge. We recommend soldering headers onto the TMP102 if you plan to use a breadboard. If you need help, this tutorial shows you the basics of soldering.

Soldered headers on a TMP102 breakout board

Connect the TMP102 as shown in one of the following diagrams (with or without the Pi Wedge). If you need help with layout of the Pi’s GPIO headers, refer to this guide.

Connecting through a Pi Wedge:

Connecting a TMP102 to a Raspberry Pi through a Pi Wedge

Click the image for a closer look.

Connecting directly to the Raspberry Pi:

Connecting a TMP102 to a Raspberry Pi

Click the image for a closer look.

Introduction to Matplotlib

Matplotlib is a wonderful tool for creating quick and professional graphs with Python. It operates very similarly to the MATLAB plotting tools, so if you are familiar with MATLAB, matplotlib is easy to pick up.

The Absolute Basics

The easiest way to make a graph is to use the pyplot module within matplotlib. We can provide 2 lists of numbers to pyplot, and it will create a graph with them. Note that the 2 lists need to have the same length (same number of elements). The first list is a collection of numbers in the X domain, and the second is a collection of numbers in the Y range.

Use your favorite text editor or Python IDE to enter the following code:

language:python
import matplotlib.pyplot as plt

xs = [0, 1, 2, 3, 4, 5, 6, 7]
ys = [1, 0.3, -2.3, 5.1, 7.6, -0.2, -1.8, 4]

plt.plot(xs, ys)
plt.show()

Save the program (e.g. as myplot.py). Run it with:

language:shell
python myplot.py

You should see the graph appear in a new window.

While the basic line graph is likely the most used graph, matplotlib is also capable of plotting other types of graphs, including bar, histogram, scatter, and pie (among others).

Getting started with matplotlib

If you want to save the image, you can click on the Save icon in the plot’s window.

Note that the points from the xs and ys lists are related to each other. The fist element of xs (i.e. xs[0]) and the first element of ys (i.e. ys[0]) make up the first point, (0, 1) in this instance. Pyplot automatically draws a line between one point and the next in the series.

Formatting

Like any good graph-creation tool, pyplot lets you change the formatting of your graphs with legends, titles, and labels. Let’s create a new plot:

language:python
import matplotlib.pyplot as plt
import math

# Create sinewaves with sine and cosine
xs = [i / 5.0 for i in range(0, 50)]
y1s = [math.sin(x) for x in xs]
y2s = [math.cos(x) for x in xs]

# Plot both sinewaves on the same graph
plt.plot(xs, y1s, 'r^', label='sin(x)')
plt.plot(xs, y2s, 'b--', label='cos(x)')

# Adjust the axes' limits: [xmin, xmax, ymin, ymax]
plt.axis([-1, 11, -1.5, 1.5])

# Give the graph a title and axis labels
plt.title('My Sinewaves')
plt.xlabel('Radians')
plt.ylabel('Value')

# Show a legend
plt.legend()

# Save the image
plt.savefig('sinewaves.png')

# Draw to the screen
plt.show()

Save and run this code. You should see two different sinewaves overlapping each other.

Multiple plots on one set of axes with matplotlib

Here, you might notice a few differences from the first plot. We are creating two different plots, and by calling plt.plot() twice, we can draw those plots on the same set of axes (i.e. on the same graph). To create those plots, we use the range() function to generate numbers from 0 to 50 (exclusive) and divide each number by 5. This creates a series of numbers from 0 to 10 equally spaced by 0.2.

Note: As it turns out, Python does not have many easy ways to interact with lists or arrays. The numpy package is a great way to work with arrays, and it offers an impressive speed boost over native Python methods. If you are looking for a free MATLAB replacement, numpy is a good contender. When you installed the matplotlib package, numpy was installed by default!

When it comes to formatting the graph, we have plenty of options at our fingertips. We can “zoom” by setting the limit on the axes with plt.axis(). We’re able to add a title and axis labels. We can also show a legend by adding label= as an argument in the plt.plot() function call.

Additionally, if you look at our call to plt.plot(), you’ll notice that we can specify how we want the plots to look with the third parameter. 'r^' says to make the points red (r) and appear as triangles (^). 'b--' says to make the plot blue (b) and use a dashed line (–). See the Notes section in the plot documentation to see the various options for formatting strings.

Finally, we were able to create the image above by calling plt.savefig(). This saves the current figure as an image in the same directory as the Python code (and we can do it programmatically!)

Refer to the pyplot documentation to see all the available functions for plotting and formatting.

Subplots

Sometimes, you may want to display multiple plots on a single image (or figure). To accomplish this, we can use supblots:

language:python
import matplotlib.pyplot as plt
import math

# Create sinewaves with sine and cosine
xs = [i / 5.0 for i in range(0, 50)]
y1s = [math.sin(x) for x in xs]
y2s = [math.cos(x) for x in xs]

# Explicitly create our figure and subplots
fig = plt.figure()
ax1 = fig.add_subplot(2, 1, 1)
ax2 = fig.add_subplot(2, 1, 2)

# Draw our sinewaves on the different subplots
ax1.plot(xs, y1s)
ax2.plot(xs, y2s)

# Adding labels to subplots is a little different
ax1.set_title('sin(x)')
ax1.set_xlabel('Radians')
ax1.set_ylabel('Value')
ax2.set_title('cos(x)')
ax2.set_xlabel('Radians')
ax2.set_ylabel('Value')

# We can use the subplots_adjust function to change the space between subplots
plt.subplots_adjust(hspace=0.6)

# Draw all the plots!
plt.show()

Run this, and you should get two sinewaves, each in its own subplot.

Several plots on separate axes with matplotlib

Up to this point, we had been calling plt.plot() to draw on the canvas. In reality, this is a shortcut to create a figure object (the background where we draw our plots) and then create a set of axes on a single plot on that figure. To create subplots, we need to explicitly create that figure so that we get a handle to it. We can then use the fig handle to create subplots on the figure.

The add_subplot() function must be given a series of numbers (or a 3-digit integer) representing the height, width, and position of the subplot to create. (2, 1, 1) says to create a 2x1 subplot grid (2 high, 1 across) and return a handle to the first subplot (the one on top). (2, 1, 2) similarly says that in the same 2x1 gird, return a handle to the second subplot (the one on bottom). We name these handles ax1 and ax2 (for axes 1 and 2).

To learn more about how to create subplots, see the add_subplot definition.

We then draw our sinewaves on the axes directly (rather than using the shortcut plt.plot()). We also add labels to everything. Without any adjustments, the labels would be hidden by the axes by default. To account for this, we set the hspace parameter, which controls the amount of height between subplots. Feel free to play around with the other parameters in subplots_adjust to see how they work.

Plot Sensor Data

In the Python Programming Tutorial: Getting Started with the Raspberry Pi, the final example shows how to sample temperature data from the TMP102 once per second over 10 seconds and then save that information to a comma separated value (csv) file. To start plotting sensor data, let’s modify that example to collect data over 10 seconds and then plot it (instead of saving it to a file).

TMP102 Module

In order to simplify I2C reading and writing to the TMP102, we will create our own TMP102 Python module that we can load into each of our programs. Open a new file named tmp102.py:

language:shell
nano tmp102.py

Copy in the following Python code:

language:python
import smbus

# Module variables
i2c_ch = 1
bus = None

# TMP102 address on the I2C bus
i2c_address = 0x48

# Register addresses
reg_temp = 0x00
reg_config = 0x01

# Calculate the 2's complement of a number
def twos_comp(val, bits):
    if (val & (1 << (bits - 1))) != 0:
        val = val - (1 << bits)
    return val

# Read temperature registers and calculate Celsius
def read_temp():

    global bus

    # Read temperature registers
    val = bus.read_i2c_block_data(i2c_address, reg_temp, 2)
    temp_c = (val[0] << 4) | (val[1] >> 5)

    # Convert to 2s complement (temperatures can be negative)
    temp_c = twos_comp(temp_c, 12)

    # Convert registers value to temperature (C)
    temp_c = temp_c * 0.0625

    return temp_c

# Initialize communications with the TMP102
def init():

    global bus

    # Initialize I2C (SMBus)
    bus = smbus.SMBus(i2c_ch)

    # Read the CONFIG register (2 bytes)
    val = bus.read_i2c_block_data(i2c_address, reg_config, 2)

    # Set to 4 Hz sampling (CR1, CR0 = 0b10)
    val[1] = val[1] & 0b00111111
    val[1] = val[1] | (0b10 << 6)

    # Write 4 Hz sampling back to CONFIG
    bus.write_i2c_block_data(i2c_address, reg_config, val)

    # Read CONFIG to verify that we changed it
    val = bus.read_i2c_block_data(i2c_address, reg_config, 2)

Save the code with ctrl + x, press y, and press enter. This allows us to call the init() and read_temp() functions to easily get temperature (in Celsius) from the TMP102.

Temperature Logging and Graphing

In the same directory as the tmp102.py file, create a new file (using your favorite editor), and paste in the following code:

language:python
import time
import datetime as dt
import matplotlib.pyplot as plt
import tmp102

# Create figure for plotting
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
xs = []
ys = []

# Initialize communication with TMP102
tmp102.init()

# Sample temperature every second for 10 seconds
for t in range(0, 10):

    # Read temperature (Celsius) from TMP102
    temp_c = round(tmp102.read_temp(), 2)

    # Add x and y to lists
    xs.append(dt.datetime.now().strftime('%H:%M:%S.%f'))
    ys.append(temp_c)

    # Wait 1 second before sampling temperature again
    time.sleep(1)

# Draw plot
ax.plot(xs, ys)

# Format plot
plt.xticks(rotation=45, ha='right')
plt.subplots_adjust(bottom=0.30)
plt.title('TMP102 Temperature over Time')
plt.ylabel('Temperature (deg C)')

# Draw the graph
plt.show()

Save (give it a name like tempgraph.py) and exit. Run the program with:

language:shell
python tempgraph.py

Wait while the program collects data (about 10 seconds). Feel free to breathe on or fan near the temperature sensor to change the ambient temperature (gives you some interesting data to look at). Once the collection has finished, you should be presented with a plot showing how the temperature changed over time.

Graphing temperature data with Python and matplotlib on a Raspberry Pi

Code to Note

We create the graph in a very similar manner to the Formatting example in Introduction to Matplotlib. The only difference is that we build the xs and ys lists programmatically. Each second, the temperature is read from the TMP102 sensor and appended to the ys list. The local time (of the Raspberry Pi) is captured with dt.datetime.now() and appended to the xs list.

The xs and ys lists are then used to create a plot with ax.plot(xs, ys). Note that we are explicitly creating a figure and a single set of axes (instead of calling the plt.plot() shortcut). We will use the handle to the axes in the next sections when we look at animating the plot.

Update a Graph in Real Time

Waiting to collect measurements from a sensor before plotting it might work in some situations. Many times, you would like to be able to monitor the output of a sensor in real time, which means you can look for trends as they happen. To accomplish that, we will create an animation where a temperature sample is taken and the graph is updated immediately.

Animation Code

Open a new file (once again, make sure it’s in the same directory as tmp102.py so that we can use the tmp102 module). Copy in the following code:

language:python
import datetime as dt
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import tmp102

# Create figure for plotting
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
xs = []
ys = []

# Initialize communication with TMP102
tmp102.init()

# This function is called periodically from FuncAnimation
def animate(i, xs, ys):

    # Read temperature (Celsius) from TMP102
    temp_c = round(tmp102.read_temp(), 2)

    # Add x and y to lists
    xs.append(dt.datetime.now().strftime('%H:%M:%S.%f'))
    ys.append(temp_c)

    # Limit x and y lists to 20 items
    xs = xs[-20:]
    ys = ys[-20:]

    # Draw x and y lists
    ax.clear()
    ax.plot(xs, ys)

    # Format plot
    plt.xticks(rotation=45, ha='right')
    plt.subplots_adjust(bottom=0.30)
    plt.title('TMP102 Temperature over Time')
    plt.ylabel('Temperature (deg C)')

# Set up plot to call animate() function periodically
ani = animation.FuncAnimation(fig, animate, fargs=(xs, ys), interval=1000)
plt.show()

Save and run the code. You should immediately see a graph that gets updated about once every second. Feel free to breathe on the sensor to see how the temperature fluctuates.

Plotting sensor data in real time with Python and matplotlib on a Raspberry Pi

Code to Note

To create a real-time plot, we need to use the animation module in matplotlib. We set up the figure and axes in the usual way, but we draw directly to the axes, ax, when we want to create a new frame in the animation.

At the bottom of the code, you’ll see the secret sauce to the animation:

ani = animation.FuncAnimation(fig, animate, fargs=(xs, ys), interval=1000)

FuncAnimation is a special function within the animation module that lets us automate updating the graph. We pass the FuncAnimation() a handle to the figure we want to draw, fig, as well as the name of a function that should be called at regular intervals. We called this function animate() and is defined just above our FuncAnimation() call.

Still in the FuncAnimation() parameters, we set fargs, which are the arguments we want to pass to our animate function (since we are not calling animate() directly from within our own code). Then, we set interval, which is how long we should wait between calls to animate() (in milliseconds).

Note: As an argument to FuncAnimation, notice that animate does not have any parentheses. This is passing a reference to the function and not the result of that function. If you accidentally add parentheses to animate here, animate will be called immediately (only once), and you’ll likely get an error (probably something about a tuple not being callable)!

If you look at the call to animate(), you’ll see that it has 3 parameters that we’ve defined:

def animate(i, xs, ys):

i is the frame number. This parameter is necessary when defining a function for FuncAnimation. Whenever animate() is called, i will be automatically incremented by 1. xs and ys are our lists containing a timestamp and temperature values, respectively. We told FuncAnimation() that we wanted to pass in xs and ys with the fargs parameter. Without explicitly saying we want xs and ys as parameters, we would need to use global variables for remembering the values in xs and ys.

Within animate(), we collect the temperature data and append a timestamp, just like in the previous example. We also truncate both xs and ys to keep them limited to 20 elements each. If we let the lists grow indefinitely, the timestamps would be hard to read, and we would eventually run our of memory.

In order to draw the plot, we must clear the axes with ax.clear() and then plot the line with ax.plot(). If we didn’t clear them each time, plots would just be drawn on top of each other, and the whole graph would be a mess. Similarly, we need to reformat the plot for each frame.

You might notice that the plot updates only once per second (as defined by interval=1000). For some sensors, such as a temperature sensor, this is plenty fast. In fact, you may only want to sample temperature once per minute, hour, or even day. However, this sampling rate might be entirely too low for other sensors, such as distance sensors or accelerometers, where your application requires updates every few milliseconds.

Try lowering the interval to something less than 500. As it turns out, clearing and redrawing the graph is quite an intensive process for our little Pi, and you likely won’t get much better than 2 or 3 updates per second. In the next section, we’re going to show a technique for speeding up the drawing rate, but it means cutting some corners, such as having to set a static range and not showing timestamps.

Speeding Up the Plot Animation

Clearing a graph and redrawing everything can be a time-consuming process (at least in terms of computer time). As a result, our Raspberry Pi can struggle keeping up with more animations when we push it past about 2-3 frames per second (fps). To remedy that, we are going to use a trick known as blitting.

Blitting is an old computer graphics technique where several graphical bitmaps are combined into one. This way, only one needed to be updated at a time, saving the computer from having to redraw the whole scene every time.

Matplotlib allows us to enable blitting in FuncAnimation, but it means we need to re-write how some of the animate() function works. To reap the true benefits of blitting, we need to set a static background, which means the axes can’t scale and we can’t show moving timestamps anymore.

Animation with Blitting Code

Open a new file in the same directory as our tmp102.py module, and copy in the following code:

language:python
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import tmp102

# Parameters
x_len = 200         # Number of points to display
y_range = [10, 40]  # Range of possible Y values to display

# Create figure for plotting
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
xs = list(range(0, 200))
ys = [0] * x_len
ax.set_ylim(y_range)

# Initialize communication with TMP102
tmp102.init()

# Create a blank line. We will update the line in animate
line, = ax.plot(xs, ys)

# Add labels
plt.title('TMP102 Temperature over Time')
plt.xlabel('Samples')
plt.ylabel('Temperature (deg C)')

# This function is called periodically from FuncAnimation
def animate(i, ys):

    # Read temperature (Celsius) from TMP102
    temp_c = round(tmp102.read_temp(), 2)

    # Add y to list
    ys.append(temp_c)

    # Limit y list to set number of items
    ys = ys[-x_len:]

    # Update line with new Y values
    line.set_ydata(ys)

    return line,

# Set up plot to call animate() function periodically
ani = animation.FuncAnimation(fig,
    animate,
    fargs=(ys,),
    interval=50,
    blit=True)
plt.show()

Save and run the code. A graph should appear with a line that animates much faster than in the previous example (i.e. around 20 fps). You should also note that there are no timestamps (i.e. the x axis does not contain any useful data), and the y axis (temperature) does not automatically scale. In fact, if you were to measure a temperature below 10° or above 40° C, it would not be drawn on the graph.

Fast graphing with Python and matplotlib on a Raspberry Pi

Code to Note

First, notice that we removed any reference to datetime or timestamps, as they won’t help us with fast plotting here. Feel free to add them back in if you would like to enable some type of logging, but remember that it will slow down the animation.

Next, we set up a number of static parameters. x_len is the number of elements we want to use to create the plot. In this case, we remove elements from the beginning of the list when the plot gets to be more than 200 elements. We also set up a static y_range, which is the minimum and maximum temperature that can be displayed on the graph. To keep things fast, we don’t want to redraw the y axis every frame!

In the animate() function, we only deal with the list of y (temperature) elements, as we know that the x axis doesn’t change. Additionally, instead of redrawing the axes ax as in the previous example, we only update the line object, which we got a handle to earlier in the code:

line, = ax.plot(xs, ys)

The trailing comma on line, allows us to “unpack” the single-element tuple returned by the ax.plot() function. ax.plot() returns a tuple of Line2D objects (in this case, there should be only one Line2D object). As a result, we want a handle to the first object, so we use the trailing comma to say that we want the first object in the tuple and not the whole list itself. See here for more about trailing commas in Python.

After updating the Line2D object with line.set_ydata(ys), we package it into another single-element tuple with return line,, as FuncAnimation() expects our animation function to return a tuple of Line2D objects.

With these changes, we can set the blit parameter to True in our call to FuncAnimation(). This changes the way FuncAnimation() works on the back end to only update the line while leaving the background (everything else) unchanged.

Resources and Going Further

Plotting sensor data can be incredibly useful if you need to make a dashboard to watch the temperature in your server room or if you want to monitor the humidity around your classroom for a science experiment. If you would like to learn more about matplotlib, here are some great resources:

If you are interested in keeping the tmp102.py file in a different directory and still access its functions, we recommend turning it into a package. Here is a good tutorial that shows you how to make your own Python package.

Python Logo

Looking for even more inspiration? Check out these other Raspberry Pi projects:

Building Large LED Installations

Learn what it takes to build large LED installations from planning to power requirements to execution.

Bark Back Interactive Pet Monitor

Monitor and interact with pets through this dog bark detector project based on the Raspberry Pi!

Raspberry Pi Zero Helmet Impact Force Monitor

How much impact can the human body handle? This tutorial will teach you how to build your very own impact force monitor using a helmet, Raspberry Pi Zero, and accelerometer!

Using Flask to Send Data to a Raspberry Pi

In this tutorial, we'll show you how to use the Flask framework for Python to send data from ESP8266 WiFi nodes to a Raspberry Pi over an internal WiFi network.

learn.sparkfun.com | CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

Pi AVR Programmer HAT Hookup Guide

$
0
0

Pi AVR Programmer HAT Hookup Guide a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t797

Introduction

In this tutorial we will use a Pi AVR Programmer HAT and a Raspberry Pi 3B+ to program an ATMega328P target IC (RedBoard). We will program the Arduino bootloader over SPI using the capsense pad to engage, and then do some programming using avrdude in the command line. We will also cover how the Pi AVR Programmer HAT hardware works in conjunction with Python, avrdude, and shell command files.

SparkFun Pi AVR Programmer HAT

DEV-14747
$19.95

The Pi AVR Programmer HAT makes it easy to program AVRs directly from the SPI hardware pins on any Raspberry Pi. It was originally designed as an in-house solution for SparkFun production, but now is offered as a robust programming tool for anyone to purchase. It is by far one of the fastest, most reliable, and hack-able (fully open sourced) AVR programming solutions available. It can be used directly from the command line using avrdude commands, or with some simple setup steps, it can function as a stand-alone programmer with capsense-pad engage and status leds!

All of the design files, firmware, and example programming files can be found here:

SparkFun Pi AVR Programmer Github Repository

There are many reasons for programming your AVR via an in-system programmer (ISP):

  • If your AVR doesn’t have a bootloader on it, it’s probably the only way to load code.
  • ISP provides a faster and more reliable code upload.
  • If your project requires that your hardware UART pins (RX/TX) be connected to another device, this can conflict with serial uploading of code. ISP programming does not require using these pins. Instead, it uses MOSI/MISO/SCK/RESET – Arduino pins D11/D12/D13/RESET. This means you can leave RX and TX connected during development and re-program your AVR with new code without un-plugging and re-plugging any of your programming lines.
  • With ISP, you can overwrite the bootloader and squeeze out some extra flash space.
  • ISP allows you to poke at the fuse bits to change many settings, including the brown-out voltage.

Covered In This Tutorial

In this tutorial we will introduce you to all of the important aspects of the Pi AVR Programmer HAT. It’s split into a series of sections, which cover:

  • Board Overview– A look at the hardware components that make up the Pi AVR Programmer HAT.
  • Raspberry Pi Setup– To get up and programming, there is a little bit of setup work to do on your Raspberry Pi. Here, we will show what settings to change and what files need to be modified and/or copied.
  • Closer Look at the Repository Files– Here you’ll find a more detailed description of each file necessary to setup your Pi.
  • Hardware Hookup– How to hookup the Pi AVR Programmer from your Raspi to the example Target AVR.
  • ISP Programming: Stand-Alone– How to use the HAT in stand-alone mode and program an arduino bootloader (or any hex file) via SPI onto an ATMega328p target IC (the Redboard).
  • ISP Programming: Command Line– A more advanced, command-line-based approach to using the Pi AVR Programmer HAT.
  • ISP Programming: Within the Arduino IDE– How to use the HAT from within the Arduino IDE. A nice one-click solution for programming your Arduino with the speed of ISP.
  • Speed Test– We take the HAT for a speed test and see just how fast it goes!

Required Materials

To complete this tutorial, you will need the following hardware. You may not need everything though depending on what you have. Add it to your cart, read through the guide, and adjust the cart as necessary.

Suggested Reading

To read even more about the history behind this project and design choices, check out the full tutorial/write up here:

Raspberry Pi Stand-Alone Programmer

March 8, 2018

This tutorial will show you how to use a headless Raspberry Pi to flash hex files onto AVR microcontrollers as a stand-alone programmer. It also tells the story about production programming challenges, how SparkFun came to this solution, and all the lessons learned along the way.

Whether you’re a beginner or experienced electronics enthusiast, the Pi AVR Programmer HAT should be easy to get up-and-running. If you’ve programmed an Arduino before, you’ll be well-prepared for the next step. Here are some addtional tutorials we’d recommend reading before continuing on with this one.

Serial Peripheral Interface (SPI)

SPI is commonly used to connect microcontrollers to peripherals such as sensors, shift registers, and SD cards.

Installing an Arduino Bootloader

This tutorial will teach you what a bootloader is and why you would need to install or reinstall it. We will also go over the process of burning a bootloader by flashing a hex file to an Arduino microcontroller.

What is an Arduino?

What is this 'Arduino' thing anyway?

Installing Arduino IDE

A step-by-step guide to installing and testing the Arduino software on Windows, Mac, and Linux.

Logic Levels

Learn the difference between 3.3V and 5V devices and logic levels.

Serial Terminal Basics

This tutorial will show you how to communicate with your serial devices using a variety of terminal emulator applications.

Raspberry Pi 3 Starter Kit Hookup Guide

Guide for getting going with the Raspberry Pi 3 Model B and Raspberry Pi 3 Model B+ starter kit.

Board Overview

Before we get into using our Pi AVR Programmer HAT, let’s quickly overview what components fill the board out:

Pi AVR Programmer HAT Labeled

  • 2x20 Raspi Header– This female header will connect down to the GPIO pins on your Raspberry Pi. When pushed all the way down into the GPIO pins, the HAT will sit flush with the top of your enclosure.

  • Target VCC Select– Jumpers to choose what logic level you’d like to talk to your target. Options include “TARGET”, 3.3V, and 5V.

  • Isolation Switch IC– The multiplexer IC that disconnects the SPI lines from your Pi to the Target.

  • SPI Interface (1x6 header)– These headers provide optional direct access to the SPI lines. This is in a 1x6 straight header format, so it will mate nicely with your 6-pin Jumper wire. Most programmers use ribbon cables, which will fail after so many insertions. This 1x6 cable and adapter solution is much more robust. You can also opt to remove the supplied jumper cable, and wire up to your target with your own jumper wires or custom adapter.

  • SPI Interface Adapter (2x3 header)– This adapter mates easily with the standard ISP header found on most AVR boards.

  • Shutdown Button– Hold this down for 6 seconds to shut down your Pi.

  • Capsense Pad– Use this to engage programming. Simply tap with your finger and that will trigger the onboard capsense ATQ421010 IC which is connected to a GPIO on the Pi.

  • Status LEDS– Used for indicating power, success and/or fail for various stages of programming.

  • Label Boxes– These blank white silk-screen boxes are handy for labeling your Pi with a project name and version of your loaded hex file.

AVR ISP Pinouts

AVRs are programmed through an SPI interface. There are six unique signals required for communication between ISP and AVR:

  • VCC
  • GND
  • Reset
  • MOSI
  • MISO
  • SCK

To route those signals between devices, there are two standardized connectors – one 10-pin, 2x5 connector and another 6-pin, 2x3 connector:

top avr isp pinouts

AVR ISP Pinouts – Top View.

The Pi AVR Programmer HAT includes a 1x6 jumper cable and adapter which terminates with a 2x3 connector. There are labels on the bottom side near each leg on the SMD header:

Adapter

ISP Adapter – Top and Bottom View.

If your target device has the 2x5 pinout option, then you could use some of our F/F jumper cables to connect directly from the right-angled 1x6 male header on the HAT PCB to your target.

Jumper Wires Premium 6" F/F Pack of 10

PRT-08430
$3.95
1

Raspberry Pi Setup

Before we can do any programming, we need to do some setup work on our Raspberry Pi. If you are fairly familiar with Raspberry Pi, then you should check out the quick setup list for advanced users below. If you are fairly new to Raspberry Pi, then we recommend checking out the following tutorial: The Raspberry Pi 3 Starter Kit Hookup Guide. This offers a great walkthrough to setting up your Raspberry Pi with NOOBS (Raspberry Pi’s easy-to-use graphical OS installer).

Raspberry Pi 3 Starter Kit Hookup Guide

April 11, 2016

Guide for getting going with the Raspberry Pi 3 Model B and Raspberry Pi 3 Model B+ starter kit.

Quick Setup List:

  1. Install avrdude: Run the following command sudo apt-get install avrdude .

  2. Put these four files in /home/pi:

    1. test.py
    2. avrdude_gpio.conf
    3. pi_program.sh
    4. optiboot.hex

  3. Put the modified version of rc.local in your /etc folder.

  4. Enable SPI hardware: Run sudo raspi-config (as explained in the “Raspberry Pi SPI and I2C Tutorial” ).

  5. Open permissions on these files (to avoid debug errors). Run the following command: sudo chmod 777 test.py avrdude_gpio.conf pi_program.sh your_firmware.hex.

  6. Adjust pi_program.h to your desired programming settings. Here you can choose fuse bits, device ID (your target type), programming speed (-b 125000 is the flag for setting this).

  7. Launch test.py. Run sudo python test.py (or reboot and rc.local will launch it for you).

  8. Tap PROGRAM!

Closer Look at Repository Files

There are a lot of files in the GitHub repository for this project.

SparkFun Pi AVR Programmer Github Repository

However, you don’t actually need all of them to get up and running. There are quite a few that are extra examples and will show you some more of the advanced features of this programmer. Let’s take a closer look at the most important ones.

test.py

The test.py is the Python module that handles all of the operations of the Pi AVR Programmer HAT. It is launched at bootup from inside rc.local. Once it is up and running, it blinks the “STAT” LED to show that it is alive. It then listens to the capsense pad, finds your firmware hex file, engages programming, parses output from avrdude, and ultimately blinks status LEDs.

It also has some functionality to watch for media drives and pull in any new hex files that live on them. This is an easy way to update your programming hex file on your Pi, but beware, it will overwrite your existing hex file, so be careful. It’s usually a good idea to stop test.py before plugging in any thumbdrives (until you’re absolutely sure you want test.py to pull in the hex file). To stop test.py (and any other background Python modules), simply use this command:

language:bash
sudo killall python

It’s also not a bad idea to back up your hex files elsewhere (outside of /home/pi).

pi_program.sh

The pi_program.sh shell file contains the actual programming calls to avrdude. Test.py launches this shell to engage programming. It is very similar to the types of programming we do in SparkFun production. It allows you to adjust some variables at the top for device and fuse bits. Fuse bits can be a little tricky. If you need to adjust these and want some help, please check out our fuse bits tutorial.

language:bash
# DEVICE 
# Here are some commonly used "part no"s in avrdude at SFE
# UN-comment the one you wish to use, or plug in something different
# Use "avrdude -p?" for a list of supported devices
DEVICE=atmega328p
#DEVICE=m32u4
#DEVICE=t2313

#FUSE BITS
HIGH_FUSE=0xD8
LOW_FUSE=0xFF
EXT_FUSE=0xFD # due to masking, 0x05 = 0xFD, 0x07 = 0xFF, ***Note on an ATMEGA2560, ext fuse writes and verifies as 0xFD
LOCK=0x0F # due to masking, 0x0F = 0xCF

Note that it also has a nice little trick at the top to search for a hex file within /home/pi and use that for programming.

language:bash
# get firmware file name
firmware=$(find /home/pi/*.hex)
$firmware .= "/home/pi/$firmware"

Beware, that if you have two hex files in this directory, it will use the first one it finds. You can modify pi_program.sh to call a specific hex file by changing the $firmware variable.

The last thing to note about this file is the manual GPIO control in the middle of calls. In between fuse bits programming and flashing of the hex, there is a manual flip of the GPIO controlling the reset line. After using this programmer for thousands of programming cycles, we found that in order to truly reset the target in between calls to avrdude, a more reliable approach is to quickly toggle that GPIO from the shell file. Without this, the second call to avrdude can occasionally fail to reset the target. But with this toggle, we’ve had 100% success!

language:bash
sudo gpio -g mode 26 output
sudo gpio -g write 26 0
sleep 0.1
sudo gpio -g write 26 1
sleep 0.1

avrdude_gpio.conf

The provided avrdude_gpio.conf configuration file is very similar to the default configuration file. The only modification necessary is adding in the linuxspi programmer definition (Note that this also defines your RESET pin). On the Pi AVR Programmer HAT, we have this hard wired to GPIO PIN 26. If you are working from a different .conf file, then this little block of text below needs to be added to the very bottom of the avrdude.conf file.

language:bash
programmer
  id = "linuxspi";
  desc = "Use the Linux SPI device in /dev/spidev*";
  type = "linuxspi";
  reset = 26;
;

rc.local

The provided rc.local file is very similar to the default rc.local file you get with most raspberry Pis. This file runs at bootup, so it is handy if you’d like to have some commands run every time you power up your Pi (very useful if you plan to run it headless). The only addtional command added to the default rc.local is as follows. It simply calls Python to launch our test.py module.

language:bash
python /home/pi/test.py &

Note the “&” is very important here. It allows your Pi to continue on and run the GUI. If it wasn’t there, then your Pi would just wake up and run the Python module, and then do nothing else, this is dangerous, because you wouldn’t be able to modify your Pi from here on out. It’s kind of like “bricking” your Pi, so please don’t forget that very important “&”.

Hardware Hookup

Once you have completed the software setup to your Raspi, then it’s time to plug in some hardware!

  • If you haven’t already, put your Pi into an enclosure. Note that this is optional; it will work just fine without.

  • Plug in the HAT on top of your enclosed Pi.

Stack the Hat

Connect Power

  • Plug in the programming cable into your target IC. In this example, we are plugging into the 2x3 SPI header on the RedBoard. Note that this is polarized. The small white line indicates “pin 1”. Make sure to align those up!

Plug in the programming cable

  • Plug in a USB cable from the Pi to the RedBoard. This will provide power to the RedBoard. You could also opt to power the board via the barrel jack if you wish.

Plug in a USB cable

ISP Programming: Stand-Alone (aka Headless)

In this section, we are going to program using the Raspberry Pi “headless” (aka no monitor, mouse or keyboard). We will use the built in capacitive touch pad to engage programming and status LEDs to indicate success or failure. For this example, we will program the Arduino optiboot bootloader onto the RedBoard.

After you have setup your raspi for use with the Pi AVR Programmer HAT, then there are two important things to consider while using it as a stand-alone programmer:

  • Your hex file– This should live in the ‘/home/pi’ directory.

  • pi_program.sh– This shell file contains all the settings for programming and can be edited with any text editor.

After your setup and powered, programming is a simple as 1-2-3:

  1. To engage programming in stand-alone use, simply tap the capacitive touch pad labeled, “TAP TO PROGRAM”.

  2. The STAT LED will go solid during programming. This can take a couple seconds – depending on the size of your hex file.

  3. Finally, the SUCCESS and FAIL LEDs will indicated the status at each stage of programming

To see more about the results of your programming (debug messages from avrdude), you will need to access some files on your raspi. During each cycle of programming, the output from avrdude is saved to some text files that live within /home/pi.

  • /home/pi/fuse_results.txt

  • /home/pi/flash_results.txt

  • /home/pi/SERIAL_UPLOAD/serial_upload_results.txt– Note that this will only be updated if you did any serial uploading

ISP Programming: Command Line

In this section, we are going to program the Target AVR IC (Redboard) using calls to avrdude in the command line. This will require a monitor, keyboard and mouse hooked up to your Pi

Download the bootloader hex file for the RedBoard here:

Download Optiboot HEX FILE (HEX)

Save it in the correct directory (i.e. /home/pi/):

Directory

Sanity Check – Device Signature Verification

Before we get into any actual programming, it’s a good idea to ensure our connections are all correct and avrdude is working properly. To do this, we are going to simply call avrdude and ping for the device ID.

The Pi AVR Programmer HAT has an isolation switch between the raspi GPIO pins and the target. This serves as both protection of your rapsi and as a means to “free up” your target once you’re done programming. You can use some handy Python modules to quickly set this switch: enable_switch.py and disable_switch.py. For easy access, it’s a good idea to save them in the /home/pi directory.

Make sure to enable the programming switch by running a quick python module named enable_switch.py.

language:bash
sudo python enable_switch.py

Then run your avrdude command. Here is our first call to avrdude to check the device ID.

language:bash
sudo avrdude -p atmega328p -C /home/pi/avrdude_gpio.conf -c linuxspi -P /dev/spidev0.0 -b 125000 -v

Your readout should look like this:

Device Signature Verification in Terminal Window

Click the image for a closer look.

This basic command defines the programmer type you’re using and the AVR it’s talking to. AVRDUDE will attempt to read the Device Signature from your AVR, which is different for each AVR type out there. Every ATmega328P should have a device signature of 0x1E950F.

Flash Programming

Now that you’ve verified that everything is in working order, you can do all sorts of memory reading and writing with AVRDUDE. The main piece of memory you probably want to write is flash – the non-volatile memory where the programs are stored.

This command will perform a basic write to flash (using this HEX file as an example):

language:bash
sudo avrdude -p atmega328p -C /home/pi/avrdude_gpio.conf -c linuxspi -P /dev/spidev0.0 -b 2000000 -D -v -u -U flash:w:blink.hex:i

Writing to flash can sometimes take a little longer than a device ID ping. With the built-in ISP hardware pins and the Pi AVR Programmer HAT, you can use up to 2MHz reliably. For blink.hex, it only takes 0.09 seconds! You’ll see a text status bar scroll by as the device is read, written to, and verified.

Terminal Output After Flashing Arduino Bootloader

Click the image for a closer look.

The -U option command handles all of the memory reads and writes. We tell it we want to work with flash memory, do a write with w, and then tell it the location of the hex file we want to write.

Useful Options

Here are just a few last AVRDUDE tips and tricks before we turn you loose on the AVR world.

Specify AVR Device

Two options required for using AVRDUDE are the programmer type and AVR device specification. The programmer definition, assuming you’re using the Pi AVR Programmer HAT, will be -c linuxspi. Note that you will also need to specify the port (because there are two SPI ports on the raspi. This is done with the -P /dev/spidev0.0 portion of the call. If you need to use a different programmer check out this page and CTRL + F to “-c programmer-id”.

The AVR device type is defined with the -p option. We’ve shown a few examples with the ATmega328P, but what if you’re using an ATtiny85? In that case, you’ll want to put -p t85 instead. Check out the top of this page for an exhaustive list of compatible AVR device types.

Verbose Output

Adding one or more -v’s to your AVRDUDE command will enable various levels of verbosity to the action. This is handy if you need a summary of your configuration options, or an in-depth view into what data is being sent to your AVR.


There’s plenty more where that came from. Check out the AVRDUDE Option Documentation for the entire list of commands.

AVRDUDE Option Documentation


ISP Programming: Within the Arduino IDE

Here, we are going to show how to use the Pi AVR Programmer HAT directly from the Arduino IDE. Note that this functionality is not completely fleshed out. We are currently developing support for this feature and working out any bugs right now. Read all about it on the GitHub pull request here:

SparkFun Arduino Boards GitHub Boards Pull Request

It is very important that you have the correct version of Arduino. The version of avrdude that comes with Arduino on your Raspi is probably not capable of using the Pi AVR Programmer HAT. You need Arduino Nightly Version because it comes with the latest version of avrdude – version 6.3-20171130. For this tutorial, we are using Arduino 1.8.6 Hourly Build 2018/07/19.

Arduino Hourly Build

You need to install the SparkFun Arduino Boards. If you are comfortable using the boards manager, then you can install them directly there. For more help, check out the instructions in the GitHub repository's README.md, and this write up for Installing Custom Boards into Arduino.

Modify the programmers.txt, avrdude.conf and platform.txt files (that is, unless it’s already pulled into the repo by now). You can view it on GitHub at the open pull request for SparkFun Arduino Boards here. For reference, the following screen-shot also shows the differences:

Differences in Repos for Arduino Boards

Select “Pi_AVR_Programmer_HAT” from the drop down menu in the Arduino IDE. If you don’t see it in your list of options, then try closing and re-opening Arduino.

Arduino IDE Board Selection

Now, instead of using the standard upload button, you can select “Upload Using Programmer”. Ctrl + Shift + U is also pretty handy.

Upload Using Programmer

Turn on verbose output to see what’s going on better.

Speed Test - How Fast Can This Thing Go?

For some fun, and to demonstrate the difference in programming speeds, we created a massive Arduino sketch, and recorded some of the programming speeds. Once compiled, this sketch used up a whopping 20440 bytes of memory – this is about 63% of the ATmega328P’s memory. For comparison, blink is only 930 bytes – or 2% of memory.

This test was done with a 5V Arduino running on a 16MHz Crystal (the SparkFun RedBoard), and so that allowed us to program reliably at 2MHz. If you are using a 3.3V Arduino at 8MHz, it would be smart to bring that down to 1MHz. Our experience in production programming at SparkFun has shown us that in fact 1/8 of oscillator speed is the best way to go for nearly 100% reliability.

Here were the speed test results:

  • Serial upload via Arduino IDE:

    • 6.32s upload

    • 6.89s verify

    • 13.21s total

  • ISP program via Arduino IDE and Pi AVR Programmer HAT:

    • 4.04s write

    • 3.40s read

    • 7.44s total

  • ISP program via Pi AVR Programmer HAT in stand alone mode – using test.py and pi_program.sh:

    • 1.57s write

    • 0.74s read

    • 2.31s total

As you can see from the results above, the Pi AVR Programmer HAT used directly from avrdude was much faster than the other options! Almost 11 seconds faster than the traditional serial upload. Dang!

Resources and Going Further

Now that you’ve successfully got your Pi AVR Programmer Hat up and running, it’s time to incorporate it into your own project!

For more information about the SparkFun Pi AVR Programmer Hat, check out the resources below:


We also recommend looking at the following resources:

Want to check out some other SparkFun production processes or information about burning bootloaders on microcontrollers? Check out some of these related tutorials:

Installing an Arduino Bootloader

This tutorial will teach you what a bootloader is and why you would need to install or reinstall it. We will also go over the process of burning a bootloader by flashing a hex file to an Arduino microcontroller.

Using the Arduino Pro Mini 3.3V

This tutorial is your guide to all things Arduino Pro Mini. It explains what it is, what it's not, and how to get started using it.

Wireless Arduino Programming with Electric Imp

Reprogram your Arduino from anywhere in the world using the Tomatoless Boots wireless bootloader with the Electric Imp.

Pocket AVR Programmer Hookup Guide

Skip the bootloader and load your program directly onto an AVR with the AVR Pocket Programmer.

Raspberry Pi SPI and I2C Tutorial

How to use the serial buses on your Raspberry Pi.

Choosing an Arduino for Your Project

Examining the diverse world of Arduino boards and understanding the differences between them before choosing one for a project.

learn.sparkfun.com | CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

Using the A111 Pulsed Radar Sensor with a Raspberry Pi

$
0
0

Using the A111 Pulsed Radar Sensor with a Raspberry Pi a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t801

Introduction

Does your project require high-precision, cutting-edge distance, speed, motion, and/or gesture sensing? We’re not talking ultrasonic, or even infrared here, but 60GHz radar! Say hello to our tiny, pulsed radar friend!

A111 Pulsed Radar Breakout

SPX-14811
$49.95

The A111 is a single-chip solution for pulsed coherent radar (PCR) – it comes complete with antennae and an SPI interface capable of speeds of up to 50MHz. Applications for PCR include distance-sensing, and gesture, motion, and speed detection. The sensor can monitor one-or-more objects at distances of up to two meters.

Our breakout board for the A111 includes a 1.8V regulator, voltage-level translation, and it breaks out all pins of the pulsed radar sensor to both 0.1-inch and Raspberry Pi-friendly headers.

Required Materials

To use the A111 you’ll need either an ARMv7 or an ARM Cortex-M4 – the closed-source SDK currently only supports these architectures. This tutorial will explain how to use the radar sensor with a Raspberry Pi– a platform based on an architecture supported by the A111’s SDK.

The A111 Breakout includes a 20-pin, 2x10 female header, which should mate to Raspberry Pi’s of any generation. If you’d rather manually wire the A111 to your Raspberry Pi, male headers and about 9 male-to-female wires should do the trick.

Raspberry Pi 3

DEV-13825
$39.95
92
Break Away Headers - Straight

PRT-00116
$1.50
20
Jumper Wires Premium 12" M/F Pack of 10

PRT-09385
$4.50
1
A111 Pulsed Radar Breakout

SPX-14811
$49.95

Setup the Hardware

Raspbian:: This tutorial assumes you've already set up a Raspberry Pi with Raspbian. For help installing the Debian-based OS on your Pi, check out the docs on Raspberrypi.org. Or -- better yet! -- check out our Headless Raspberry Pi Setup tutorial.

The A111 Pulsed Radar Breakout is designed to sit directly on top of a Raspberry Pi. It doesn’t span all 40 (2x20) pins of a Raspberry Pi B+ (or later), but the 26-pin – 2x13 – header should be compatible with any Pi.

Solder the 2x13 header so the female side is facing away from the greenish-black A111 IC. Then connect the shield to a Raspberry Pi ensuring that the “Pi Display” text on the breakout matches up with the display header on your Pi. The sensor should be facing up after plugging it in.

https://cdn.sparkfun.com//assets/parts/1/3/0/7/8/14811-A111_Pulsed_Radar_Breakout-04.jpg

A111 Breakout plugged into a Raspberry Pi.

Or, if you’d like to manually wire the breakout up to a Pi, here is the pin-out we’ll use through the rest of this tutorial:

Breakout PinRaspberry Pi Pin NameRasPi Pin Number
CSSPI0 CS024
SCLKSPI0 SCLK23
MISOSPI0 MISO21
MOSISPI0 MOSI19
INTGPIO2522
ENGPIO2713
VCCIO3.3V1,17
GNDGND6, 14, 20, etc.
VIN5V2, 4

This board breaks out both "VIN" and "VCCIO" pins. "VIN" should power the sensor, which can consume up to about 80mA. "VCCIO" sets the I/O voltage, which may be lower than VIN.

The Raspberry Pi pin breakouts, for example, connect VIN to 5V and VCCIO to 3.3V, as the Raspberry Pi's 3.3V bus may not be able to fully power the A111, but the Pi can only handle 3.3V I/O.

Get the SDK

The software development kit (SDK) for the A111 is, unfortunately, locked behind a closed source blob that currently only supports Cortex-M4 and ARMv7 platforms.

To download the SDK, visit Acconeer’s “Products” page. Towards the bottom, under the “A1 Software Development Kit” header is a link to GET SOFTWARE**. Read through the license, and agree, then request the A1 SDK for Linux ARMv7 software.

Requesting the ARMv7 SDK

Requesting the ARMv7 SDK from Acconeer.

After supplying your email address, you should receive a download link email nearly instantaneously.

SCP the SDK to your Pi

Once downloaded, you’ll probably need to transfer the ZIP'ed SDK over to your Pi. To achieve this, we recommend SCP. If you’re on Windows, WinSCP works very well for transferring files from one device to another.

Using WinSCP to upload the SDK ZIP file to your P i

Using WinSCP to drag-and-drop the SDK into the home directory of your Pi.

If you’re on a Mac or Linux machine, with SCP available, you can use a command like the below to copy the ZIP file over:

scp acconeer_evk_service_linux_armv7l_xc111_r4a_xr111-3_r1c_a111_r2c_v1_3_5.zip 192.168.0.100:~

(Make sure you replace “192.168.0.100” with your Pi’s address or localhost name.)

Unzip the SDK

Once uploaded, you can use the terminal to unzip the SDK using the following commands (included are commands to install unzip):

unzip acconeer_evk_service_linux_armv7l_xc111_r4a_xr111-3_r1c_a111_r2c_v1_3_5.zip -d a111

(Make sure you replace the acconeer ZIP file name with that of your downloaded SDK version.)

Then cd to the “a111/evk_service/…” directory to prepare to build the example software.

SDK Overview

The A111 SDK includes source code, archived libraries, include files, and documentation for using the A111 pulsed radar sensor. Here’s a quick overview of what’s included with the SDK:

  • doc– Doxygen-generated documentation for the A111 API and source code.
  • include– Header and API files which describe how to interact with the pre-compiled A111 libraries.
  • lib– Pre-compiled A111 static archives. API for these files are provided in the “include” directory.
  • out– Compiled board and example object and executable files.
  • rule– Recursive Makefile rules for board and example files.
  • source– C source files for custom boards and example applications.
  • makefile– Top-level makefile. Recursively calls files in the “rule” directory to build example and board files.

Adding Custom Example and Board Files

The SparkFun A111 Breakout’s default pins will not work with those of the SDK’s examples. To build and run an example with this board, we have an example board definition, make scripts, and example applications. Click the button below to download these files:

Download the SparkX A111 Example Code

If you copy this ZIP file to your home directory, this command will unzip it to the right directory (assuming your SDK was unzipped to: “~/a111/evk_service_linux_armv7l_xc111_r4a_xr111-3_r1c_a111_r2c”

unzip sparkx-a111-source.zip -d a111/evk_service_linux_armv7l_xc111_r4a_xr111-3_r1c_a111_r2c

The SparkX ZIP includes these files, which should be extracted to their matching SDK directories:

  • rule/makefile_build_sparkx_detector_distance.inc– Build rules/Makefile for the sparkx_detector_distance.c source file.
  • rule/makefile_build_example_*_sparkx– Build rules/Makefile for the sparkx-brekaout example files.
  • source/acc_board_rpi_sparkx.c– Board definitions – pin connections, clock frequency, etc, for the SparkX A111 Breakout.
  • source/sparkx_detector_distance.c– Modified distance detector source file.

Once downloaded, these files should be extracted to the like spot in the original ZIP file.

Rule directory structure

Example of SparkX example files added to the “rule” directory. (Don’t forget the “source” directory files too!)

Build and Run the Test Sketch

Building the Board and Example Applications

Once uploaded to your Pi, executing the make file – and it’s recursive dependencies – should build all of the examples you may use with the A111. To build all board and example files, navigate to the SDK’s top-level directory and type make.

make example

Troubleshooting

If you have any trouble building the board and example files, ensure that you have gcc and make packages installed. (E.g. apt-get install make gcc)

Running the Example Applications

Once compiled you can run the example application (from the top-level SDK folder) by typing:

./out/sparkx_detector_distance

Example application run

This will run our modified distance-detector example application. This application will begin by calculating raw peak-distances, with a maximum of ten reflections. Following about 125 samples, the example will briefly estimate minimum and maximum thresholds, then continuously monitor for nearby objects until CTRL+C is pressed.

Evaluating the Example Application

The output of the example application can be a little difficult to parse. Here’s an example output, and an explanation of what each of those values printed out means:

Distance detector: Reflections: 5. Seq. nr: 424. (200-700 mm): 648 mm (137), 658 mm (250), 665 mm (255), 676 mm (209), 686 mm (65)
  • Reflections: <r>r is the number of reflections – a value between 0 and 10 – visible to the A111 sensor.
  • Seq. nr <n>– This number – n– should increment with each successive measurement.
  • (200-700m)– This is the set measurement range of the A111 sensor.
  • <d0> mm (<a0>), <d1> mm (<a1>), …– dn in this example is the distance of reflection n and an is the amplitude of that reflection.

Running Other Examples

In addition to the distance detector, the SDK includes a few extra examples. To execute these files, run them from the out directory:

  • sparkx_envelope_service_example– Reads in the envelope data, which us usually further-processed and used in distance, measurement, or other types of algorithms.
  • sparkx_envelope_iq_example– Advanced version of the envelope service, which includes phase information for very small variations in distance.
  • sparkx_power_bins_example– Demonstrates how to use A111 “power bins,” which are still, kind of, a mystery to us…

Going Further

For help building bigger, better applications around the A111, refer to Acconeer’s SDK documentation, including:

If you need any reference material surrounding our A111 Breakout Board, check out this documentation:


learn.sparkfun.com | CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado


AVR-Based Serial Enabled LCDs Hookup Guide

$
0
0

AVR-Based Serial Enabled LCDs Hookup Guide a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t789

Introduction

The AVR-based serial enabled LCD (a.k.a. SerLCD) is a simple and cost effective solution for adding Liquid Crystal Displays (LCDs) into your project. The PCB design on the back of the screen includes an ATMega328P that handles all of the screen control. It can accept commands via serial, I2C and SPI. This simplifies the number of wires needed and allows your project to display all kinds of text and numbers.

The firmware is fully opensource and available for download at the github repo here:

OpenLCD Firmware Github Repository

This allows for any customizations you may need. Uploading firmware (custom or updates), is easily done from the Arduino IDE using a Serial Basic. See firmware update instructions in the troubleshooting section of this tutorial for more info.

Also note, the example code used below is all available in the repo (along with many more examples). Before beginning this tutorial, it’s a good idea to clone the repository (or download the entire repo as a zip), to grab all of the examples. But if you prefer, you can always use the “COPY CODE” button on each of the examples below.

We offer three varieties of the AVR-based Serial Enabled LCDs:

SparkFun 16x2 SerLCD - Black on RGB 3.3V

LCD-14072
$19.95
SparkFun 16x2 SerLCD - RGB on Black 3.3V

LCD-14073
$19.95
SparkFun 20x4 SerLCD - Black on RGB 3.3V

LCD-14074
$24.95

Note that these all have identical firmware and can accept the same commands. However, you must adjust your display characters and cursor position as necessary for each model. Also note, there is a jumper on the back of each screen, and this “tells” the firmware how to correctly set the lines and columns for each screen.

Required Materials

To follow along with this tutorial, you will need the following materials at a minimum. Depending on what you have, you may not need everything on this list. Add it to your cart, read through the guide, and adjust the cart as necessary.

Tools

You may need a soldering iron, solder, and general soldering accessories, and screw driver depending on your setup.

Solder Lead Free - 100-gram Spool

TOL-09325
$7.95
7
Pocket Screwdriver Set

TOL-12891
$3.95
3
Weller WLC100 Soldering Station

TOL-14228
$44.95

Suggested Reading

If you aren’t familiar with the following concepts, we recommend checking out these tutorials before continuing.

How to Solder: Through-Hole Soldering

This tutorial covers everything you need to know about through-hole soldering.

Serial Communication

Asynchronous serial communication concepts: packets, signal levels, baud rates, UARTs and more!

Serial Peripheral Interface (SPI)

SPI is commonly used to connect microcontrollers to peripherals such as sensors, shift registers, and SD cards.

What is an Arduino?

What is this 'Arduino' thing anyway?

Installing Arduino IDE

A step-by-step guide to installing and testing the Arduino software on Windows, Mac, and Linux.

Logic Levels

Learn the difference between 3.3V and 5V devices and logic levels.

I2C

An introduction to I2C, one of the main embedded communications protocols in use today.

ASCII

A brief history of how ASCII came to be, how it's useful to computers, and some helpful tables to convert numbers to characters.

Hardware Overview

The AVR-based SerLCD has some new features that make it even more powerful and economical:

  • AVR microcontroller utilizes 11.0592 MHz crystal for greater communication accuracy
    • Adjustable baud rates of 1200, 2400, 4800, 9600 (default), 14400, 19200, 38400, 57600, 115200, 230400, 460800, 921600, 1000000
  • The AVR ATMega328p (with Arduino-compatible bootloader) is populated on the back of each LCD screen and handles all of the LCD control
  • 3 communication options: Serial, I2C and SPI
  • Adjustable I2C address controlled via software special commands (0x72 default)
  • Emergency reset to factory settings (Jumper RX to GND on bootup)
  • Operational backspace character
  • Incoming buffer stores up to 80 characters
  • Pulse width modulation of backlight allows direct control of backlight brightness and current consumption
  • Pulse width modulation of contrast allows for software defined contrast amount. The previous backpack versions of this product required adjusting the contrast via a hardware trim-pot which was less precise and less accessible in most enclosed projects.
  • User definable splash screen
  • Open-sourced firmware and Arduino-compatible bootloader enables updates via the Arduino IDE

AVR-Based Serial Controller (3.3V logic only)

Using these screens, it is easy to connect to any microcontroller that has a serial UART, I2C, or SPI. You could also use a single board computer such as the Raspberry Pi if you wanted. Whatever you choose, please make sure you convert to 3.3V Logic! In our examples below, we chose to use our Redboard with a Logic Level Converter.

Logic level converter between the 5V RedBoard and the 3.3V LCD Screen

Example setup including 5V Redboard and Logic Level Converter

Connection Options

Both sizes of these screens (16x2 and 20x4) have a row of headers along the top side. This is where you can connect power and your choice of communication protocol (Serial UART, I2C, or SPI). It also has our 6-pin Arduino Serial port available for convenient firmware updates.

Power, I2C, SPI, and Serial pins are highlighted

Main header pinouts

Note, if you choose Serial UART, there is a handy 3-pin JST footprint. This includes the minimum connections needed: RX, GND and VIN. Our JST Jumper 3 Wire Assembly is a good way to go:

Location on screenJST Jumper 3 Wire Assembly

Input Voltage (VDD) and Logic Levels

All of these screens can be powered by 3.3-9V. You have two pin options for connecting up power. One is labeled “RAW” and the other (on the 3-pin JST) is labeled “3.3-9V”. Note, the pin labeled “+” is NOT a power input pin! This is connected to the VCC of the ATMega329p (3.3V).

VIn and 3.3V input

Power Input pin options and Atmega328 VCC pin

Pro tip: If you plan to run 100% brightness on all three colors (red, green, blue), then it would be best to keep your power input voltage low. As close to 3.3V as possible is best. This will keep the on-board linear 3.3V voltage regulator nice and cool. It can accept up to 9V and power all three backlights at 100%, but it will get a little warm, and over years of use, potentially damage the vreg. For more information about vregs and why they heat up sometimes, please check out our tutorial: Power and Thermal Dissipation

Contrast Control

The on-board ATMega328p controls the contrast of the screen using a PWM signal. This can be adjusted by sending a command via Serial UART, I2C, or SPI. The screens ship out with the contrast setting set to 10, which we have found works well for most environments. Temperature and supply voltage can affect the contrast of the LCD, so you may need to adjust it accordingly. For more info about contrast and a detailed example, please see the section below called: Serial UART: Example Code - Contrast Control with a Trimpot.

Hardware Hookup - Initial

Install Headers

For this tutorial, we are going to try out Serial UART, I2C, and SPI. In order to easily follow along using a breadboard, solder some headers to the connection ports along the side of your screen. Also solder some headers onto either side of the Logic Level converter. This will allow us to easily plug these into the breadboard and wire each data line up with jumper wires.

Headers on screenHeaders on logic level converter

Note, we are going to use the 16x2 model with RGB backlight during this tutorial. If you are using a different model (RGB text or the 20x4), then the header pin-out and spacing is identical.

Connecting to an Arduino

The TX pin is used for Serial Uploads of new sketches onto your Arduino, and will cause problems for both your Arduino and the LCD. In other words, when you upload new code to your “project” Arduino, it will be confused because the screen is sharing that TX pin. Please only use software serial to control your LCD. For all of the Serial UART examples, we have setup software serial on D7.

For the first set of examples in this tutorial (SERIAL UART), there are three connections you need to make to the LCD: RX, GND, and RAW. For the other communication protocols that we will explore later, you will need to wire up some other lines. Please see the following Fritzing graphic to see how to wire up your connections through a logic level converter.

Fritzing diagram showing how to do basic wiring of Redboard, Logic Level Converter, and LCDscreen

Firmware Overview

The most basic way to use these screens is to simply send characters to them. They will display on the screen as you send them, and then if you go beyond the last character of the screen, it will begin overwriting from the first spot.

You can choose to send characters over Serial UART, I2C, or SPI. The best way to learn about each communication protocol is to try out the “basic” example located in the github repository.

Note: The examples in this tutorial assume you are using the latest version of the Arduino IDE on your desktop. If this is your first time using Arduino, please review our tutorial on installing the Arduino IDE.

In addition to basic operation, there are special commands you can send the screen for special operations (like “clear screen” or set cursor position) and configuration settings (like BAUD RATE).

Configuration & Command Set

The special character for “or” (aka ‘|’) used to tell the screen to enter “settings mode”. You then follow this command with another special character (usually “ctrl+c”, ctrl+d, etc.). A complete table of commands are shown below in ASCII, DEC and HEX. Any one of these representations is acceptable when sending a command character.

The HD44780 LCD controller is very common. The extended commands for this chip include but are not limited to those described in table. Please refer to the HD44780 datasheet for more information.

Note, this “cheat sheet” is also located at the top of each example code section for easy reference.

ASCII DEC HEX Description
'|'1240x7CEnter Settings Mode
ctrl+h80x08Software reset of the system
ctrl+i90x09Enable/disable splash screen
ctrl+j100x0ASave currently displayed text as splash
ctrl+k110x0BChange baud to 2400bps
ctrl+l120x0CChange baud to 4800bps
ctrl+m130x0DChange baud to 9600bps
ctrl+n140x0EChange baud to 14400bps
ctrl+o150x0FChange baud to 19200bps
ctrl+p160x10Change baud to 38400bps
ctrl+q170x11Change baud to 57600bps
ctrl+r180x12Change baud to 115200bps
ctrl+s190x13Change baud to 230400bps
ctrl+t200x14Change baud to 460800bps
ctrl+u210x15Change baud to 921600bps
ctrl+v220x16Change baud to 1000000bps
ctrl+w230x17Change baud to 1200bps
ctrl+x240x18Change the contrast. Follow Ctrl+x with number 0 to 255. 40 is default.
ctrl+y250x19Change the TWI address. Follow Ctrl+x with number 0 to 255. 114 (0x72) is default.
ctrl+z260x1AEnable/disable ignore RX pin on startup (ignore emergency reset)
'-'450x2DClear display. Move cursor to home position.
n/a128-1570x80-0x9DSet the primary backlight brightness. 128 = Off, 157 = 100%.
n/a158-1870x9E-0xBBSet the green backlight brightness. 158 = Off, 187 = 100%.
n/a188-2170xBC-0xD9Set the blue backlight brightness. 188 = Off, 217 = 100%.

OpenLCD “Cheat Sheet” Command Set

Clear Screen and Set Cursor Position

Clear display and set cursor position are the two commands that are used frequently. To clear the screen, send the control character ‘|’ followed by ‘-’. Clearing the screen resets the cursor position back to position 0 (i.e. the first character on the first line).

Here’s how you could do it doing a Serial UART write on software serial:

language:cpp
OpenLCD.write('|'); //Send setting character
OpenLCD.write('-'); //Send clear display character

Note, most of the example sketches in the repo use these two commands during setup(), so you can try any of the examples out to see these commands in action.

To set the active cursor position, send the control character 254 followed by 128 + row + position. To give this a shot, check out the complete example sketch in the github repo or copy and paste the following into your Arduino IDE:

language:cpp
/*
 OpenLCD is an LCD with Serial/I2C/SPI interfaces.
 By: Nathan Seidle
 SparkFun Electronics
 Date: April 19th, 2015
 License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).

 OpenLCD gives the user multiple interfaces (serial, I2C, and SPI) to control an LCD. SerLCD was the original
 serial LCD from SparkFun that ran on the PIC 16F88 with only a serial interface and limited feature set.
 This is an updated serial LCD.

 This example shows how to change the position of the cursor. This is very important as this is the
 fastest way to update the screen, ie - rather than clearing the display and re-transmitting a handful of bytes
 a cursor move allows us to re-paint only what we need to update.

 We assume the module is currently at default 9600bps.

 We use software serial because if OpenLCD is attached to an Arduino's hardware serial port during bootloading 
 it can cause problems for both devices.

 Note: If OpenLCD gets into an unknown state or you otherwise can't communicate with it send 18 (0x12 or ctrl+r) 
 at 9600 baud while the splash screen is active and the unit will reset to 9600 baud.

 Emergency reset: If you get OpenLCD stuck into an unknown baud rate, unknown I2C address, etc, there is a 
 safety mechanism built-in. Tie the RX pin to ground and power up OpenLCD. You should see the splash screen 
 then "System reset Power cycle me" and the backlight will begin to blink. Now power down OpenLCD and remove 
 the RX/GND jumper. OpenLCD is now reset to 9600bps with a I2C address of 0x72. Note: This feature can be 
 disabled if necessary. See *Ignore Emergency Reset* for more information.

 To get this code to work, attached an OpenLCD to an Arduino Uno using the following pins:
 RX (OpenLCD) to Pin 7 (Arduino)
 VIN to 5V
 GND to GND

 Command cheat sheet:
 ASCII / DEC / HEX
 '|'    / 124 / 0x7C - Put into setting mode
 Ctrl+c / 3 / 0x03 - Change width to 20
 Ctrl+d / 4 / 0x04 - Change width to 16
 Ctrl+e / 5 / 0x05 - Change lines to 4
 Ctrl+f / 6 / 0x06 - Change lines to 2
 Ctrl+g / 7 / 0x07 - Change lines to 1
 Ctrl+h / 8 / 0x08 - Software reset of the system
 Ctrl+i / 9 / 0x09 - Enable/disable splash screen
 Ctrl+j / 10 / 0x0A - Save currently displayed text as splash
 Ctrl+k / 11 / 0x0B - Change baud to 2400bps
 Ctrl+l / 12 / 0x0C - Change baud to 4800bps
 Ctrl+m / 13 / 0x0D - Change baud to 9600bps
 Ctrl+n / 14 / 0x0E - Change baud to 14400bps
 Ctrl+o / 15 / 0x0F - Change baud to 19200bps
 Ctrl+p / 16 / 0x10 - Change baud to 38400bps
 Ctrl+q / 17 / 0x11 - Change baud to 57600bps
 Ctrl+r / 18 / 0x12 - Change baud to 115200bps
 Ctrl+s / 19 / 0x13 - Change baud to 230400bps
 Ctrl+t / 20 / 0x14 - Change baud to 460800bps
 Ctrl+u / 21 / 0x15 - Change baud to 921600bps
 Ctrl+v / 22 / 0x16 - Change baud to 1000000bps
 Ctrl+w / 23 / 0x17 - Change baud to 1200bps
 Ctrl+x / 24 / 0x18 - Change the contrast. Follow Ctrl+x with number 0 to 255. 120 is default.
 Ctrl+y / 25 / 0x19 - Change the TWI address. Follow Ctrl+x with number 0 to 255. 114 (0x72) is default.
 Ctrl+z / 26 / 0x1A - Enable/disable ignore RX pin on startup (ignore emergency reset)
 '-'    / 45 / 0x2D - Clear display. Move cursor to home position.
        / 128-157 / 0x80-0x9D - Set the primary backlight brightness. 128 = Off, 157 = 100%.
        / 158-187 / 0x9E-0xBB - Set the green backlight brightness. 158 = Off, 187 = 100%.
        / 188-217 / 0xBC-0xD9 - Set the blue backlight brightness. 188 = Off, 217 = 100%.

 For example, to change the baud rate to 115200 send 124 followed by 18.

*/

#include <SoftwareSerial.h>

SoftwareSerial OpenLCD(6, 7); //RX (not used), TX

int counter = 250;

void setup()
{
  Serial.begin(9600); //Start serial communication at 9600 for debug statements
  Serial.println("OpenLCD Example Code");

  OpenLCD.begin(115200); //Begin communication with OpenLCD

  //Send the reset command to the display - this forces the cursor to return to the beginning of the display
  OpenLCD.write('|'); //Send setting character
  OpenLCD.write('-'); //Send clear display character

  OpenLCD.print("Hello World!    Counter: "); //For 16x2 LCDs
  //OpenLCD.print("Hello World!        Counter: "); //For 20x4 LCDs
}

void loop()
{
  OpenLCD.write(254); //Send command character
  OpenLCD.write(128 + 64 + 9); //Change the position (128) of the cursor to 2nd row (64), position 9 (9)

  OpenLCD.print(counter++); //Re-print the counter
  //OpenLCD.print(""); //When the counter wraps back to 0 it leaves artifacts on the display

  delay(2); //Hang out for a bit if we are running at 115200bps
}

The two lines of code that are actually changing the cursor position are as follows:

language:cpp
OpenLCD.write(254); //Send command character
OpenLCD.write(128 + 64 + 9); //Change the position (128) of the cursor to 2nd row (64), position 9 (9)

The example sets the cursor to the second row, position 9. To set the cursor to the first row, position 0, the command would look like this:

language:cpp
OpenLCD.write(254); //Send command character
OpenLCD.write(128 + 0 + 0); //Change the position (128) of the cursor to 1st row (0), position 0 (0)

Use the following tables to see row commands and available positions:

16 Character Displays
Line Number (command) Viewable Cursor Positions
1 (0)0-15
2 (64)0-15
20 Character Displays
Line Number (command) Viewable Cursor Positions
1 (0)0-19
2 (64)0-19
3 (20)0-19
4 (84)0-19

Setting Up the LCD Size

You should never need to send any screen size configuration commands to setup these screens. During setup(), the firmware looks at a specific pin that is either left floating or tied high. From this it can determine which screen size it is populated on (16x2 or 20x4). However, the commands are still available for manually setting the width and lines.

ASCII DEC HEX Description
'|'1240x7CEnter Settings Mode
ctrl+c30x03Change width to 20
ctrl+d40x04Change width to 16
ctrl+e50x05Change lines to 4
ctrl+f60x06Change lines to 2
ctrl+g70x07Change lines to 1

Changing the Baud Rate

The screens ship out with a default baud rate setting to 9600 baud, but they can be set to a variety of baud rates. The 11.0592 MHz crystal provides greater clock accuracy and allows for baud rates up to 1MHz!

To change the baud rate, you will need to send two commands: First, send the “|” command to enter settings mode. Second, send the desired baud rate command. (For example, to set it to 57600, you’d send |, then Ctrl + q)

Here is a table will all of the available baud rate settings commands:

ASCII DEC HEX Description
'|'1240x7CEnter Settings Mode
ctrl+k110x0BChange baud to 2400bps
ctrl+l120x0CChange baud to 4800bps
ctrl+m130x0DChange baud to 9600bps
ctrl+n140x0EChange baud to 14400bps
ctrl+o150x0FChange baud to 19200bps
ctrl+p160x10Change baud to 38400bps
ctrl+q170x11Change baud to 57600bps
ctrl+r180x12Change baud to 115200bps
ctrl+s190x13Change baud to 230400bps
ctrl+t200x14Change baud to 460800bps
ctrl+u210x15Change baud to 921600bps
ctrl+v220x16Change baud to 1000000bps

OpenLCD Baud Rate Command Set

If your screen enters into an unknown state or you otherwise can’t communicate with it, try sending a Ctrl + r (0x12) character at 9600 baud while the splash screen is active (during the first 500 ms of boot-up) and the unit will reset to 9600 baud.

Backlight Brightness

These screens provide you with control of the backlight to one of 30 different brightness levels on each of the colors (Red, Green and Blue). With this, you can mix colors together to get almost any custom color you’d like. This is also handy when power consumption of the unit must be minimized. By reducing the brightness, the overall backlight current consumption is reduced.

To change the backlight brightness, you will need to send two commands: First, send the “|” command to enter settings mode. Second, send a number that corresponds to the color and brightness you’d like to set. (For example, to set the Green backlight to 100%, you’d send |, then 187). For some good example code on how to adjust any and all of the colors, check out the example sketch here or copy and paste the code below into your Arduino IDE:

language:cpp
/*
 OpenLCD is an LCD with serial/I2C/SPI interfaces.
 By: Nathan Seidle
 SparkFun Electronics
 Date: April 19th, 2015
 License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).
 OpenLCD gives the user multiple interfaces (serial, I2C, and SPI) to control an LCD. SerLCD was the original
 serial LCD from SparkFun that ran on the PIC 16F88 with only a serial interface and limited feature set.
 This is an updated serial LCD.

 This example shows how to change the backlight brightness. We assume the module is currently at default 9600bps.
 We use software serial because if OpenLCD is attached to an Arduino's hardware serial port during bootloading 
 it can cause problems for both devices.
 Note: If OpenLCD gets into an unknown state or you otherwise can't communicate with it send 18 (0x12 or ctrl+r) 
 at 9600 baud while the splash screen is active and the unit will reset to 9600 baud.
 Emergency reset: If you get OpenLCD stuck into an unknown baud rate, unknown I2C address, etc, there is a 
 safety mechanism built-in. Tie the RX pin to ground and power up OpenLCD. You should see the splash screen 
 then "System reset Power cycle me" and the backlight will begin to blink. Now power down OpenLCD and remove 
 the RX/GND jumper. OpenLCD is now reset to 9600bps with a I2C address of 0x72. Note: This feature can be 
 disabled if necessary. See *Ignore Emergency Reset* for more information.
 To get this code to work, attached an OpenLCD to an Arduino Uno using the following pins:
 RX (OpenLCD) to Pin 7 (Arduino)
 VIN to 5V
 GND to GND

 Command cheat sheet:
 ASCII / DEC / HEX
 '|'    / 124 / 0x7C - Put into setting mode
 Ctrl+c / 3 / 0x03 - Change width to 20
 Ctrl+d / 4 / 0x04 - Change width to 16
 Ctrl+e / 5 / 0x05 - Change lines to 4
 Ctrl+f / 6 / 0x06 - Change lines to 2
 Ctrl+g / 7 / 0x07 - Change lines to 1
 Ctrl+h / 8 / 0x08 - Software reset of the system
 Ctrl+i / 9 / 0x09 - Enable/disable splash screen
 Ctrl+j / 10 / 0x0A - Save currently displayed text as splash
 Ctrl+k / 11 / 0x0B - Change baud to 2400bps
 Ctrl+l / 12 / 0x0C - Change baud to 4800bps
 Ctrl+m / 13 / 0x0D - Change baud to 9600bps
 Ctrl+n / 14 / 0x0E - Change baud to 14400bps
 Ctrl+o / 15 / 0x0F - Change baud to 19200bps
 Ctrl+p / 16 / 0x10 - Change baud to 38400bps
 Ctrl+q / 17 / 0x11 - Change baud to 57600bps
 Ctrl+r / 18 / 0x12 - Change baud to 115200bps
 Ctrl+s / 19 / 0x13 - Change baud to 230400bps
 Ctrl+t / 20 / 0x14 - Change baud to 460800bps
 Ctrl+u / 21 / 0x15 - Change baud to 921600bps
 Ctrl+v / 22 / 0x16 - Change baud to 1000000bps
 Ctrl+w / 23 / 0x17 - Change baud to 1200bps
 Ctrl+x / 24 / 0x18 - Change the contrast. Follow Ctrl+x with number 0 to 255. 120 is default.
 Ctrl+y / 25 / 0x19 - Change the TWI address. Follow Ctrl+x with number 0 to 255. 114 (0x72) is default.
 Ctrl+z / 26 / 0x1A - Enable/disable ignore RX pin on startup (ignore emergency reset)
 '-'    / 45 / 0x2D - Clear display. Move cursor to home position.
        / 128-157 / 0x80-0x9D - Set the primary backlight brightness. 128 = Off, 157 = 100%.
        / 158-187 / 0x9E-0xBB - Set the green backlight brightness. 158 = Off, 187 = 100%.
        / 188-217 / 0xBC-0xD9 - Set the blue backlight brightness. 188 = Off, 217 = 100%.

 For example, to change the baud rate to 115200 send 124 followed by 18.
*/

#include <SoftwareSerial.h>

SoftwareSerial OpenLCD(6, 7); //RX (not used), TX

byte counter = 0;

void setup()
{
  Serial.begin(9600); //Begin local communication for debug statements

  OpenLCD.begin(9600); //Begin communication with OpenLCD

  OpenLCD.write('|'); //Put LCD into setting mode
  OpenLCD.write(158 + 0); //Set green backlight amount to 0%

  OpenLCD.write('|'); //Put LCD into setting mode
  OpenLCD.write(188 + 0); //Set blue backlight amount to 0%
}

void loop()
{
  //Control red backlight
  Serial.println("Mono/Red backlight set to 0%");
  OpenLCD.write('|'); //Put LCD into setting mode
  OpenLCD.write(128); //Set white/red backlight amount to 0%

  delay(2000);

  //Control red backlight
  Serial.println("Mono/Red backlight set to 51%");
  OpenLCD.write('|'); //Put LCD into setting mode
  OpenLCD.write(128 + 15); //Set white/red backlight amount to 51%

  delay(2000);

  //Control red backlight
  Serial.println("Mono/Red backlight set to 100%");
  OpenLCD.write('|'); //Put LCD into setting mode
  OpenLCD.write(128 + 29); //Set white/red backlight amount to 100%

  delay(2000);

  //The following green and blue backlight control only apply if you have an RGB backlight enabled LCD

  all_off(); // turn off all backlights - see function below

  //Control green backlight
  Serial.println("Green backlight set to 51%");
  OpenLCD.write('|'); //Put LCD into setting mode
  OpenLCD.write(158 + 15); //Set green backlight amount to 51%

  delay(2000);

  //Control green backlight
  Serial.println("Green backlight set to 100%");
  OpenLCD.write('|'); //Put LCD into setting mode
  OpenLCD.write(158 + 29); //Set green backlight amount to 100%

  delay(2000);

  all_off(); // turn off all backlights - see function below

  //Control blue backlight
  Serial.println("Blue backlight set to 51%");
  OpenLCD.write('|'); //Put LCD into setting mode
  OpenLCD.write(188 + 15); //Set blue backlight amount to 51%

  delay(2000);

  //Control blue backlight
  Serial.println("Blue backlight set to 100%");
  OpenLCD.write('|'); //Put LCD into setting mode
  OpenLCD.write(188 + 29); //Set blue backlight amount to 100%

  delay(2000);

  all_off(); // turn off all backlights - see function below  

}

void all_off(void)
{
  // Set all colors to 0

  OpenLCD.write('|'); //Put LCD into setting mode
  OpenLCD.write(128); //Set white/red backlight amount to 0%    

  OpenLCD.write('|'); //Put LCD into setting mode
  OpenLCD.write(158 + 0); //Set green backlight amount to 0%

  OpenLCD.write('|'); //Put LCD into setting mode
  OpenLCD.write(188 + 0); //Set blue backlight amount to 0%

  delay(2000);  
}

And here is a table showing all of the available backlight settings and commands:

ASCII DEC HEX Description
n/a128-1570x80-0x9DSet the primary backlight brightness. 128 = Off, 157 = 100%.
n/a158-1870x9E-0xBBSet the green backlight brightness. 158 = Off, 187 = 100%.
n/a188-2170xBC-0xD9Set the blue backlight brightness. 188 = Off, 217 = 100%.

OpenLCD Backlight Command Set

Splash Screen

These LCD screens have a splash screen by default that reads “SparkFun OpenLCD Baud:9600”. This splash screen verifies that the unit is powered, working correctly, and that the connection to the LCD is correct. The splash screen is displayed for 500 ms during boot-up and may be turned off if desired.

Setting Splash Screen

Default Splash Screen showing SparkFun OpenLCD Baud:9600 vs custom Splash screen showing Custom Splash Looking Good!

To make a custom splash screen, you need to send the characters you want to display (above we sent the characters “Custom Splash Looking good!”) followed by |, then Ctrl + j). You will see a quick pop-up message display “Flash Recorded”. Cycle power to test. You can also try out the example sketch located in the github repo or copy and paste the code below into your Arduino IDE:

language:cpp
/*
 OpenLCD is an LCD with serial/I2C/SPI interfaces.
 By: Nathan Seidle, Pete Lewis
 SparkFun Electronics
 Date: 7/26/2018
 License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).
 OpenLCD gives the user multiple interfaces (serial, I2C, and SPI) to control an LCD. SerLCD was the original
 serial LCD from SparkFun that ran on the PIC 16F88 with only a serial interface and limited feature set.
 This is an updated serial LCD.

 This example shows how to change the Splash Screen contents. We assume the module is currently at default 9600bps.
 We use software serial because if OpenLCD is attached to an Arduino's hardware serial port during bootloading 
 it can cause problems for both devices.
 Note: If OpenLCD gets into an unknown state or you otherwise can't communicate with it send 18 (0x12 or ctrl+r) 
 at 9600 baud while the splash screen is active and the unit will reset to 9600 baud.
 Emergency reset: If you get OpenLCD stuck into an unknown baud rate, unknown I2C address, etc, there is a 
 safety mechanism built-in. Tie the RX pin to ground and power up OpenLCD. You should see the splash screen 
 then "System reset Power cycle me" and the backlight will begin to blink. Now power down OpenLCD and remove 
 the RX/GND jumper. OpenLCD is now reset to 9600bps with a I2C address of 0x72. Note: This feature can be 
 disabled if necessary. See *Ignore Emergency Reset* for more information.
 To get this code to work, attached an OpenLCD to an Arduino Uno using the following pins:
 RX (OpenLCD) to Pin 7 (Arduino)
 VIN to 5V
 GND to GND

 Command cheat sheet:
 ASCII / DEC / HEX
 '|'    / 124 / 0x7C - Put into setting mode
 Ctrl+c / 3 / 0x03 - Change width to 20
 Ctrl+d / 4 / 0x04 - Change width to 16
 Ctrl+e / 5 / 0x05 - Change lines to 4
 Ctrl+f / 6 / 0x06 - Change lines to 2
 Ctrl+g / 7 / 0x07 - Change lines to 1
 Ctrl+h / 8 / 0x08 - Software reset of the system
 Ctrl+i / 9 / 0x09 - Enable/disable splash screen
 Ctrl+j / 10 / 0x0A - Save currently displayed text as splash
 Ctrl+k / 11 / 0x0B - Change baud to 2400bps
 Ctrl+l / 12 / 0x0C - Change baud to 4800bps
 Ctrl+m / 13 / 0x0D - Change baud to 9600bps
 Ctrl+n / 14 / 0x0E - Change baud to 14400bps
 Ctrl+o / 15 / 0x0F - Change baud to 19200bps
 Ctrl+p / 16 / 0x10 - Change baud to 38400bps
 Ctrl+q / 17 / 0x11 - Change baud to 57600bps
 Ctrl+r / 18 / 0x12 - Change baud to 115200bps
 Ctrl+s / 19 / 0x13 - Change baud to 230400bps
 Ctrl+t / 20 / 0x14 - Change baud to 460800bps
 Ctrl+u / 21 / 0x15 - Change baud to 921600bps
 Ctrl+v / 22 / 0x16 - Change baud to 1000000bps
 Ctrl+w / 23 / 0x17 - Change baud to 1200bps
 Ctrl+x / 24 / 0x18 - Change the contrast. Follow Ctrl+x with number 0 to 255. 120 is default.
 Ctrl+y / 25 / 0x19 - Change the TWI address. Follow Ctrl+x with number 0 to 255. 114 (0x72) is default.
 Ctrl+z / 26 / 0x1A - Enable/disable ignore RX pin on startup (ignore emergency reset)
 '-'    / 45 / 0x2D - Clear display. Move cursor to home position.
        / 128-157 / 0x80-0x9D - Set the primary backlight brightness. 128 = Off, 157 = 100%.
        / 158-187 / 0x9E-0xBB - Set the green backlight brightness. 158 = Off, 187 = 100%.
        / 188-217 / 0xBC-0xD9 - Set the blue backlight brightness. 188 = Off, 217 = 100%.

 For example, to change the baud rate to 115200 send 124 followed by 18.
*/

#include <SoftwareSerial.h>

SoftwareSerial OpenLCD(6, 7); //RX (not used), TX

void setup()
{
  Serial.begin(9600); //Begin local communication for debug statements

  OpenLCD.begin(9600); //Begin communication with OpenLCD

  delay(1000);

  OpenLCD.write('|'); //Put LCD into setting mode
  OpenLCD.write('-'); // clear screen

  delay(1000);

  OpenLCD.print("Custom Splash   Looking good!"); // Send our new content to display - this will soon become our new splash screen.

  OpenLCD.write('|'); //Put LCD into setting mode
  OpenLCD.write(10); //Set current contents to splash screen memory (this is also a "ctrl-j", if you are doing it manually)

}

void loop()
{
  // nothing here, just doing this example in setup()
}

Turning Splash Screen On/Off

To disable the splash screen, send |, then Ctrl + i. Every time this command is sent to the unit, the splash screen display option will toggle. If the splash screen is currently being displayed, sending |, then Ctrl + i will disable the splash screen during the next boot, and sending |, then Ctrl + i characters again will enable the splash screen.

Serial UART: Hardware Hookup

Here’s how to setup your hardware for most of the Serial UART example code.

Fritzing diagram showing the wiring for Serial UART with a redboard, a logic level converter, and the SerLCD

Note, some other examples require additional wiring (for example the contrast example requires a trimpot for variable control). We will show Fritzing graphics for each example covered in this tutorial. For the remaining tutorials, please look at the comments at the top of the example code for info on how to hookup the hardware.

Serial UART: Example Code - Basic

You can download the latest example code for this experiment from the github repo or you can copy and paste the following code into your Arduino IDE:

language:cpp
/*
 OpenLCD is an LCD with serial/I2C/SPI interfaces.
 By: Nathan Seidle
 SparkFun Electronics
 Date: April 19th, 2015
 License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).

 This example shows how to display a counter on the display over serial. We use software serial because if 
 OpenLCD is attached to an Arduino's hardware serial port during bootloading  it can cause problems for both devices.

 To get this code to work, attached an OpenLCD to an Arduino Uno using the following pins:
 RX (OpenLCD) to Pin 7 (Arduino)
 VIN to 5V
 GND to GND

*/

#include <SoftwareSerial.h>

SoftwareSerial OpenLCD(6, 7); //RX, TX

byte counter = 0;
byte contrast = 10;

void setup()
{
  Serial.begin(9600); //Start serial communication at 9600 for debug statements
  Serial.println("OpenLCD Example Code");

  OpenLCD.begin(9600); //Start communication with OpenLCD

  //Send contrast setting
  OpenLCD.write('|'); //Put LCD into setting mode
  OpenLCD.write(24); //Send contrast command
  OpenLCD.write(contrast);

}

void loop()
{
  //Send the clear command to the display - this returns the cursor to the beginning of the display
  OpenLCD.write('|'); //Setting character
  OpenLCD.write('-'); //Clear display

  OpenLCD.print("Hello World!    Counter: "); //For 16x2 LCD
  //OpenLCD.print("Hello World!        Counter: "); //For 20x4 LCD
  OpenLCD.print(counter++);

  delay(250); //Hang out for a bit
}

Here's what you should see after uploading the code to your Arduino. Try changing the text with a different message!

Hello World! Counter: 11 is displayed on LCD screen once code is uploaded to the redboard

To send text to the board, wait 1/2 second (500ms) after power up for the splash screen to clear, then send text to the display through your serial port. The display understands all of the standard ASCII characters (upper and lowercase text, numbers, and punctuation), plus a number of graphic symbols and Japanese characters. See the HD44780 datasheet for the full list of supported characters.

If you send data that goes past the end of the first line, it will skip to the start of the second line. If you go past the end of the second line, the display will jump back up to the beginning of the first line.

Serial UART: Example Code - Contrast Control with a Trimpot

For this contrast control example, you will need to wire up a trimpot. This will allow you to adjust the contrast in real time and find the best setting for your environment. Wire things up like this:

Fritzing diagram showing the wiring for Serial UART with a redboard, a logic level converter, the SerLCD, and the trimpot

You can download the latest example code for this experiment from the github repo or you can copy and paste the following code into your Arduino IDE:

language:cpp
 /*
 OpenLCD is an LCD with Serial/I2C/SPI interfaces.
 By: Nathan Seidle
 SparkFun Electronics
 Date: April 19th, 2015
 License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).

 OpenLCD gives the user multiple interfaces (serial, I2C, and SPI) to control an LCD. SerLCD was the original
 serial LCD from SparkFun that ran on the PIC 16F88 with only a serial interface and limited feature set.
 This is an updated serial LCD.

 This example shows how to change the contrast using a trimpot. We assume the module is currently at 
 default 9600bps.

 We use software serial because if OpenLCD is attached to an Arduino's hardware serial port during bootloading 
 it can cause problems for both devices.

 Note: If OpenLCD gets into an unknown state or you otherwise can't communicate with it send 18 (0x12 or ctrl+r) 
 at 9600 baud while the splash screen is active and the unit will reset to 9600 baud.

 Emergency reset: If you get OpenLCD stuck into an unknown baud rate, unknown I2C address, etc, there is a 
 safety mechanism built-in. Tie the RX pin to ground and power up OpenLCD. You should see the splash screen 
 then "System reset Power cycle me" and the backlight will begin to blink. Now power down OpenLCD and remove 
 the RX/GND jumper. OpenLCD is now reset to 9600bps with a I2C address of 0x72. Note: This feature can be 
 disabled if necessary. See *Ignore Emergency Reset* for more information.

 To get this code to work, attached an OpenLCD to an Arduino Uno using the following pins:
 RX (OpenLCD) to Pin 7 (Arduino)
 VIN to 5V
 GND to GND

 Hook a trimpot up:
 Pin 1 - 5V
 Pin 2 - A0
 Pin 3 - GND

*/

#include <SoftwareSerial.h>

SoftwareSerial OpenLCD(6, 7); //RX (not used), TX

byte counter = 0;

void setup()
{
  Serial.begin(9600); //Start serial communication at 9600 for debug statements
  Serial.println("OpenLCD Example Code");

  OpenLCD.begin(9600); //Begin communication with OpenLCD

  //Send the reset command to the display - this forces the cursor to return to the beginning of the display
  OpenLCD.write('|'); //Send setting character
  OpenLCD.write('-'); //Send clear display character
  OpenLCD.print("Contrast test");

  pinMode(A0, INPUT);
}

int oldContrast = 0;
long startTime = 0;
bool settingSent = false;

void loop()
{
  int trimpot = averageAnalogRead(A0);
  int newContrast = map(trimpot, 0, 1023, 0, 255); //Map this analog value down to 0-255

  //Only send new contrast setting to display if the user changes the trimpot
  if(newContrast != oldContrast)
  {
    Serial.print("nc: ");
    Serial.println(newContrast);

    oldContrast = newContrast; //Update

    startTime = millis();
    settingSent = false;
  }

  //Wait at least 100ms for user to stop turning trimpot
  //OpenLCD displays the contrast setting for around 2 seconds so we can't send constant updates
  if(millis() - startTime > 500 && settingSent == false)
  {  
    //Send contrast setting
    OpenLCD.write('|'); //Put LCD into setting mode
    OpenLCD.write(24); //Send contrast command
    OpenLCD.write(newContrast);

    settingSent = true;

    Serial.print("New contrast: ");
    Serial.println(newContrast);
  }

  delay(100); //Hang out for a bit
}

//Takes an average of readings on a given pin
//Returns the average
int averageAnalogRead(byte pinToRead)
{
  byte numberOfReadings = 8;
  unsigned int runningValue = 0; 

  for(int x = 0 ; x < numberOfReadings ; x++)
    runningValue += analogRead(pinToRead);
  runningValue /= numberOfReadings;

  return(runningValue);  
}

After uploading your sketch, you can now try adjusting the trimpot and watch the contrast change in real time. Here are a few examples that I see:

Contrast Setting: 0Contrast Setting: 55Contrast Setting: 80

Note, if you are not seeing any text in the LCD, make sure and try rotating to either extreme. If you are up above 100, then in some cases you may not see any text. Watching your serial monitor from your Arduino can be helpful as well. It will tell you the settings as you are sending them to the LCD. Here is some example serial debug that I see while I adjust the trimpot:

Serial Monitor output showing the contrast levels changing

Serial UART: Example Code - Backlight Control

For this next example, you can use the same exact hardware setup as in the previous two examples (Serial Basic or Serial Contrast). To jump right in and start playing with backlight control, you can get the latest example code from the github repo or you can copy and paste the following code into your Arduino IDE:

language:cpp
/*
 OpenLCD is an LCD with serial/I2C/SPI interfaces.
 By: Nathan Seidle
 SparkFun Electronics
 Date: April 19th, 2015
 License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).
 OpenLCD gives the user multiple interfaces (serial, I2C, and SPI) to control an LCD. SerLCD was the original
 serial LCD from SparkFun that ran on the PIC 16F88 with only a serial interface and limited feature set.
 This is an updated serial LCD.

 This example shows how to change the backlight brightness. We assume the module is currently at default 9600bps.
 We use software serial because if OpenLCD is attached to an Arduino's hardware serial port during bootloading 
 it can cause problems for both devices.
 Note: If OpenLCD gets into an unknown state or you otherwise can't communicate with it send 18 (0x12 or ctrl+r) 
 at 9600 baud while the splash screen is active and the unit will reset to 9600 baud.
 Emergency reset: If you get OpenLCD stuck into an unknown baud rate, unknown I2C address, etc, there is a 
 safety mechanism built-in. Tie the RX pin to ground and power up OpenLCD. You should see the splash screen 
 then "System reset Power cycle me" and the backlight will begin to blink. Now power down OpenLCD and remove 
 the RX/GND jumper. OpenLCD is now reset to 9600bps with a I2C address of 0x72. Note: This feature can be 
 disabled if necessary. See *Ignore Emergency Reset* for more information.
 To get this code to work, attached an OpenLCD to an Arduino Uno using the following pins:
 RX (OpenLCD) to Pin 7 (Arduino)
 VIN to 5V
 GND to GND

 Command cheat sheet:
 ASCII / DEC / HEX
 '|'    / 124 / 0x7C - Put into setting mode
 Ctrl+c / 3 / 0x03 - Change width to 20
 Ctrl+d / 4 / 0x04 - Change width to 16
 Ctrl+e / 5 / 0x05 - Change lines to 4
 Ctrl+f / 6 / 0x06 - Change lines to 2
 Ctrl+g / 7 / 0x07 - Change lines to 1
 Ctrl+h / 8 / 0x08 - Software reset of the system
 Ctrl+i / 9 / 0x09 - Enable/disable splash screen
 Ctrl+j / 10 / 0x0A - Save currently displayed text as splash
 Ctrl+k / 11 / 0x0B - Change baud to 2400bps
 Ctrl+l / 12 / 0x0C - Change baud to 4800bps
 Ctrl+m / 13 / 0x0D - Change baud to 9600bps
 Ctrl+n / 14 / 0x0E - Change baud to 14400bps
 Ctrl+o / 15 / 0x0F - Change baud to 19200bps
 Ctrl+p / 16 / 0x10 - Change baud to 38400bps
 Ctrl+q / 17 / 0x11 - Change baud to 57600bps
 Ctrl+r / 18 / 0x12 - Change baud to 115200bps
 Ctrl+s / 19 / 0x13 - Change baud to 230400bps
 Ctrl+t / 20 / 0x14 - Change baud to 460800bps
 Ctrl+u / 21 / 0x15 - Change baud to 921600bps
 Ctrl+v / 22 / 0x16 - Change baud to 1000000bps
 Ctrl+w / 23 / 0x17 - Change baud to 1200bps
 Ctrl+x / 24 / 0x18 - Change the contrast. Follow Ctrl+x with number 0 to 255. 120 is default.
 Ctrl+y / 25 / 0x19 - Change the TWI address. Follow Ctrl+x with number 0 to 255. 114 (0x72) is default.
 Ctrl+z / 26 / 0x1A - Enable/disable ignore RX pin on startup (ignore emergency reset)
 '-'    / 45 / 0x2D - Clear display. Move cursor to home position.
        / 128-157 / 0x80-0x9D - Set the primary backlight brightness. 128 = Off, 157 = 100%.
        / 158-187 / 0x9E-0xBB - Set the green backlight brightness. 158 = Off, 187 = 100%.
        / 188-217 / 0xBC-0xD9 - Set the blue backlight brightness. 188 = Off, 217 = 100%.

 For example, to change the baud rate to 115200 send 124 followed by 18.
*/

#include <SoftwareSerial.h>

SoftwareSerial OpenLCD(6, 7); //RX (not used), TX

byte counter = 0;

void setup()
{
  Serial.begin(9600); //Begin local communication for debug statements

  OpenLCD.begin(9600); //Begin communication with OpenLCD

  OpenLCD.write('|'); //Put LCD into setting mode
  OpenLCD.write(158 + 0); //Set green backlight amount to 0%

  OpenLCD.write('|'); //Put LCD into setting mode
  OpenLCD.write(188 + 0); //Set blue backlight amount to 0%
}

void loop()
{
  //Control red backlight
  Serial.println("Mono/Red backlight set to 0%");
  OpenLCD.write('|'); //Put LCD into setting mode
  OpenLCD.write(128); //Set white/red backlight amount to 0%

  delay(2000);

  //Control red backlight
  Serial.println("Mono/Red backlight set to 51%");
  OpenLCD.write('|'); //Put LCD into setting mode
  OpenLCD.write(128 + 15); //Set white/red backlight amount to 51%

  delay(2000);

  //Control red backlight
  Serial.println("Mono/Red backlight set to 100%");
  OpenLCD.write('|'); //Put LCD into setting mode
  OpenLCD.write(128 + 29); //Set white/red backlight amount to 100%

  delay(2000);

  //The following green and blue backlight control only apply if you have an RGB backlight enabled LCD

  all_off(); // turn off all backlights - see function below

  //Control green backlight
  Serial.println("Green backlight set to 51%");
  OpenLCD.write('|'); //Put LCD into setting mode
  OpenLCD.write(158 + 15); //Set green backlight amount to 51%

  delay(2000);

  //Control green backlight
  Serial.println("Green backlight set to 100%");
  OpenLCD.write('|'); //Put LCD into setting mode
  OpenLCD.write(158 + 29); //Set green backlight amount to 100%

  delay(2000);

  all_off(); // turn off all backlights - see function below

  //Control blue backlight
  Serial.println("Blue backlight set to 51%");
  OpenLCD.write('|'); //Put LCD into setting mode
  OpenLCD.write(188 + 15); //Set blue backlight amount to 51%

  delay(2000);

  //Control blue backlight
  Serial.println("Blue backlight set to 100%");
  OpenLCD.write('|'); //Put LCD into setting mode
  OpenLCD.write(188 + 29); //Set blue backlight amount to 100%

  delay(2000);

  all_off(); // turn off all backlights - see function below  

}

void all_off(void)
{
  // Set all colors to 0

  OpenLCD.write('|'); //Put LCD into setting mode
  OpenLCD.write(128); //Set white/red backlight amount to 0%    

  OpenLCD.write('|'); //Put LCD into setting mode
  OpenLCD.write(158 + 0); //Set green backlight amount to 0%

  OpenLCD.write('|'); //Put LCD into setting mode
  OpenLCD.write(188 + 0); //Set blue backlight amount to 0%

  delay(2000);  
}

With this code running, you should see your backlight colors cycle through a pattern of 0%, then 50%, then 100%. It will show this for each color individually (Red, Green, and Blue). Here are some shots of what it looks like for me when I run the code. Note, yours may vary slightly due to your RAW input voltage and the temperature of your environment.

I2C: Hardware Hookup & Example Code - Basic

For I2C, there are only 2 communication lines you need to connect: SDA and CLK. But remember, these must be 3.3V logic. So if you are using a 5V Redboard like we are, then you’ll need to convert SDA and SCL from 5V to 3.3V. See the following Fritzing diagram for how you can wire this up:

Fritzing diagram showing the wiring for I2C with a redboard, a logic level converter, and the SerLCD

After you’ve got your I2C lines wired up properly, you can get the latest example code from the github repo or you can copy and paste the following code into your Arduino IDE:

language:cpp
/*
 OpenLCD is an LCD with Serial/I2C/SPI interfaces.
 By: Nathan Seidle
 SparkFun Electronics
 Date: April 19th, 2015
 License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).
 This is example code that shows how to send data over I2C to the display.
 Note: This code expects the display to be listening at the default I2C address. If your display is not at 0x72, you can
 do a hardware reset. Tie the RX pin to ground and power up OpenLCD. You should see the splash screen
 then "System reset Power cycle me" and the backlight will begin to blink. Now power down OpenLCD and remove
 the RX/GND jumper. OpenLCD is now reset.
 To get this code to work, attached an OpenLCD to an Arduino Uno using the following pins:
 SCL (OpenLCD) to A5 (Arduino)
 SDA to A4
 VIN to 5V
 GND to GND
 Command cheat sheet:
 ASCII / DEC / HEX
 '|'    / 124 / 0x7C - Put into setting mode
 Ctrl+c / 3 / 0x03 - Change width to 20
 Ctrl+d / 4 / 0x04 - Change width to 16
 Ctrl+e / 5 / 0x05 - Change lines to 4
 Ctrl+f / 6 / 0x06 - Change lines to 2
 Ctrl+g / 7 / 0x07 - Change lines to 1
 Ctrl+h / 8 / 0x08 - Software reset of the system
 Ctrl+i / 9 / 0x09 - Enable/disable splash screen
 Ctrl+j / 10 / 0x0A - Save currently displayed text as splash
 Ctrl+k / 11 / 0x0B - Change baud to 2400bps
 Ctrl+l / 12 / 0x0C - Change baud to 4800bps
 Ctrl+m / 13 / 0x0D - Change baud to 9600bps
 Ctrl+n / 14 / 0x0E - Change baud to 14400bps
 Ctrl+o / 15 / 0x0F - Change baud to 19200bps
 Ctrl+p / 16 / 0x10 - Change baud to 38400bps
 Ctrl+q / 17 / 0x11 - Change baud to 57600bps
 Ctrl+r / 18 / 0x12 - Change baud to 115200bps
 Ctrl+s / 19 / 0x13 - Change baud to 230400bps
 Ctrl+t / 20 / 0x14 - Change baud to 460800bps
 Ctrl+u / 21 / 0x15 - Change baud to 921600bps
 Ctrl+v / 22 / 0x16 - Change baud to 1000000bps
 Ctrl+w / 23 / 0x17 - Change baud to 1200bps
 Ctrl+x / 24 / 0x18 - Change the contrast. Follow Ctrl+x with number 0 to 255. 120 is default.
 Ctrl+y / 25 / 0x19 - Change the TWI address. Follow Ctrl+x with number 0 to 255. 114 (0x72) is default.
 Ctrl+z / 26 / 0x1A - Enable/disable ignore RX pin on startup (ignore emergency reset)
 '-'    / 45 / 0x2D - Clear display. Move cursor to home position.
        / 128-157 / 0x80-0x9D - Set the primary backlight brightness. 128 = Off, 157 = 100%.
        / 158-187 / 0x9E-0xBB - Set the green backlight brightness. 158 = Off, 187 = 100%.
        / 188-217 / 0xBC-0xD9 - Set the blue backlight brightness. 188 = Off, 217 = 100%.
 For example, to change the baud rate to 115200 send 124 followed by 18.
*/

#include <Wire.h>

#define DISPLAY_ADDRESS1 0x72 //This is the default address of the OpenLCD

int cycles = 0;

void setup()
{
  Wire.begin(); //Join the bus as master

  //By default .begin() will set I2C SCL to Standard Speed mode of 100kHz
  //Wire.setClock(400000); //Optional - set I2C SCL to High Speed Mode of 400kHz

  Serial.begin(9600); //Start serial communication at 9600 for debug statements
  Serial.println("OpenLCD Example Code");

  //Send the reset command to the display - this forces the cursor to return to the beginning of the display
  Wire.beginTransmission(DISPLAY_ADDRESS1);
  Wire.write('|'); //Put LCD into setting mode
  Wire.write('-'); //Send clear display command
  Wire.endTransmission();
}

void loop()
{
  cycles++; //Counting cycles! Yay!
  //  Serial.print("Cycle: "); //These serial.print statements take multiple miliseconds
  //  Serial.println(cycles);

  i2cSendValue(cycles); //Send the four characters to the display

  delay(50); //The maximum update rate of OpenLCD is about 100Hz (10ms). A smaller delay will cause flicker
}

//Given a number, i2cSendValue chops up an integer into four values and sends them out over I2C
void i2cSendValue(int value)
{
  Wire.beginTransmission(DISPLAY_ADDRESS1); // transmit to device #1

  Wire.write('|'); //Put LCD into setting mode
  Wire.write('-'); //Send clear display command

  Wire.print("Cycles: ");
  Wire.print(value);

  Wire.endTransmission(); //Stop I2C transmission
}

You may notice that this is very similar to the example above, Serial Basic. Well, that’s because it is doing the exact same thing but instead of Serial UART communication, it is sending the commands over I2C. If you’ve got it wired up correctly and the example code running, then you should see the “Hello World Counter:XX” displaying in your LCD screen.

SPI: Hardware Hookup & Example Code - Basic

Here’s how to wire up your Redboard to talk SPI to your LCD screen. Remember, convert those logic levels to 3.3Vs! Also note, you could choose a different output pin for the csPin, but in this example we are using D10.

Fritzing diagram showing the wiring for SPI with a redboard, a logic level converter, and the SerLCD

With your hardware now hooked up, the following code is the SPI basic example - it simply writes some characters to the screen over SPI. It has a counter that will increment on each cycle of your main loop. It clears the screen at the top of each loop, so you simply see “Cycles: 1”, “Cycles: 2” and so on.

You can get the latest example code from the github repo or you can copy and paste the following code into your Arduino IDE:

language:cpp
/*
 OpenLCD is an LCD with Serial/I2C/SPI interfaces.
 By: Nathan Seidle
 SparkFun Electronics
 Date: April 19th, 2015
 License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).

 This is example code that shows how to send data over SPI to the display.

 To get this code to work, attached an OpenLCD to an Arduino Uno using the following pins:
 CS (OpenLCD) to 10 (Arduino)
 SDI to 11
 SDO to 12 (optional)
 SCK to 13
 VIN to 5V
 GND to GND

 Command cheat sheet:
 ASCII / DEC / HEX
 '|'    / 124 / 0x7C - Put into setting mode
 Ctrl+c / 3 / 0x03 - Change width to 20
 Ctrl+d / 4 / 0x04 - Change width to 16
 Ctrl+e / 5 / 0x05 - Change lines to 4
 Ctrl+f / 6 / 0x06 - Change lines to 2
 Ctrl+g / 7 / 0x07 - Change lines to 1
 Ctrl+h / 8 / 0x08 - Software reset of the system
 Ctrl+i / 9 / 0x09 - Enable/disable splash screen
 Ctrl+j / 10 / 0x0A - Save currently displayed text as splash
 Ctrl+k / 11 / 0x0B - Change baud to 2400bps
 Ctrl+l / 12 / 0x0C - Change baud to 4800bps
 Ctrl+m / 13 / 0x0D - Change baud to 9600bps
 Ctrl+n / 14 / 0x0E - Change baud to 14400bps
 Ctrl+o / 15 / 0x0F - Change baud to 19200bps
 Ctrl+p / 16 / 0x10 - Change baud to 38400bps
 Ctrl+q / 17 / 0x11 - Change baud to 57600bps
 Ctrl+r / 18 / 0x12 - Change baud to 115200bps
 Ctrl+s / 19 / 0x13 - Change baud to 230400bps
 Ctrl+t / 20 / 0x14 - Change baud to 460800bps
 Ctrl+u / 21 / 0x15 - Change baud to 921600bps
 Ctrl+v / 22 / 0x16 - Change baud to 1000000bps
 Ctrl+w / 23 / 0x17 - Change baud to 1200bps
 Ctrl+x / 24 / 0x18 - Change the contrast. Follow Ctrl+x with number 0 to 255. 120 is default.
 Ctrl+y / 25 / 0x19 - Change the TWI address. Follow Ctrl+x with number 0 to 255. 114 (0x72) is default.
 Ctrl+z / 26 / 0x1A - Enable/disable ignore RX pin on startup (ignore emergency reset)
 '-'    / 45 / 0x2D - Clear display. Move cursor to home position.
        / 128-157 / 0x80-0x9D - Set the primary backlight brightness. 128 = Off, 157 = 100%.
        / 158-187 / 0x9E-0xBB - Set the green backlight brightness. 158 = Off, 187 = 100%.
        / 188-217 / 0xBC-0xD9 - Set the blue backlight brightness. 188 = Off, 217 = 100%.

 For example, to change the baud rate to 115200 send 124 followed by 18.
*/

#include <SPI.h>

int csPin = 10; //You can use any output pin but for this example we use 10

int cycles = 0;

void setup() 
{
  pinMode(csPin, OUTPUT);
  digitalWrite(csPin, HIGH); //By default, don't be selecting OpenLCD

  SPI.begin(); //Start SPI communication
  //SPI.beginTransaction(SPISettings(100000, MSBFIRST, SPI_MODE0));
  SPI.setClockDivider(SPI_CLOCK_DIV128); //Slow down the master a bit
}

void loop() 
{
  cycles++; //Counting cycles! Yay!

  //Send the clear display command to the display - this forces the cursor to return to the beginning of the display
  digitalWrite(csPin, LOW); //Drive the CS pin low to select OpenLCD
  SPI.transfer('|'); //Put LCD into setting mode
  SPI.transfer('-'); //Send clear display command
  digitalWrite(csPin, HIGH); //Release the CS pin to de-select OpenLCD

  char tempString[50]; //Needs to be large enough to hold the entire string with up to 5 digits
  sprintf(tempString, "Cycles: %d", cycles);
  spiSendString(tempString);

  //25ms works well
  //15ms slight flickering
  //5ms causes flickering
  delay(250);
}

//Sends a string over SPI
void spiSendString(char* data)
{
  digitalWrite(csPin, LOW); //Drive the CS pin low to select OpenLCD
  for(byte x = 0 ; data[x] != '\0' ; x++) //Send chars until we hit the end of the string
    SPI.transfer(data[x]);
  digitalWrite(csPin, HIGH); //Release the CS pin to de-select OpenLCD
}

Troubleshooting

Random Character

If the display is powered up without the RX line connected to anything, the display may fill with strange characters. This is because the display is receiving random noise on the disconnected line. If you connect the RX line to a true TX port, this will not happen.

Faded Characters on Display

If the display is unreadable or washed out, the contrast may need to be adjusted. This is done in software, so you will need to send your display some contrast control commands via Serial UART, I2C or SPI. There is a specific example for each of these communication types inside the github repository here:

Emergency Reset

If your LCD screen has entered an unknown state, or you are unable to communicate with it, it’s probably a good idea to try resetting everything back to default settings. The OpenLCD firmware has a built-in “emergency reset” feature. When the screen first boots up, the AVR on the back will watch its RX pin. If that pin is held LOW (aka tied to ground), for 2 seconds, then it will reset all settings to default. Most importantly, your baud rate will be set back to 9600. After the reset is complete, the screen will display the message “System Reset Power Cycle Me”, and flicker the backlight on and off repeatedly until you cycle power.

After Emergency Reset is performed, LCD display reads System reset Power cycle me

To perform an emergency reset, please be sure to follow these exact steps in this order:

  • Ensure your screen is OFF.
  • Tie RX to GND.
  • Power your screen.
  • Wait 2 seconds. Verify “System Reset” message.
  • Remove connection from RX to GND.
  • Cycle Power.

Now, please enjoy your default settings (including 9600 baud).

Firmware Update

To update the firmware on your LCD, you can use an FTDI Basic 3.3V - beefy model and the Arduino IDE software. The AVR on the back of your LCD actually has an Arduino-compatible bootloader. That said, it is slightly custom in that it was compiled for the 11.0592 crystal. This means you will need to install the SparkFun AVR Boards, and then select “Sparkfun OpenLCD” as your board type.

If you’ve made it this far, presumably you have the latest version of the Arduino IDE on your desktop. If you do not, please review our tutorial on installing the Arduino IDE.

Here’s the tutorial for installing custom board packages:

Installing Custom Board Packages

Once you have that installed, you should see “SparkFun OpenLCD” as a board option from the drop down menu here:

Look for the Board in the tools->Board drop down menu

Now plug in your serial FTDI basic into your LCD screen.

FTDI basic is plugged into the back of the LCD

Make sure to line it up properly so the “-” is lined up withe the “GND”, and the “R” is lined up with “DTR”.

Make sure when the FTDI basic is plugged in it aligns with the leftmost pins as the LCD faces you

Grab the latest firmware located here:

OPEN LCD FIRMWARE DOWNLOAD

Note, you will need all of the files in the “https://github.com/sparkfun/OpenLCD/blob/master/firmware/OpenLCD/” directory. When you open the OpenLCD.ino sketch in arduino, the other necessary files will open as tabs.

  • OpenLCD.ino
  • Setting_Control.ino
  • System_Functions.ino
  • settings.h

Four tabls should be open when you open the OpenLCD.ino file. The other three files are Setting_Control.ino, System_Functions.ino, and settings.h

Click the UPLOAD button in the IDE (the right facing arrow), and this will get the latest code onto your LCD!

Note, any of the settings stored in EEPROM memory (like baud, splash screen contents, backlight settings, etc.) will not be overwritten. If you are using a fresh IC (or you erased your EEPROM), then all of the defaults will return. To reset these settings to default, you must perform an “Emergency Reset”. The instructions for this are in another part of this troubleshooting section.

Using the Serial Enabled LCD on an Atmega32U4’s Hardware UART

If you are using the serial enabled LCD with an Atmega32U4-based Arduino (like a Pro Micro, Arduino Leonardo, Arduino LilyPad USB, etc), you might need to add a small delay in the setup before you can get it working with the hardware UART (pins 0 and 1). Here’s an example:

language:cpp
///test example using ATmega32U4's hardware UART and delay
void setup() {
  delay(2000);//add delay so the ATmega32U4 can have a second before sending serial data to the LCD
  Serial1.begin(9600);//set up the hardware UART baud
}

void loop() {
  Serial1.print("print something");//send something to the serial enabled LCD
  delay(50);
}

Software Serial for Arduino Due

Unfortunately, you are not able to use the serial enabled LCDs with an Arduino Due due the differences in how change interrupts are used for the ARM processor. The software serial library is not included in the Arduino Due’s tree:

Arduino.cc Forums - Software Serial for Arduino Due?

Try using the other hardware serial UARTs that are not connected to the Arduino Due’s programming pins for uploading. Make sure to adjust the code for the hardware serial UART.

Resources and Going Further

Now that you’ve successfully got your OpenLCD up and running, it’s time to incorporate it into your own project! When it is complete (or even during the design and build phases) please share in comments section of this tutorial, we’d love to hear about it! We also like doing project highlights, so please don’t hesitate to reach out when it’s finished. Maybe we could even feature your project with a blog post and video!

Also, if you ran into any issues during this hookup guide, or something wasn’t crystal clear the first time you read it, please let us know in the comments section of this tutorial. We strive to make the best documentation possible, and really want to hear about any pain points you discovered. Thanks in advance!

For more information, check out the resources below:

  • OpenLCD GitHub Repo - OpenLCD design files, default firmware, and example code.
  • HD44780
    • Datasheet
    • LCD User-Defined Graphics - If you would like to create a custom character, you would need to send a command byte before controlling the individual pixels in the character square.

Need some inspiration for your next project? Check out some of these related tutorials:

Using OpenSegment

How to hook up and use the OpenSegment display shield. The OpenSegment is the big brother to the Serial 7-Segment Display. They run on the same firmware, however the OpenSegment is about twice as big.

RGB Panel Hookup Guide

Make bright, colorful displays using the 32x16, 32x32, and 32x64 RGB LED matrix panels. This hookup guide shows how to hook up these panels and control them with an Arduino.

RGB Panel Jumbotron

This tutorial will show you how to combine a webcam, a 32x32 RGB LED panel, and a Teensy 3.1 to stream video from the webcam, pixelate it, and display it on the LED panel - LIVE.

SparkFun LED Array (8x7) Hookup Guide

Getting started with the Charlieplexed 8x7 LED array.

learn.sparkfun.com | CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

Single Supply Logic Level Converter Hookup Guide

$
0
0

Single Supply Logic Level Converter Hookup Guide a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t791

Introduction

The Single Supply Logic Level Converter combines a boost converter (TPS61200), adjustable voltage regulator (MIC5205), and logic level translator (TXB0104) into one board. It provides 5V to the high side of the TXB0104 and the low side is programmable to 3.3V, 2.5V and 1.8V. The default low side voltage is 3.3V. With this device you can use your 5V microcontroller with 3.3V sensors and vice versa without the need for a second power supply!

SparkFun Logic Level Converter - Single Supply

PRT-14765
$14.95

What makes this logic level converter truly special is the fact that you can supply it with 3.3V and it will boost it to 5V - meaning you can use your 3.3V system, and convert directly to another 5V sensor - and even power your sensor or other board! We will use a 3.3V microcontroller and a 5V sensor for the example. However, you can use still this board with a 5V microcontroller and a 3.3V sensor.

Required Materials

To follow along with this project tutorial, you will need the following materials to level shift between a 3.3V microcontroller with a 5V sensor. You may not need everything, depending on what you have. Add it to your cart, read through the guide, and adjust the cart as necessary.

Tools

You will need a soldering iron, solder, and general soldering accessories.

Solder Lead Free - 100-gram Spool

TOL-09325
$7.95
7
Weller WLC100 Soldering Station

TOL-14228
$44.95

Suggested Reading

If you aren’t familiar with the following concepts, we recommend checking out these tutorials before continuing.

How to Solder: Through-Hole Soldering

This tutorial covers everything you need to know about through-hole soldering.

How to Use a Breadboard

Welcome to the wonderful world of breadboards. Here we will learn what a breadboard is and how to use one to build your very first circuit.

Installing Arduino IDE

A step-by-step guide to installing and testing the Arduino software on Windows, Mac, and Linux.

Logic Levels

Learn the difference between 3.3V and 5V devices and logic levels.

How to Install FTDI Drivers

How to install drivers for the FTDI Basic on Windows, Mac OS X, and Linux.

Using the Arduino Pro Mini 3.3V

This tutorial is your guide to all things Arduino Pro Mini. It explains what it is, what it's not, and how to get started using it.

Hardware Overview

Before we discuss hooking up the breakout, let’s go over some of the features of this board.

Top View of Single Supply Logic Level Converter

Pinout

The following table describes the pins that are broken out.

PinDescription
VINInput Supply Voltage (3V - 5.5V)
GNDGround
VOUT, 5VBoost Converter's Voltage Output Set to 5V
VOUT, 3.3VRegulated Voltage Output Set to 3.3V
(can be adjusted depending on resistor)
A1-A4Programmable VCCA Port for Lower TTL Logic Levels - Default = 3.3V
B1-B4VCCB Port for Higher TTL Logic Levels - Set to 5V

Logic Level Shifter

The Single Supply Logic Level Converter breaks out Texas Instrument's TXB0104 module. The TXB0104 is a 4-bit, noninverting, bi-directional voltage-level translator with automatic direction sensing.

TXB0104 Highlighted on the board with Low and High Side TTL pins

Each pin on this module is broken out for you to easily access ports A and B. Port A (A1-A4) is for low side TTL levels. This device’s VCCA is set to 3.3V by default but can easily be programmable with a resistor to 2.5V and 1.8V. Port B (B1-B4) is for high side TTL levels. VCCB is hard wired to 5V. VCCA should not exceed VCCB. Depending on which voltage is chosen for VCCA the data rate may vary.

Adjusting the Lower Voltage Side (i.e. VCCA)

To adjust the reference voltage for the low side, you will need an associated resistor value to adjust the MIC5205’s output voltage. Below is a table of calculated resistor values that can be used. For more information, check out equation 4-7 on page 11 of the datasheet.

VCCAResistor Value
3.3VDefault = 13k&ohm;
2.5V22k&ohm;
1.8V49k&ohm;

Simply remove the default surface mount resistor with a blob of solder so that heat can be transferred to both terminals. Once heated, the surface mount resistor can be removed with tweezers or a gentle sweep of a soldering iron. Once removed, a resistor of your choice can be used to adjust the VCCA's reference voltage.

Resistor to Modify When Adjusting the Low Side Voltage Reference Pin

Power Supply and Voltage Regulator

The TPS61200 buck/boost converter on the Single Supply Logic Level Converter takes an input between 3V - 5.5V (most likely from your microcontroller’s VCC pin) and regulates it to 5V. This output is also connected to the high side on VCCB for reference.

Input Voltage Pins

The output current of the TPS61200 depends on the input to output voltage ratio. The TPS61200 provides output currents up to 600 mA at 5V. The maximum average input current is limited to 1.5A. For more information, check out the datasheet.

Components Highlighted on the Single Supply Logic Level Converter for a Buck/Boost Voltage of 5V

The regulated 5V is then further regulated to 3.3V, which is connected to the low side on VCCA for reference. There is an option to reprogram VCCA's voltage using an external PTH resistor as explained earlier.

Components Highlighted on the Single Supply Logic Level Converter for Regulated 3.3V

Timing Requirements

Not all logic level converters are the same! Compared to the lower cost bi-directional logic level converter with BSS138, the single supply logic level converter with TXB0104 is able to achieve higher data rates. The speed is dependent on the reference voltage that is used for the low side voltage on VCCA. This is indicated by the table below and was taken from the datasheet. For more information, check out page 8 of the datasheet.

VCCAData RatePulse Duration
1.5V40 Mbps25 ns
1.8V60 Mbps17 ns
2.5V100 Mbps10 ns
3.3V100 Mbps10 ns

Hardware Hookup

Grab some straight header pins, break the pins apart, and solder them to the single supply logic level converter.

Soldered Single Supply Logic Level Converter

This would also be a good time to solder headers to the 3.3V/8MHz Arduino Pro Mini if you have not already!

Soldered Arduino Pro Mini

Circuit Diagram

Ready to start hooking everything up? Check out the circuit diagram below to connect the components together.

Fritzing Diagram of Example Circuit to Translate 5V Sensor Data to a 3.3V Arduino Microcontroller

Having a hard time seeing the circuit? Click on the image for a closer look.

Example Code

Note: This example assumes you are using the latest version of the Arduino IDE on your desktop. If this is your first time using Arduino, please review our tutorial on installing the Arduino IDE.

The single supply logic level converter can be used to shift data in either direction. In this example, we are going to shift levels from a 3.3V Arduino microcontroller and a 5V sensor.

Level Shifting Between a 3.3V Microcontroller w/ 5V Sensor

Copy the code below and paste the following code into the Arduino IDE. Since we are using an Arduino Pro Mini 3.3V/8MHz, make sure that you are selecting the correct board selection. Additionally, make sure to have the correct COM port selected when uploading. When ready, upload the example code!

language:c
/*
Single Supply Logic Level Converter Hookup Guide

This project will beep continuosly with a frequency proportional
to distance. As objects get closer, the beep gets faster.

Hardware:
 HC-SR04 Ultrasonic Sensor
 Arduino Pro Mini 3.3V/8MHz
 SparkFun Single Supply Logic Level Converter
 Piezo Buzzer

*/


#define TRIG_PIN 10
#define ECHO_PIN 11
#define Beep 3

void setup() {
  Serial.begin (9600);
  pinMode(TRIG_PIN, OUTPUT);
  digitalWrite(TRIG_PIN, LOW);
  pinMode(Beep, OUTPUT);
}

void loop() {
  unsigned long t1;
  unsigned long t2;
  unsigned long pulse_width;
  float cm1;


  // Hold the trigger pin high for at least 10 us
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);

  // Wait for pulse on echo pin
  while (digitalRead(ECHO_PIN) == 0 );

  // Measure how long the echo pin was held high (pulse width)
  // Note: the micros() counter will overflow after ~70 min
  t1 = micros();
  while (digitalRead(ECHO_PIN) == 1);
  t2 = micros();
  pulse_width = t2 - t1;

  // Calculate distance in centimeters.
  cm1 = pulse_width*0.034/2;
  if (cm1 >= 200 || cm1 <= 0){
    Serial.println("Out of range");
  }
  else {
    Serial.print(cm1);
    Serial.println(" cm");

    tone(Beep,528);
    delay(100);
    noTone(Beep);
    delay(cm1);


  }
}

After uploading, place your hand in front of the ultrasonic sensor. When your hand is within a certain range, the buzzer will begin beeping! As you move your hand toward the sensor, the buzzer will beep faster. Moving your hand away from the sensor will slow down the beeping until you are out of range.

Circuit for shifting logic between a 3.3V microcontroller and 5V sensor

Resources and Going Further

Now that you know how to get the Single Supply Logic Level Converter up and running, it’s time to incorporate it into your own project!

For more on the Single Supply Logic Level Converter, check out the links below:

Need some inspiration for your next project? Check out some of these related tutorials:

PCA9306 Level Translator Hookup Guide

A quick primer to get you going with the PCA9306 Logic Level Converter.

Bi-Directional Logic Level Converter Hookup Guide

An overview of the Bi-Directional Logic Level Converter, and some example circuits to show how it works.

learn.sparkfun.com | CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

Python GUI Guide: Introduction to Tkinter

$
0
0

Python GUI Guide: Introduction to Tkinter a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t803

Introduction

Python is generally more popular as a sequential programming language that is called from the command line interface (CLI). However, several frameworks exist that offer the ability to create slick graphical user interfaces (GUI) with Python. Combined with a single board computer, like the Raspberry Pi, this ability to build GUIs opens up new possibilities to create your own dashboard for watching metrics, explore virtual instrumentation (like LabVIEW), or make pretty buttons to control your hardware.

Raspberry Pi with sensor dashboard and live plot

In this tutorial, we’ll go through the basics of Tkinter (pronounced “Tee-Kay-Inter”, as it’s the “TK Interface” framework), which is the default GUI package that comes bundled with Python. Other frameworks exist, such as wxPython, PyQt, and Kivy. While some of these might be more powerful, Tkinter is easy to learn, comes with Python, and shares the same open source license as Python.

Later in the tutorial, we’ll show how to control various pieces of hardware from a Tkinter GUI and then how to pull a Matplotlib graph into an interface. The first part of the tutorial (Tkinter basics) can be accomplished on any computer without special hardware. The parts that require controlling hardware or reading from a sensor will be shown on a Raspberry Pi.

Notice: This tutorial was written with Raspbian version "June 2018" and Python version 3.5.3. Other versions may affect how some of the steps in this guide are performed.

Required Materials

To work through the activities in this tutorial, you will need a few pieces of hardware:

Optional Materials

You have several options when it comes to working with the Raspberry Pi. Most commonly, the Pi is used as a standalone computer, which requires a monitor, keyboard, and mouse (listed below). To save on costs, the Pi can also be used as a headless computer (without a monitor, keyboard, and mouse).

Note that for this tutorial, you will need access to the Raspbian (or other Linux) graphical interface (known as the desktop). As a result, the two recommended ways to interact with your Pi is through a monitor, keyboard, and mouse or by using Virtual Network Computing (VNC).

SmartiPi Touch

PRT-14059
$24.95
8
Raspberry Pi LCD - 7" Touchscreen

LCD-13733
$64.95
35
Multimedia Wireless Keyboard

WIG-14271
$29.95
2

Prepare the Software

Before diving in to Tkinter and connecting hardware, you’ll need to install and configure a few pieces of software. You can work through the first example with just Python, but you’ll need a Raspberry Pi for the other sections that involve connecting hardware (we’ll be using the RPi.GPIO and SMBus packages).

Tkinter comes with Python. If Python is installed, you will automatically have access to the the Tkinter package.

Follow the steps outlined in the Prepare Your Pi section of the Graph Sensor Data with Python and Matplotlib tutorial to install Raspbian and configure Python 3. You will only need to perform the last “Install Dependencies” step if you plan to replicate the final example in this guide (integrating Matplotlib with Tkinter).

Suggested Reading

If you aren’t familiar with the following concepts, we recommend checking out these tutorials before continuing:

Raspberry gPIo

How to use either Python or C++ to drive the I/O lines on a Raspberry Pi.

Preassembled 40-pin Pi Wedge Hookup Guide

Using the Preassembled Pi Wedge to prototype with the Raspberry Pi B+.

Raspberry Pi 3 Starter Kit Hookup Guide

Guide for getting going with the Raspberry Pi 3 Model B and Raspberry Pi 3 Model B+ starter kit.

Getting Started with the Raspberry Pi Zero Wireless

Learn how to setup, configure and use the smallest Raspberry Pi yet, the Raspberry Pi Zero - Wireless.

Python Programming Tutorial: Getting Started with the Raspberry Pi

This guide will show you how to write programs on your Raspberry Pi using Python to control hardware.

How to Use Remote Desktop on the Raspberry Pi with VNC

Use RealVNC to connect to your Raspberry Pi to control the graphical desktop remotely across the network.
New!

Graph Sensor Data with Python and Matplotlib

Use matplotlib to create a real-time plot of temperature data collected from a TMP102 sensor connected to a Raspberry Pi.
Please note: If you have trouble seeing any of the images throughout this tutorial, feel free to click on it to get a better look!
Python Logo

Hello, World!

Let’s start with a basic example. If you don’t have a Raspberry Pi, you can install Python on your computer to run this demo and the “Temperature Converter” experiment.

Run the Program

Copy the following into a new file. Save it, and give it a name like tkinter_hello.py.

language:python
import tkinter as tk

# Create the main window
root = tk.Tk()
root.title("My GUI")

# Create label
label = tk.Label(root, text="Hello, World!")

# Lay out label
label.pack()

# Run forever!
root.mainloop()

Run the program from the command line with python tkinter_hello.py. You should see a new window pop up with the phrase “Hello, World!” If you expand the window, you should see the phrase “My GUI” set in the title bar (you might have to expand the window to see it).

Tkinter Hello, World! application

Code to Note

Let’s break down the relatively simple program. In the first line,

language:python
import tkinter as tk

we import the Tkinter module and shorten the name to tk. We do this to save us some typing in the rest of the code: we just need to type tk instead of tkinter.

In other Tkinter guides, you might see the import written as from tkinter import *. This says to import all classes, functions, and variables from the Tkinter package into the global space. While this might make typing easier (e.g. you would only need to type Tk() instead of tk.Tk()), it has the downside of cluttering your global workspace. In a larger application, you would need to keep track of all these global variables in your head, which can be quite difficult! For example, Tkinter has a variable named E (which we’ll see in a later example), and it’s much easier to remember that you mean Tkinter’s version of E (rather than E from another module) by having to write tk.E.

Next, we create a root window by calling Tkinter’s constructor, tk.Tk().

language:python
root = tk.Tk()

This automatically creates a graphical window with the necessary title bar, minimize, maximize, and close buttons (the size and location of these are based on your operating system’s preferences). We save a handle to this window in the variable root. This handle allows us to put other things in the window and reconfigure it (e.g. size) as necessary. For example, we can change the name in the title bar by calling the title method in the root window:

language:python
root.title("My GUI")

In this window, we can add various control elements, known as widgets. Widgets can include things like buttons, labels, text entry boxes, and so on. Here, we create a Label widget:

language:python
label = tk.Label(root, text="Hello, World!")

Notice that when we create any widget, we must pass it a reference to its parent object (the object that will contain our new widget). In this example, we want the root window to be the parent object of our label (i.e. root will own your label object). We also set the default message in the label to be the classic “Hello, World!”

When it comes to creating GUIs with Tkinter, it’s generally a good idea to create your widgets first and then lay out your widgets together within the same hierarchy. In this example, root is at the top of our hierarchy followed by our label object under that.

Hierarchy diagram showing object ownership

After creating our label, we lay it out using the pack() geometry manager.

language:python
label.pack()

A geometry manager is a piece of code that runs (as part of the Tkinter framework–we don’t see the backend parts) to organize our widgets based on criteria that we set. pack() just tells the geometry manager to put widgets in the same row or column. It’s usually the easiest to use if you just want one or a few widgets to appear (and not necessarily be nicely organized).

Finally, we tell Tkinter to start running:

language:python
root.mainloop()

Note that if we don’t call mainloop(), nothing will appear on our screen. This method says to take all the widgets and objects we created, render them on our screen, and respond to any interactions (such as button pushes, which we’ll cover in the next example). When we exit out of the main window (e.g. by pressing the close window button), the program will exit out of mainloop().

Tkinter Overview

This section is meant to give you an overview of the “building blocks” that are available in Tkinter and is in no way a complete list of classes, functions, and variables. The official Python docs and TkDocs offer a more comprehensive overview of the Tkinter package. Examples will be discussed in more details throughout this tutorial, but feel free to refer back to these reference tables as you build your own application.

Widgets

A widget is a controllable element within the GUI, and all Tkinter widgets have a shared set of methods. The Tkinter guide on effbot.org offers an easy-to-read reference for the core widget methods (these are the methods that all widgets have access to, regardless of which individual widget you might be using).

The following table shows all the core widgets with an example screenshot. Click on the widget name to view its reference documentation from effbot.org.

WidgetDescriptionExample
ButtonClickable area with text that calls an associated function whenever the user clicks in the area.Tkinter Button widget
CanvasGeneral purpose widget that can display simple graphics or provide an area to implement a custom widget.Tkinter Canvas widget
CheckbuttonAllows a user to read and select between two distinct values (e.g. on/off). Also known as a "checkbox."Tkinter Checkbutton widget
EntryArea that allows the user to enter one line of text. For entering multiple lines, use the Text widget.Tkinter Entry widget
FrameA container for other widgets. A Frame can be useful for grouping other widgets together in a complex layout.Tkinter Frame widget
LabelUsed to display text or an image that may not be edited by the user.Tkinter Label widget
LabelFrameA rectangular area that contains other widgets, but unlike a Frame, a border and label may be added to help group widgets together.Tkinter LabelFrame widget
ListboxDisplays a list of text alternatives. The user can choose (highlight) one or more options.Tkinter Listbox widget
MenuUsed to create menus and submenus within an interface. Can be used to create the always-shown "menu bar" popular in many GUI applications.Tkinter Menu widget
MenubuttonObsolete as of Tk 8.0. Use Menu widget instead.See Menu
MessageUsed to display static text, like Label, but allows for multiple lines, text wrapping, and maintaining aspect ratios.Tkinter Message widget
OptionMenuDrop-down (or pop-up) menu that allows users to select one option from several options.Tkinter OptionMenu widget
PanedWindowContainer for one or more widgets split into multiple "panes." These panes can be resized by the user by dragging the serparator line(s) (known as "sashes").Tkinter PanedWindow widget
RadiobuttonSeveral Radiobuttons can be used together to allow the user to select one option out of a group of options.Tkinter Radiobutton widget
ScaleUser can select a numerical value by moving a slider.Tkinter Scale widget
ScrollbarPaired with a Canvas, Entry, Listbox, or Text widget to allow for scrolling within that widget.Tkinter Scrollbar widget
SpinboxAllows the user to select only one option out of a list of options.Tkinter Spinbox widget
TextArea used to display and edit multiple lines of text. Can be used as a full text editor by the user.Tkinter Text widget
ToplevelA container for other widgets (much like the Frame widget) that appears in its own window. It can be useful for creating other application windows or pop-up notifications.Tkinter Toplevel widget

The code below was used to create the example widgets in the above table. Note that they are for demonstration purposes only, as much of the functionality has not been implemented (e.g. no functions for button pushes).

language:python
import tkinter as tk

# Create the main window
root = tk.Tk()
root.title("My GUI")

# Create a set of options and variable for the OptionMenu
options = ["Option 1", "Option 2", "Option 3"]
selected_option = tk.StringVar()
selected_option.set(options[0])

# Create a variable to store options for the Radiobuttons
radio_option = tk.IntVar()

###############################################################################
# Create widgets

# Create widgets
button = tk.Button(root, text="Button")
canvas = tk.Canvas(root, bg='white', width=50, height=50)
checkbutton = tk.Checkbutton(root, text="Checkbutton")
entry = tk.Entry(root, text="Entry", width=10)
frame = tk.Frame(root)
label = tk.Label(root, text="Label")
labelframe = tk.LabelFrame(root, text="LabelFrame", padx=5, pady=5)
listbox = tk.Listbox(root, height=3)
menu = tk.Menu(root)
# Menubutton: deprecated, use Menu instead
message = tk.Message(root, text="Message", width=50)
optionmenu = tk.OptionMenu(root, selected_option, *options)
panedwindow = tk.PanedWindow(root, sashrelief=tk.SUNKEN)
radiobutton_1 = tk.Radiobutton( root, 
                                text="Option 1", 
                                variable=radio_option,
                                value=1)
radiobutton_2 = tk.Radiobutton( root, 
                                text="Option 2", 
                                variable=radio_option, 
                                value=2)
scale = tk.Scale(root, orient=tk.HORIZONTAL)
scrollbar = tk.Scrollbar(root)
spinbox = tk.Spinbox(root, values=(0, 2, 4, 10))
text = tk.Text(root, width=15, height=3)
toplevel = tk.Toplevel()

# Lay out widgets
button.pack(padx=5, pady=5)
canvas.pack(padx=5, pady=5)
checkbutton.pack(padx=5, pady=5)
entry.pack(padx=5, pady=5)
frame.pack(padx=5, pady=10)
label.pack(padx=5, pady=5)
labelframe.pack(padx=5, pady=5)
listbox.pack(padx=5, pady=5)
# Menu: See below for adding the menu bar at the top of the window
# Menubutton: deprecated, use Menu instead
message.pack(padx=5, pady=5)
optionmenu.pack(padx=5, pady=5)
panedwindow.pack(padx=5, pady=5)
radiobutton_1.pack(padx=5)
radiobutton_2.pack(padx=5)
scale.pack(padx=5, pady=5)
scrollbar.pack(padx=5, pady=5)
spinbox.pack(padx=5, pady=5)
text.pack(padx=5, pady=5)
# Toplevel: does not have a parent or geometry manager, as it is its own window

###############################################################################
# Add stuff to the widgets (if necessary)

# Draw something in the canvas
canvas.create_oval(5, 15, 35, 45, outline='blue')
canvas.create_line(10, 10, 40, 30, fill='red')

# Add a default value to the Entry widgets
entry.insert(0, "Entry")

# Create some useless buttons in the LabelFrame
button_yes = tk.Button(labelframe, text="YES")
button_no = tk.Button(labelframe, text="NO")

# Lay out buttons in the LabelFrame
button_yes.pack(side=tk.LEFT)
button_no.pack(side=tk.LEFT)

# Put some options in the Listbox
for item in ["Option 1", "Option 2", "Option 3"]:
    listbox.insert(tk.END, item)

# Add some options to the menu
menu.add_command(label="File")
menu.add_command(label="Edit")
menu.add_command(label="Help")

# Add the menu bar to the top of the window
root.config(menu=menu)

# Create some labels to add to the PanedWindow
label_left = tk.Label(panedwindow, text="LEFT")
label_right = tk.Label(panedwindow, text="RIGHT")

# Add the labels to the PanedWindow
panedwindow.add(label_left)
panedwindow.add(label_right)

# Put some default text into the Text widgets
text.insert(tk.END, "I am a\nText widget")

# Create some widgets to put in the Toplevel widget (window)
top_label = tk.Label(toplevel, text="A Toplevel window")
top_button = tk.Button(toplevel, text="OK", command=toplevel.destroy)

# Lay out widgets in the Toplevel pop-up window
top_label.pack()
top_button.pack()

###############################################################################
# Run!

root.mainloop()

Geometry Managers

Just instantiating (creating) a widget does not necessarily mean that it will appear on the screen (with the exception of Toplevel(), which automatically creates a new window). To get the widget to appear, we need to tell the parent widget where to put it. To do that, we use one of Tkinter’s three geometery managers (also known as layout managers).

A geometry manager is some code that runs on the backend of Tkinter (we don’t interact with the geometry managers directly). We simply choose which geometry manager we want to use and give it some parameters to work with.

The three geometry managers are: grid, pack, and place. You should never mix geometry managers within the same hierarchy, but you can embed different managers within each other (for example, you can lay out a frame widget with grid in a Toplevel and then use pack to put different widgets within the frame).

Here is a table showing examples of the different geometry managers:

ManagerDescriptionExample
GridThe grid manager places widgets in a table format with rows and columns. It will avoid overlapping widgets and will resize rows/columns as necessary to fit the widgets.Tkinter grid layout example
PackPack is often the easiest geometry manager to use, as it just puts widgets in a single row or column (default). It "packs" the widgets by putting them side-by-side (or top-to-bottom).Tkinter pack layout example
PlaceThe place geometry manager offers the most control but can be the most difficult to use. It allows you to specify the absolute or relative positions of the widgets in a window (or parent widget).Tkinter place layout example

The code below was used to create the examples shown in the above table. Note that it creates 3 windows (1 with the Tk() constructor call and 2 others with Toplevel()) and uses different geometry managers to lay out 3 widgets in each.

language:python
import tkinter as tk

###############################################################################
# Grid layout example

# Create the main window (grid layout)
root = tk.Tk()
root.title("Grid")

# Create widgets
label_grid_1 = tk.Label(root, text="Widget 1", bg='red')
label_grid_2 = tk.Label(root, text="Widget 2", bg='green')
label_grid_3 = tk.Label(root, text="Widget 3", bg='blue')

# Lay out widgets in a grid
label_grid_1.grid(row=0, column=2)
label_grid_2.grid(row=1, column=1)
label_grid_3.grid(row=2, column=0)

###############################################################################
# Pack layout example

# Create another window for pack layout
window_pack = tk.Toplevel()
window_pack.title("Pack")

# Create widgets
label_pack_1 = tk.Label(window_pack, text="Widget 1", bg='red')
label_pack_2 = tk.Label(window_pack, text="Widget 2", bg='green')
label_pack_3 = tk.Label(window_pack, text="Widget 3", bg='blue')

# Lay out widgets with pack
label_pack_1.pack()
label_pack_2.pack()
label_pack_3.pack()

###############################################################################
# Place layout example

# Create another window for pack layout
window_place = tk.Toplevel()
window_place.title("Place")

# Create widgets
label_place_1 = tk.Label(window_place, text="Widget 1", bg='red')
label_place_2 = tk.Label(window_place, text="Widget 2", bg='green')
label_place_3 = tk.Label(window_place, text="Widget 3", bg='blue')

# Lay out widgets with pack
label_place_1.place(relx=0, rely=0.1)
label_place_2.place(relx=0.1, rely=0.2)
label_place_3.place(relx=0.7, rely=0.6)

###############################################################################
# Run!

root.mainloop()

Variables

If you want to dynamically change a widget’s displayed value or text (e.g. change the text in a Label), you need to use one of Tkinter’s Variables. This is because Python has no way of letting Tkinter know that a variable has been changed (known as tracing). As a result, we need to use a wrapper class for these variables.

Each Tkinter Variable has a get() and set() method so you can read and change with the Variable’s value. This page also gives you a list of other methods available to each Variable. You must choose the appropriate Variable for the values you plan to work with, and this table shows you which Variables you have available:

ManagerDescriptionExamples
BooleanVarWorks with Boolean values.True, False
DoubleVarWorks with floating point values.-68.0, 2.718281
IntVarWorks with integer values.-3, 0, 42
StringVarWorks with strings."Hello", "world!"

If you want to see this in action, run the following code:

language:python
import tkinter as tk

# Declare global variables
counter = None

# This function is called whenever the button is pressed
def count():

    global counter

    # Increment counter by 1
    counter.set(counter.get() + 1)

# Create the main window
root = tk.Tk()
root.title("Counter")

# Tkinter variable for holding a counter
counter = tk.IntVar()
counter.set(0)

# Create widgets (note that command is set to count and not count() )
label_counter = tk.Label(root, width=7, textvariable=counter)
button_counter = tk.Button(root, text="Count", command=count)

# Lay out widgets
label_counter.pack()
button_counter.pack()

# Run forever!
root.mainloop()

You should see a window appear with a number and button. Try pressing the button a few times to watch the number increment.

Example of a Tkinter IntVar being used to store a number

In the program, we create a button that calls the count() function whenever it is pressed. We also create an IntVar named counter and set its initial value to 0. Take a look at where we create the label:

language:python
label_counter = tk.Label(root, width=7, textvariable=counter)

You’ll notice that we assign our IntVar (counter) to the textvariable parameter. This tells Tkinter that whenever the counter variable is changed, the Label widget should automatically update its displayed text. This saves us from having to write a custom loop where we manually update all the displayed information!

From here, all we need to do is worry about updating the counter variable each time the button is pressed. In the count() function, we do that with:

language:python
counter.set(counter.get() + 1)

Notice that we can’t get the IntVar’s value by the normal means, and we can’t set it with the equals sign (=). We need to use the get() and set() methods, respectively.

Experiment 1: Temperature Converter

Before we connect any hardware, it can be helpful to try a more complicated example to get a feel for laying out a GUI and using Tkinter to build your vision. We’ll start with a simple example: a Celsius-to-Fahrenheit temperature converter.

The Vision

Before writing any code, pull out a piece of paper and a pencil (or dry erase board and marker). Sketch out how you want your GUI to look: where should labels go? Do you want text entry fields at the top or the bottom? Should you have a “Quit” button, or let the user click the window’s “Close” button?

Here is what I came up with for our simple converter application. Note that we can divide it into a simple 3x3 grid, as shown by the red lines (more or less–we might need to nudge some of the widgets to fit into their respective cells).

GUI design sketch with a 3x3 grid overlay

As a result, we can determine that using the grid manager would be the best for this layout.

Implementation

Copy the following code into your Python editor.

language:python
import tkinter as tk

# Declare global variables
temp_c = None
temp_f = None

# This function is called whenever the button is pressed
def convert():

    global temp_c
    global temp_f

    # Convert Celsius to Fahrenheit and update label (through textvariable)
    try:
        val = temp_c.get()
        temp_f.set((val * 9.0 / 5) + 32)
    except:
        pass

# Create the main window
root = tk.Tk()
root.title("Temperature Converter")

# Create the main container
frame = tk.Frame(root)

# Lay out the main container, specify that we want it to grow with window size
frame.pack(fill=tk.BOTH, expand=True)

# Allow middle cell of grid to grow when window is resized
frame.columnconfigure(1, weight=1)
frame.rowconfigure(1, weight=1)

# Variables for holding temperature data
temp_c = tk.DoubleVar()
temp_f = tk.DoubleVar()

# Create widgets
entry_celsius = tk.Entry(frame, width=7, textvariable=temp_c)
label_unitc = tk.Label(frame, text="°C")
label_equal = tk.Label(frame, text="is equal to")
label_fahrenheit = tk.Label(frame, textvariable=temp_f)
label_unitf = tk.Label(frame, text="°F")
button_convert = tk.Button(frame, text="Convert", command=convert)

# Lay out widgets
entry_celsius.grid(row=0, column=1, padx=5, pady=5)
label_unitc.grid(row=0, column=2, padx=5, pady=5, sticky=tk.W)
label_equal.grid(row=1, column=0, padx=5, pady=5, sticky=tk.E)
label_fahrenheit.grid(row=1, column=1, padx=5, pady=5)
label_unitf.grid(row=1, column=2, padx=5, pady=5, sticky=tk.W)
button_convert.grid(row=2, column=1, columnspan=2, padx=5, pady=5, sticky=tk.E)

# Place cursor in entry box by default
entry_celsius.focus()

# Run forever!
root.mainloop()

Give it a name like tkinter_temp_converter.py, and run it. You should see a new window appear with an area to type in a number (representing degrees Celsius). Press the “Convert” button, and the equivalent temperature in Fahrenheit should appear in the label next to “°F.”

Tkinter temperature converter GUI example

Code to Note

Let’s break down some of the code we saw in the previous example. After importing Tkinter, we define our convert() function. This is a callback, as we pass the function as an argument to our button, and Tkinter calls our function whenever a button press event occurs (i.e. we never call convert() directly).

While not completely necessary, you’ll notice that we declared temp_c and temp_f as global variables, as we want to be able to access them from within the function, and they were not passed in as parameters. Additionally, you’ll see that we calculate temp_f within a try/except block. If the user enters a string (instead of numbers), our conversion will fail, so we just tell Python to ignore the exception and don’t perform any calculation on the incorrectly typed data.

The next thing we do is create a frame within our main window and use the fill and expand parameters to allow it to grow with the window size.

language:python
# Create the main container
frame = tk.Frame(root)

# Lay out the main container, specify that we want it to grow with window size
frame.pack(fill=tk.BOTH, expand=True)

In our previous examples, we had been placing our widgets directly in the main window. This is generally not considered good practice, so we pack a frame within the window first, and then put our widgets within the frame. By doing this, we can more easily control how the widgets behave when we resize the window.

Hierarchy diagram showing how to use a frame as a container for widgets in Tkinter

Before creating our widgets, we tell the frame that it should expand with the window if the user resizes it:

language:python
# Allow middle cell of grid to grow when window is resized
frame.columnconfigure(1, weight=1)
frame.rowconfigure(1, weight=1)

Note that because we used the pack() manager for the frame, we must tell column/rowconfigure that the location of the cell is (1, 1). If were were using these methods with a grid() manager, we could specify different rows and columns. The weight parameter tells the geometry manager how it should resize the given row/column proportionally to all the others. By setting this to 1 for each configure method, we’re telling Tkinter to just resize the whole frame to fill the window. To learn more, see the Handling Resize section of this TkDocs article.

Example of Tkinter resizing the frame widget to fill the window

After that, we create our Tkinter Variables, temp_c and temp_f and create all of our widgets that belong in the frame. Note that we assign our convert() function to our button with command=convert parameter assignment. By doing this, we tell Tkinter that we want to call the convert() function whenever the button is pressed.

We then lay out each of the widgets using the grid geometry manager. We go through each widget and assign it to a cell location. There is nothing in the top-left cell (0, 0), so we leave it blank. We put the text entry widget in the next column over (0, 1) followed by the units (0, 2). We replicate this process for the next row (row 1) with the label for “is equal to,” the solution, and the units for Fahrenheit. Finally, we add the convert button to the bottom-right. However, because the button is wider than the unit labels, we have it take up two cells: (2, 1) and (2, 2). We do that with columnspan=2, which works like the “merge” command in most modern spreadsheet programs.

Note that in some of the .grid() layout calls, we use the sticky parameter. This tells the geometry manager how to put the widget in its cell. By default (i.e. not using sticky), the widget will be centered within the cell. tk.W says that the widget should be left-aligned in its cell, and tk.E says it should be right-alighted. You can use the following anchor constants to align your widget:

Sticky anchors for widgets in Tkinter

Finally, before running our mainloop, we tell Tkinter that the Entry box should have focus.

language:python
# Place cursor in entry box by default
entry_celsius.focus()

This places the cursor in the entry box so the user can immediately begin typing without having to click on the Entry widget.

Experiment 2: Lights and Buttons

Let’s connect some hardware! If you want to dig deeper into user interface design, a book on design theory, like this one, might be a good place to start. By controlling hardware, we can begin to connect GUI design to the real world. Want to make your own Nest-style thermostat? This is a good place to start.

Hardware Connections

We’ll start with a few basic examples that show how to control an LED and respond to a physical button push. Connect the LED, button, and resistors as shown in the diagrams.

Having trouble seeing the diagrams? Click on them to see the full-size version!

If you have a Pi Wedge, it can make connecting to external hardware on a breadboard easier. If you don’t, you can still connect directly to the Raspberry Pi with jumper wires.

Connecting through a Pi Wedge:

Pi Wedge Fritzing diagram to connect LED and button

Connecting directly to the Raspberry Pi:

Raspberry Pi Fritzing diagram to connect LED and button

Code Part 1: LED Light Switch

Depending on your version of Raspbian, the RPi.GPIO package may or may not be already installed (e.g. Raspbian Lite does not come with some Python packages pre-installed). In a terminal, enter the following:

language:bash
pip install rpi.gpio

Copy the following code into a new file:

language:python
import tkinter as tk
from tkinter import font

import RPi.GPIO as GPIO

# Declare global variables
button_on = None
button_off = None

# Pin definitions
led_pin = 12

# This gets called whenever the ON button is pressed
def on():

    global button_on
    global button_off

    # Disable ON button, enable OFF button, and turn on LED
    button_on.config(state=tk.DISABLED, bg='gray64')
    button_off.config(state=tk.NORMAL, bg='gray99')
    GPIO.output(led_pin, GPIO.HIGH)

# This gets called whenever the OFF button is pressed
def off():

    global button_on
    global button_off

    # Disable OFF button, enable ON button, and turn off LED
    button_on.config(state=tk.NORMAL, bg='gray99')
    button_off.config(state=tk.DISABLED, bg='gray64')
    GPIO.output(led_pin, GPIO.LOW)

# Use "GPIO" pin numbering
GPIO.setmode(GPIO.BCM)

# Set LED pin as output and turn it off by default
GPIO.setup(led_pin, GPIO.OUT)
GPIO.output(led_pin, GPIO.LOW)

# Create the main window
root = tk.Tk()
root.title("LED Switch")

# Create the main container
frame = tk.Frame(root)

# Lay out the main container
frame.pack()

# Create widgets
button_font = font.Font(family='Helvetica', size=24, weight='bold')
button_on = tk.Button(frame, text="ON", width=4, command=on, 
                        state=tk.NORMAL, font=button_font, bg='gray99')
button_off = tk.Button(frame, text="OFF", width=4, command=off, 
                        state=tk.DISABLED, font=button_font, bg='gray64')

# Lay out widgets
button_on.grid(row=0, column=0)
button_off.grid(row=1, column=0)

# Run forever!
root.mainloop()

# Neatly release GPIO resources once window is closed
GPIO.cleanup()

Save your file with a name like tkinter_switch.py and run it with python tkinter_switch.py. You should see a new window pop up with two buttons: ON and OFF. OFF should be grayed out, so try pressing ON. The LED should turn on and OFF should now be the only available button to press. Press it, and the LED should turn off. This is the software version of a light switch!

Virtual light switch on the Raspberry Pi with Tkinter and Python controlling an LED

Code to Note:

In the on() and off() function definitions, we enable and disable the buttons by using the .config() method. For example:

language:python
button_on.config(state=tk.DISABLED, bg='gray64')
button_off.config(state=tk.NORMAL, bg='gray99')

.config() allows us to dynamically change the attributes of widgets even after they’ve been created. In our switch example, we change their state and bg (background color) to create the effect of the switch being active or “grayed out.”

You might also notice that we use the font module within Tkinter to create a custom font for the buttons. This allows us to change the typeface as well as make the font bigger and bolder. We then assign this new font to the buttons' text with font=button_font.

At the end of the code, we place the following line after our root.mainloop():

language:python
GPIO.cleanup()

This line tells Linux to release the resources it was using to handle all the pin toggling that we were doing after we close the main window. Without this line, we would get a warning next time we ran the program (or tried to use the RPi.GPIO module).

Code Part 2: Dimmer Switch

Since we proved we can turn an LED on and off, let’s try dimming it. In fact, let’s make a virtual dimmer switch! In a new file, copy in the following code:

language:python
import tkinter as tk

import RPi.GPIO as GPIO

# Declare global variables
pwm = None

# Pin definitions
led_pin = 12

# This gets called whenever the scale is changed--change brightness of LED
def dim(i):

    global pwm

    # Change the duty cycle based on the slider value
    pwm.ChangeDutyCycle(float(i))

# Use "GPIO" pin numbering
GPIO.setmode(GPIO.BCM)

# Set LED pin as output
GPIO.setup(led_pin, GPIO.OUT)

# Initialize pwm object with 50 Hz and 0% duty cycle
pwm = GPIO.PWM(led_pin, 50)
pwm.start(0)

# Create the main window and set initial size
root = tk.Tk()
root.title("LED Dimmer")
root.geometry("150x300")

# Create the main container
frame = tk.Frame(root)

# Lay out the main container (center it in the window)
frame.place(relx=0.5, rely=0.5, anchor=tk.CENTER)

# Create scale widget
scale = tk.Scale(   frame,
                    orient=tk.VERTICAL,
                    from_=100,
                    to=0,
                    length=200,
                    width=50,
                    sliderlength=50,
                    showvalue=False,
                    command=dim )

# Lay out widget in frame
scale.pack()

# Run forever!
root.mainloop()

# Stop, cleanup, and exit when window is closed
pwm.stop()
GPIO.cleanup()

Give the file a name like tkinter_dimmer.py and run it. You should see a Scale widget pop up in a new window. Try sliding it, and you should see the attached LED get brighter.

Virtual dimmer switch made with Python and Tkinter used to control the brightness of an LED

Code to Note:

When constructing our Scale widget, we need to set a good number of attributes:

language:python
scale = tk.Scale(   frame,
                    orient=tk.VERTICAL,
                    from_=100,
                    to=0,
                    length=200,
                    width=50,
                    sliderlength=50,
                    showvalue=False,
                    command=dim )

By default, scales appear horizontally, so we use orient=tk.VERTICAL to have it work like a dimmer switch you might find in a house. Next, the Scale will count from 0 to 100 by default, but 0 will be at the top (in the vertical orientation). As a result, we swap the from_ and to parameters so that 0 starts at the bottom. Also, notice that from_ has an underscore after it; from is a reserved keyword in Python, so Tkinter had to name it something else. We use 0 through 100, as those are the acceptable values for the pwm.ChangeDutyCycle() method parameter.

We can adjust the size and shape of the Scale with length and width. We made it a little bigger than default so that you can manipulate it more easily on a touchscreen. The slider part of the Scale (the part you click and drag) can by sized with sliderlength. Once again, we make the slider larger so that it’s easier to work with on a touchscreen.

By default, the numerical value of the Scale is shown next to the slider. We want to turn that off to provide a cleaner interface. The user only needs to drag the slider to a relative position; the exact number does not quite translate to perceived brightness anyway.

Additionally, by setting command=dim, we tell Tkinter that we want to call the dim() function every time the slider is moved. This allows us to set up a callback where we can adjust the PWM value of the LED each time the user interacts with the Scale.

Finally, notice that the dim(i) function now takes a parameter, i. Unlike our button functions in previous examples (which do not take any parameters), the Scale widget requires its callback (as set by command=dim) to accept one parameter. This parameter is the value of the slider; each time the slider is moved, dim(i) is called and i is set to the value of the slider (0-100 in this case).

Code Part 3: Respond to a Button Push

Blinking LEDs is fun, but what about responding to some kind of user input (I don’t mean on the screen)? Responding to physical button pushes can be important if you don’t want your user to have to use a touchscreen or mouse and keyboard. In a new file, enter the following code:

language:python
import tkinter as tk

import RPi.GPIO as GPIO

# Declare global variables
root = None
canvas = None
circle = None

# Pins definitions
btn_pin = 4

# Parameters
canvas_width = 100
canvas_height = 100
radius = 30

# Check on button state and update circle color
def poll():

    global root
    global btn_pin
    global canvas
    global circle

    # Make circle red if button is pressed and black otherwise
    if GPIO.input(btn_pin):
        canvas.itemconfig(circle, fill='black')
    else:
        canvas.itemconfig(circle, fill='red')

    # Schedule the poll() function for another 10 ms from now
    root.after(10, poll)

# Set up pins
GPIO.setmode(GPIO.BCM)
GPIO.setup(btn_pin, GPIO.IN)

# Create the main window
root = tk.Tk()
root.title("Button Responder")

# Create the main container
frame = tk.Frame(root)

# Lay out the main container (center it in the window)
frame.place(relx=0.5, rely=0.5, anchor=tk.CENTER)

# Create a canvas widget
canvas = tk.Canvas(frame, width=canvas_width, height=canvas_height)

# Lay out widget in frame
canvas.pack()

# Calculate top left and bottom right coordinates of the circle
x0 = (canvas_width / 2) - radius
y0 = (canvas_height / 2) - radius
x1 = (canvas_width / 2) + radius
y1 = (canvas_height / 2) + radius

# Draw circle on canvas
circle = canvas.create_oval(x0, y0, x1, y1, width=4, fill='black')

# Schedule the poll() function to be called periodically
root.after(10, poll)

# Run forever
root.mainloop()

Save it (with a name like tkinter_button.py), and run it. You should see a black circle appear in the middle of your window. When you press the button on the breadboard, the circle should turn red. Neat.

Pushing a button to control a Tkinter element on a Raspberry Pi

Code to Note:

The most important part of this example is how to poll for a physical button press (or any other hardware interaction on the Pi’s GPIO pins). You might have noticed that root.mainloop() is blocking. That is, it takes over your program, and your Python script essentially stops running while it sits in the mainloop method. In reality, there is a lot going on in the background: Tkinter is looking for and responding to events, resizing widgets as necessary, and drawing things to your screen. But for our purposes, it looks like the script just sits there while the GUI is displayed (if the user closes the main GUI window, root.mainloop() will exit).

Since we have a blocking method call, how do we check for a button push? That’s where the .after() method comes into play. We set up the poll() function to be called every 10 ms without being in any sort of loop. Since we’ve moved into the realm of event-driven programming, we must do everything with callbacks!

language:python
root.after(10, poll)

This line says that after 10 ms, the poll() function should be called. The bulk of the poll() function is fairly straightforward: we see if the button has been pressed (the button’s GPIO pin is low), and we change the color of the circle in the canvas if it is. However, the end of the function is very important:

language:python
root.after(10, poll)

That’s right, at the very end of the poll() function, we tell our main window that it should call the poll() function again! This makes it so that we are checking the state of the button many times every second. We will use this concept of polling for hardware information (separately from the GUI mainloop()) in the next experiment.

We created a circle on the screen by drawing on the canvas with:

language:python
circle = canvas.create_oval(x0, y0, x1, y1, width=4, fill='black')

If you want to learn more about Tkinter’s drawing methods, check out this guide on python-course.eu. Additionally, effbot.org has a good reference for all the different drawing methods.

Experiment 3: Sensor Dashboard

In this next experiment, we’re going to connect a couple of I2C sensors and display their information in real time on our monitor. We start by just showing the sensor’s numerical values and then bring in Matplotlib to create a live updating graph of that data. Note that these are just example sensors; feel free to use whatever sensors you’d like for your particular application.

Hardware Connections

Connect a TMP102 Temperature Sensor breakout and APDS-9301 Ambient Light Sensor breakout to the Raspberry Pi as shown in the diagrams below.

Connecting through a Pi Wedge:

Connecting TMP102 and APDS-9301 to a Raspberry Pi through a Pi Wedge

Connecting directly to the Raspberry Pi:

Connecting TMP102 and APDS-9301 to a Raspberry Pi

Sensor Modules

To simplify our I2C reading and writing, we’re going to copy in Python modules to read data from the TMP102 and APDS-9301 sensors. Open a new file named tmp102.py:

language:bash
nano tmp102.py

Copy in the following Python code:

language:python
import smbus

# Module variables
i2c_ch = 1
bus = None

# TMP102 address on the I2C bus
i2c_address = 0x48

# Register addresses
reg_temp = 0x00
reg_config = 0x01

# Calculate the 2's complement of a number
def twos_comp(val, bits):
    if (val & (1 << (bits - 1))) != 0:
        val = val - (1 << bits)
    return val

# Read temperature registers and calculate Celsius
def read_temp():

    global bus

    # Read temperature registers
    val = bus.read_i2c_block_data(i2c_address, reg_temp, 2)
    temp_c = (val[0] << 4) | (val[1] >> 5)

    # Convert to 2s complement (temperatures can be negative)
    temp_c = twos_comp(temp_c, 12)

    # Convert registers value to temperature (C)
    temp_c = temp_c * 0.0625

    return temp_c

# Initialize communications with the TMP102
def init():

    global bus

    # Initialize I2C (SMBus)
    bus = smbus.SMBus(i2c_ch)

    # Read the CONFIG register (2 bytes)
    val = bus.read_i2c_block_data(i2c_address, reg_config, 2)

    # Set to 4 Hz sampling (CR1, CR0 = 0b10)
    val[1] = val[1] & 0b00111111
    val[1] = val[1] | (0b10 << 6)

    # Write 4 Hz sampling back to CONFIG
    bus.write_i2c_block_data(i2c_address, reg_config, val)

    # Read CONFIG to verify that we changed it
    val = bus.read_i2c_block_data(i2c_address, reg_config, 2)

Save the code with ctrl + x, press y, and press enter. This module allows us to call init() and read_temp() functions to initialize and read temperature data from the TMP102.

Similarly, we need to create a module for our APDS-9301. Create a new file named apds9301.py:

language:bash
nano apds9301.py

Copy in the following code:

language:python
import smbus

# Module variables
i2c_ch = 1
bus = None

# APDS-9301 address on the I2C bus
apds9301_addr = 0x39

# Register addresses
apds9301_control_reg = 0x80
apds9301_timing_reg = 0x81
apds9301_data0low_reg = 0x8C
apds9301_data1low_reg = 0x8E

# Initialize communications and turn on the APDS-9301
def init():

    global bus

    # Initialize I2C (SMBus)
    bus = smbus.SMBus(i2c_ch)

    # Read the CONTROL register (1 byte)
    val = bus.read_i2c_block_data(apds9301_addr, apds9301_control_reg, 1)

    # Set POWER to on in the CONTROL register
    val[0] = val[0] & 0b11111100
    val[0] = val[0] | 0b11

    # Enable the APDS-9301 by writing back to CONTROL register
    bus.write_i2c_block_data(apds9301_addr, apds9301_control_reg, val)

# Read light data from sensor and calculate lux
def read_lux():

    global bus

    # Read channel 0 light value and combine 2 bytes into 1 number
    val = bus.read_i2c_block_data(apds9301_addr, apds9301_data0low_reg, 2)
    ch0 = (val[1] << 8) | val[0]

    # Read channel 1 light value and combine 2 bytes into 1 number
    val = bus.read_i2c_block_data(apds9301_addr, apds9301_data1low_reg, 2)
    ch1 = (val[1] << 8) | val[0]

    # Make sure we don't divide by 0
    if ch0 == 0.0:
        return 0.0

    # Calculate ratio of ch1 and ch0
    ratio = ch1 / ch0

    # Assume we are using the default 13.7 ms integration time on the sensor
    # So, scale raw light values by 1/0.034 as per the datasheet
    ch0 *= 1 / 0.034
    ch1 *= 1 / 0.034

    # Assume we are using the default low gain setting
    # So, scale raw light values by 16 as per the datasheet
    ch0 *= 16;
    ch1 *= 16;

    # Calculate lux based on the ratio as per the datasheet
    if ratio <= 0.5:
        return (0.0304 * ch0) - ((0.062 * ch0) * ((ch1/ch0) ** 1.4))
    elif ratio <= 0.61:
        return (0.0224 * ch0) - (0.031 * ch1)
    elif ratio <= 0.8:
        return (0.0128 * ch0) - (0.0153 * ch1)
    elif ratio <= 1.3:
        return (0.00146 * ch0) - (0.00112*ch1)
    else:
        return 0.0

Save and exit with ctrl + x, y, and enter. Like our tmp102 module, we can call init() and read_lux() to initialize and read the ambient light values from the APDS-9301 sensor.

Note: Make sure that tmp102.py and apds9301.py are in the same directory as your main application code. Otherwise, your import statements will not be able to find your modules.

Code Part 1: Fullscreen Numerical Dashboard

Let’s start by making a simple display that takes up the full screen and shows the numerical temperature and ambient light values. Copy the following code into a new file:

language:python
import tkinter as tk
import tkinter.font as tkFont

import tmp102
import apds9301

###############################################################################
# Parameters and global variables

# Declare global variables
root = None
dfont = None
frame = None
temp_c = None
lux = None

# Global variable to remember if we are fullscreen or windowed
fullscreen = False

###############################################################################
# Functions

# Toggle fullscreen
def toggle_fullscreen(event=None):

    global root
    global fullscreen

    # Toggle between fullscreen and windowed modes
    fullscreen = not fullscreen
    root.attributes('-fullscreen', fullscreen)
    resize()

# Return to windowed mode
def end_fullscreen(event=None):

    global root
    global fullscreen

    # Turn off fullscreen mode
    fullscreen = False
    root.attributes('-fullscreen', False)
    resize()

# Automatically resize font size based on window size
def resize(event=None):

    global dfont
    global frame

    # Resize font based on frame height (minimum size of 12)
    # Use negative number for "pixels" instead of "points"
    new_size = -max(12, int((frame.winfo_height() / 10)))
    dfont.configure(size=new_size)

# Read values from the sensors at regular intervals
def poll():

    global root
    global temp_c
    global lux

    # Update labels to display temperature and light values
    try:
        val = round(tmp102.read_temp(), 2)
        temp_c.set(val)
        val = round(apds9301.read_lux(), 1)
        lux.set(val)
    except:
        pass

    # Schedule the poll() function for another 500 ms from now
    root.after(500, poll)

###############################################################################
# Main script

# Create the main window
root = tk.Tk()
root.title("The Big Screen")

# Create the main container
frame = tk.Frame(root)

# Lay out the main container (expand to fit window)
frame.pack(fill=tk.BOTH, expand=1)

# Variables for holding temperature and light data
temp_c = tk.DoubleVar()
lux = tk.DoubleVar()

# Create dynamic font for text
dfont = tkFont.Font(size=-24)

# Create widgets
label_temp = tk.Label(frame, text="Temperature:", font=dfont)
label_celsius = tk.Label(frame, textvariable=temp_c, font=dfont)
label_unitc = tk.Label(frame, text="°C", font=dfont)
label_light = tk.Label(frame, text="Light:", font=dfont)
label_lux = tk.Label(frame, textvariable=lux, font=dfont)
label_unitlux = tk.Label(frame, text="lux", font=dfont)
button_quit = tk.Button(frame, text="Quit", font=dfont, command=root.destroy)

# Lay out widgets in a grid in the frame
label_temp.grid(row=0, column=0, padx=5, pady=5, sticky=tk.E)
label_celsius.grid(row=0, column=1, padx=5, pady=5, sticky=tk.E)
label_unitc.grid(row=0, column=2, padx=5, pady=5, sticky=tk.W)
label_light.grid(row=1, column=0, padx=5, pady=5, sticky=tk.E)
label_lux.grid(row=1, column=1, padx=5, pady=5, sticky=tk.E)
label_unitlux.grid(row=1, column=2, padx=5, pady=5, sticky=tk.W)
button_quit.grid(row=2, column=2, padx=5, pady=5)

# Make it so that the grid cells expand out to fill window
for i in range(0, 3):
    frame.rowconfigure(i, weight=1)
for i in range(0, 3):
    frame.columnconfigure(i, weight=1)

# Bind F11 to toggle fullscreen and ESC to end fullscreen
root.bind('<F11>', toggle_fullscreen)
root.bind('<Escape>', end_fullscreen)

# Have the resize() function be called every time the window is resized
root.bind('<Configure>', resize)

# Initialize our sensors
tmp102.init()
apds9301.init()

# Schedule the poll() function to be called periodically
root.after(500, poll)

# Start in fullscreen mode and run
toggle_fullscreen()
root.mainloop()

Save the file with a name like tkinter_fullscreen.py and run it. Your entire screen should be taken over by the GUI, and you should see the local ambient temperature and light values displayed. Try covering the light sensor or breathing on the temperature sensor to change their values. Press esc to exit fullscreen or press F11 to toggle fullscreen on and off.

Fullscreen GUI with live sensor data made with Python and Tkinter

Code to Note:

To control having our application take up the entire screen, we use the following method:

language:python
root.attributes('-fullscreen', fullscreen)

where the fullscreen variable is a boolean (True or False). If you look toward the end of the code, you’ll see the following two lines:

language:python
root.bind('<F11>', toggle_fullscreen)
root.bind('<Escape>', end_fullscreen)

These bind the key presses F11 and esc to the toggle_fullscreen() and end_fullscreen() functions, respectively. These allow the user to control if the application takes up the entire screen or is in a window.

We also use the rowconfigure() and columnconfigure() methods again to control how the grid cells resize within the window. We combine this with a dynamic font:

language:python
dfont = tkFont.Font(size=-24)

Note that the negative number (-24) means we want to specify the font size in pixels instead of “points.” We also have our resize() function called every time the window is resized with the following:

language:python
root.bind('<Configure>', resize)

In our resize() function, we calculate a new font size based on the height of the resized frame with:

language:python
new_size = -max(12, int((frame.winfo_height() / 10)))

This says that the new font size should be the height of the frame divided by 10, but no smaller than 12. We turn it into a negative value, as we want to specify font height in pixels instead of points (once again). We then set the new font size with:

language:python
dfont.configure(size=new_size)

Try it! With the application running, press esc to exit fullscreen mode and try resizing the window. You should see the text grow and shrink as necessary. It’s not perfect, as certain aspect ratios will cut off portions of the text, but it should work without a problem in fullscreen mode (the intended application).

If you are using a touchscreen, you might not have an easy way for users to resize the window or quit out of the application (in some instances, that might be a good thing, but for our example, we want users to be able to exit). To accomplish this, we add a “Quit” button to our GUI:

language:python
button_quit = tk.Button(frame, text="Quit", font=dfont, command=root.destroy)

We assign the callback function to be root.destroy. This is a built-in method within Tkinter that says to close the associated window and exit out of mainloop.

You’ll also notice that we are relying on the after() method again to call our poll() function at regular intervals.

Code Part 2: Complete Dashboard with Plotting

Now it’s time to get fancy. Let’s take the basic dashboard concept and add plotting. To do this, we’ll need to pull in the Matplotlib package. If you have not already installed it, run the following commands in a terminal:

language:bash
sudo apt-get update
sudo apt-get install libatlas3-base libffi-dev at-spi2-core python3-gi-cairo
pip install cairocffi
pip install matplotlib

In a new file, copy in the following code:

language:python
import datetime as dt
import tkinter as tk
import tkinter.font as tkFont

import matplotlib.figure as figure
import matplotlib.animation as animation
import matplotlib.dates as mdates
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import tmp102
import apds9301

###############################################################################
# Parameters and global variables

# Parameters
update_interval = 60000 # Time (ms) between polling/animation updates
max_elements = 1440     # Maximum number of elements to store in plot lists

# Declare global variables
root = None
dfont = None
frame = None
canvas = None
ax1 = None
temp_plot_visible = None


# Global variable to remember various states
fullscreen = False
temp_plot_visible = True
light_plot_visible = True

###############################################################################
# Functions

# Toggle fullscreen
def toggle_fullscreen(event=None):

    global root
    global fullscreen

    # Toggle between fullscreen and windowed modes
    fullscreen = not fullscreen
    root.attributes('-fullscreen', fullscreen)
    resize(None)   

# Return to windowed mode
def end_fullscreen(event=None):

    global root
    global fullscreen

    # Turn off fullscreen mode
    fullscreen = False
    root.attributes('-fullscreen', False)
    resize(None)

# Automatically resize font size based on window size
def resize(event=None):

    global dfont
    global frame

    # Resize font based on frame height (minimum size of 12)
    # Use negative number for "pixels" instead of "points"
    new_size = -max(12, int((frame.winfo_height() / 15)))
    dfont.configure(size=new_size)

# Toggle the temperature plot
def toggle_temp():

    global canvas
    global ax1
    global temp_plot_visible

    # Toggle plot and axis ticks/label
    temp_plot_visible = not temp_plot_visible
    ax1.collections[0].set_visible(temp_plot_visible)
    ax1.get_yaxis().set_visible(temp_plot_visible)
    canvas.draw()

# Toggle the light plot
def toggle_light():

    global canvas
    global ax2
    global light_plot_visible

    # Toggle plot and axis ticks/label
    light_plot_visible = not light_plot_visible
    ax2.get_lines()[0].set_visible(light_plot_visible)
    ax2.get_yaxis().set_visible(light_plot_visible)
    canvas.draw()

# This function is called periodically from FuncAnimation
def animate(i, ax1, ax2, xs, temps, lights, temp_c, lux):

    # Update data to display temperature and light values
    try:
        new_temp = round(tmp102.read_temp(), 2)
        new_lux = round(apds9301.read_lux(), 1)
    except:
        pass

    # Update our labels
    temp_c.set(new_temp)
    lux.set(new_lux)

    # Append timestamp to x-axis list
    timestamp = mdates.date2num(dt.datetime.now())
    xs.append(timestamp)

    # Append sensor data to lists for plotting
    temps.append(new_temp)
    lights.append(new_lux)

    # Limit lists to a set number of elements
    xs = xs[-max_elements:]
    temps = temps[-max_elements:]
    lights = lights[-max_elements:]

    # Clear, format, and plot light values first (behind)
    color = 'tab:red'
    ax1.clear()
    ax1.set_ylabel('Temperature (C)', color=color)
    ax1.tick_params(axis='y', labelcolor=color)
    ax1.fill_between(xs, temps, 0, linewidth=2, color=color, alpha=0.3)

    # Clear, format, and plot temperature values (in front)
    color = 'tab:blue'
    ax2.clear()
    ax2.set_ylabel('Light (lux)', color=color)
    ax2.tick_params(axis='y', labelcolor=color)
    ax2.plot(xs, lights, linewidth=2, color=color)

    # Format timestamps to be more readable
    ax1.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M'))
    fig.autofmt_xdate()

    # Make sure plots stay visible or invisible as desired
    ax1.collections[0].set_visible(temp_plot_visible)
    ax2.get_lines()[0].set_visible(light_plot_visible)

# Dummy function prevents segfault
def _destroy(event):
    pass

###############################################################################
# Main script

# Create the main window
root = tk.Tk()
root.title("Sensor Dashboard")

# Create the main container
frame = tk.Frame(root)
frame.configure(bg='white')

# Lay out the main container (expand to fit window)
frame.pack(fill=tk.BOTH, expand=1)

# Create figure for plotting
fig = figure.Figure(figsize=(2, 2))
fig.subplots_adjust(left=0.1, right=0.8)
ax1 = fig.add_subplot(1, 1, 1)

# Instantiate a new set of axes that shares the same x-axis
ax2 = ax1.twinx()

# Empty x and y lists for storing data to plot later
xs = []
temps = []
lights = []

# Variables for holding temperature and light data
temp_c = tk.DoubleVar()
lux = tk.DoubleVar()

# Create dynamic font for text
dfont = tkFont.Font(size=-24)

# Create a Tk Canvas widget out of our figure
canvas = FigureCanvasTkAgg(fig, master=frame)
canvas_plot = canvas.get_tk_widget()

# Create other supporting widgets
label_temp = tk.Label(frame, text='Temperature:', font=dfont, bg='white')
label_celsius = tk.Label(frame, textvariable=temp_c, font=dfont, bg='white')
label_unitc = tk.Label(frame, text="C", font=dfont, bg='white')
label_light = tk.Label(frame, text="Light:", font=dfont, bg='white')
label_lux = tk.Label(frame, textvariable=lux, font=dfont, bg='white')
label_unitlux = tk.Label(frame, text="lux", font=dfont, bg='white')
button_temp = tk.Button(    frame, 
                            text="Toggle Temperature", 
                            font=dfont,
                            command=toggle_temp)
button_light = tk.Button(   frame,
                            text="Toggle Light",
                            font=dfont,
                            command=toggle_light)
button_quit = tk.Button(    frame,
                            text="Quit",
                            font=dfont,
                            command=root.destroy)

# Lay out widgets in a grid in the frame
canvas_plot.grid(   row=0, 
                    column=0, 
                    rowspan=5, 
                    columnspan=4, 
                    sticky=tk.W+tk.E+tk.N+tk.S)
label_temp.grid(row=0, column=4, columnspan=2)
label_celsius.grid(row=1, column=4, sticky=tk.E)
label_unitc.grid(row=1, column=5, sticky=tk.W)
label_light.grid(row=2, column=4, columnspan=2)
label_lux.grid(row=3, column=4, sticky=tk.E)
label_unitlux.grid(row=3, column=5, sticky=tk.W)
button_temp.grid(row=5, column=0, columnspan=2)
button_light.grid(row=5, column=2, columnspan=2)
button_quit.grid(row=5, column=4, columnspan=2)

# Add a standard 5 pixel padding to all widgets
for w in frame.winfo_children():
    w.grid(padx=5, pady=5)

# Make it so that the grid cells expand out to fill window
for i in range(0, 5):
    frame.rowconfigure(i, weight=1)
for i in range(0, 5):
    frame.columnconfigure(i, weight=1)

# Bind F11 to toggle fullscreen and ESC to end fullscreen
root.bind('<F11>', toggle_fullscreen)
root.bind('<Escape>', end_fullscreen)

# Have the resize() function be called every time the window is resized
root.bind('<Configure>', resize)

# Call empty _destroy function on exit to prevent segmentation fault
root.bind("<Destroy>", _destroy)

# Initialize our sensors
tmp102.init()
apds9301.init()

# Call animate() function periodically
fargs = (ax1, ax2, xs, temps, lights, temp_c, lux)
ani = animation.FuncAnimation(  fig, 
                                animate, 
                                fargs=fargs, 
                                interval=update_interval)               

# Start in fullscreen mode and run
toggle_fullscreen()
root.mainloop()

Save the program (with a fun name like tkinter_dashboard.py), and run it. You should see your sensor data displayed as numerical values as well as a plot that updates once per minute.

Raspberry Pi showing a live update of temperature and light sensor data wit Tkinter and Matplotlib

Try pushing the “Toggle Temperature” and “Toggle Light” buttons. You should see the graph of each one disappear and reappear with each button press. This demonstrates how you can make an interactive plot using both Tkinter and Matplotlib.

You can update the update_interval variable to have the sensors polled more quickly, but it can also be fun to poll once per minute (default) and let it run for a day, as I did in my office:

Tkinter dashboard with live sensor data

If you look closely at the graph, you can see that the temperatures fell a little after 7pm, rose again, and then fell once more just before the workday started at 9am the following morning. We can surmise that the building air conditioning was running at those times to make it cooler.

Additionally, you can see that someone came into the office in the 6-7pm timeframe, as the ambient light value picked up for a short amount. Considering I did not move the sensors the next day, it looks like either more lights were on, or it was a sunnier day outside, as more light was falling on the sensor.

Code to Note:

There is a lot going on in this example, so we’ll try to cover it as succinctly as possible. Many of the concepts from the previous example, like binding key presses to trigger toggling fullscreen, are still present. Animating a graph is covered in the previous Python tutorial that introduced Matplotlib (specifically, the section about updating a graph in real time). If you are not familiar with Matplotlib, we recommend working through the following tutorial:

New!

Graph Sensor Data with Python and Matplotlib

July 23, 2018

Use matplotlib to create a real-time plot of temperature data collected from a TMP102 sensor connected to a Raspberry Pi.

The key to embedding a Matplotlib graph into a Tkinter GUI is to work with Matplotlib’s backend, which is why we import the following:

language:python
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

With that, we first create our Matplotlib figure and a set of axes to draw our plot on:

language:python
# Create figure for plotting
fig = figure.Figure(figsize=(2, 2))
fig.subplots_adjust(left=0.1, right=0.8)
ax1 = fig.add_subplot(1, 1, 1)

A few lines later, we create a Tkinter widget out of that figure:

language:python
# Create a Tk Canvas widget out of our figure
canvas = FigureCanvasTkAgg(fig, master=frame)
canvas_plot = canvas.get_tk_widget()

These lines use our imported FigureCanvasTkAgg function to take a figure and turn it into a Tkinter Canvas. We get a handle to this canvas and lay it out in our grid just like any other widget:

language:python
canvas_plot.grid(   row=0, 
                    column=0, 
                    rowspan=5, 
                    columnspan=4, 
                    sticky=tk.W+tk.E+tk.N+tk.S)

Instead of the periodic poll() callback that we used in the previous examples, we set up a FuncAnimation() to handle the polling and updating of the graph:

language:python
# Call animate() function periodically
fargs = (ax1, ax2, xs, temps, lights, temp_c, lux)
ani = animation.FuncAnimation(  fig, 
                                animate, 
                                fargs=fargs, 
                                interval=update_interval)

In the animate() function, we read the sensors' data (just like we did in poll()) and append it to the end of some arrays. We use this to redraw the plots on the axes (which are ultimately drawn on the Tkinter canvas widget). Note that we used .fill_between() to create the translucent red graph for temperature and a regular .plot() to create the basic blue line graph for light value.

For another example on importing Matplotlib into Tkinter, see this demo from the official Matplotlib documentation.

Resources and Going Further

Creating a GUI can be a good way to offer an easy-to-use interface for your customer or create a slick-looking dashboard for yourself (and your team). If you would like to learn more about Tkinter, we recommend the following resources:

Try out the various widgets and play with different layouts to get the effect you are looking for.

Note: If you think the default Tkinter widgets look outdated (hello Windows 95!), check out the ttk themed widgets package. Widgets from this set have a much more modern and updated look to them.
Python Logo

Looking for even more inspiration? Check out these other Raspberry Pi projects:

Building Large LED Installations

Learn what it takes to build large LED installations from planning to power requirements to execution.

Bark Back Interactive Pet Monitor

Monitor and interact with pets through this dog bark detector project based on the Raspberry Pi!

Raspberry Pi Zero Helmet Impact Force Monitor

How much impact can the human body handle? This tutorial will teach you how to build your very own impact force monitor using a helmet, Raspberry Pi Zero, and accelerometer!

Using Flask to Send Data to a Raspberry Pi

In this tutorial, we'll show you how to use the Flask framework for Python to send data from ESP8266 WiFi nodes to a Raspberry Pi over an internal WiFi network.

learn.sparkfun.com | CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

ESP32 LoRa 1-CH Gateway, LoRaWAN, and the Things Network

$
0
0

ESP32 LoRa 1-CH Gateway, LoRaWAN, and the Things Network a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t804

Introduction

The ESP32 LoRa 1-CH Gateway combines an ESP32 – a programmable microcontroller featuring both WiFi and Bluetooth radios – with an RFM95W LoRa transceiver to create a single-channel LoRa gateway. It’s a perfect, low-cost tool for monitoring a dozen-or-so LoRa devices, and relaying their messages up to the cloud.

ESP32 LoRa 1-Channel Gateway

ESP32 LoRa 1-Channel Gateway

SPX-14893
$29.95

Complete with a Qwiic connector and a breadboard-compatible array of ESP32 pin-breakouts, this board can can also serve as a general-purpose ESP32/RFM95W development platform. So, instead of using it as a LoRaWAN gateway, you can turn it into a LoRa device, and use the powerful ESP32 microcontroller to monitor sensors, host a web server, run a display or more.

These boards are a great way to begin dipping your toes into the world of LoRa and LoRaWAN. Not only can they be programmed as versatile single-channel gateway, but they can also be used as a LoRa device, or a general ESP32/RFM95W development board.

The goal of this tutorial is to get you quickly up-and-running with the ESP32 LoRa 1-CH Gateway. It’ll explain how to program the board in Arduino, how to our recommended gateway firmware, and even how to turn the board into a LoRa device.

Shopping List

The ESP32 LoRa Single-Channel Gateway is designed to be a nearly-complete LoRa gateway. There are just a few extra components you may need to get it up-and-running.

To power and program the board, you’ll need a micro-B USB cable and a computer with Arduino installed.

To boost your LoRa radio’s signal, you’ll also need an antenna. You can either use the included U.FL connector – with a U.FL-to-SMA adapter and 900 MHz SMA antenna– or solder on a ~3-inch strip of wire.

Hook-Up Wire - Assortment (Solid Core, 22 AWG)

Hook-Up Wire - Assortment (Solid Core, 22 AWG)

PRT-11367
$16.95
28
USB micro-B Cable - 6 Foot

USB micro-B Cable - 6 Foot

CAB-10215
$4.95
9
900/1800MHz Dual Frequency Duck Antenna RP-SMA

900/1800MHz Dual Frequency Duck Antenna RP-SMA

WRL-09143
$7.95
Interface Cable RP-SMA to U.FL

Interface Cable RP-SMA to U.FL

WRL-00662
$4.95
1

Hardware Setup

The ESP32 LoRa 1-CH Gateway includes almost everything you need to set up either a LoRaWAN gateway or device. You may not even have to solder anything to it to get started! Here’s a quick rundown of the bare minimum you’ll need to get started with the board.

Antenna

To allow the board to communicate with other LoRa devices, you’ll need to add an antenna. This can be attached to either the U.FL connector or the ANT pin on the board.

The U.FL connector can be attached to an SMA to U.FL adapter cable, which can then be paired with a 900 MHz Duck Antenna.

ESP32/LoRa board with wire antenna soldered in

3.07" strip of 22-AWG solid-core wire soldered to the ANT pin. Use the hole adjacent to the ANT pin for strain relief!

In lieu of a U.FL antenna, a strip of wire soldered to the ANT pin and sticking straight up will work as well. Here are wire lengths for quarter-wave antennas at 915MHz and 434MHz:

FrequencyLength (inches)Length (mm)
915 MHz3.07" (3 + 1/16")78mm
434 MHz6.47" (6 + 1/2")164mm

Powering the Board

The board is nominally powered via the on-board micro-USB connector. The other end of your USB cable can be plugged into either a computer, wall adapter, or a USB battery pack.

Examples power supplies -- USB or 3.3V

Alternatively, the board can be powered using a regulated 3.3V power supply. This supply should be applied to the 3.3V and GND pins.

Under normal operation the ESP32 LoRa 1-CH Gateway consumes between 50-100mA. (Running the ESP-sc-gway sketch.)

Arduino IDE Setup

To set up the gateway software you’ll need to install the ESP32 Arduino core as well as the library dependencies of the ESP32 LoRa Gateway sketch.

Arduino Board Setup

The example code and libraries for this board are all written for the Arduino IDE. If you haven’t already done so, you’ll need to install the Arduino core for ESP32. The ESP32 Arduino core must be installed manually. You can find the core files on espressif’s GitHub: https://github.com/espressif/arduino-esp32. Follow the Installation Instructions to add the core to your Arduino IDE.

Adding a Custom Board

Although it’s possible to upload code to the board using the standard board definitions, we recommend customizing the core to add support for the SparkX ESP32 LoRa Gateway.

To add the custom board, begin by downloading the board’s variant file here below.

Download the SparkX ESP32 LoRa Arduino variant definition

Then unzip the contents into {Arduino Sketchbook}/hardware/espressif/esp32/variants.

Variant install location

The “sparkx_esp32_lora” folder should live in the “variants” folder of your ESP32 hardware directory.

Next, copy the text below and add it to the bottom of {Arduino Sketchbook}/hardware/espressif/esp32/boards.txt:

##############################################################

sparkx_esp32_lora.name=SparkX ESP32 LoRa Gateway

sparkx_esp32_lora.upload.tool=esptool
sparkx_esp32_lora.upload.maximum_size=1310720
sparkx_esp32_lora.upload.maximum_data_size=294912
sparkx_esp32_lora.upload.wait_for_upload_port=true

sparkx_esp32_lora.serial.disableDTR=true
sparkx_esp32_lora.serial.disableRTS=true

sparkx_esp32_lora.build.mcu=esp32
sparkx_esp32_lora.build.core=esp32
sparkx_esp32_lora.build.variant=sparkx_esp32_lora
sparkx_esp32_lora.build.board=ESP32_DEV

sparkx_esp32_lora.build.f_cpu=240000000L
sparkx_esp32_lora.build.flash_size=4MB
sparkx_esp32_lora.build.flash_freq=40m
sparkx_esp32_lora.build.flash_mode=dio
sparkx_esp32_lora.build.boot=dio
sparkx_esp32_lora.build.partitions=default

sparkx_esp32_lora.menu.PartitionScheme.default=Default
sparkx_esp32_lora.menu.PartitionScheme.default.build.partitions=default
sparkx_esp32_lora.menu.PartitionScheme.minimal=Minimal (2MB FLASH)
sparkx_esp32_lora.menu.PartitionScheme.minimal.build.partitions=minimal
sparkx_esp32_lora.menu.PartitionScheme.no_ota=No OTA (Large APP)
sparkx_esp32_lora.menu.PartitionScheme.no_ota.build.partitions=no_ota
sparkx_esp32_lora.menu.PartitionScheme.no_ota.upload.maximum_size=2097152
sparkx_esp32_lora.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (Large APPS with OTA)
sparkx_esp32_lora.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs
sparkx_esp32_lora.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080

sparkx_esp32_lora.menu.FlashMode.qio=QIO
sparkx_esp32_lora.menu.FlashMode.qio.build.flash_mode=dio
sparkx_esp32_lora.menu.FlashMode.qio.build.boot=qio
sparkx_esp32_lora.menu.FlashMode.dio=DIO
sparkx_esp32_lora.menu.FlashMode.dio.build.flash_mode=dio
sparkx_esp32_lora.menu.FlashMode.dio.build.boot=dio
sparkx_esp32_lora.menu.FlashMode.qout=QOUT
sparkx_esp32_lora.menu.FlashMode.qout.build.flash_mode=dout
sparkx_esp32_lora.menu.FlashMode.qout.build.boot=qout
sparkx_esp32_lora.menu.FlashMode.dout=DOUT
sparkx_esp32_lora.menu.FlashMode.dout.build.flash_mode=dout
sparkx_esp32_lora.menu.FlashMode.dout.build.boot=dout

sparkx_esp32_lora.menu.FlashFreq.80=80MHz
sparkx_esp32_lora.menu.FlashFreq.80.build.flash_freq=80m
sparkx_esp32_lora.menu.FlashFreq.40=40MHz
sparkx_esp32_lora.menu.FlashFreq.40.build.flash_freq=40m

sparkx_esp32_lora.menu.FlashSize.4M=4MB (32Mb)
sparkx_esp32_lora.menu.FlashSize.4M.build.flash_size=4MB

sparkx_esp32_lora.menu.UploadSpeed.921600=921600
sparkx_esp32_lora.menu.UploadSpeed.921600.upload.speed=921600
sparkx_esp32_lora.menu.UploadSpeed.115200=115200
sparkx_esp32_lora.menu.UploadSpeed.115200.upload.speed=115200
sparkx_esp32_lora.menu.UploadSpeed.256000.windows=256000
sparkx_esp32_lora.menu.UploadSpeed.256000.upload.speed=256000
sparkx_esp32_lora.menu.UploadSpeed.230400.windows.upload.speed=256000
sparkx_esp32_lora.menu.UploadSpeed.230400=230400
sparkx_esp32_lora.menu.UploadSpeed.230400.upload.speed=230400
sparkx_esp32_lora.menu.UploadSpeed.460800.linux=460800
sparkx_esp32_lora.menu.UploadSpeed.460800.macosx=460800
sparkx_esp32_lora.menu.UploadSpeed.460800.upload.speed=460800
sparkx_esp32_lora.menu.UploadSpeed.512000.windows=512000
sparkx_esp32_lora.menu.UploadSpeed.512000.upload.speed=512000

sparkx_esp32_lora.menu.DebugLevel.none=None
sparkx_esp32_lora.menu.DebugLevel.none.build.code_debug=0
sparkx_esp32_lora.menu.DebugLevel.error=Error
sparkx_esp32_lora.menu.DebugLevel.error.build.code_debug=1
sparkx_esp32_lora.menu.DebugLevel.warn=Warn
sparkx_esp32_lora.menu.DebugLevel.warn.build.code_debug=2
sparkx_esp32_lora.menu.DebugLevel.info=Info
sparkx_esp32_lora.menu.DebugLevel.info.build.code_debug=3
sparkx_esp32_lora.menu.DebugLevel.debug=Debug
sparkx_esp32_lora.menu.DebugLevel.debug.build.code_debug=4
sparkx_esp32_lora.menu.DebugLevel.verbose=Verbose
sparkx_esp32_lora.menu.DebugLevel.verbose.build.code_debug=5

This custom board file specifies the SPI and built-in LED pins, without it you’ll need to re-define them in your sketch.

Once the custom board has been added to the ESP32 core, open Arduino and select “SparkX ESP32 LoRa Gateway” under the Tools > Board > ESP32 Arduino menu.

SparkX ESP32 LoRa board in Arduino

Single-Channel LoRaWAN Gateway Code

The ESP32 single-channel gateway example code is hosted by things4u on GitHub. Download it from their repository: https://github.com/things4u/ESP-1ch-Gateway-v5.0.

This repository includes both the Arduino sketch and the libraries it depends on. Before compiling the sketch you’ll need to extract all libraries from the repository’s “library” folder into your Arduino sketchbook’s “libraries” folder. For more help installing the libraries, check out the Getting Started section of the README.

To open the example code, open the ESP-sc-gway.ino file. When the IDE loads, it should include another dozen-or-so tabs – it’s a hefty, but well-segmented sketch!

Configure the Gateway Sketch

Before uploading the ESP-1ch-Gateway sketch to your board, you’ll need to make a handful of modifications to a couple of files. Here’s a quick overview:

ESP-sc-gway.h

This file is the main source of configuration for the gateway sketch. The definitions you’ll probably have to modify are:

  • Radio
    • _LFREQ– This sets the frequency range your radio will communicate on. Set this to either 433 (Asia), 868 (EU), or 915 (US)
    • _SPREADING– This sets the LoRa spread factor. SF7, SF8, SF9, SF10, SF11, or SF12 can be used. Note that this will affect which devices your gateway can communicate with.
    • _CAD– Channel Activity Detection. If enabled (set to 1) CAD will allow the gateway to monitor messages sent at any spread factor. The tradeoff if enabled: very weak signals may not be picked up by the radio.
  • Hardware
    • _OLED– This board does not include an OLED, set this to 0.
    • _PIN_OUT– This configures the SPI and other hardware settings. Set this to 6, we’ll add a custom hardware definition later.
    • CFG_sx1276_radio– Ensure this is defined and CFG_sx1272_radio is not. This configures the LoRa radio connected to the ESP32.
  • The Things Network (TTN)
    • _TTNSERVER– The server for your LoRa router. E.g. “router.eu.thethings.network” or “us-west.thethings.network”
    • _TTNPORT– 1700 is the standard port for TTN
    • _DESCRIPTION– Customize the name of your gateway
    • _EMAIL– Your email address, or that of the owner of the gateway
    • _LAT and _LON– GPS coordinates of your gateway
  • WiFi
    • Add at least one WiFi network to the wpas wpa[] array, but leave the first entry blank. For example:

language:c
wpas wpa[] = {
  { "" , "" },                          // Reserved for WiFi Manager
  { "my_wifi_network", "my_wifi_password" }
};

There are a lot of other values which can all optionally be configured. For a complete rundown, check out the Editing the ESP-sc-gway.h part of the README.

loramodem.h

This file defines how the LoRa modem is configured, including which frequency channels it can use and which pins the ESP32 uses to communicate with it. Be careful modifying most of the definitions in here, but one section you will have to modify is the _PIN_OUT declarations.

First, find the line that says #error "Pin Definitions _PIN_OUT must be 1(HALLARD) or 2 (COMRESULT)" and delete it. Then copy and paste these lines in its place (between the #else and #endif):

language:c
struct pins {
  uint8_t dio0 = 26;
  uint8_t dio1 = 33;
  uint8_t dio2 = 32;
  uint8_t ss = 16;
  uint8_t rst = 27; // Reset not used
} pins;
#define SCK  14
#define MISO 12
#define MOSI 13
#define SS  16
#define DIO0 26

The int freqs[] array can be adjusted, if you want to use different subbands, but, beyond that, there’s not much else in here we recommend modifying.

Upload the Sketch

With your modifications made, try compiling and uploading the sketch to your ESP32. After it’s uploaded, open up your serial monitor and set the baud rate to 115200. Debug messages here can be very handy, and finding your gateway’s IP address is critical if you want to monitor the web server.

The sketch may take a long time to set up the first time through – it will format your SPIFFS file system and create a non-volatile configuration file. Once that’s complete, you should see the ESP32 attempt to connect to your WiFi network, then initialize the radio.

After the ESP32 has connected, look for it to print out an IP address. Open up your computer’s web browser and plug that into the address bar. You should be greeted by the ESP Gateway Config web portal:

ESP Gateway Config served by the ESP32

Config and log page served by the ESP32.

This web page can be used to monitor messages coming through and what frequencies and spread factors they came in on. It can also be used to change your gateway’s configuration on-the-fly. You can adjust the channel or spread factor, or turn CAD on/off, or even turn on simplistic frequency-hopping.

Of course, to see any messages get through you’ll need a LoRa device (or device_s_) set up to communicate with your gateway. Check out the next section for a quick guide on setting up a second ESP32 LoRa board as a LoRa device.

Turning a Gateway Into a Device

If you have a pair of ESP32 gateway’s you can use one of them as a LoRaWAN device. This section will get you set up with our preferred LoRaWAN Arduino library and a simple example sketch to get started.

Get the Arduino-LMIC Library to Set up a device

If you have a pair of ESP32 Gateways and want to set one of them up as a LoRa device, we recommend using the Arduino-LMIC library. There seem to be many versions of the Arduino-LMIC library hanging around, we’ve had good success with the library forked by mcci-catena: https://github.com/mcci-catena/arduino-lmic.

To install the library, download the ZIP file from GitHub. Then use the Arduino’s “Add ZIP library” feature (Sketch > Include Library > Add .ZIP Library) to import the zip file into your Arduino sketchbook.

Configure LMIC

Before can use an example sketch in the LMIC library, you’ll need to configure it. To configure the library, navigate to the “arduino-lmic” library in your {Arduino Sketchbook}/libraries folder. Then go to project_config and open lmic_project_config.h.

Here you’ll define which frequency bands your LoRa device will use. You can also turn on debugging and enable/disable a host of features with definitions in this file.

Make sure you uncomment one-and-only-one of the “CFG…” declarations. If you’re in the USA, uncomment #define CFG_us915. Ultimately, this frequency should match what you set in the gateway.

Below is my config file – I’ve turned on debugging, because I’m a log junkie.

language:c
// project-specific definitions
//#define CFG_eu868 1
#define CFG_us915 1
//#define CFG_au921 1
//#define CFG_as923 1
// #define LMIC_COUNTRY_CODE LMIC_COUNTRY_CODE_JP   /* for as923-JP */
//#define CFG_in866 1
#define CFG_sx1276_radio 1

//#define LMIC_PRINTF_TO Serial
#define LMIC_DEBUG_LEVEL 2

//#define DISABLE_INVERT_IQ_ON_RX

If you try to use the “raw” example in this library, you’ll need to uncomment DISABLE_INVERT_IQ_ON_RX, otherwise keep it commented-out.

Modify the “SPI.begin” call

Just to be sure your pin definitions are correct, I recommend modifying the SPI.begin line in arduino-lmic/src/hal/hal.cpp (line 136 as of this commit) to:

language:c
SPI.begin(14, 12, 13, 16);

This will ensure that your SPI pins are set correctly – this may only be necessary if you’re not using the custom “SparkX ESP32 LoRa Gateway” Arduino board.

Load the Single-Channel Device Example

We’ve taken one of the examples in the Arduino-LMIC library and modified it to work more reliably with a single-channel gateway.

Click the button below to download the example. Then open up ESP-1CH-TTN-Device-ABP.ino:

Download the single-channel LoRaWAN device example

Among the modifications in this example are the pin map between radio and ESP32 – set with these lines:

language:c
const lmic_pinmap lmic_pins = {
  .nss = 16,
  .rxtx = LMIC_UNUSED_PIN,
  .rst = 5,
  .dio = {26, 33, 32},
};

We’ve also modified the enabled channels to only use a single channel with the lines below (note this modification hasn’t yet been tested on non-US frequency bands).

language:c
// First disable all sub-bands
for (int b = 0; b < 8; ++b) {
  LMIC_disableSubBand(b);
}
// Then enable the channel(s) you want to use
LMIC_enableChannel(8); // 903.9 MHz

The spread factor is set near the end of setup() with the LMIC_setDrTxpow(DR_SF7, 14); line. This can be replaced with DR_SF8, DR_SF9, or DR_SF10 at the default 903.9MHz frequency.

But wait! Before uploading this example, there’s one more modification you need to make: your LoRaWAN application, network session, and device keys! For that, and an application server, we recommend The Things Network.

Routing to The Things Network

The final components to a LoRaWAN network are a server and application. You can set up a LoRaWAN server of your own, but, for prototyping at least, The Things Network is a great, free tool for authenticating and routing your data.

Single-Channel Blues

At the trade-off of being low-cost, this gateway is only capable of monitoring a single LoRa channel on a limited set of spread factors. Single-channel gateway's don't get much support from LoRaWAN platforms like The Things Network, as they are not, necessarily, LoRaWAN-compliant. They are, however, a great way to begin exploring the world of LoRa and LoRaWAN!

If you haven’t already, head to thethingsnetwork.org and create an account. Once that’s done, go to your Console.

Create an Application

In order to create a device, you first need to create an application to house it under. In the console, click “Aplications” then click “add application”.

Fill out any ID and description you’d like. The Application EUI will automatically be generated when you create the application. You can also pick your preferred handler for the application (e.g. ttn-handler-us-west).

Creating a TTN application

Create and Configure a Device

Next create a device in your application. Under the “Devices” section, click “register device”.

This is again pretty simple. Fill out a unique device ID, click the “generate” button under “Device EUI” to automatically generate a EUI. Then click “Register.”

Creating a TTN device

This example sketch only supports ABP activation, so you’ll need to modify that in the device settings. In the “Device Overview” page, click “Settings”. From there, under “Activation Method” click ABP. I also recommend disabling Frame Counter Checks. The gateway is capable of frame-counter checks, but it can get out of sync – especially if you have another gateway nearby.

Modifying TTN device settings

Save the settings and go back to your “Device Overview” page. You should see new keys, including “Network Session Key”, “App Session Key”, and “Device Address.” These will need to be plugged into the device sketch and uploaded to the device.

Update the Example Code

With your application, network session, and device keys in-hand, you’re ready to finish configuring the ESP32 LoRa device sketch and start posting data!

On the “Device Overview” page, click the “code” symbol (<>) next to “Network Session Key” and “App Session Key” – this will make the key visible and display it as a 16-byte array. Copy each of those keys, and paste them in place of the {PASTE KEY HERE} place-holders. “Network Session Key” should be pasted into the NWKSKEY variable and “App Session Key” should be pasted into the APPSKEY variable.

The DEVADDR variable expects a single 32-bit variable, so copy the “Device Address” key as shown and paste that into the PASTE_DEV_ADDR_HERE placeholder.

Grabbing your device keys

Here’s an example of what your three constants should look like once done:

language:c
// LoRaWAN NwkSKey, network session key
// This is the default Semtech key, which is used by the early prototype TTN
// network.
static const PROGMEM u1_t NWKSKEY[16] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF };

// LoRaWAN AppSKey, application session key
// This is the default Semtech key, which is used by the early prototype TTN
// network.
static const u1_t PROGMEM APPSKEY[16] = { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 };

// LoRaWAN end-device address (DevAddr)
static const u4_t DEVADDR = 0x01234567;

And that’s it! Now upload the code to your ESP32 LoRa board.

Testing the Code

After setup, the device should immediately send a “Hello, World” message. It’ll continue to send a message every minute or any time the “0” button on the board is pressed.

To check if your gateway is receiving the message, you can either check the Serial Monitor or monitor the ESP Gateway Config page served by the gateway. Every time a message is received it should be added to the “Message History” table.

If messages are getting through to your gateway, click the “Data” tab on your device to check for new messages.

TTN device data visible

The message’s paylod – which was encrypted between leaving the device and getting to the router – should be a series of hex values adding up to “Hello, world”.

Troubleshooting

If messages are not getting to your gateway, first make sure the channel and spread factor match up. Left unchanged, the device example code should be sending data out on the 903.9MHz channel at a spread factor of 7 (that’s assuming you’ve set the LMIC library to CFG_us915, if it’s set to a European frequency spectrum it’ll be 868.1MHz, SF7).

You can use the gateway’s web server to adjust these setting on the fly. Note that the channel numbers should sequentially match the freqs array in loraModem.h – e.g. channel 0 should be 903.9MHz (again, assuming US frequencies).

If messages are getting to your gateway, but not showing up on your TTN device console, consider changing the _TTNSERVER variable in “ESP-sc-gway.h”. I haven’t had success with the us-west router, but "router.eu.thethings.network" has worked perfectly (even in the US).

Resources

Thanks for coming on this single-channel LoRaWAN gateway journey with us! Here are a few links and documents that might prove handy as you continue exploring the world of LoRa with this board:


learn.sparkfun.com | CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

DIY Light Sculpture

$
0
0

DIY Light Sculpture a learn.sparkfun.com tutorial

Available online at: http://sfe.io/t807

Introduction

Design and build time: 5 Hours

In this project, we’ll create a beautiful desktop light sculpture by edge-lighting laser cut acrylic with addressable LEDs. This project is embedded with a QDuino Mini, 8x8 Adafruit Neopixel Matrix, potentiometer, momentary pushbutton, and switch.

overview light sculpture

Required Materials

Let’s go over all of the things you’ll need to put your project together. Depending on what you have, you may not need everything listed here. Add it to your cart, read through the guide, and adjust the cart as necessary.

Tools

You will need a soldering iron, solder, and general soldering accessories as well as a 3D printer and black filament:

TAZ 6 3D Printer

TAZ 6 3D Printer

TOL-13880
$2,499.95
2
ABS Filament 3mm - 1kg (Black)

ABS Filament 3mm - 1kg (Black)

TOL-12954
$42.95
1

You will also need the following items:

  • Laser Cutter
  • Clear Acrylic (1/8" thick)
  • Hot Glue Gun and Glue

Suggested Reading

Before you get started, take some time to familiarize yourself with the following:

How to Solder: Through-Hole Soldering

This tutorial covers everything you need to know about through-hole soldering.

Installing an Arduino Library

How do I install a custom Arduino library? It's easy! This tutorial will go over how to install an Arduino library using the Arduino Library Manager. For libraries not linked with the Arduino IDE, we will also go over manually installing an Arduino library.

Working with Wire

How to strip, crimp and work with wire.

What is an Arduino?

What is this 'Arduino' thing anyway?

Installing Arduino IDE

A step-by-step guide to installing and testing the Arduino software on Windows, Mac, and Linux.

Addressable LED Strip Hookup Guide

Add blinking lights to any holiday decoration with our Holiday Lights Kit.

Software Installation

Arduino IDE

The Qduino Mini is programmable via the Arduino IDE. If this is your first time using Arduino, please review our tutorial on installing the Arduino IDE.

Installing Arduino IDE

March 26, 2013

A step-by-step guide to installing and testing the Arduino software on Windows, Mac, and Linux.

Qduino Mini Drivers and Board Add-On

If this is your first time working with the Qduino Mini, you may need to add drivers and the board add-on through the boards manager. Please visit the Qduino Mini quick start guide for detailed instructions on installing drivers and programming a Qduino Mini via the Arduino IDE.

Qduino Mini Quick Start Guide

Example Code

Note: This example assumes you are using the latest version of the Arduino IDE on your desktop. If this is your first time using Arduino, please review our tutorial on installing the Arduino IDE. If you have not previously installed an Arduino library, please check out our installation guide.

In this program, we will also be utilizing the Adafruit Neopixel Library. You can obtain this library through the Arduino Library Manager. Search for Adafruit Neopixel and you should be able to install the latest version of the library. If you prefer downloading the library manually you can grab it from the GitHub repository:

Download the Adafruit Neopixel Library (ZIP)

We have provided the code for this project below. Copy and paste it into your Arduino IDE and then upload it to your board. Make sure you have the correct board selected in the boards manager as well as the port under the port drop down.

language:c
    /******************************************************************************
  lightsculpture.ino
  Melissa Felderman @ SparkFun Electronics
  creation date: July 31, 2018


  Resources:
  Adafruit_NeoPixel.h - Adafruit Neopixel library and example functions

*****************************************************************************/

        #include <Adafruit_NeoPixel.h> //include afafruit library 
    #define PIN 6 //LED matrix pin
    #define brightPot A0 //potentiometer to controll brightness
    #define pwrSwitch 4 //power switch
    #define momBut 5 //button to control LED mode
    int numPix = 64; //total LED count
    int brightPotVal; //Variable to hold pot value
    int pixelBrightness; //variabe to hold brightness value
    int switchState; //variable to hold switch value
    int butState; //variable to hold button value
    int mode = 0; //starting mode for switch state
    int prevButState = LOW;
    boolean butBool = false;
    int topMode = 4; //max number of LED modes in switch state

    unsigned long lastDebounceTime = 0;
    unsigned long debounceDelay = 200;

    Adafruit_NeoPixel strip = Adafruit_NeoPixel(numPix, PIN, NEO_GRB + NEO_KHZ800); //declare neopixel matrix


    //create an array for each row of LEDs
    int rowOne[] = {0, 1, 2, 3, 4, 5, 6, 7};
    int rowTwo[] = {8, 9, 10, 11, 12, 13, 14, 15};
    int rowThree[] = {16, 17, 18, 19, 20, 21, 22, 23};
    int rowFour[] = {24, 25, 26, 27, 28, 29, 30, 31};
    int rowFive[] = {32, 33, 34, 35, 36, 37, 38, 39};
    int rowSix[] = {40, 41, 42, 43, 44, 45, 46, 47};
    int rowSeven[] = {48, 49, 50, 51, 52, 53, 54, 55};
    int rowEight[] = {56, 57, 58, 59, 60, 61, 62, 63};

    void setup() {
      Serial.begin(9600);
      strip.begin();
      strip.show();

      pinMode(momBut, INPUT);
      pinMode(pwrSwitch, INPUT);

    }


    void loop() {
      brightPotVal = analogRead(brightPot);
      pixelBrightness = map(brightPotVal, 0, 1023, 0, 200);

      switchState = digitalRead(pwrSwitch);
      butState = digitalRead(momBut);

      strip.setBrightness(pixelBrightness);
      strip.show();

      //function to debounce button
      if ((millis() - lastDebounceTime) > debounceDelay) {
        if ((butState == HIGH) && (butBool == false)) {
          butBool = true;
          mode++;
          lastDebounceTime = millis();
        } butBool = false;
      } if (mode > topMode) {
        mode = 0;
      }

      Serial.println(mode);

      //switch state function to cycle through modes on LEDs, you can add as many or as few as you would like
      if (switchState == HIGH) {

        switch ( mode ) {
          case 0:
            for (int i = 0; i < numPix; i++) {
              strip.setPixelColor(i, 255, 255, 255);
            }
            strip.show();
            break;
          case 1:
            rainbow();
            break;
          case 2:
            buleGreenGradient();
            break;
          case 3:
            pinkGradient();
            break;
          case 4:
            yellowGradient();
            break;

        }
      } else if (switchState == LOW) {
        for (int i = 0; i < numPix; i++) {
          strip.setPixelColor(i, 0, 0, 0);
        }
        strip.show();
      }
    }



    //functions for LED colors


    void everyOther() {
      for (int i = 0; i < 8; i++) {
        strip.setPixelColor(rowOne[i], 255, 255, 255);
        strip.setPixelColor(rowThree[i], 255, 255, 255);
        strip.setPixelColor(rowFive[i], 255, 255, 255);
        strip.setPixelColor(rowSeven[i], 255, 255, 255);

        strip.setPixelColor(rowTwo[i], 0, 0, 0);
        strip.setPixelColor(rowFour[i], 0, 0, 0);
        strip.setPixelColor(rowSix[i], 0, 0, 0);
        strip.setPixelColor(rowEight[i], 0, 0, 0);
      }
      strip.show();
    }


    void pinkGradient() {
      for (int i = 0; i < 8; i++) {
        strip.setPixelColor(rowOne[i], 185, 0, 255);
        strip.setPixelColor(rowTwo[i], 195, 0, 230);
        strip.setPixelColor(rowThree[i], 205, 0, 200);
        strip.setPixelColor(rowFour[i], 215, 0, 160);
        strip.setPixelColor(rowFive[i], 225, 0, 120);
        strip.setPixelColor(rowSix[i], 235, 0, 80);
        strip.setPixelColor(rowSeven[i], 245, 0, 40);
        strip.setPixelColor(rowEight[i], 255, 0, 10);
      }
      strip.show();
    }

    void buleGreenGradient() {
      for (int i = 0; i < 8; i++) {
        strip.setPixelColor(rowOne[i], 0, 75, 255);
        strip.setPixelColor(rowTwo[i], 0, 100, 225);
        strip.setPixelColor(rowThree[i], 0, 125, 200);
        strip.setPixelColor(rowFour[i], 00, 150, 175);
        strip.setPixelColor(rowFive[i], 0, 175, 150);
        strip.setPixelColor(rowSix[i], 0, 200, 125);
        strip.setPixelColor(rowSeven[i], 0, 225, 100);
        strip.setPixelColor(rowEight[i], 0, 255, 75);
      }
      strip.show();
    }

    void yellowGradient() {
      for (int i = 0; i < 8; i++) {
        strip.setPixelColor(rowOne[i], 255, 255, 25);
        strip.setPixelColor(rowTwo[i], 255, 220, 25);
        strip.setPixelColor(rowThree[i], 255, 190, 25);
        strip.setPixelColor(rowFour[i], 255, 160, 25);
        strip.setPixelColor(rowFive[i], 255, 130, 25);
        strip.setPixelColor(rowSix[i], 255, 100, 25);
        strip.setPixelColor(rowSeven[i], 255, 70, 25);
        strip.setPixelColor(rowEight[i], 255, 40, 25);
      }
      strip.show();
    }
    void rainbow() {
      for (int i = 0; i < 8; i++) {
        strip.setPixelColor(rowOne[i], 255, 0, 0);
      } for (int i = 0; i < 8; i++) {
        strip.setPixelColor(rowTwo[i], 255, 100, 0);
      } for (int i = 0; i < 8; i++) {
        strip.setPixelColor(rowThree[i], 255, 255, 0);
      } for (int i = 0; i < 8; i++) {
        strip.setPixelColor(rowFour[i], 0, 255, 0);
      } for (int i = 0; i < 8; i++) {
        strip.setPixelColor(rowFive[i], 0, 255, 200);
      } for (int i = 0; i < 8; i++) {
        strip.setPixelColor(rowSix[i], 0, 0, 255);
      } for (int i = 0; i < 8; i++) {
        strip.setPixelColor(rowSeven[i], 255, 0, 255);
      } for (int i = 0; i < 8; i++) {
        strip.setPixelColor(rowEight[i], 255, 0, 130);
      }
      strip.show();
    }

Understanding Your Circuit

Inside the light sculpture enclosure is one NeoPixel NeoMatrix 8x8 - 64 RGB LED containing a total of 64 addressable WS2812 LEDs, a 100uF Capacitor to protect the first LED, one Qduino Mini - Arduino Dev Board to act as the brains of the project, a Mini Power Switch to easily turn the project on or off, a Tactile Button to navigate between light modes, and a Potentiometer to control brightness. A small piece of Snappable Protoboard is used to extend the ‘+’ and ‘-’ terminals on the Qduino Mini making it easier to connect the ‘+’ and ‘-’ leads from your components. A MicroB USB cable is used to supply wall power directly to the USB port on the Qduino, but a large LiPo battery would work as well.

As shown in the circuit diagram below, the Qduino Mini is the brains of this project. Pin D6 is connected to the NeoPixel NeoMatrix, the potentiometer is connect to pin A0, the switch to pin D4, and the momentary pushbutton to D5. The first LED on the NeoPixel Matrix is protected using a 100uF capacitor between ‘+’ and ‘-’ on the matrix and ‘+’ and ‘-’ on the Qduino Mini. You may also notice that while the rest of the components directly connect to ‘+’ on the Qduini Mini, the switch and button both connect to ‘-’ of the Qduino via a resistor. This is called a pulldown resistor and allows the Qduino to get accurate readings of HIGH and LOW. To learn more about how to use pull up and pull down resistors with Arduino, check out our tutorial.

Light Sculpture Fritzing Diagram

Having a hard time seeing the circuit? Click on the wiring diagram for a closer look.

Enclosure Fabrication

The first part of this project is printing the enclosure on a 3D printer. If you do not have access to a 3D printer, check with your local library or maker space. There are also 3D printing services which you can use online like Shapeways.

Download 3D Printer Drivers

Download any drivers and firmware needed to control your 3D printer. If you are working with a LulzBot like the ones sold through SparkFun, check out their downloads page in the support section of their website. If you are working with a different printer, check out the printer brand’s website for information on drivers and firmware.

Download Project File

Download the .stl file from the project page on thingiverse.

Download File Here

download stl

Prepare GCode

Prepare your Gcode by loading the .stl into your driver software. Either save the Gcode to an SD card or prepare to print by connecting your computer to the printer via USB. Make sure your settings match the material you plan to use. I recommend using black filament because it is effective in blocking light. A lighter color may leak light. If you prefer a light colored enclosure, I would print it in black and then spray paint it afterwards before adding the electronics.

Heads up! To save time and filament, flip the enclosure over in your driver so that the horizontal slots are flat against the bed.

3D Printer Driver Prep

Print

Print the enclosure!

print the enclosure

Putting Your Electronics Together

Now that we have printed the enclosure, let’s prepare the electronics for our circuit.

PLEASE NOTE! Always test your circuit on a breadboard before soldering it together in the enclosure.

Solder Wire Leads

Solder wire leads of about 2" to your components using solid core hook up wire. To make things easier for yourself later, use red wire for ‘+’, black from GND, and white for GPIO input/output. Use heat shrink to secure and isolate your connections on the button and switch.

solder leads light sculpture

Click the image for a closer look.

Place Electronics

Place the electronics in their respective spaces in the enclosure. For the NeoPixel matrix, make sure your DIN pin is in the opposite corner of the potentiometer. This is to ensure your LED patterns align with the slots. You can secure the potentiometer in place with the nut that comes with it.

place electronics light sculpture

For the button and switch, use a small dab of hot glue on the backside to hold them in place.

hot glue electronics light sculpture

Solder a ‘+’ and ‘-’ lead to the VCC and GND of your Qduino respectively. There is only one ‘+’ and one ‘-’ pin on the Qduino so we will need to extend these two pins in order for your components to connect. To do this, grab a small piece of protoboard and solder the opposite end of the ‘+’ lead to one corner and the opposite end of the ‘-’ lead to the opposite corner.

solder entensions light sculpture

Plug the USB cable into the Qduino and place it face down behind the potentiometer with the USB cable threaded through the tab in the back of the enclosure.

plug in Qduino Light Sculpture

Before you begin soldering your circuit together, all parts in the enclosure should look like this:

All the parts together light scultprue

Solder Circuits

Solder your circuit together according to the fritzing diagram provided above. Use the ‘+’ and ‘-’ extensions on the protoboard for all of your ‘+’ and ‘-’ leads. Don't forget to solder a resistor between the GND extension and the the GND leads on your switch and button. It is also best practice to use a capacitor between the ‘+’ and ‘-’ leads on your NeoPixel matrix and the ‘+’ and ‘-’ extensions to protect the first LED from a rush of current.

Solder it together

Verify

Test your circuit. Turn it on and make sure it is working according to the program.

Laser Cutting Your Design

Now that we have the base enclosure completed with the electronics soldered together into a circuit, let’s take a look at how to add a decorative flair to your project.

Download Templates

Download the laser cutter template from the project thingiverse page to prepare to cut your acrylic inserts. Open this with illustrator and begin to design your etching and/or cuts. I have found that the light is picked up by both the etched design and the edges of the plastic, so you can use both of these elements to create your final design. There are 8 rows of LEDs on your matrix so you will want to make 8 different acrylic inserts.

Cut Your Designs

These inserts were cut and the designs rastered on our Epilog 75W laser cutter according to the manufacturer’s specifications. If you do not have access to a laser cutter, check out your local library or hackerspace. Alternatively, you can order your designs online at Ponoko.

laser cut acrylic inserts light culpture

Light up your Life!

Pop the inserts into your enclosure and enjoy!

light sculpture gif

final light sculpture

Resources and Going Further

For more information related to this tutorial, check out the following links:

There is some great information on the WS2812s as well as powering LED projects in the following tutorials:

WS2812 Breakout Hookup Guide

How to create a pixel string with the WS2812 and WS2812B LEDs!

RGB Panel Hookup Guide

Make bright, colorful displays using the 32x16, 32x32, and 32x64 RGB LED matrix panels. This hookup guide shows how to hook up these panels and control them with an Arduino.

Mean Well LED Switching Power Supply Hookup Guide

In this tutorial, we will be connecting a Mean Well LED switching power supply to an addressable LED strip controlled by an Arduino.

Looking for another project? Have a look at some of the following tutorials:

Marquee Party Bag

This tutorial provides everything you need to know to make your own Marquee Party Bag!

DIY Light-Up Shoes

This tutorial provides everything you need to know to make your own light up high top sneakers!

DIY Heated Earmuffs

Embedded with heating pads and four Neopixel rings, these earmuffs do more than your average winter accessory to keep you warm while still looking good.

Check out these blog posts for even more great ideas!


learn.sparkfun.com | CC BY-SA 3.0 | SparkFun Electronics | Niwot, Colorado

Viewing all 1122 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>