Posts with «arduino» label

Tutorial – Using Long Range 315MHz RF Wireless Transceivers with Arduino

You can send data from one Arduino to another, or create a wireless remote-control system using inexpensive long-range 315MHz or 433MHz wireless data units.

Using this tutorial so you can quickly test and use your units, giving you the knowledge to build upon and make your own projects. So let’s get started!

Testing the modules

Our first guide is to simply test that data can be sent and received from one module to another. This is also an ideal setup for testing the radio range of the units in your area.

You will need:

You also need to install the VirtualWire Arduino library. To do this:

  • Download this .zip file into a temporary or your download directory.
  • Open the Arduino IDE and select Sketch > Include Library > Add .zip Library…
  • Navigate to the library .zip download and click “Open”:

After a few moments the library will be installed. You can check that this has completed by selecting Sketch > Include Library> then scroll down the long pop-up menu until you see “VirtualWire” as shown below:

Now – back to the hardware. Allocate one Arduino to be the transmitter, and one the receiver. Upload the following sketch to the transmitter board:

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
// transmitter.ino
//
// Simple example of how to use VirtualWire to transmit messages
// Implements a simplex (one-way) transmitter with an TX-C1 module
//
// See VirtualWire.h for detailed API docs
// Author: Mike McCauley (mikem@airspayce.com)
// Copyright (C) 2008 Mike McCauley
// $Id: transmitter.pde,v 1.3 2009/03/30 00:07:24 mikem Exp $
#include <VirtualWire.h>
const int led_pin = 11;
const int transmit_pin = 12;
const int receive_pin = 2;
const int transmit_en_pin = 3;
void setup()
{
// Initialise the IO and ISR
vw_set_tx_pin(transmit_pin);
vw_set_rx_pin(receive_pin);
vw_set_ptt_pin(transmit_en_pin);
vw_set_ptt_inverted(true); // Required for DR3100
vw_setup(2000); // Bits per sec
pinMode(led_pin, OUTPUT);
}
byte count = 1;
void loop()
{
char msg[7] = {'h','e','l','l','o',' ','#'};
msg[6] = count;
digitalWrite(led_pin, HIGH); // Flash a light to show transmitting
vw_send((uint8_t *)msg, 7);
vw_wait_tx(); // Wait until the whole message is gone
digitalWrite(led_pin, LOW);
delay(1000);
count = count + 1;
}
view raw transmitter.ino hosted with ❤ by GitHub

… and upload the following sketch to the receiver board:

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
// receiver.ino
//
// Simple example of how to use VirtualWire to receive messages
// Implements a simplex (one-way) receiver with an Rx-B1 module
//
// See VirtualWire.h for detailed API docs
// Author: Mike McCauley (mikem@airspayce.com)
// Copyright (C) 2008 Mike McCauley
// $Id: receiver.pde,v 1.3 2009/03/30 00:07:24 mikem Exp $
#include <VirtualWire.h>
const int led_pin = 2;
const int transmit_pin = 12;
const int receive_pin = 11;
const int transmit_en_pin = 3;
void setup()
{
delay(1000);
Serial.begin(9600);
Serial.println("setup");
// Initialise the IO and ISR
vw_set_tx_pin(transmit_pin);
vw_set_rx_pin(receive_pin);
vw_set_ptt_pin(transmit_en_pin);
vw_set_ptt_inverted(true); // Required for DR3100
vw_setup(2000); // Bits per sec
vw_rx_start(); // Start the receiver PLL running
pinMode(led_pin, OUTPUT);
}
void loop()
{
uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen = VW_MAX_MESSAGE_LEN;
if (vw_get_message(buf, &buflen)) // Non-blocking
{
int i;
digitalWrite(led_pin, HIGH); // Flash a light to show received good message
// Message with a good checksum received, dump it.
Serial.print("Got: ");
for (i = 0; i < buflen; i++)
{
Serial.print(buf[i], HEX);
Serial.print(' ');
}
Serial.println();
digitalWrite(led_pin, LOW);
}
}
view raw receiver.ino hosted with ❤ by GitHub

Wiring the modules is very easy, they are labelled well and drop straight into a solderless breadboard:

Now connect the transmitter module to your transmitter Arduino as such:

  • Arduino GND to transmitter GND
  • Arduino 5V to transmitter Vcc
  • Arduino digital pin 12 to transmitter SIG:

Next, connect the receiver module to your transmitter Arduino as such:

  • Arduino GND to receiver GND
  • Arduino 5V to receiver Vcc
  • Arduino digital pin 11 to receiver SIG
  • LED and resistor in series between Arduino digital pin 2 and GND

Now that you’ve assembled both circuits, and uploaded the transmitter and receiver sketches to each board – it’s time to test. 

Connect the transmitter board to power, and connect the receiver board to the PC. If not already open, run the Arduino IDE and open the serial monitor. You should notice two things:

  1. The LED on your receiver circuit should blink around once per second. When the LED blinks, this indicates the receiver circuit has successfully received a complete message from the transmitter
  2. The data sent from the transmitter is displayed in the serial monitor.

You can see this in action through the following video:

Our camera had trouble capturing the LED blink in some moments, but that’s ok.

You can also use this two Arduino setup to test the radio range – simply power the transmitter, and power the receiver circuit with a portable source of energy, such as a USB power bank – then walk away from the transmitter. The LED will stop blinking when you’re out of radio range. 

You can increase the radio range by increasing the voltage to the transmitter unit – up to 12V DC. 

Wireless Remote Control

Now to do something useful – create a wireless digital output control. Our transmitter will have two buttons, and our receiver will control two LEDs via digital outputs. Naturally this is an example, you can use this as a base to control other devices if required. 

You will need:

We will use two tactile buttons and 10k Ohm pull-down resistors for input. If you’re not familiar with digital inputs and buttons, the building block for this is shown below.

The example diagram uses D12 as the input pin, however for this project your transmitter circuit will need two button circuits, using D8 and D7:

To save time we will use button breakout boards which combine the circuit into a neat unit ideal for prototyping:

Your receiver circuit is the same as the test circuit at the start of this tutorial, except that anothe LED circuit is added to digital pin 3.

Now for the sketches. Upload the following sketch to the transmitter (buttons) Arduino…

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
// transmitter sketch
//
#include <VirtualWire.h>
uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen = VW_MAX_MESSAGE_LEN;
const char *on2 = "a";
const char *off2 = "b";
const char *on3 = "c";
const char *off3 = "d";
void setup()
{
vw_set_ptt_inverted(true); // Required for RF Link modules
vw_setup(300); // set data speed
vw_set_tx_pin(12);
pinMode(8, INPUT);
pinMode(7, INPUT);
}
void loop()
{
if (digitalRead(8)==HIGH)
{
vw_send((uint8_t *)on2, strlen(on2)); // send the data out to the world
vw_wait_tx(); // wait a moment
delay(200);
}
if (digitalRead(8)==LOW)
{
vw_send((uint8_t *)off2, strlen(off2));
vw_wait_tx();
delay(200);
}
if (digitalRead(7)==HIGH)
{
vw_send((uint8_t *)on3, strlen(on3));
vw_wait_tx();
delay(200);
}
if (digitalRead(7)==LOW)
{
vw_send((uint8_t *)off3, strlen(off3));
vw_wait_tx();
delay(200);
}
}
view raw tx.ino hosted with ❤ by GitHub

… and upload the following sketch to the receiver (LEDs) Arduino:

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
// receiver sketch
//
#include <VirtualWire.h>
uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen = VW_MAX_MESSAGE_LEN;
void setup()
{
vw_set_ptt_inverted(true); // Required for RF link modules
vw_setup(300);
vw_set_rx_pin(11);
vw_rx_start();
pinMode(3, OUTPUT);
pinMode(2, OUTPUT);
}
void loop()
{
if (vw_get_message(buf, &buflen))
{
switch(buf[0])
{
case 'a':
digitalWrite(2, HIGH);
break;
case 'b':
digitalWrite(2, LOW);
break;
case 'c':
digitalWrite(3, HIGH);
break;
case 'd':
digitalWrite(3, LOW);
break;
}
}
}
view raw rx2.ino hosted with ❤ by GitHub

You can see a quick demonstration in the following video:

So how did that work? 

Review the transmitter sketch. A character is sent over the wireless link which determines the latest operation of the buttons – a, b, c or d (button one high/low, button two high/low).

Review the receiver sketch – on line 19 the switch-case function interrogates the incoming character from the wireless link and determines the action – in this case, controlling the digital outputs which have the two LEDs. 

The response speed may seem a little slow – this will be affected by the data speed (300 bps). You can experiment with data speed and radio range (and voltage to the transmitter unit)

You can then alter this for your own means. You may not want to continuously send data as our example does, depending on your needs. As always, have fun and experiment. 

Sending data wirelessly from one Arduino to another

Now we’ll show how to send some data in the form of an integer over our wireless link. This is ideal for sending the values of analog inputs, or other data that can be represented as an integer.

The hardware is the same as before – one Arduino transmitting and one Arduino receiving – with the receiver unit connected to a PC so we can use the Serial Monitor to display the received data. 

Upload the following sketch to the transmitter Arduino…

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
// data transmitter sketch//
//
#include <VirtualWire.h>
// use onboard LED for status
const int ledPin = 13;
// we'll send the value of analog pin 1
const int Sensor1Pin = A1;
int Sensor1Data;
char Sensor1CharMsg[4];
void setup()
{
pinMode(ledPin, OUTPUT);
pinMode(A1, INPUT);
vw_setup(2000); // data speed in bps
vw_set_tx_pin(12); //digital pin to data transmitter
}
void loop()
{
// get data from analog pin 1
Sensor1Data = analogRead(Sensor1Pin);
// convert data from integer to character array
itoa(Sensor1Data, Sensor1CharMsg, 10);
digitalWrite(13, true); // onboard LED on to indicate transmitting
vw_send((uint8_t *)Sensor1CharMsg, strlen(Sensor1CharMsg)); // send array
vw_wait_tx(); // wait until data is sent
digitalWrite(13, false); // onboard LED off to indicate finished transmitting
delay(1000); // wait
}
view raw dtx1.ino hosted with ❤ by GitHub

… and the following sketch to the receiver Arduino.

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
// data receiver sketch
//
#include <VirtualWire.h>
// use onboard LED for status
const int ledPin = 13;
int Sensor1Data;
// holds data from receiver
char Sensor1CharMsg[4];
void setup() {
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
vw_set_ptt_inverted(true);
vw_setup(2000); // data speed in bps
vw_set_rx_pin(11); // receiver data pin to digital 11
vw_rx_start();
}
void loop() {
uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen = VW_MAX_MESSAGE_LEN;
if (vw_get_message(buf, &buflen))
{
int i;
// LED on to indicate message coming in
digitalWrite(13, true);
for (i = 0; i < buflen; i++)
{
// fill array with data from receiver
Sensor1CharMsg[i] = char(buf[i]);
}
// null terminate the char array, indicates the end of the data
Sensor1CharMsg[buflen] = '\0';
// convert data in array to a usable integer
Sensor1Data = atoi(Sensor1CharMsg);
// send data to serial monitor
Serial.print("tx analog pin 1 reads: ");
Serial.println(Sensor1Data);
// message reception finished, turn off onboard LED
digitalWrite(13, false);
}
}
view raw drx2.ino hosted with ❤ by GitHub

Once operating and in radio range, the onboard LEDs will indicate successful transmission and reception of data. Open the serial monitor, and after a moment you will be presented with the data from analogue pin 1 of the transmitter Arduino – for example:

So how did that work? 

Review the trasmitter sketch. We took a value from analog pin 1, and stored it into an integer variable on line 25. The VirtualWire library is geared to send data as characters so we convert the integer to a character array on line 28 – which is then sent as usual as shown in line 31.

Now review the receiver sketch. Nothing unusual, and the data from the receiver (in character form) is fed into the array at line 35. Once completed, we add “\0” to the end of the array to signify the end of the data. 

The array is then converted back to an integer on line 42, then sent to the Serial Monitor.

So there you have it, we’ve sent integers across the airwaves. You can use your own “codes” with integers to mean all sorts of things and send them across. Ideal for temperature sensors, or anything really. 

I hope you had fun experimenting with wireless units, or at least enjoyed reading about the possibilities. To keep up to date with new posts at tronixstuff.com, please subscribe to the mailing list in the box on the right, or follow us on x – @tronixstuff.

If you find this sort of thing interesting, please consider ordering one or more of my books from amazon:

Tronixstuff 23 Apr 06:05
arduino  wireless  

Tiny, Hackable Telepresence Robot for under $100? Meet Goby

[Charmed Labs] are responsible for bringing numerous open-source hardware products to fruition over the years, and their latest device is an adorably small robotic camera platform called Goby, currently crowdfunding for its initial release. Goby has a few really clever design features and delivers a capable (and hackable) platform for under 100 USD.

Goby embraces its small size, delivering what its creators dub “tinypresence” — or the feeling of being there, but on a very small scale. Cardboard courses, LEGO arenas, or even tabletop gaming scenery hits different when experienced from a first-person perspective. Goby is entirely reprogrammable with nothing more than a USB cable and the Arduino IDE, while costing less than most Arduino starter kits.

Recharging happens by driving over the charger, then pivoting down so the connectors (the little blunt vampire fangs under and to each side of the camera) come into contact with the charger.

One of the physical features we really like is the tail-like articulated caster at the rear. Flexing this pivots Goby up or down (and can even flip Goby completely over), allowing one to pan and tilt the view without needing to mount the camera on a gimbal. It also comes into play for recharging; Goby simply moves over the disc-shaped charger and pivots down to make contact.

At Goby‘s heart is an ESP32-S3 and OmniVision OV2640 camera sensor streaming a live video feed (and driving controls) with WebRTC. Fitting the WebRTC stack onto an ESP32 wasn’t easy, but opens up possibilities beyond just media streaming.

Goby is set up to make launching an encrypted connection as easy as sharing a URL or scanning a QR code. The link is negotiated between bot and client with the initial help of an external server, and once a peer-to-peer connection is established, the server’s job is done and it is out of the picture. [Charmed Labs]’s code for this functionality — named BitBang — is in beta and destined for an open release as well. While BitBang is being used here to make it effortless to access Goby remotely, it’s more broadly intended to make web access for any ESP32-based device easier to implement.

As far as tiny remote camera platforms go, it might not be as small as rebuilding a Hot Wheels car into a micro RC platform, but it’s definitely more accessible and probably cheaper, to boot. Check it out at the Kickstarter (see the first link in this post) and watch it in action in the video, embedded just below the page break.

Project – Fun with Arduino-controlled Traffic Lights

The goal of this project is to make a pair of traffic lights that can be used for learning about Arduino digital inputs and outputs – or as the prototype for your own traffic lights in model layouts such as trains, dioramas, LEGO and so on. 

Imagine a two-way road that has a single-lane bridge – cars can only travel in one direction at a time. You need to build a system to stop drivers being impatient and risking their lives by approaching the bridge from both sides at the same time. 

Your solution is a set of traffic lights. One set at each end of the bridge – east and west, and a sensor to detect cars approaching the lights. We’ll use our traffic light and button modules to keep things simple:

When a car approaches one side – and the lights are red, the car must wait until the light changes. The sensor detects the car and the system changes the lights at the other end from green to yellow to red.

Then the lights at the other side hold red and flash yellow, to give the awaiting motorists a little notice before crossing the bridge – which they can do when the lights change to green. And vice-versa! So let’s get started.

Parts List

We use the tactile button boards as they are the equivalent to a button circuit with a 10k pull-down resistor; and we use the traffic lights as they are the equivalent of three LEDs with current-limiting resistors… that are much more convenient.

Putting it all together

Thanks to the modules we’re using, the whole system is plug-and-play. The following image is our example in action. But don’t panic – we’ll go through it step-by-step.

First we’ll connect the traffic lights. When you look at the bottom, you can see the pinout labels as such:

We’ll call this the east side. Plug the traffic light module into a solderless breadboard, with the pins across the numerical columns as shown in the final image. Then connect four jumper wires from the solderless breadboard columns matching R Y G GND to the Arduino’s D11, D10, D9 and GND respectively. 

Repeat this with another solderless breadboard (we’ll call it the west side) – connect four more jumper wires from the solderless breadboard columns matching R Y G GND to the Arduino’s D4, D3, D2 and GND respectively.

Now for the buttons. They have three pins – 5V, OUT and GND. When the button is pressed, the OUT pin goes from LOW to HIGH:

First, run a jumper wire from the 5V on the Arduino to a blank column on one solderless breadboard. Then run another wire from that column over to the the other solderless breadboard. This gives you 5V on both breadboards.

Next, on each breadboard, run a jumper wire from the traffic lights’ GND pin column to a column next to your 5V column on the breadboard. This gives you 5V and GND on each breadboard. 

To connect the west button – connect 5V and GND to the new spots on the solderless breadboard, and the OUT pin to Arduino D5. 

And for the east button – connect 5V and GND to the new spots on the solderless breadboard, and the OUT pin to Arduino D12. 

Now go back and double-check your wiring – once you’re satisfied it’s time to upload the sketch. 

The Arduino sketch

Time for the brains of the operation. Copy the sketch below and upload to your Arduino:

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
// https://tronixstuff.com/2025/04/15/project-arduino-controlled-traffic-lights/
//
// define the I/O pins that are used on the Arduino
// … the buttons
#define westButton 5
#define eastButton 12
// the LEDs on the traffic light modules
#define westRed 4
#define westYellow 3
#define westGreen 2
#define eastRed 11
#define eastYellow 10
#define eastGreen 9
#define yellowBlinkTime 500 // 0.5 seconds for yellow light blink
boolean trafficWest = true; // west = true, east = false
int flowTime = 5000; // amount of time to let traffic flow
int changeDelay = 2000; // amount of time between color changes
void setup()
{
// this code runs when the Arduino first powers-up
// or after a reset
// setup digital I/O pins
// buttons are INPUTs
pinMode(westButton, INPUT);
pinMode(eastButton, INPUT);
// LEDs are OUTPUTs
pinMode(westRed, OUTPUT);
pinMode(westYellow, OUTPUT);
pinMode(westGreen, OUTPUT);
pinMode(eastRed, OUTPUT);
pinMode(eastYellow, OUTPUT);
pinMode(eastGreen, OUTPUT);
// set initial state for lights – west side is green first
digitalWrite(westRed, LOW);
digitalWrite(westYellow, LOW);
digitalWrite(westGreen, HIGH);
digitalWrite(eastRed, HIGH);
digitalWrite(eastYellow, LOW);
digitalWrite(eastGreen, LOW);
}
void loop()
// this code runs continuously until power-off or a reset
{
if ( digitalRead(westButton) == HIGH )
// request west to east traffic flow
{
if ( trafficWest != true )
// only continue if traffic flowing in the opposite (east) direction
{
trafficWest = true; // change traffic flow flag to west>east
delay(flowTime); // give time for traffic to clear the bridge
digitalWrite(eastGreen, LOW); // change east-facing lights from green…
// to yellow to red
digitalWrite(eastYellow, HIGH);
delay(changeDelay);
digitalWrite(eastYellow, LOW);
digitalWrite(eastRed, HIGH);
delay(changeDelay);
for ( int a = 0; a < 5; a++ ) // blink yellow light
{
digitalWrite(westYellow, LOW);
delay(yellowBlinkTime);
digitalWrite(westYellow, HIGH);
delay(yellowBlinkTime);
}
digitalWrite(westYellow, LOW);
digitalWrite(westRed, LOW); // change west-facing lights from red to green
digitalWrite(westGreen, HIGH);
}
}
if ( digitalRead(eastButton) == HIGH ) // request east to west traffic flow
{
if ( trafficWest == true )
// only continue if traffic flow is in the opposite (west) direction
{
trafficWest = false; // change traffic flow flag to east>west
delay(flowTime); // give time for traffic to clear the bridge
digitalWrite(westGreen, LOW);
// change west lights from green to yellow to red
digitalWrite(westYellow, HIGH);
delay(changeDelay);
digitalWrite(westYellow, LOW);
digitalWrite(westRed, HIGH);
delay(changeDelay);
for ( int a = 0 ; a < 5 ; a++ ) // blink yellow light
{
digitalWrite(eastYellow, LOW);
delay(yellowBlinkTime);
digitalWrite(eastYellow, HIGH);
delay(yellowBlinkTime);
}
digitalWrite(eastYellow, LOW);
digitalWrite(eastRed, LOW); // change east-facing lights from red to green
digitalWrite(eastGreen, HIGH);
}
}
}
view raw traffic.ino hosted with ❤ by GitHub

You can now operate your traffic lights! If you are facing the red light, press the matching button and wait until the lights change before you can cross the bridge.

You can adjust the delays, the speed of light-changing and the other aspects in the sketch. In some countries you may not have flashing yellow before green – so you could remove that feature.

You can see our example in operation from the video below:

Where to from here? 

You can now understand how the basic inputs and outputs of an Arduino development board can be harnessed for fun and useful projects. You could expand on this system by adding more traffic lights and buttons – use an Arduino Mega-compatible board as it has plenty more inputs and outputs.

Or you could experiment by using different types of sensors instead of buttons – such as motion detectors, beam-break switches or something home-made.

I hope you had fun with the traffic lights, or at least enjoyed reading about the blinking fun. To keep up to date with new posts at tronixstuff.com, please subscribe to the mailing list in the box on the right, or follow us on x – @tronixstuff.

If you find this sort of thing interesting, please consider ordering one or more of my books from amazon:

Tronixstuff 15 Apr 04:24

DIY scanning spectrometer is a bright idea

Spectroscopy seems simple: split a beam of light into its constituent wavelengths with a prism or diffraction grating, and measure the intensity of each wavelength. The devil is in the details, though, and what looks simple is often much harder to pull of in practice. You’ll find lots of details in [Gary Boyd]’s write-up of his optical scanning spectrometer project, but no devils.

Schematic diagram of [Gary Boyd]’s Czerny-Turner type scanning spectrometer.
A scanning spectrometer is opposed to the more usual camera-type spectrometer we see on these pages in that it uses a single-pixel sensor that sweeps across the spectrum, rather than spreading the spectrum across an imaging sensor.

Specifically, [Gary] has implemented a Czerny-Turner type spectrometer, which is a two-mirror design. The first concave mirror collimates the light coming into the spectrometer from its entrance slit, focusing it on a reflective diffraction grating. The second concave mirror focuses the various rays of light split by the diffraction grating onto the detector.

In this case [Gary] uses a cheap VEML 7700 ambient light sensor mounted to a small linear stage from amazon to achieve a very respectable 1 nm resolution in the range from 360 nm to 980 nm. That’s better than the human eye, so nothing to sneeze at — but [Gary] includes some ideas in his blog post to extend that even further. The whole device is controlled via an Arduino Uno that streams data to [Gary]’s PC.

[Gary] documents everything very well, from his optical mounts to the Arduino code used to drive the stepper motor and take measurements from the VEML 7700 sensor. The LED and laser “turrets” used in calibration are great designs as well. He also shares the spectra this device is capable of capturing– everything from the blackbody of a tungsten lamp used in calibration, to a cuvette of tea, to the sun itself as you can see here. If you have a couple minutes, [Gary]’s full writeup is absolutely worth a read.

This isn’t the first spectrometer we’ve highlighted– you might say we’ve shown a whole spectrum of them.

Tutorial – TCA9548A 1-to-8 I2C Multiplexer Breakout with Arduino

Now and again you may find yourself needing to use more than one device with the same I2C bus address with your Arduino.

Such as four OLEDs for a large display – or seven temperature sensors that are wired across a chicken hatchling coop. 

These types of problems can be solved with the TCA9548A 1-to-8 I2C Multiplexer Breakout, and in this guide we’ll run through the how to make it happen with some example devices. 

Getting Started

First, consider the TCA9548A itself. It is the gateway between your Arduino and eight separate I2C buses. You have a single bus on one side, connected to your Arduino.

On the other side of the TCA9548A, you have eight I2C buses, and only one of these can be connected to the Arduino at a time. For example (from the data sheet):

The TCA9548 can operate on voltages between 1.8 and 5V DC… and operate with devices that have operating voltages between 1.8 and 5V DC. This is very convenient, as (for example) you can use devices made for 3.3V operation with 5V Arduinos, or vice versa. Awesome. So let’s get started. 

The breakout board includes inline header pins, which are not soldered to the board. So you need to do that. An easy way to line up the pins properly is to drop them into a solderless breadboard, as such:

Then after a moment or two of soldering, you’re ready to use:

Next, insert your module into a solderless breadboard and wire it up as shown:

We are using the red and blue vertical strips on the breadboard as 5V and GND respectively. Finally, we connect the 5V and GND from the Arduino to the solderless breadboard, and A4/A5 to SDA/SCL respectively on the breakout board:

The electrical connections are as follows (Module — Arduino):

  • Vin to 5V
  • GND to GND
  • A0 to GND
  • A1 to GND
  • A2 to GND
  • SDA to A4
  • SCL to A5

Next, we consider the I2C bus address for the TCA9548A. Using the wiring setup shown above, the address is set to 0x70. You only need to change this if one of your other devices also has an address of 0x70, as shown in the next step.

Changing the I2C address of the TCA9548A

The bus address of the TCA9548A is changed using the connections to the A0, A1 and A2 pins. By default in the tutorial we use 0x70, by wiring A0~A2 to GND (known as LOW). Using the table below, you can reconfigure to an address between 0x70 and 0x77 by matching the inputs to HIGH (5V) or LOW (GND):

Testing 

Before we get too excited, now is a good time to test our wiring to ensure the Arduino can communicate with the TCA9548A. We’ll do this by running an I2C scanner sketch, which returns the bus address of a connected device. 

Copy and paste this sketch into your Arduino IDE and upload it to your board.

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
#include <Wire.h>
void setup() {
Wire.begin();
Serial.begin(115200);
Serial.println("\nI2C Scanner");
}
void loop() {
byte error, address;
int nDevices;
Serial.println("Scanning…");
nDevices = 0;
for(address = 1; address < 127; address++ ) {
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0) {
Serial.print("I2C device found at address 0x");
if (address<16) {
Serial.print("0");
}
Serial.println(address,HEX);
nDevices++;
}
else if (error==4) {
Serial.print("Unknow error at address 0x");
if (address<16) {
Serial.print("0");
}
Serial.println(address,HEX);
}
}
if (nDevices == 0) {
Serial.println("No I2C devices found\n");
}
else {
Serial.println("done\n");
}
delay(5000);
}
view raw i2cscanner.ino hosted with ❤ by GitHub

Then, open the serial monitor and set the data rate to 115200. You should be presented with something like the following:

As you can see, our scanner returned an address of 0x70, which matches the wiring described in the bus address table mentioned earlier. If you did not find success, unplug the Arduino from the computer and double-check your wiring – then try again.

Controlling the bus selector

Using the TCA9548A is your sketch is not complex at all, it only requires one step before using your I2C device as normal. That extra step is to instruct the TCA9548A to use one of the eight buses that it controls. 

To do this, we send a byte of data to the TCA9548A’s bus register which represents which of the eight buses we want to use. Each bit of the byte is used to turn the bus on or off, with the MSB (most significant bit) for bus 7, and the LSB (least significant bit) for bus 0.

For example, if you sent:

0b00000001 (in binary) or 0 in decimal

… this would activate bus zero. 

Or if you sent:

0b00010000 (in binary)

… this would activate bus five. 

Once you select a bus, the TCA9548A channels all data in and out of the bus to the Arduino on the selected bus. You only need to send the bus selection data when you want to change buses. We’ll demonstrate that later. 

So to make life easier, we can use a little function to easily select the required bus:

void TCA9548A(uint8_t bus)
{
  Wire.beginTransmission(0x70);  // TCA9548A address is 0x70
  Wire.write(1 << bus);          // send byte to select bus
  Wire.endTransmission();
}

This function accepts a bus number and places a “1” in the TCA9548A’s bus register matching our requirements. Then, you simply slip this function right before needing to access a device on a particular I2C bus. For example, a device on bus 0: 

TCA9548A(0);

 … or a device on bus 6:

TCA9548A(6);

A quick note about pull-up resistors

You still need to use pull-up resistors on the eight I2C buses eminating from the TCA9548A. If you’re using an assembled module, such as our example devices – they will have the resistors – so don’t panic.

If not, check the data sheets for your devices to determine the appropriate pull-up resistors value. If this information isn’t available, try 10k0 resistors.

Controlling our first device

Our first example device is the tiny 0.49″ OLED display. If you haven’t seen this display before, click here for the tutorial.

It is has four connections, which are wired as follows (OLED — TCA9548A/Arduino):

  • GND to GND
  • Vcc to Arduino 3.3V
  • CL to TCA9548A SC0 (bus #0, clock pin)
  • DA to TCA9548A SD1 (bus #0, data pin)

The OLED runs from 3.3V, so that’s why we’re powering it directly from the Arduino’s 3.3V pin. 

Now, copy and upload this sketch to your Arduino:

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
#include <Arduino.h>
#include <U8g2lib.h>
#include <Wire.h>
void TCA9548A(uint8_t bus)
{
Wire.beginTransmission(0x70); // TCA9548A address is 0x70
Wire.write(1 << bus); // send byte to select bus
Wire.endTransmission();
}
U8G2_SSD1306_64X32_1F_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
void setup()
{
Wire.begin();
u8g2.begin();
}
void loop()
{
TCA9548A(0); // tell the TCA9548A we want to use I2C bus number zero (to talk to the OLED)
// use the OLED as normal
for (int a = 999; a >= 0; –a)
{
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_inb24_mr ); // choose a suitable font
u8g2.setCursor(0, 24);
u8g2.print(a);
a = a – 47;
u8g2.sendBuffer(); // transfer internal memory to the display
delay(100);
}
}

After a moment the OLED will display some numbers counting down in various amounts (video):

So how did that work? We inserted our bus selection function at line 5 of the sketch, then called the function in at line 22 to tell the TCA9548A that we wanted to use I2C bus zero. Then the rest of the sketch used the OLED as normal. 

Controlling two devices

Let’s add another device, a BMP180 barometric pressure sensor module. We’ll connect this to I2C bus number seven on the TCA5948A. There are four connections, which are wired as follows (BMP180 — TCA9548A/Arduino):

  • GND to GND
  • Vcc to Arduino 3.3V
  • CL to TCA9548A SC0 (bus #7, clock pin)
  • DA to TCA9548A SD1 (bus #7, data pin)

Now, copy and upload this sketch to the Arduino, and after a moment the OLED will display the ambient temperature from the BMP180 in whole degrees Celsius.

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
#include <Arduino.h>
#include <U8g2lib.h>
#include <Adafruit_BMP085.h>
#include <Wire.h>
U8G2_SSD1306_64X32_1F_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
Adafruit_BMP085 bmp;
int temperature;
void TCA9548A(uint8_t bus)
{
Wire.beginTransmission(0x70); // TCA9548A address is 0x70
Wire.write(1 << bus); // send byte to select bus
Wire.endTransmission();
}
void setup()
{
Wire.begin();
u8g2.begin();
TCA9548A(7); // select I2C bus 7 for the BMP180
if (!bmp.begin())
{
Serial.println("Could not find a valid BMP085 sensor, check wiring!");
while (1) {}
}
}
void loop()
{
// first, get the temperature from the BMP180
TCA9548A(7); // select I2C bus 7 for the BMP180
temperature = int(bmp.readTemperature());
// next, display the temperature on the OLED
TCA9548A(0); // select I2C bus 0 for the OLED
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_inb24_mr ); // choose a suitable font
u8g2.setCursor(0, 24);
u8g2.print(temperature);
u8g2.sendBuffer();
delay(100);
}
view raw TCA9548A3.ino hosted with ❤ by GitHub

This is demonstrated in the following video (finger is placed on the BMP180 for force a rise in temperature)(video):

So how did that work? We set up the libraries and required code for the OLED, BMP180 and TCA5948A as usual. 

We need to intialise the BMP180, so this is done at line 24 – where we select the I2C bus 7 before initiating the BMP180.

The the sketch operates. On line 34 we again request I2C bus 7 from the TCA9548A, then get the temperature from the BMP180.

On line 38 we request I2C bus 0 from the TCA9548A, and then display the temperature on the OLED. Then repeat.

A quick note about the reset pin

More advanced users will be happy to know they can reset the TCA9548A status, to recover from a bus-fault condition. To do this, simply drop the RESET pin LOW (that is, connect it to GND). 

Where to from here? 

You can now understand through our worked example how easy it is to use the TCA9548A and access eight secondary I2C buses through the one bus from your Arduino. Don’t forget that the TCA9548A also does double-duty as a level converter, thereby increasing its value to you. 

I hope you enjoyed reading about these useful TCA9548A boards. To keep up to date with new posts at tronixstuff.com, please subscribe to the mailing list in the box on the right, or follow us on x – @tronixstuff.

If you find this sort of thing interesting, please consider ordering one or more of my books from amazon:

And, as always, have fun and make something.

Tronixstuff 14 Apr 01:25
arduino  i2c  tca9548a  

Hewlett-Packard 5082-7415 LED Display from 1976

In this article we examine a five digit, seven-segment LED display from Hewlett-Packard, the 5082-7415:

We realise they’re most likely now pure unobtanium, but we like some old display p0rn so here you go.

2025 update – Tronixlabs in Australia has a limited quantity of new, old-stock four-digit QDSP6064 displays. Email john at tronixlabs dot com for more information.

According to the data sheet (HP 5082-series.pdf) and other research this was available for a period of time around 1976 and used with other 5082-series modules in other HP products. Such as the Hewlett-Packard 3x series of calculators, for example:

Using the display is very easy – kudos to the engineers at HP for making a simple design that could be reusable in many applications. The 5082-7415 is a common-cathode unit and wiring is very simple – there are the usual eight anodes for segments a~f and the decimal point, and the five cathodes.

As this module isn’t too easily replaceable, I was very conservative with the power supply – feeding just under 1.6V at 10mA to each of the anode pins. A quick test proved very promising:

Excellent – it worked! But now to get it displaying some sort of interesting way. Using the following hardware…

Don’t forget to use the data sheet (HP 5082-series.pdf). You don’t have to use Arduino – any microcontroller with the appropriate I/O can take care of this.

Here is a simple Arduino sketch that scrolls through the digits with and then without the decimal point:

// Arduino sketch to demonstrate HP 5082-7415 LED Display unit
// John Boxall, April 2012
int clockPin=6;
int latchPin=7;
int dataPin=8;
// array for cathodes - sent to second shift register
byte digits[]={
  B10000000,
  B01000000,
  B00100000,
  B00010000,
  B00001000,
  B11111000}; // use digits[6] to turn all on
// array for anodes (to display 0~0) - sent to first shift register
byte numbers[]={
  B11111100,
  B01100000,
  B11011010,
  B11110010,
  B01100110,
  B10110110,
  B10111110,
  B11100000,
  B11111110,
  B11110110};
void setup()
{
  pinMode(clockPin, OUTPUT);
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}
void loop()
{
  int i;
  for ( i=0 ; i<10; i++ )
  {
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, LSBFIRST, digits[6]);
    shiftOut(dataPin, clockPin, LSBFIRST, numbers[i]);
    digitalWrite(latchPin, HIGH);
    delay(250);
  }
  // now repeat with decimal point
  for ( i=0 ; i<10; i++ )
  {
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, LSBFIRST, digits[6]);
    shiftOut(dataPin, clockPin, LSBFIRST, numbers[i]+1);
    digitalWrite(latchPin, HIGH);
    delay(250);
  }
}

And the results:

Now for something more useful. Here is a function that sends a single digit to a position on the display with the option of turning the decimal point on or off:

void displayDigit(int value, int posit, boolean decPoint)
// displays integer value at digit position posit with decimal point on/off
{
 digitalWrite(latchPin, LOW);
 shiftOut(dataPin, clockPin, LSBFIRST, digits[posit]);
 if (decPoint==true)
 {
 shiftOut(dataPin, clockPin, LSBFIRST, numbers[value]+1); 
 } 
 else 
 {
 shiftOut(dataPin, clockPin, LSBFIRST, numbers[value]); 
 }
 digitalWrite(latchPin, HIGH);
}

So if you wanted to display the number three in the fourth digit, with the decimal point – use

displayDigit(3,3,true);

with the following result:

We make use of the displayDigit() function in our next sketch. We introduce a new function:

displayInteger(number,cycles);

It accepts a long integer between zero and 99999 (number) and displays it on the module for cycles times:

// Arduino sketch to demonstrate HP 5082-7415 LED Display unit
// Displays numbers on request
// John Boxall, April 2012
int clockPin=6;
int latchPin=7;
int dataPin=8;
// array for cathodes - sent to second shift register
byte digits[]={
 B10000000,
 B01000000,
 B00100000,
 B00010000,
 B00001000,
 B11111000}; // use digits[6] to turn all on
// array for anodes (to display 0~0) - sent to first shift register
byte numbers[]={
 B11111100,
 B01100000,
 B11011010,
 B11110010,
 B01100110,
 B10110110,
 B10111110,
 B11100000,
 B11111110,
 B11110110};
void setup()
{
 pinMode(clockPin, OUTPUT);
 pinMode(latchPin, OUTPUT);
 pinMode(dataPin, OUTPUT);
 randomSeed(analogRead(0));
}
void clearDisplay()
// turns off all digits
{
 digitalWrite(latchPin, LOW);
 shiftOut(dataPin, clockPin, LSBFIRST, 0);
 shiftOut(dataPin, clockPin, LSBFIRST, 0); 
 digitalWrite(latchPin, HIGH);
}
void displayDigit(int value, int posit, boolean decPoint)
// displays integer value at digit position posit with decimal point on/off
{
 digitalWrite(latchPin, LOW);
 shiftOut(dataPin, clockPin, LSBFIRST, digits[posit]);
 if (decPoint==true)
 {
 shiftOut(dataPin, clockPin, LSBFIRST, numbers[value]+1); 
 } 
 else 
 {
 shiftOut(dataPin, clockPin, LSBFIRST, numbers[value]); 
 }
 digitalWrite(latchPin, HIGH);
}
void displayInteger(long number,int cycles)
// displays a number 'number' on the HP display. 
{
 long i,j,k,l,z;
 float f;
 clearDisplay();
 for (z=0; z
void loop()
{
 long l2;
 l2=random(0,100001);
 displayInteger(l2,400);
}

For demonstration purposes the sketch displays random numbers, as shown in the video below:

Update – four-digit versions…

They worked very nicely and can be driven in the same method as the 5082-7415s described earlier. In the following video we have run the same sketches with the new displays:

In the meanwhile, I hope you found this article of interest. Thanks to the Vintage Technology Association website and the Museum of HP Calculators for background information.

To keep up to date with new posts at tronixstuff.com, please subscribe to the mailing list in the box on the right, or follow us on x – @tronixstuff.

I hope you enjoyed reading about the displays. If you find this sort of thing interesting, please consider ordering one or more of my books from amazon.

And as always, have fun and make something.

Tutorial – Ethernet Shields and Arduino

In this chapter we will introduce and examine the use of Ethernet networking with Arduino over local networks and the greater Internet.

It will be assumed that you have a basic understanding of computer networking, such as the knowledge of how to connect computers to a hub/router with RJ45 cables, what an IP and MAC address is, and so on. Furthermore, here is a good quick rundown about Ethernet.

Getting Started

You will need an Arduino Uno or compatible board with an Ethernet shield that uses the W5100 Ethernet controller IC (pretty much all of them):

Furthermore you will need to power the board via the external DC socket – the W5100 IC uses more current than the USB power can supply. A 9V 1.5A plug pack/wall wart will suffice.

Finally it does get hot – so be careful not to touch the W5100 after extended use. In case you’re not sure – this is the W5100 IC:

Once you have your Ethernet-enabled Arduino, and have the external power connected – it’s a good idea to check it all works. Open the Arduino IDE and select File > Examples > Ethernet > Webserver. This loads a simple sketch which will display data gathered from the analogue inputs on a web browser. However don’t upload it yet, it needs a slight modification.

You need to specify the IP address of the Ethernet shield – which is done inside the sketch. This is simple, go to the line:

IPAddress ip(192,168,1, 177);

And alter it to match your own setup. For example, in my home the router’s IP address is 10.1.1.1, the printer is 10.1.1.50 and all PCs are below …50. So I will set my shield IP to 10.1.1.77 by altering the line to:

IPAddress ip(10,1,1,77);

You also have the opportunity to change your MAC address. Each piece of networking equipment has a unique serial number to identify itself over a network, and this is normall hard-programmed into the equipments’ firmware. However with Arduino we can define the MAC address ourselves.

If you are running more than one Ethernet shield on your network, ensure they have different MAC addresses by altering the hexadecimal values in the line:

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

However if you only have one shield just leave it be. There may be the very, very, statistically rare chance of having a MAC address the same as your existing hardware, so that would be another time to change it.

Once you have made your alterations, save and upload the sketch. Now open a web browser and navigate to the IP address you entered in the sketch, and you should be presented with something similar to the following:

What’s happening? The Arduino has been programmed to offer a simple web page with the values measured by the analogue inputs. You can refresh the browser to get updated values.

At this point – please note that the Ethernet shields use digital pins 10~13, so you can’t use those for anything else. Some Arduino Ethernet shields may also have a microSD card socket, which also uses another digital pin – so check with the documentation to find out which one.

Nevertheless, now that we can see the Ethernet shield is working we can move on to something more useful. Let’s dissect the previous example in a simple way, and see how we can distribute and display more interesting data over the network. For reference, all of the Ethernet-related functions are handled by the Ethernet Arduino library. If you examine the previous sketch we just used, the section that will be of interest is:

 for (int analogChannel = 0; analogChannel < 6; analogChannel++) 
          {
            int sensorReading = analogRead(analogChannel);
            client.print("analog input ");
            client.print(analogChannel);
            client.print(" is ");
            client.print(sensorReading);
            client.println("<br />");       
          }
          client.println("</html>");

Hopefully this section of the sketch should be familiar – remember how we have used serial.print(); in the past when sending data to the serial monitor box? Well now we can do the same thing, but sending data from our Ethernet shield back to a web browser – on other words, a very basic type of web page.

However there is something you may or may not want to  learn in order to format the output in a readable format – HTML code. I am not a website developer (!) so will not delve into HTML too much.

However if you wish to serve up nicely formatted web pages with your Arduino and so on, here would be a good start. In the interests of simplicity, the following two functions will be the most useful:

client.print(" is ");

Client.print (); allows us to send text or data back to the web page. It works in the same way as serial.print(), so nothing new there. You can also specify the data type in the same way as with serial.print(). Naturally you can also use it to send data back as well. The other useful line is:

client.println("<br />");

which sends the HTML code back to the web browser telling it to start a new line. The part that actually causes the carriage return/new line is the <br /> which is an HTML code (or “tag”) for a new line. So if you are creating more elaborate web page displays, you can just insert other HTML tags in the client.print(); statement.

If you want to learn more about HTML commands, here’s a good tutorial site. Finally – note that the sketch will only send the data when it has been requested, that is when it has received a request from the web browser.

Accessing your Arduino over the Internet

So far – so good. But what if you want to access your Arduino from outside the local network?

You will need a static IP address – that is, the IP address your internet service provider assigns to your connection needs to stay the same. If you don’t have a static IP, as long as you leave your modem/router permanently swiched on your IP shouldn’t change. However that isn’t an optimal solution.

If your ISP cannot offer you a static IP at all, you can still move forward with the project by using an organisation that offers a Dynamic DNS. These organisations offer you your own static IP host name (e.g. mojo.monkeynuts.com) instead of a number, keep track of your changing IP address and linking it to the new host name. From what I can gather, your modem needs to support (have an in-built client for…) these DDNS services. As an example, two companies are No-IP andDynDNS.com. Please note that I haven’t used those two, they are just offered as examples.

Now, to find your IP address… usually this can be found by logging into your router’s administration page – it is usually 192.168.0.1 but could be different. Check with your supplier or ISP if they supplied the hardware. For this example, if I enter 10.1.1.1 in a web browser, and after entering my modem administration password, the following screen is presented:

What you are looking for is your WAN IP address, as you can see in the image above. To keep the pranksters away, I have blacked out some of my address.

The next thing to do is turn on port-forwarding. This tells the router where to redirect incoming requests from the outside world. When the modem receives such a request, we want to send that request to the port number of our Ethernet shield. Using the:

EthernetServer server(125);

function in our sketch has set the port number to 125. Each modem’s configuration screen will look different, but as an example here is one:

So you can see from the line number one in the image above, the inbound port numbers have been set to 125, and the IP address of the Ethernet shield has been set to 10.1.1.77 – the same as in the sketch.

After saving the settings, we’re all set. The external address of my Ethernet shield will be the WAN:125, so to access the Arduino I will type my WAN address with :125 at the end into the browser of the remote web device, which will contact the lonely Ethernet hardware back home.

Furthermore, you may need to alter your modem’s firewall settings, to allow the port 125 to be “open” to incoming requests. Please check your modem documentation for more information on how to do this.

Now from basically any Internet connected device in the free world, I can enter my WAN and port number into the URL field and receive the results. For example, from a phone when it is connected to the Internet via LTE mobile data:

So at this stage you can now display data on a simple web page created by your Arduino and access it from anywhere with unrestricted Internet access. With your previous Arduino knowledge you can now use data from sensors or other parts of a sketch and display it for retrieval.

Displaying sensor data on a web page

As an example of displaying sensor data on a web page, let’s use an inexpensive and popular temperature and humidity sensor – the DHT22. You will need to install the DHT22 Arduino library which can be found on this page. If this is your first time with the DHT22, experiment with the example sketch that’s included with the library so you understand how it works.

Connect the DHT22 with the data pin to Arduino D2, Vin to the 5V pin and GND to … GND.

Now for our sketch – to display the temperature and humidity on a web page. If you’re not up on HTML you can use online services such as this to generate the code, which you can then modify to use in the sketch.

In the example below, the temperature and humidity data from the DHT22 is served in a simple web page:

#include <SPI.h>
#include <Ethernet.h>

// for DHT22 sensor
#include "DHT.h"
#define DHTPIN 2
#define DHTTYPE DHT22

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {   0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(10,1,1,77);

// Initialize the Ethernet server library
// with the IP address and port you want to use 
// (port 80 is default for HTTP):
EthernetServer server(125);
DHT dht(DHTPIN, DHTTYPE);

void setup() 
{
  dht.begin();
 // Open serial communications and wait for port to open:
  Serial.begin(9600);
   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
}

void loop() 
{
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) {
    Serial.println("new client");
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == 'n' && currentLineIsBlank) 
        {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
	  client.println("Refresh: 30");  // refresh the page automatically every 30 sec
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");

          // get data from DHT22 sensor
          float h = dht.readHumidity();
          float t = dht.readTemperature();
          Serial.println(t);
          Serial.println(h);

          // from here we can enter our own HTML code to create the web page
          client.print("<head><title>Office Weather</title></head><body><h1>Office Temperature</h1><p>Temperature - ");
          client.print(t);
          client.print(" degrees Celsius</p>");
          client.print("<p>Humidity - ");
          client.print(h);
          client.print(" percent</p>");
          client.print("<p><em>Page refreshes every 30 seconds.</em></p></body></html>");
          break;
        }
        if (c == 'n') {
          // you're starting a new line
          currentLineIsBlank = true;
        } 
        else if (c != 'r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
    Serial.println("client disonnected");
  }
}

It is a modification of the IDE’s webserver example sketch that we used previously – with a few modifications. First, the webpage will automatically refresh every 30 seconds – this parameter is set in the line:

client.println("Refresh: 30");  // refresh the page automatically every 30 sec

… and the custom HTML for our web page starts below the line:

// from here we can enter our own HTML code to create the web page

You can then simply insert the required HTML inside client.print() functions to create the layout you need.

Finally – here’s an example screen shot of the example sketch at work:

You now have the framework to create your own web pages that can display various data processed with your Arduino.

Conclusion

I hope you enjoyed making this or at least reading about it. If you find this sort of thing interesting, please consider ordering one or more of my books from amazon.

And as always, have fun and make something.

To keep up to date with new posts at tronixstuff.com, please subscribe to the mailing list in the box on the right, or follow us on twitter @tronixstuff.

Tronixstuff 09 Apr 08:09

Tutorial – the Arduino AREF Pin

Learn how to measure smaller voltages with greater accuracy using your Arduino.

In this tutorial we’ll look at how you can measure smaller voltages with greater accuracy using the analogue input pins on your Arduino Uno R1 to R3 (not R4!) or compatible board in conjunction with the AREF pin. However first we’ll do some revision to get you up to speed. Please read this post entirely before working with AREF the first time.

Revision

You may recall from previous Arduino tutorials that we used the analogRead() function to measure the voltage of an electrical current from sensors and so on using one of the analogue input pins. The value returned from analogRead() would be between zero an 1023, with zero representing zero volts and 1023 representing the operating voltage of the Arduino board in use.

And when we say the operating voltage – this is the voltage available to the Arduino after the power supply circuitry. For example, if you have a typical Arduino Uno board and run it from the USB socket – sure, there is 5V available to the board from the USB socket on your computer or hub – but the voltage is reduced slightly as the current winds around the circuit to the microcontroller – or the USB source just isn’t up to scratch.

This can easily be demonstrated by connecting an Arduino Uno to USB and putting a multimeter set to measure voltage across the 5V and GND pins. Some boards will return as low as 4.8 V, some higher but still below 5V. So if you’re gunning for accuracy, power your board from an external power supply via the DC socket or Vin pin – such as 9V DC. Then after that goes through the power regulator circuit you’ll have a nice 5V, for example:

This is important as the accuracy of any analogRead() values will be affected by not having a true 5 V. If you don’t have any option, you can use some maths in your sketch to compensate for the drop in voltage. For example, if your voltage is 4.8V – the analogRead() range of 0~1023 will relate to 0~4.8V and not 0~5V. This may sound trivial, however if you’re using a sensor that returns a value as a voltage (e.g. the TMP36 temperature sensor) – the calculated value will be wrong. So in the interests of accuracy, use an external power supply.

Why does analogRead() return a value between 0 and 1023?

This is due to the resolution of the ADC. The resolution (for this article) is the degree to which something can be represented numerically. The higher the resolution, the greater accuracy with which something can be represented. We measure resolution in the terms of the number of bits of resolution.

For example, a 1-bit resolution would only allow two (two to the power of one) values – zero and one. A 2-bit resolution would allow four (two to the power of two) values – zero, one, two and three. If we tried to measure  a five volt range with a two-bit resolution, and the measured voltage was four volts, our ADC would return a numerical value of 3 – as four volts falls between 3.75 and 5V. It is easier to imagine this with the following image:

 So with our example ADC with 2-bit resolution, it can only represent the voltage with four possible resulting values. If the input voltage falls between 0 and 1.25, the ADC returns numerical 0; if the voltage falls between 1.25 and 2.5, the ADC returns a numerical value of 1. And so on. With our Arduino’s ADC range of 0~1023 – we have 1024 possible values – or 2 to the power of 10. So our Arduinos have an ADC with a 10-bit resolution.

So what is AREF? 

To cut a long story short, when your Arduino takes an analogue reading, it compares the voltage measured at the analogue pin being used against what is known as the reference voltage. In normal analogRead use, the reference voltage is the operating voltage of the board. For the more popular Arduino boards such as the Uno, Mega, Duemilanove and Leonardo/Yún boards, the operating voltage of 5V. If you have an Arduino Due board, the operating voltage is 3.3V. If you have something else – check the Arduino product page or ask your board supplier.

So if you have a reference voltage of 5V, each unit returned by analogRead() is valued at 0.00488 V. (This is calculated by dividing 1024 into 5V). What if we want to measure voltages between 0 and 2, or 0 and 4.6? How would the ADC know what is 100% of our voltage range?

And therein lies the reason for the AREF pin. AREF means Analogue REFerence. It allows us to feed the Arduino a reference voltage from an external power supply. For example, if we want to measure voltages with a maximum range of 3.3V, we would feed a nice smooth 3.3V into the AREF pin – perhaps from a voltage regulator IC. Then the each step of the ADC would represent around 3.22 millivolts (divide 1024 into 3.3).

Note that the lowest reference voltage you can have is 1.1V. There are two forms of AREF – internal and external, so let’s check them out.

External AREF

An external AREF is where you supply an external reference voltage to the Arduino board. This can come from a regulated power supply, or if you need 3.3V you can get it from the Arduino’s 3.3V pin. If you are using an external power supply, be sure to connect the GND to the Arduino’s GND pin. Or if you’re using the Arduno’s 3.3V source – just run a jumper from the 3.3V pin to the AREF pin.

To activate the external AREF, use the following in void setup():

analogReference(EXTERNAL); // use AREF for reference voltage

This sets the reference voltage to whatever you have connected to the AREF pin – which of course will have a voltage between 1.1V and the board’s operation voltage.

Very important note – when using an external voltage reference, you must set the analogue reference to EXTERNAL before using analogRead(). This will prevent you from shorting the active internal reference voltage and the AREF pin, which can damage the microcontroller on the board.

If necessary for your application, you can revert back to the board’s operating voltage for AREF (that is – back to normal) with the following:

analogReference(DEFAULT);

Now to demonstrate external AREF at work. Using a 3.3V AREF, the following sketch measures the voltage from A0 and displays the percentage of total AREF and the calculated voltage:

#include <LiquidCrystal.h>
LiquidCrystal lcd(8,9,4,5,6,7);

int analoginput = 0; // our analog pin
int analogamount = 0; // stores incoming value
float percentage = 0; // used to store our percentage value
float voltage =0; // used to store voltage value

void setup()
{
  lcd.begin(16, 2);
  analogReference(EXTERNAL); // use AREF for reference voltage
}

void loop()
{
  lcd.clear();
  analogamount=analogRead(analoginput);
  percentage=(analogamount/1024.00)*100;
  voltage=analogamount*3.222; // in millivolts
  lcd.setCursor(0,0);
  lcd.print("% of AREF: ");
  lcd.print(percentage,2);
  lcd.setCursor(0,1);  
  lcd.print("A0 (mV): ");
  lcd.println(voltage,2);
  delay(250);
}

The results of the sketch above are shown in the following video:

Internal AREF

The microcontrollers on our Arduino boards can also generate an internal reference voltage of 1.1V and we can use this for AREF work. Simply use the line:

analogReference(INTERNAL);

For Arduino Mega boards, use:

analogReference(INTERNAL1V1);

in void setup() and you’re off. If you have an Arduino Mega there is also a 2.56V reference voltage available which is activated with:

analogReference(INTERNAL2V56);

Finally – before settling on the results from your AREF pin, always calibrate the readings against a known good multimeter.

Conclusion

The AREF function gives you more flexibility with measuring analogue signals. If you are interested in using specific ADC components, we have tutorials on the ADS1110 16-bit ADC and the NXP PCF 8591 8-bit A/D and D/A IC.

To keep up to date with new posts at tronixstuff.com, please subscribe to the mailing list in the box on the right, or follow us on X – @tronixstuff.

I hope you enjoyed making this or at least reading about it. If you find this sort of thing interesting, please consider ordering one or more of my books from amazon.

And as always, have fun and make something.

Tutorial – Numeric Keypads and Arduino

Numeric keypads can provide a simple end-user alternative for various interfaces for your projects. Or if you need a lot of buttons, they can save you a lot of time with regards to construction. We’ll run through connecting them, using the Arduino library and then finish with a useful example sketch.

Getting Started

No matter where you get your keypads from, make sure you can get the data sheet – as this will make life easier when wiring them up. For example:

The data sheet is important as it will tell you which pins or connectors on the keypad are for the rows and columns. If you don’t have the data sheet – you will need to manually determine which contacts are for the rows and columns.

This can be done using the continuity function of a multimeter (the buzzer). Start by placing one probe on pin 1, the other probe on pin 2, and press the keys one by one. Make a note of when a button completes the circuit, then move onto the next pin. Soon you will know which is which. For example, on the example keypad pins 1 and 5 are for button “1″, 2 and 5 for “4″, etc…

At this point please download and install the keypad Arduino library. Now we’ll demonstrate how to use both keypads in simple examples. 

Using a 12 digit keypad

We’ll use the small black keypad, an Arduino Uno-compatible and an LCD with an I2C interface for display purposes. If you don’t have an LCD you could always send the text to the serial monitor instead.

Wire up your LCD then connect the keypad to the Arduino in the following manner:
  • Keypad row 1 to Arduino digital 5
  • Keypad row 2 to Arduino digital 4
  • Keypad row 3 to Arduino digital 3
  • Keypad row 4 to Arduino digital 2
  • Keypad column 1 to Arduino digital 8
  • Keypad column 2 to Arduino digital 7
  • Keypad column 3 to Arduino digital 6

If your keypad is different to ours, take note of the lines in the sketch from:

// keypad type definition

As you need to change the numbers in the arrays rowPins[ROWS] and colPins[COLS]. You enter the digital pin numbers connected to the rows and columns of the keypad respectively.

Furthermore, the array keys stores the values displayed in the LCD when a particular button is pressed. You can see we’ve matched it with the physical keypad used, however you can change it to whatever you need. But for now, enter and upload the following sketch once you’re satisfied with the row/pin number allocations:

/* Numeric keypad and I2C LCD
   http://tronixstuff.com
   Uses Keypad library for Arduino
   http://www.arduino.cc/playground/Code/Keypad
   by Mark Stanley, Alexander Brevig */

#include "Keypad.h"
#include "Wire.h" // for I2C LCD
#include "LiquidCrystal_I2C.h" // for I2C bus LCD module 
// http://www.dfrobot.com/wiki/index.php/I2C/TWI_LCD1602_Module_(SKU:_DFR0063)
LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display

// keypad type definition
const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] =
 {{'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}};

byte rowPins[ROWS] = {
  5, 4, 3, 2}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {
  8, 7, 6}; // connect to the column pinouts of the keypad

int count=0;

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

void setup()
{
  lcd.init();          // initialize the lcd
  lcd.backlight(); // turn on LCD backlight
}

void loop()
{
  char key = keypad.getKey();
  if (key != NO_KEY)
  {
    lcd.print(key);
    count++;
    if (count==17)
    {
      lcd.clear();
      count=0;
    }
  }
}

And the results of the sketch are shown in this video.

So now you can see how the button presses can be translated into data for use in a sketch. We’ll now repeat this demonstration with the larger keypad.

Using a 16 digit keypad

We’ll use the larger 4×4 keypad, an Arduino Uno-compatible and for a change the I2C LCD from Akafugu for display purposes. Again, if you don’t have an LCD you could always send the text to the serial monitor instead. Wire up the LCD and then connect the keypad to the Arduino in the following manner:

  • Keypad row 1 (pin eight) to Arduino digital 5
  • Keypad row 2 (pin 1) to Arduino digital 4
  • Keypad row 3 (pin 2) to Arduino digital 3
  • Keypad row 4 (pin 4) to Arduino digital 2
  • Keypad column 1 (pin 3) to Arduino digital 9
  • Keypad column 2 (pin 5) to Arduino digital 8
  • Keypad column 3 (pin 6) to Arduino digital 7
  • Keypad column 4 (pin 7) to Arduino digital 6
Now for the sketch – take note how we have accommodated for the larger numeric keypad:
  • the extra column in the array char keys[]
  • the extra pin in the array colPins[]
  • and the byte COLS = 4.
/* Numeric keypad and I2C LCD
   http://tronixstuff.com
   Uses Keypad library for Arduino
   http://www.arduino.cc/playground/Code/Keypad
   by Mark Stanley, Alexander Brevig */

#include "Keypad.h"
#include "Wire.h" // for I2C LCD
#include "TWILiquidCrystal.h"
// http://store.akafugu.jp/products/26
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
char keys[ROWS][COLS] =
 {{'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}};
byte rowPins[ROWS] = {
  5, 4, 3, 2}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {
  9, 8, 7, 6}; //connect to the column pinouts of the keypad
int count=0;

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

void setup()
{
  Serial.begin(9600);
  lcd.begin(16, 2);
  lcd.print("Keypad test!");  
  delay(1000);
  lcd.clear();
}

void loop()
{
  char key = keypad.getKey();
  if (key != NO_KEY)
  {
    lcd.print(key);
    Serial.print(key);
    count++;
    if (count==17)
    {
      lcd.clear();
      count=0;
    }
  }
}

And again you can see the results of the sketch above in this video.

And now for an example project, one which is probably the most requested use of the numeric keypad…

Example Project – PIN access system

The most-requested use for a numeric keypad seems to be a “PIN” style application, where the Arduino is instructed to do something based on a correct number being entered into the keypad. The following sketch uses the hardware described for the previous sketch and implements a six-digit PIN entry system. The actions to take place can be inserted in the functions correctPIN() and incorrectPIN(). And the PIN is set in the array char PIN[6]. With a little extra work you could create your own PIN-change function as well. 

// PIN switch with 16-digit numeric keypad
// http://tronixstuff.com
#include "Keypad.h"
#include <Wire.h>
#include <TWILiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
char keys[ROWS][COLS] =
{
  {
    '1','2','3','A'  }
  ,
  {
    '4','5','6','B'  }
  ,
  {
    '7','8','9','C'  }
  ,
  {
    '*','0','#','D'  }
};
byte rowPins[ROWS] = {
  5, 4, 3, 2}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {
  9, 8, 7, 6}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

char PIN[6]={
  '1','2','A','D','5','6'}; // our secret (!) number
char attempt[6]={ 
  '0','0','0','0','0','0'}; // used for comparison
int z=0;

void setup()
{
  Serial.begin(9600);
  lcd.begin(16, 2);
  lcd.print("PIN Lock ");
  delay(1000);
  lcd.clear();
  lcd.print("  Enter PIN...");
}

void correctPIN() // do this if correct PIN entered
{
  lcd.print("* Correct PIN *");
  delay(1000);
  lcd.clear();
  lcd.print("  Enter PIN...");
}

void incorrectPIN() // do this if incorrect PIN entered
{
  lcd.print(" * Try again *");
  delay(1000);
  lcd.clear();
  lcd.print("  Enter PIN...");
}

void checkPIN()
{
  int correct=0;
  int i;
  for ( i = 0;   i < 6 ;  i++ )
  {

    if (attempt[i]==PIN[i])
    {
      correct++;
    }
  }
  if (correct==6)
  {
    correctPIN();
  } 
  else
  {
    incorrectPIN();
  }

  for (int zz=0; zz<6; zz++) 
  {
    attempt[zz]='0';
  }
}

void readKeypad()
{
  char key = keypad.getKey();
  if (key != NO_KEY)
  {
    attempt[z]=key;
    z++;
    switch(key)
    {
    case '*':
      z=0;
      break;
    case '#':
      z=0;
      delay(100); // for extra debounce
      lcd.clear();
      checkPIN();
      break;
    }
  }
}

void loop()
{
  readKeypad();
}

The project is demonstrated in this video.

Conclusion

So now you have the ability to use twelve and sixteen-button keypads with your Arduino systems. I’m sure you will come up with something useful and interesting using the keypads in the near future.

To keep up to date with new posts at tronixstuff.com, please subscribe to the mailing list in the box on the right, or follow us on x – @tronixstuff.

I hope you enjoyed making this or at least reading about it. If you find this sort of thing interesting, please consider ordering one or more of my books from amazon.

And as always, have fun and make something.

Tracking the ISS Made Easy

If you made something blink, and now it’s time for you to make something move, something like a point-to-a-satellite tracker is a great idea. [Farid Rener] made this moving arrow that always points at the ISS, and documented it nicely to boot.

And there’s a little bit of everything here, from orbital mechanics and fetching the two-line elements (TLE) from the web, to writing the code to translate that into the tabletop machine’s coordinate system. It looks like [Farid] hadn’t done much 3D CAD before, so he got a chance to stretch those muscles too. Finally, it served as an introduction to resource-constrained programming: “This was the first time I’ve had to think about the size of a compiled binary – the most frustrating part was figuring out that using a C++ stringstream was adding too much code to my binary.”

[Farid] is learning a lot here, and you might too. For instance, using pencil lead (graphite) as a lubricant on sliding 3D-printed parts is new to us, but makes sense. We’ll have to try that out.

And while this is a simple desktop tracker, with a lot more mechanical design, the same basics could be put to real use for pointing a receiver dish. Of course, who says you need fancy motors and computers to point a satellite dish anyway? If you work on your arm muscles a bit, you could become the satellite pointer.