Projects

Exploring DIYsplay - Part 3

3 more Arduino Uno-based projects

Liam Davies

Issue 65, December 2022

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

Log in

Learn how to make three more awesome projects with the DIYsplay! - by Liam Davies

This month marks the fourth issue since we have released the DIYsplay, our first real product. Thanks to its huge array of customisable screens, we’ve been building a bunch of projects to show off just how much can be done with it. In the final part of this mini-series, we’ve created three new projects to build and experiment with.

Project 6:

NERF Gun Ammo Counter

Parts RequiredJaycarAltronicsPakronics
1x DIYsplayhttps://diyode.store--
1x Arduino UnoXC4410Z6240ARD-A000066
1x Red Binding PostPT0460P9252-
1x Black/Blue Binding PostPT0461P9254-
4x 7mm Dome PushbuttonsSP0700S1084-
4x 10nF Ceramic CapacitorsRC5348R2846DF-FIT0118*
4x 6mm M3 BoltsHP0401*H3110A*DF-FIT0060*
4x M3 NutsHP0426*H3175*DF-FIT0060*
Silicone Hookup Wire---

Parts Required

This is a bit of a goofy project, but we still thought it was awesome to showcase some awesome possibilities with the DIYsplay. If you have a NERF blaster lying around the house and want to add some awesome electronic trickery to it, this is a great way to do so.

We can use one of the “counter” screens pre-loaded onto the DIYsplay to create a cool ammunition counter. As we fire more darts, the number decreases and the progress bar empties. Once we take the magazine out, the DIYsplay switches to a reloading screen and starts a timer - how fast can you reload? After the magazine is reinserted, it shows you how fast your reload was, and goes back to the counter screen.

This project checks if your dart fired by using an optical sensor in front of the barrel, so if for some reason it doesn’t fire, it won’t count. Note that it won’t pick up on partially-filled magazines - it just assumes they are full when reinserted.

This project is cool, but would be even cooler with lasers! We added a laser to our build to both assist with aiming and provide a visual indication of the ammunition status of the NERF blaster. In normal use, the laser is on and steady. When there is low ammunition, it will pulse to indicate it’s soon time to switch over the magazine.

When the magazine is out completely, the laser turns off, making it easier to swing the blaster around without the fear of shining the laser in someone's eye. Once it’s reloaded, the laser turns back on and the counter starts again. The only downside of this laser system is that anybody playing with you will know when you’re low on ammo!

3D Printing

We created a 3D printed mount for our NERF blaster, which locks onto the bayonet rails and holds the DIYsplay steady while it’s showing the counter information. It also holds the laser which points forward.

While the whole 3D printed mount isn’t the most compact thing in the world, it’s good enough for our purposes and adds a cool-looking gadget to your favourite NERF blaster. We printed ours in a nice bright yellow filament to match the rest of the NERF gun.

The rail on the front of the gun holds the enclosure with a slide-fit, so it should fit fairly comfortably - you may need to adjust the 3D printing tolerances depending on how snug it is.

Battery Mount

We need somewhere to power our Ammo Counter from! We opted to use a 9V battery attached to the back stock of the NERF gun. We 3D printed a small friction-fit enclosure that prevents the 9V battery falling out. The 9V battery is in series with a simple SPDT switch that enables or disables power. We clamped the battery between two pieces of moulded plastic and it seems to hold pretty firm. Simple!

Adding Sensors

We need to make a few additions to the NERF blaster to connect to our Arduino and the DIYsplay. We first added a limit switch to detect when the magazine is inserted.

To affix it, we used hot glue to secure the switch somewhere the magazine doesn’t physically interfere with. We want the magazine to be easily insertable and consistently detectable. The cable was routed through the front of the blaster, connected to a basic two-pin header so we can disconnect the wires.

We also need to add a detection sensor to the barrel to detect when a dart exits. To do this, we disconnected the front half of the gun and created a 3D printed LED holder to fit around the tube. An infrared LED and an infrared detector sit opposite each other in the tube. Normally, the detector is in full view of the LED and the optical path between them will only be broken when a dart fires.

To detect when the dart fires, we’re simply polling the analog pin it’s connected to and counting a “fire” event whenever the signal goes below a certain threshold. We’ll show this more in the code. The aiming laser is a simple red laser diode. When in use, we do not recommend aiming this (or any laser, for that matter) at people as these cheap diodes have a relatively unknown power output! It only needs to be connected to 5V which turns it on automatically.

The DIYsplay itself also needs some modification. We want only the display unit, not the frame around it to save some space in our NERF gun enclosure. It can be desoldered with a desoldering gun or with solder wick, however be aware it will require a fair amount of heat to successfully desolder.

We ended up using a unit that hadn’t been fully assembled, which doesn’t include the breadboard-compatible frame around the DIYsplay.

After routing the wires into the 3D printed enclosure, we soldered onto Arduino Nano without headers to save space. We deliberately used soft silicone wire to make our lives easier squeezing the cables inside the box.

If you’re interested in following along, we have a Fritzing available which should clarify the wiring process.

Code

While there is a bit to the code of this project, it’s nothing super complex. If you’re not interested in digging through it, just download it to your computer and upload it to your Arduino! There are the following sections for configuring the Ammo Counter, which you can use to suit your own setup.

#include <Arduino.h>
#include "DIYsplay.h"
#define FIRE_DETECT_PIN A0
#define MAG_DETECT_PIN A1
#define FIRE_DETECT_THRESHOLD 300
#define MAG_DETECT_THRESHOLD 500
#define FIRE_COOLDOWN_TIME 250
#define DIYSPLAY_UPDATE_TIME 10
#define RELOAD_FLASH_TIME 200
#define MAX_AMMO 12

FIRE_DETECT_PIN: The analogue pin to detect the ‘firing’ optical signal.

MAG_DETECT_PIN: The analogue pin to detect the ‘magazine’ optical signal.

FIRE_DETECT_THRESHOLD: The minimum reading required to detect a ‘firing’ event. (0-1023)

MAG_DETECT_THRESHOLD: The minimum reading required to register the magazine’s presence. (0-1023)

FIRE_COOLDOWN_TIME: The time to wait in milliseconds after a bullet is fired until another one can be registered.

DIYSPLAY_UPDATE_TIME: How often should the DIYsplay update when reloading?

RELOAD_FLASH_TIME: How often should the reload timer flash in milliseconds?

MAX_AMMO: The size of a full magazine for your NERF blaster.

The code is quite straightforward, although those new to Arduino programming might find it more understandable to visit our earlier DIYsplay project articles and build code knowledge from there instead.

The setup function is solely dedicated towards setting up our digital pins and ensuring that we start the ammo counter in the right mode - that is, if we don’t have a magazine inserted when we start the Arduino, we go straight to the reloading screen.

void setup() {
  diysplay.begin();
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(FIRE_DETECT_PIN, INPUT);
  pinMode(MAG_DETECT_PIN, INPUT_PULLUP);
  pinMode(LASER_PIN, OUTPUT);
  
  if(digitalRead(MAG_DETECT_PIN)) {
    digitalWrite(LASER_PIN, LOW);
    writeReloadScreen();
  } else {
    digitalWrite(LASER_PIN, HIGH);
    diysplay.setScreen(METAL_BAR_METER_SINGLE);
    diysplay.setData(0, MAX_AMMO);
  }
}

We aren’t showing the whole loop function here to save space, but the most important part is shown below. The FIRE_DETECT_THRESHOLD determines at what analog level the project should trigger a successful fire. You’ll have to experiment with this to determine a value that works for you. We also have a FIRE_COOLDOWN_TIME variable that prevents the same dart triggering the ammo counter multiple times thanks to the infrared LEDs.

 void loop() {
  // If we detect a new fire event, 
  // and the cooldown has expired.
  if(analogRead(FIRE_DETECT_PIN) < FIRE_DETECT_THRESHOLD && millis() > last_fire_time + FIRE_COOLDOWN_TIME) {
    last_fire_time = millis();
    fire();
    showAmmo();
  }
  …

Throughout the loop function, we’re calling showAmmo() which updates the screen on the DIYsplay. It’s a pretty simple routine, and mostly ensures that both the progress bar on the left and the ammo display itself are updated to the correct values. The progress bar is scaled from 0-100, so we also make sure to rescale the ammo capacity to the bar. For example, if MAX_AMMO is 12 and we have 6 darts left, we know to send 50 to the progress bar.

void showAmmo() {
  if(current_ammo > 0) {
    diysplay.setData(0, current_ammo);
  } else {
    // Send a value to the DIYsplay that 
    // will make it say 'EEE'.
    diysplay.setData(0, 1000);
  }
  
  uint8_t progress = (100.0 * (current_ammo / (float)MAX_AMMO));
  progress = constrain(progress, 0, 100);
  diysplay.setData(1, progress);
}

The good news is that if you want a short weekend project, you can just download this code from the project files, upload it to your Arduino and not have to worry about the technical stuff!

This was one of the most fun projects we’ve worked on, and it was a blast to fire some darts at cardboard (NOT people) in the office and try to hit targets drawn with sharpies with the laser alignment. The reload timer was a great feature and led to some very competitive reloading across the DIYODE staff. We’ll definitely be showing this off on our social media, so stay tuned!

Project 7:

Spotify Dashboard

Parts RequiredJaycarAltronicsPakronics
1x DIYsplayhttps://diyode.store--
1x Arduino UNO WiFi REV2XC4411^-ARD-ABX00021

Parts Required

^This board will require additional configuration to get working. Check the manual for details.

Create an awesome dashboard for viewing what song is currently playing on Spotify, as well as a music visualiser. This is a more advanced project, but showcases how you can use Web APIs to create sophisticated functionality.

DIYsplay includes a screen called MEDIA_PLAYER_RED that displays a ton of information about a current song. This includes a custom text field and multiple light-up elements such as play, stop, seek and genre buttons.

Spotify API

There are countless APIs on the internet available for interfacing with virtually any service you can think of. Depending on the API, there can be stringent security requirements, so you’ll need to follow what’s typically referred to as an ‘Authorization Flow’, as Spotify requires. It’s not as simple as just sending a GET request to a specific URL - there are a few extra steps required to make this work.

To get started, head into the Spotify Developer console at https://developer.spotify.com/dashboard/applications and click “Create An App”. It will ask for an App Name and an App Description, which we just filled in with “DIYsplay Monitor”.

Once the application has been made, two IDs will be generated - a Client ID and a Secret ID. You should treat these IDs as passwords - especially the Secret ID, hence the reason why we’ve blurred them.

We also need to click on the App and click on “Edit Settings” to add a callback URL. After Spotify authorises the user, it will redirect them to the provided URL. If you have a personal website, you may wish to use that URL, but it doesn’t really matter for our purposes as we can get the API information we need anyway.

To send the first few web requests to get the tokens we need to use the API, we used a web app called Postman. Postman is a platform to build and test APIs, but we’re using a basic workplace to get us the Spotify info required.

We need to send a request to the accounts.spotify.com/authorize endpoint to get a authorization token, which requires user input to permit our software to read and write data to our Spotify player. We also need to pass headers containing client_id and redirect_uri - we did this whole process in Postman, but if you’re developing a small-scale program you may wish to automate it with real return addresses and so forth.

Spotify should send the following request once the user has authorised our DIYsplay program:

https:///callback?code=NApCCg..BkWtQ&state=34fFs29kd09

We now have an authorization code that we can exchange for an Access Token by making a request to the /api/token endpoint. We need to make a request to this page while

also passing an Authorization header to prove that we know the client_id and client_secret we first generated. Spotify requires it in this format:

Authorization: Basic <base64 encoded client_id:client_secret>

Once we have a token, we can use this token to continually generate new Access Tokens as old ones expire. They expire after 1 hour, so it’s a bad idea to assume they’re not going to change! After the token expires, it’s no longer usable and will simply return an error after a request is made. Fortunately, this is the only part of our program that our Arduino has to automate. Everything else it’ll do will be related to actually reading and sending data to Spotify. Speaking of which, we used an Arduino Uno WiFi REV2 to connect to our local WiFi.

After we connected to local WiFi, we tested that pinging works on Google. Once we’ve verified that, we can now start implementing our code for Spotify interaction. The function below will automatically receive new access tokens whenever called, which we set up to do once at boot and once every 45 minutes after that.

void getAccessToken(WiFiSSLClient client) {
  client.flush();
  if (client.connect(auth_server, 443)) {
        client.print("POST /api/token?grant_type=refresh_token&refresh_token=");
        client.print(refresh_token);
        client.println(" HTTP/1.1");
        client.print("Host: ");
        client.println(auth_server);
        client.println("User-Agent: ArduinoWiFi/1.1");
        client.println("Connection: keep-alive");
        client.print("Content-Length: ");
        //client.println(accessTokenRequest.length());
        client.println("0");
        client.println("Content-Type: application/x-www-form-urlencoded");
        client.print("Authorization: Basic ");
        client.println(auth_token);
        client.println();
  } else {
    Serial.println("Connection Failed.");
  }
  delay(1500);
  …
}

Above, we’re manually writing HTTP headers to the WiFi client which the Spotify API will receive. If you’ve ever seen a raw HTTP packet, this format will look familiar to you. We’re also using variables to store our secret client_secret, client_id and auth_token values, so you’ll need to pop your own into the top of the code file.

We must make sure we wait until Spotify sends back data, which in our experimentation tends to be around 1000 to 1200 milliseconds. Once we read the stream, we can use the ArduinoJSON library to deserialize the data and convert it into an object. We only want the ‘access_token’ data from the response, so we can use a filter to discard the rest and save some memory!


char c;
  while (client.available()) {
    c = client.read();
    Serial.print(c);
    if(client.peek() == '{') {
      break;
    }
  }
  Serial.println("Received packet. 
Attempting to read payload.");
  authFilter["access_token"] = true;
  DeserializationError error = deserializeJson(authDoc, client, DeserializationOption::Filter(authFilter));
  if (error) {
    Serial.print(F("deserializeJson() failed: "));
    Serial.println(error.f_str());
  }
  serializeJsonPretty(authDoc, Serial);
  strcpy(access_token, authDoc["access_token"]);
  Serial.print("Got new Access Token: ");
  Serial.println(access_token);
  client.stop();
}

We have a carbon-copy of this function to actually source the current Spotify Player data, with the exception of the request URL (we’re using api.spotify.com) and the endpoints - requesting /v1/me/player/play would start the Spotify player for example. We dump all of the data we request into a struct like below:

struct PlayerData {
  bool isPlaying;
  uint8_t volume;
  String name;
  String artist;
  bool fetchedData = false;
  float bpm;
};

And yes, we’re actually sourcing the BPM of the song too! We set up the DIYsplay’s media player screen to bounce in beat with the music, which works incredibly well and adds an immersive aspect to the screen.

Finally, we can run this code to update the DIYsplay!

  player = getPlayerData(client);
  diysplay.setScreen(MEDIA_PLAYER_RED);
  diysplay.setData(1, 1 - player.isPlaying);
  diysplay.setData(2, player.isPlaying);
  diysplay.setData(14, 
player.artist + " - " + player.name);

Once the code has uploaded, just start playing something on Spotify and it’ll appear within a few seconds on the DIYsplay, including the song name, artist and the current playing state. It doesn’t matter what device your Spotify account is playing on - whether it’s a smartphone, computer or smart home devices, the DIYsplay will pick it up every time.

We unfortunately ran out of time to flesh out this project as much as we wanted. In future, we’d love to add play/pause and volume buttons to this project, and 3D print a case to hold everything in a nice neat package. We also may look into faster WiFi hardware, so that our Arduino doesn’t spend so much time waiting for requests to return - a second for a website to respond is a frustratingly long time.

There is a ton of potential with this project, because Spotify exposes a staggering amount of information about songs with their API - it has somewhat hilarious JSON fields such as “danceability” and “energy” as well as more interesting data points such as the musical time signature and key. We encourage you to read Spotify’s Web API reference (https://developer.spotify.com/documentation/web-api/reference/#/) as it’s fascinating seeing how much analysis they apply to every song!

Project 8:

Advanced Frequency Generator

Parts RequiredJaycarAltronicsPakronics
1x DIYsplayhttps://diyode.store--
1x Arduino UnoXC4410Z6240ARD-A000066
1x Red Binding PostPT0460P9252-
1x Black/Blue Binding PostPT0461P9254-
4x 7mm Dome PushbuttonsSP0700S1084-
4x 10nF Ceramic CapacitorsRC5348R2846DF-FIT0118*
4x 6mm M3 BoltsHP0401*H3110A*DF-FIT0060*
4x M3 NutsHP0426*H3175*DF-FIT0060*
Silicone Hookup Wire---

Parts Required

For our final project in the “Exploring DIYsplay” series, we’re looking at a more advanced application. The DIYsplay includes a handy screen called WAVE_STAT_DISPLAY which displays the frequency and duty cycle of data that we send to it. So, why don’t we build a frequency generator to make square waves?

We also took this project one step further by fully implementing it in hardware with register manipulation of the microcontroller! That way, the accuracy and performance of the frequency generated is much higher than would be possible with simple delay() and digitalWrite() commands. For that reason, the code for this project will be much more advanced than the others, which is why we’re including it last.

Our frequency generator can output signals from 60Hz to 10KHz, which is limited mainly by the DIYsplay screen - it has a format of x.xxxKHz, so we can’t go above 9999Hz. However, the hardware itself can actually reach 8MHz - albeit the output turns into a sine wave somewhat.

We’ve made frequency generators at DIYODE before, but this one also includes customization of duty cycle for controlling servos, LEDs and so forth. Before we dig into the code, let’s build the 3D printed chassis.

Assembly

We chose to use four buttons and a DIYsplay on the front panel to make an incredibly cute and functional frequency generator. Two buttons are dedicated to increasing or decreasing the duty cycle in 5% amounts, and two buttons are used for changing the frequency to any number of preset frequencies of your choosing.

The DIYsplay sits in the panel snugly, which we also affixed

with hot glue to secure it down. The buttons have 10nF ceramic capacitors across them to prevent chatter messing with the Arduino.

This is included in a 3D printed chassis that cosily houses a standard Arduino Uno. Once printed, it can be secured down with four M3 nuts and bolts. The USB and power ports should be usable at the front of the chassis, which is how we provide power to our Frequency Generator.

The binding posts sit above the Arduino Uno and act as the output. You can, of course, swap this out to use whatever connector is easiest for you.

Like the other projects, you can check the Fritzing we’ve included to make sure the project is wired correctly. We ended up soldering to the underside of the Arduino Uno directly to save space on using full-size header pins. Note that it’s very important that our Frequency generator output is on Pin 3, as it’s the Timer 2 OCR2B output as we’ll talk about shortly.

Code

The code we’ve written for the frequency generator part of this project is very robust, so this project can be adapted to whatever interface you like. If you have a keypad, rotary encoder or even another Arduino with a serial line, this code can be easily run to set Duty Cycle and Frequency variables to any value.

uint16_t freq_presets[] = {70, 100, 150, 200, 250, 300, 350, 400, 450, 500, 1000, 1250, 1500, 1750, 2000, 3500, 5000, 7500, 10000};
float duty = 0.5;
float freq = 70;
uint16_t duty_step_amount = 5;

At the very top of the code file are the configuration variables - if you’re not confident with code, only change these to customise the frequency generator. The ‘freq_presets’ variable is a list of frequencies that the generator will cycle through. If you have a specific frequency you want, such as middle C in a musical sense (256Hz), you can add it to this list in any order desired.

The ‘duty’ and ‘freq’ variables beneath it are the current settings of the frequency generator, and are also the default settings when it starts. If you’re writing your own code, feel free to change these variables to make your own functionality.

TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);
TCCR2B = _BV(WGM22) | ((prescale + 1) & B111);

This code is in the setup function to correctly set the registers within the Atmega328 chip - the processor used by the Arduino Uno. There is quite a bit of technical knowledge behind why we’re setting these individual registers, but it primarily comes down to using Timer 2 in the Arduino to turn on and off a pin with a specific frequency and duty cycle. Timers are awesome because they’re part of the Arduino Uno’s hardware, which aren’t susceptible to slowdowns from other routines. If you need to do a time-consuming task whilst you are driving an LED on and off, for example, Timers are invaluable. The Arduino Uno has three timers, usually referred to as Timer0, Timer1, and Timer2.

Timer0

Timer1

Timer2

Resolution

8-bit

16-bit

8-bit

Used by

millis(), delay(), micros(), PWM on pins 5/6.

SoftwareSerial, Servo, PWM on pins 9/10.

tone(), noTone(), PWM on pins 3/11.

Minimum Period

125ns

Max Period (No Prescaler)

16μs

4ms

16μs

Max Period (1024 Prescaler)

16ms

4.2s

16ms

Timer0 is used for many of the most common Arduino commands, such as millis() and delay(), so if you’re planning to use these functions, or have a library that relies on them, it’s best not to mess about with Timer0 too much.

Timer1 is interesting because it’s a 16-bit timer on the Arduino Uno, while the others are 8 bits. This allows much more precision and the possibility of more complex functionality. However, it is also used by various Arduino libraries such as SoftwareSerial and Servo, so, again, if you’re using these, don’t mess about with Timer1. Since the DIYsplay is set up to use SoftwareSerial by default, we don’t want to use Timer1.

Timer2 is much like Timer0 however it’s used for much fewer core functions, so we can be a bit less careful with using it. The most common Arduino function that uses Timer2 is the tone() function, which we’re not using in this project. So, we’re free to use it for our own purposes!

There are many different configurations available for timers, which can be found in the ATmega328’s datasheet. At its most basic, the timer can increment once every processor cycle, and will reset (overflow) once it has reached the maximum value. Since the Arduino Uno runs at 16MHz, and Timer2 has 8 bits, we know that it will trigger at 16MHz / 256 = 62.5KHz, which is far too fast for our needs. We can use a timer ‘prescaler’ to divide the timer’s counting process by up to 1024 times, which is where our frequency generator’s minimum of 60Hz comes from!

But what about custom frequencies? Our prescaler can only select certain powers of 8 to divide by (8, 32, 64, 128, 256 and 1024), so we can’t choose any frequencies besides those. To do this, we can set a custom value for Timer2 to reset at, which we do by assigning a value to OCR2A (Output Compare Register). For example, if our prescaler is 1024, and we assigned ‘100’ to OCR2A, our output frequency will be 16MHz / 1024 / (100 + 1) = 154Hz. 1 is added here to account for the timer resetting to 0. This formula can be used to calculate the OCR2A value for any desired frequency.

Controlling duty cycle is a similar deal, but we write a special ‘compare’ value to the OCR2B register. If the current value of Timer2 is lower than what’s in OCR2B, the output pin is high. For example, if OCR2A is 200 and OCR2B is 100, we get a duty cycle that is approximately 50%.

Buttons

For a challenge, we aimed to use only direct register access for polling when buttons are pressed. Is it overkill? Yes, but it also speeds up the polling process and also lets us learn about how the Arduino internally manages the pins.

When you use digitalRead() on an Arduino, the Arduino actually is accessing a whole ‘port’ of pins at once. The Arduino Uno has three ports, B, C and D - pins are usually referred to as P[port][number], so PB0 or PD4 for example. If you look up “ATmega328 Pinout” on Google Images, you can see how the pins are laid out internally on an Arduino board.

We’re using Port C for the four buttons on our function generator, which consists of all analog pins. That is, A0 is actually PC0, A1 is PC1 and so forth. To access all pins on Port C at once, we can simply use the phrase ‘PINC’ in any Arduino code, which will return the current state of the pins as a 8-bit number. Without any buttons pressed, PINC will normally have the value of 00001111 - the latter four bits are our button states. A value of 1 represents ‘not pressed’, while 0 represents ‘pressed’.

So all we need to do is run code when any of the last four bits are 0, right? Not quite, as we only want to change things on the function generator when we press a button once, not constantly for as long as we hold the button.

uint8_t changed_bits = PINC ^ last_button_state;

uint8_t changed_bits = PINC ^ last_button_state;
if(changed_bits != 0) {
  last_button_state = PINC;
}

The code above lets us detect when any pin in Port C (any analog pin) changes state in an extremely efficient way - although it can be a little mystifying as to why it does it. The variable ‘last_button_state’ is an 8-bit number that keeps track of the last state of the PINC register. If we notice that last_button_state is no longer equal to PINC, we know that PINC has changed!

We use the XOR operator (^) to detect this. XOR operates on each bit - that is, each bit of the left and right number is compared. If they’re identical, the output bit is 0, and if they’re not, it’s 1.

Pin state hasn’t changed

Variable

Example Value

PINC

1111

last_button_state

1111

PINC ^ last_button_state

0000

Pin state has changed

Variable

Example Value

PINC

1011

last_button_state

1111

PINC ^ last_button_state

0100

You can see in the table above, where the third pin has changed, the XOR operation no longer equals zero. In our code, you can see we’re detecting when that’s the case with our ‘changed_bits’ variable.

Using this ‘changed_bits’ variable, we can decide what we want to do with the buttons based on which have changed.

Of course, this approach is more complex than simply using digitalRead(), but we thought for those who are interested in the more advanced side of Arduino programming, this may be interesting.

Testing

We’re happy with our cute little frequency generator - it’s barely bigger than the Arduino Uno itself and works extremely well. The buttons act as a great interface for using the Frequency Generator, and will be handy on any workbench. As mentioned, this frequency generator is capable of generating well into Megahertz range, however, the DIYsplay can only display up to 10KHz on the Frequency generator display. If more code is used to switch to a different display, high frequencies can be used.

Our hardware-based frequency generator producing 2KHz with 99.9% accuracy! Impressive!

We wanted to compare the results of a software-based Frequency Generator to a hardware-based one. We wrote a small sketch to generate a frequency while writing to the DIYsplay, and we found that it could barely go above 100Hz without significant changes in its duty cycle or frequency. A hardware-based implementation of this project was definitely the right call here!

Final Thoughts

This month marks the fourth issue since we’ve released the DIYsplay, so we’ve had plenty of time to refine the development and production process. Since then, we’ve also received a bunch of awesome feedback from our readers about bugs, fixes and general improvements to the product. We’ll be improving the Arduino library where necessary to improve performance and usability, so be sure to install the latest library updates as they become available.

There really is no limit to the amount of projects you can create with it, and we’re even discovering new ways to use it ourselves for really compact projects. The DIYsplay frame can be desoldered if you just want to use the pads onboard the display module, which makes life easier for projects where size is limited.

You’ll most likely see us using the DIYsplay for all sorts of general DIYODE projects over the next few months, where it’ll be integrated into the design of the project. Since it’s super easy to interface with, you can use more than just an Arduino to talk to the DIYsplay, provided you’re confident with using UART with your microcontroller of choice.

One limitation to keep in mind is that our DIYsplay relies on the MatesController library to work properly, which is the underlying Serial communication library to work with the DIYsplay. While it doesn’t handle any of the logic for each screen, it does talk directly to the hardware on the Arduino.

This means that while our DIYsplay library should be compatible with most Arduino architectures, the MatesController library may need some adjustments depending on what you’re using it with. An ESP8266 controller, for example, requires some fixes before the code compiles properly.

Speaking of fixes, if you’re keen to contribute and help make the DIYsplay better for everyone, all of the code is open-source and can be improved on our GitHub by making a pull request. We’ll be doing this ourselves as we squash more bugs, but if you’ve got some hardware development experience under your belt, feel free to chip in!

We can’t wait to see what you’ll make with the DIYsplay! Be sure to clue us in at @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: