Projects

Exploring DIYsplay - Part 2

3 more Arduino-based DIYsplay projects

Liam Davies

Issue 64, November 2022

This article includes additional downloadable resources.
Please log in to access.

Log in

Last month, we explored the possibilities of the DIYsplay, a customisable display that comes preloaded with over 70 individual screens. This month, we're upping the ante with some more practical projects! They are more advanced than last month, so makers who are experienced with Arduino will have a blast building these!

DIYsplay Review
Part 1 Projects 1 - 2
Part 3 Projects 6 - 7

Project 3:
9V Battery Tester

Parts RequiredJaycarAltronicsPakronics
1 x Arduino Uno R3 or compatible boardXC4410Z6240ARD-A000066
1 x BreadboardPB8820P1002PAKR-A0066
1 x Jumper Wires*WC6027P1017ADA1957
1 x PC Mount 9V Battery HolderPH9235S5048ADA80 ^
2 x 47Ω Resistors *#RR0540R0526SS110990043

Parts Required

You'll also need a DIYsplay from the DIYODE Store

*Quantity required, may be sold in packs. ^ You may need an additional 2.1mm female jack adapter for this product. # While we used 2.2kΩ resistors for our build, we recommend 2x 47Ω resistors instead for a better voltage indication under load.

This is a fun, simple project to get you started with measuring your own voltages with an Arduino. This project is very open-ended so we encourage you to get creative and experiment with your own screens and layouts!

We’re choosing to measure only 9V batteries in this project, however we’re sure you could expand this project to measure all sorts of batteries. The basic idea of this project is to measure the voltage of the battery with an analog pin on the Arduino board.

To do this, we inserted a 9V battery holder directly into the breadboard. We also added a wire to the DIYsplay’s ground pin. Connecting a pin to the Ground is vital whenever we’re measuring any sort of voltage, as we need a reference voltage to refer from.

However, the 9V of the battery is too high to measure directly - a maximum of 5V can be measured with the Arduino without damaging the pin. We need to hook up a voltage divider with two resistors to convert the voltage to a level that’s safe for our Arduino to read.

By using two equal resistors in series, the voltage in the middle will be half of whatever the source voltage is. We used two 2.2kΩ resistors for this, although you can use

whatever reasonable value of resistors you have on hand. In hindsight, it would probably have been better to use two 47Ω resistors in series to load the battery and thus get a more accurate voltage reading. It’s not the best idea to go below 50Ω or above a few million ohms in total, as at that point you may either be effectively short-circuiting the battery or making it difficult for the Arduino to read.

In between the resistors, we inserted a Dupont wire and connected it to the Arduino’s A0 pin. This will be our measurement pin.

The setup() function in the Arduino program has a few operations we need to before we read the voltage:

void setup() {
  pinMode(BATTERY_PIN, INPUT);
  //Starts the DIYsplay.
  diysplay.begin();
  diysplay.setScreen(BATTERY_LEVEL_GAUGE_BLUE);
}

It’s a very simple setup function which is mostly dedicated towards setting up the analog pin for the battery and the DIYsplay itself.

The Arduino Uno has a 10-bit Analog-to-Digital Converter (ADC), meaning that it will return a 10-bit number between 0 and 1023 (or 210 - 1) corresponding to the range between 0 and your supply voltage (in our case, 5V). So, in order to convert the ADC reading into a voltage, we need to do a few operations.

First, we need to divide the reading by 1023. This converts the 0-1023 to a 0-1 range, which we can now scale by whatever number we want.

We then multiplied this number by 5 to get a 0-5V range. But wait, we used a voltage divider! If we see 3V on the analog pin, we need to multiply it by 2 to get 6V - our initial battery voltage.

All of these processes can be done on one line. We’re using the ‘*=’ operator here which is the same as saying ‘reading = reading * VALUE’ - it’s simply multiplying the existing value by the value we chose.

double reading = analogRead(BATTERY_PIN);
reading *= 2.0 * 5.0 / 1023.0;

The above code is all inserted in the loop() function. So now we have our battery voltage, we’re done right? Not quite, we still need to format it for viewing on the DIYsplay. There are two display elements on the battery gauge we’re using:

Even though this screen appears blue in the documentation, you may find that the battery gauge appears a different colour depending on your DIYsplay’s firmware version. In our case, it appears red. This doesn’t affect functionality at all, however in future we’ll be working on matching the widget colour with the code and its documentation. Some other screens on the DIYsplay are similarly coloured, but it does not change any code requirements! On a side note, most DIYsplay widget colours can’t be changed while it’s running. This is by design in order to keep the DIYsplay running fast, and also helps with stability.

The most prominent element is the digit display itself. This is just a three-digit display that can be customised to display whatever number desired. We’re using it to display the voltage of the battery that we calculated earlier.

You’ll notice in the code below that we’re multiplying the reading variable by 10. This is because the widget has a decimal point, but the decimal point isn’t seen by the code - it’s essentially a purely visual representation. To the Arduino, the widget display is simply a 3 digit number. This may be changed in the DIYsplay library in the future to help with readability.

diysplay.setData(1, reading * 10);

The battery level meter itself is a little more nuanced. The bar itself has a range of 0-100, so whatever value we put into it needs to be scaled appropriately. That begs the question, what range of voltages should we use for the battery scale?

This is more a question of personal preference and application, but we chose the voltage range between 6.5V and 9.5V. These constants can be seen at the top of the file, which can be changed as needed.

#define MIN_BAT_VOLTAGE 6.5
#define MAX_BAT_VOLTAGE 9.5

We’re using the inbuilt map() function to convert the voltage range into a bar between 0 and 100. It’s also important that we constrain the output of this range, as the map() function will actually give us values beyond 100 if we gave it 12V, for example.

// Map the voltage of the battery to a value between 0 and 100.
double percentage = map(reading, MIN_BAT_VOLTAGE, MAX_BAT_VOLTAGE, 0.0, 100.0);
percentage = constrain(percentage, 0, 100);
diysplay.setData(0, percentage);

And we’re done! Hit upload and give it a try. When inserting your 9V battery, be absolutely sure that the terminals are around the right way. The larger negative terminal should fit around the smaller terminal on the holder, and vice-versa for the positive terminal. Connecting the 9V battery in reverse will almost certainly damage your Arduino, so just make sure to check the polarity before you connect it. There are circuits that can (relatively) safely protect your Arduino from this, but it’s out of the scope of this guide.

This project can be adapted to use any voltage of battery, and batteries that have a maximum voltage of under 5V do not even need a voltage divider. You’ll just need to change the voltage calculation and the min/max voltage constants at the top of the code file. Since it’s a live measurement, measuring batteries can be done instantly.

DIYsplay Review
Part 1 Projects 1 - 2
Part 3 Projects 6 - 7

Project 4:
Digital Compass and GPS

Additional Parts Required:JaycarAltronicsPakronics
1 x GPS Module - GY-NEO6MV2XC3710Z6333XADA746

Additional Parts Required:

This project is a little more advanced, but we figure those who are more experienced with Arduino may want to embark on a project with data to play around with. What we’re essentially doing is getting GPS and Compass data from a GPS module and plotting it on the DIYsplay’s inbuilt screen for location data.

There are many affordable GPS modules available for use with regular Arduino boards - we’re using a GY-NEO6MV2. You may have to make changes to our code to suit your exact module, but most have fairly simple code libraries so it shouldn’t be a huge fuss. To wire it up, it just needs a TX pin running to Pin 9 on the Arduino board.

Note that we don’t need an RX pin for this project, as we won’t be talking to the GPS module - it will simply send us location information over the TX pin without needing setup.

Below is the setup code for the GPS system. There is a bit more setup than usual since we’re setting up an additional SoftwareSerial line and initialising the GPS module too.

#include "TinyGPS++.h"
#include <SoftwareSerial.h>
#include "DIYsplay.h"
DIYsplay diysplay = DIYsplay();
static const int RXPin = 9, TXPin = 8;
static const uint32_t GPSBaud = 9600;
TinyGPSPlus gps;
SoftwareSerial ss(RXPin, TXPin);
double old_longitude;
double old_latitude;
double longitude;
double latitude;

For those who have had some experience with Arduino programming already, this shouldn’t be too tricky. We’re using the “TinyGPS” library in addition to the SoftwareSerial library.

We chose Pin 8 and 9 for our GPS module, however, we don’t actually need the TX pin as the module will happily give us GPS data without any forwards communication.

void setup()
{
  diysplay.begin();
  diysplay.setScreen(
COMPASS_WITH_LONGITUDE_LATITUDE);
  diysplay.setData(1, "Searching");
  diysplay.setData(2, "Searching");
  Serial.begin(115200);
  ss.begin(GPSBaud);
}

Our setup function should be fairly self-explanatory. We start up our DIYsplay, and set the Latitude and Longitude fields to "Searching" while we are waiting for a GPS fix.

void displayInfo()
{
  if (gps.location.isValid())
  {
    old_longitude = longitude;
    old_latitude = latitude;
    longitude = gps.location.lng();
    latitude = gps.location.lat();
  }
  else
  {
    longitude = -1;
    latitude = -1;
  }
}

The displayInfo() function fetches the GPS data and stores it in two variables, latitude and longitude. We also have each of those variables with '_old' prefixed to it. This will help us calculate the direction we're traveling later on, by figuring out the difference in coordinates from one reading to the next. We aren't implementing any of the fancy maths here ourselves, as that involves some involved trigonometry - we're letting the TinyGPS library do all the heavy lifting.

void loop()
{
  // This sketch displays information every time a new sentence is correctly encoded.
  while (ss.available() > 0)
    if (gps.encode(ss.read())) {
      displayInfo();
      delay(2000);
      
      diysplay.listen();
      diysplay.setData(1, String(longitude,5));
      diysplay.setData(2, String(latitude,5));
      double heading = gps.courseTo(old_latitude, old_longitude, latitude, longitude);
      Serial.print(" Heading: ");
      Serial.print(heading);
      diysplay.setData(0, heading);
      
      ss.listen();
  }
  // (serial output code omitted)
}

This last paragraph is our loop function which handles the real work of the project. If there is data available from the GPS module, we run the displayInfo() function which fetches the GPS data and writes it to the old_longitude, longitude, old_latitude and latitude. As previously mentioned, the variables prefixed with ‘old’ let us calculate the previous position our GPS module was in. We can use the ‘courseTo’ to calculate the compass bearing our movement. This will only work while we are moving, which is the main limitation of this rudimentary compass. You may wish to use a dedicated digital compass module if you’d like a much more accurate reading.

In any case, we then write the calculated heading to the DIYsplay, which just takes the number in degrees from 0 to 360. Now let’s upload it and give it a go!

Once it's uploaded, you'll see the "Searching" or "-1.0000" text appear in the latitude and longitude fields. Depending on where you are, the GPS module may take several minutes to secure a GPS fix. Inside our office, it took 4-5 minutes, but outside with a clear line of sight to the sky it usually takes less than 60 seconds.

We've blurred out our exact coordinates for privacy reasons, so rest assured the GPS is accurate! The DIYsplay has enough room for five decimal points, which can pinpoint the GPS module down to a few meters. Impressive performance for such a small module!

Project 5:
RGB LED Controller

Additional Parts Required:JaycarAltronicsPakronics
8 x NeoPixel/WS2812B LEDs (on strip)XC4380X3222ASS104990000
1 x Joystick ModuleXC4422Z6363ADA512
1 x 330Ω Resistor *RR0560R7546SS110990043

Additional Parts Required:

Ever wanted to control your own RGB strips using an Arduino? This project makes it easy with a game controller-style joystick, and a DIYsplay-powered colour display to show you precisely what values are being sent to the lights. It can control up to eight RGB leds at once, and with some additional code and hardware modifications, it’s possible to control many more.

The LED’s we’re using are very common, typically sold as NeoPixels by Australian suppliers, but most strips that use the SK6812 or WS2812B LEDs are fully compatible with this project. You may have to make some small changes to the code, but besides that it should be mostly a plug-and-play type deal. This project involves the most code out of any so far, so we won’t be showing all of the code since it’s on the more complex side. There are also a few advanced code tricks that may be confusing to beginners, but feel free to upload the code directly and give it a go.

First up, we need to hook up our circuit. The joystick module we’re using has a fairly simple pinout, although if you get your own you may need to adapt the wires. Since we wanted to keep the wiring as simple as possible, we set up the joystick so it works solely on one bank of pins, with the exception of the ground pin.

The Fritzing shows how it is connected, so be sure to refer to the diagram to connect the modules correctly.

The LED strip is connected to the Arduino with a 5V pin, Ground and a data pin. We connected the data pin to Pin D8, through a 330Ω resistor for limiting the current. While we’ve used these strips without the current limiting pin before, it’s safer and will probably help the strip live longer.

Great, lets work on the code! As we mentioned, the code is more advanced than the other projects although you may wish to modify the constants at the top of the file to suit your needs.

You can customise the number and assignments of the LEDs with the LED_COUNT and LED_PIN constants. The other constants are related to the Joystick and can be changed if you’re using different pin assignments. The A0 pin is intended to provide 5V power to the Joystick - we did this because there weren't any 5V pins remaining on the Arduino and we wanted to keep the wiring simple. Since the joystick draws very little current, this should be okay. You can, of course, power the Joystick with another 5V pin if you have one available.

#define LED_COUNT 8
#define LED_PIN 8
#define POWER_JOYSTICK_PIN A0
#define JOYSTICK_X_PIN A1
#define JOYSTICK_BUTTON A3
#define MIN_MOVE 200

The setup code is dead simple, and doesn’t use any fancy commands beyond what we’ve already seen. We’re using the COLOUR_LED_WITH_GAUGES DIYsplay screen, however, there are other RGB displays available which may be of interest instead.

void setup() {
  pinMode(POWER_JOYSTICK_PIN, OUTPUT);
  digitalWrite(POWER_JOYSTICK_PIN, HIGH);
  pinMode(JOYSTICK_X_PIN, INPUT);
  pinMode(JOYSTICK_BUTTON, INPUT_PULLUP);
  
  diysplay.begin();
  strip.begin();
  diysplay.setScreen(COLOUR_LED_WITH_GAUGES);
}

The screen itself has three sets of elements - the multicolour LED, the RGB bar display and the RGB value display.

On the next page is the code responsible for updating the colour based on the R, G and B values.

Probably the most confusing part of this code is the bitwise operations occurring on the ‘colour’ variable. This is needed because the multicolour LED on the left side of the display doesn’t use a simple set of three bytes for the colours. It instead uses 16-bit colour in 565 format. That means 5 bits are used for the red colour, 6 bits are used for the green colour, and 5 bits are used for the blue colour. The left and right-shift operations (the << and >> operators) have been written to carefully manipulate the input R, G and B values into 5, 6 and 5 bit numbers respectively.

void setColour(byte r, byte g, byte b) { 
  uint16_t colour = 0;
  colour |= (r >> 3) << 0;
  colour |= (g >> 2) << 5;
  colour |= (b >> 3) << 11;
  diysplay.setData(0, colour);
  //Blue
  diysplay.setData(1, b);
  diysplay.setData(4, b);
  //Green
  diysplay.setData(2, g);
  diysplay.setData(5, g);
  //Red
  diysplay.setData(3, r);
  diysplay.setData(6, r);
}

This has also given us inspiration for some library improvements - we’re planning to implement this function for any widgets that need it, so new users can set the colour automatically without having to worry about all this bitwise magic. Long story short, if we call the function setColour(255, 127, 0), we will see a vivid orange appear on the screen, together with its constituent R, G, and B colours.

In our loop function, we wrote some code to test out a basic menu system:

 if(mode == 0) { 
    uint32_t colour = strip.ColorHSV(colour_wheel);
    setColour((byte)(colour >> 16), (byte)(colour >> 8), (byte)(colour >> 0));
    strip.setPixelColor(selected_led, colour);
    strip.show();
    if(joystickDir == 1) {
      colour_wheel += 1000;
    } else if(joystickDir == -1) {
      colour_wheel -= 1000;
    }
    
    delay(5);
  } else if (mode == 1) {
    for(int i = 0; i < LED_COUNT; i++) {
    diysplay.setData(i, i == selected_led ? 1 : 0);
    }
    if(joystickDir) {
      selected_led += joystickDir;
      selected_led %= 8;
--

In mode 0, which allows us to select a colour, we can use a Joystick to scroll through the various colour hues. We’re using the ColorHSV() function from the Adafruit_NeoPixel library to convert a number into a hue - incrementing the hue continuously will send back the colours of the rainbow. If we’re holding the Joystick left or right, we can slowly scroll through these colours as we update it on the LED strip.

In mode 1, we set the DIYsplay to the _8_X_FLAT_ROUND_LED (code not shown above) and let the user select a specific LED. The screen only has eight LED zones, but could be coded to control entire zones of LEDs if desired. By pressing the joystick, we can switch modes. We’ll be showing off this cool system on our social media, so be sure to tune in!

Once the code is uploaded, check that you can change individual LED brightness when moving the Joystick left or right. This is an endlessly tunable system, so feel free to mess about with this code to your heart’s content!

Troubleshooting

We’ve tried to make the DIYsplays as simple as possible, even if you’ve never touched an Arduino before, however it’s not impossible to run into a roadblock every now and then. The first thing we suggest doing if your DIYsplay is misbehaving is to plug just the 5V and Ground wires in, and check that the DIYsplay logo appears. If the screen stays

black, you may have incorrectly connected your power wires or inadvertently connected them in reverse. If you’re sure that the power wires are connected correctly and powered, you may unfortunately have a faulty DIYsplay.

If the DIYsplay logo does appear, the problem most likely lies with your Arduino or how you are programming it. Double check the pin connections, and check the cables to ensure they aren’t broken or have unreliable pins. If the pinout is okay, check the Arduino IDE and ensure you’re on the correct COM port - only available ports will appear, so you may need to select another COM port to get it to work. Also ensure that you have selected the correct board type. Finally, be sure you’re pressing “Compile & Upload” button rather than just the “Compile” button - the buttons aren’t in an obvious order.

Where To From Here

It probably won’t come as surprise to hear that there is a lot more that can be done with the DIYsplay! We’re fairly certain that the DIYsplay is a prime contender anywhere that a small data display is needed. We have a number of full-sized projects lined up over the next few months that will probably use a DIYsplay or two to make the job of displaying data significantly easier, so expect some more project ideas in the coming issues.

If you’re more advanced, and looking for more to do with the DIYsplay, there is plenty of ways to bring the DIYsplay to its full potential. There may be a specific screen that would be perfect for a certain project, but the ones we have included by default are just not what you’re looking for. Fear not, you can make your own!

Just download the Mates Studio software and connect your DIYsplay with a 4D Programmer FTDI chip (regular FTDI chips should work too, although they aren’t officially supported as of writing). From here, it’s possible to reprogram the default DIYsplay firmware and add custom screens. These custom screens can have your own images, widgets and even gauges if needed. Bear in mind that the default firmware is specifically mapped to our DIYsplay library, so you will have to directly access the Mates Controller library within your Arduino code to use custom screens.

If there’s anything missing that you’ve noticed in the DIYsplay code, feel free to head over to the GitHub repository and help us fix bugs or add features! Just make a pull request and modify the code to your heart's content! We’re not professional programmers by any means, so there is a very good chance that the DIYsplay library can be sped up or improved.

We’ve spent the last few months getting our mini production line up and running, so we’re super excited to see what you make with these little powerhouses. Be sure to share your creations with @diyodemag!

DIYsplays are now available on the DIYODE store, so head over to diyode.store and grab yours now!

DIYsplay is available from our very own Online Store:

Learn More

Read our original review published in Issue 62:

Own a DIYsplay?

If you have received a DIYsplay then here are some handy links to get things started: