Projects

Retro Computer Dashboard

Custom Analogue Resource Monitor

Liam Davies

Issue 28, November 2019

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

Log in

See at a glance how your computer is performing with this Nano-based PC Status Dashboard.

BUILD TIME: 3 Hours + 3D Printing Time
DIFFICULTY RATING: Intermediate

Realising your PC’s memory is getting eaten up by an unwarranted antivirus scan is one of the most frustrating experiences for any computer user. Fear not! With this project, you’ll be able to keep a keen eye on your PC’s precious resources with a set of retro-looking analogue gauges sitting right below your monitor. Sure, it won’t make your computer run faster, but your setup will certainly look the part!

THE BROAD OVERVIEW

A common issue any PC gamer is familiar with is noticing their game is running sluggishly, most often conveniently in the middle of a match – only to discover some program in the background has decided to auto-update.

A good way to spot something on your computer becoming a nuisance is leaving a resource monitor program open on your computer, but that’s no fun! We need something a bit more physical. If having a set of live-updated analogue meters sitting on your desktop isn’t cool, we don’t know what is.

IMAGE CREDIT: Core Electronics

This is a great beginners project to throw together to experiment with analogue gauges, PWM signals and serial data over USB.

We’ll also design a custom 3D printed enclosure, faceplate, and DIYODE letters to tie this project off. We’ve included all the project files for this project so you can follow along. You can even change the colours, meters or the info displayed on them to suit your own computer setup!

HOW IT WORKS

The concept behind this project is fairly straightforward. The analogue performance meters are just 5V analogue panel voltmeters in disguise. We’ll replace the aluminium backgrounds of the meters from displaying a scale 0-5V to displaying a scale 0-100%, of whatever quantity we are displaying on that meter.

Most Arduino boards are capable of outputting a 0-5V PWM signal – we’re going to use that to our advantage. If we wire each PWM output from the Arduino to individual voltmeters, it’ll be a breeze updating the voltmeters to the position we want. A duty cycle of 0% means the needle sits on its minimum value, and a duty cycle of 100% means the needle sits on its maximum value.

If you’re wondering why we aren’t smoothing out the Arduino’s PWM signal using a capacitor, the mass of the needle will do that for us. The voltmeter needle will swing around to the average PWM voltage we give to it, and hold there until we change the duty cycle again. The frequency of the Arduino’s PWM is high enough that the rising and falling signal are not shown on the meter.

XC4414 Duinotech Nano from Jaycar.

Speaking of Arduino, we’ll be using the Arduino Nano. It’s functionally identical to the UNO, meaning we can use all the normal bells and whistles in a minuscule form factor. It’s connected to the four analogue voltmeters and the flashing lights on the faceplate. The Nano is responsible for sending all of our PWM signals to the meters and, in the main build of our project, enabling the flashing lights when any meter goes over 90%. It’ll be secured in our enclosure on a perfboard and connected with a Mini-USB port extender that allows us to disconnect the meter if necessary.

The Nano will receive serial data (containing CPU usage, memory usage, etc.) from the host computer, which is generated by a custom Windows command line application. We’ll look at how we gather, process and send this data in the final build section of this project.

The Fundamental Build:

Breadboard Prototype

Parts Required:JaycarAltronicsCore Electronics
4 × 0-5VDC Analogue Panel Meters*--TOL-10285
1 × Arduino Nano V3.0 Board (Or Equivalent)XC4414Z6372CE05101
1 × Breadboard (Any size)PB8815P1009ACE00304
Alligator Clips ^WC6010P0415PRT-12978
Jumper Wires ^WC6027P1022ADA1955

Parts Required:

* As you'll see shortly, we ended up having inaccuracy problems with these cheaper meters. Feel free to swap them out for higher quality 5V panel voltmeters.

^ Alligator clips and Jumper wires aren't strictly necessary, just make sure you can connect the PWM pins on the Arduino to the threaded terminals on the back of the voltmeters.

To prove that this idea is plausible, we put together a prototype with an Arduino Nano and four analogue 5V voltmeters.

As mentioned in the How It Works section of this project, the basic premise of the wiring is hooking each meter up to a PWM pin on an Arduino. We inserted the Nano to a breadboard and connected pins D3, D5, D6, and D9 to the positive side of the meters using some Dupont wires and alligator clips. If you want to add additional meters, or have a different Arduino entirely, just make sure whatever digital pins you use are PWM-compatible. The wiring for the fundamental and final build is effectively identical, but we’ll be adding some more features including a 3D-printed enclosure and LEDs to polish up the project.

THE CODE

After hooking up the four meters to our Nano, we wrote some code that randomly assigns meter values in a 0.5 second cycle. This simulates randomly changing values we’ll get from our computer. We wrote this in the Arduino IDE and used a mini-USB cable to upload it to the Nano.

int meterPins = {3,5,6,9};
void setup() {
  for(int i = 0; i < 3; i++) {
    pinMode(meterPins[i], OUTPUT);
  }
}
void loop() {
   for(int i = 0; i < 3; i++) {
    random_val = random(0,255);
    analogWrite(meterPins[i], random_val);
  }
  delay(500);
}

The first thing this code does is assign an array of the PWM pins we’re using for the meters – namely, digital pins 3, 5, 6, and 9. This lets us reference each pin by its index and not by the pin itself. For example, if we wanted to set the third meter to the 100% position, we could simply run analogWrite(meterPins[2], 255);

The setup then defines all our PWM pins as outputs. Not strictly necessary, but good convention. After that, our loop function continuously writes values to each meter between 0V and 5V. (Note that the analogWrite function we’re using takes a value 0-255, and maps that number to the voltage it puts out. A value of 127, for example, will be close to 2.5V.) The program then waits half a second, and updates all the meters again.

What follows uploading this code is a delightful dance show of meter needles, jumping around and hastily swinging to their requested values. Awesome! We did find, however, by modifying the code to get the meters alternating between 0 and 5V, some meters needed calibrating. One meter was reading only 4.3V at a 100% PWM cycle from the Arduino! These inaccuracy problems were frustrating, however, we will now describe how it can be fixed.

INACCURACY

As you might expect, using old-school technology for a precise information display does have its caveats.

The first problem is that our Arduino Nano doesn’t run on exactly 5V. Instead, it usually will hover around 4.7V-4.9V (Because of the voltage drop across its internal voltage regulator). This isn’t too much of a problem for digital sensors and displays, because so long as the encoded signal reaches the device, the rising and falling data signals – regardless of voltage – will send all the information it needs. This isn’t the case for analogue devices like we’re using. To display the 5V on our panel meters, we must send the 5V it needs, period. There’s no meter.setPosition(1.0) or the digital controls you’d expect to find in a digital device.

Practically, this means that even if we send a 100% duty cycle PWM signal from the Arduino, the output voltage is limited to the voltage the Arduino is running on and thus the meters can’t reach their maximum value.

The second problem is that the meters themselves are simply not accurate. The slight variations in manufacturing of the magnet, copper coil and wire resistance in the meter throw the reading off - especially considering that these are cheap voltmeters. Even if we supply 5V from a bench power supply, the meters still fall short of indicating 5V and end up displaying 4.8-4.9V regardless.

The combination of these two problems means that the voltmeters we have don’t reach the 100% position when a 100% PWM signal is applied. They hover a couple divisions short – 90-95% of the maximum value. There are a couple ways around this problem:

  • Use a power supply that is slightly above the maximum voltage of the meters and use a transistor to activate the meter instead. For example, we could use a 6V power supply (alongside the USB port which is 5V) and feed that voltage to the meters when activated by a transistor controlled by the Arduino. We didn’t try doing this as we feel using two power supplies for a desk gadget is absolutely overkill.
  • Modifying the internal resistor of the voltmeters. The position of the needle is technically based on the current flowing through the solenoid inside, and because current is directly proportional to voltage, as we change the voltage, the position changes accordingly. For example, by reducing the resistance of the resistor at the positive terminal inside the meter, we increase the current flow and thus the position of the needle reacts more to the same voltage. We attempted this by placing another resistor in parallel with the one already in the meter (therefore reducing resistance), however, we realised quite quickly that even then, the meter was too sensitive and needed adjusting further.

The method we ended up using was a little less accurate, but it will retain the simplicity of this project. Behind the plastic screen of each meter, at the base of the needle, is a gold nut, internal screw, and a soldered tab with a red wire on it. By tweaking each of these components, we can change the position and behaviour of the magnetic field that controls the needle. (By the way, this should work with any analogue voltmeter!)

  • Tighten the internal screw to add mechanical resistance onto the needle. This will make the needle move slower and react less to changes in voltage.
  • Move the solder tab to change the voltage offset. Twisting the solder tab anticlockwise will orient the needle more clockwise. We moved ours about 15 degrees to the left to get the needle reaching 100% at 5V.
  • When you are happy with the calibration of the meter, tighten the gold nut to secure everything in place.

We found that each meter varies in accuracy, and even with our best attempts of calibrating them, they didn’t quite reach the accuracy we were hoping for. Some meters still didn’t reach the 5V mark when 5V was applied, while others did but didn’t return to the 0V mark when disconnected entirely. Next time we’ll try using higher-quality meters that won’t have such problems with inaccuracy. For now, we’ll have to stick it out. Onto the main build!

The Main Build:

Retro Computer Meter

It’s showtime! Let’s put together this cool little desk gadget. We’ll be making a soldered circuit with some prototyping board, adding some LEDs, and 3D printing a custom enclosure. Check out the part list below for the stuff you’ll need (also including the parts from the Fundamental Build)

ADDITIONAL Parts Required:JaycarAltronicsCore Electronics
1 × Panel Mount Extension Mini-USB Cable--ADA3318
1 × Mini-USB to USB-A Male-Male CableWC7709P1891ASS321010005
1 × 40 Pin Female Header StripHM3230P5390PRT-00115
4 × 2 Way Screw TerminalsHM3130P2028PRT-08432
2 × 5mm Red LEDs #ZD0150Z0800COM-09856
2 × 200Ω Resistors *RR0555R0541CE05092
1 × 7cm × 9cm Perfboard--ADA2670
4 × M3 10mm Screws *HP0404H3120AFIT0270
16 × M3 Nuts *HP0426H3175POLOLU-1069
8 × M3 Washers *HP0430H3180-
8 × Eye or Forked Spade Connectors (to fit Meters) *PT4523H2071A-
Crimping Tool (for Insulated Lugs)TH1829--
2-Core Cable (for Meters and LEDs) ^---
Hookup Wire---
Variety of Heatshrink---

ADDITIONAL Parts Required:

* Quantity required, may only be sold in packs.

# Feel free to use any colour of LED you like. Keep in mind you may need to adjust the resistors used with the LEDs as different colours have different forward voltages.

^ We chose to use AC cable because it the two wire cores is handy for only having one insulated cable for each meter. You could use any amount or type of cable that keeps the build clean in the enclosure.

MAIN CIRCUIT BOARD

The main circuit board is where our Arduino and any connectors will sit. Instead of soldering the Arduino or any wires connecting to the meters directly onto the board, we’re going to be adding headers and screw terminals that allow us to swap out any components should we need to. That way, we don’t need to sacrifice an Arduino just for this project, we can just take it out of the header pins it sits in so we can use it in another project. If you are having trouble keeping track of the wiring for this project, refer to the schematic.

To start, choose a place on the prototyping board to place components. We left plenty of space either end so we could add more connectors in the future. It’s worth noting we’re going to be snapping off the bottom 40mm of the board to save space, so solder all components in the top 30mm.

We started with the screw terminals at the top of the board, and by doing the wiring they need before placing headers for the Arduino, we avoid working on a cramped board. Plan ahead!

By joining the small dovetail connectors on each end of the four screw terminals, we can make an eight-way terminal block - two for each meter. We inserted it into the top-most slot (with the wire openings facing outwards) and soldered it in place. The purpose of these screw terminals is to allow us to screw in or remove the cables leading to the meters even after we have assembled the project, for sake of convenience or repair.

Now it’s time to position the Nano and route the pins we are using to the screw terminals. Snap two lots of 18 pins from the 40-pin female header block, and push them onto the pins on the bottom of the Nano. We left 3 pin spaces between the screw terminal and the Arduino for space for connecting wires. Wires need to be soldered from pins D3, D5, D6 and D9 to a screw terminal. A connection to ground (GND on the Nano) can be added to the remaining screw terminals. As you might’ve guessed, each pair of the screw terminal will be used to control one meter, one for a PWM pin (+ on the meter) and the other for ground (- on the meter).

The two 18 pin blocks can be soldered onto the board. Since we’re also adding flashing LEDs to the main build, we’re going to add another 4 pin block for two LEDs to be connected. These LEDs will be mounted to the front of the enclosure and will alternately illuminate when any meter we are displaying goes above 90% (E.g. 90% or more of RAM is in use). This will let you know when your computer is working on something and shouldn’t be interrupted. It’s also important that these lights don’t light up too bright, we don’t want them to be distracting. By using a 200Ω resistor in series with each red LED, we can reduce them to a soft glow.

3D PRINTING

Like a lot of projects you’ll see in DIYODE, we’ve chosen to design a 3D-printed enclosure to keep a clean, minimalistic feel to the project.

We’ve divided this project’s 3D printing into two main parts – the enclosure and the faceplate. The enclosure is the bucket-shaped part that everything slots into, including electronics and the back mini-USB mount. We’ve shown it with a transparent rendering to show the mounting holes for the circuit board and USB port. The faceplate is the flat frame that the meters screw into, which is then pushed onto the enclosure.

If you’re printing this at home, bear in mind that the enclosure is quite long – 220mm to be precise. Make sure your printer can support the length. The entire enclosure is designed so that it can be printed with minimal support, so make sure that the rear face of the enclosure is faced downwards. We recommend using two or more perimeter walls and 15% infill for both prints. To make this project suit the colour scheme of your computer setup, feel free to print in whatever filament colour you like. We used a bright red to print the enclosure, and black to print the faceplate.

We had problems printing on our Flashforge Guider due to some z-spacing issues, which caused the models to be slightly enlarged when printed. The faceplate became nearly impossible to fit on to the enclosure, and so after wrapping some masking tape around areas we didn’t want scuffed, we used a Dremel to sand down the red lip of the enclosure. We continued sanding until the faceplate fitted comfortably onto the enclosure. To hopefully avoid these problems if you print the models at home, we’ve added some tolerance to the .stl file in the project files.

We’ve also included some press-fit DIYODE letters that can be printed. These letters are intentionally printed smaller than the black recesses in the faceplate so they should press-fit. We found the two Ds and O we printed went in with some encouragement from a vice, but the others needed some superglue to hold. This was a mistake as the superglue left some nasty – and unfortunately permanent – white residue that’s especially visible on the black faceplate. Nonetheless, the letters are in and staying in.

After we printed the enclosure, we found that it sat quite flat on the table and was difficult to see, so we designed and 3D printed a stand that holds it up at a 20° angle. We printed two of these stand holders in black PLA. We’ve included all 3D print files for this project in the project files.

PREPARING METERS

Download the PDF from the project files and print it at 100% scale. Regular A4 paper will work, but feel free to experiment with card stock or thicker paper for a nicer look on your meters. To make sure the print is the right size, there is a scale that should be exactly 50mm when printed. If you’d like to make your own, just throw the aluminum 5V meter background already in the meter onto your scanner, edit it, and print it!

After it’s printed, grab a craft knife, and carefully slice out the black outlines. We used a glue stick to stick the paper background on the reverse side of the aluminum background. Once the background is screwed back into the meter, the meter will now have your own custom scale!

DOWNLOAD THE METER BACKGROUNDS:

See the Resources section at the end of this article

CONNECTING THE METERS

The voltmeters we are using for this project have 3mm thread on their positive and negative terminals, so we need to connect these to the screw terminals on the main circuit board.

For wires, we found a 240V AC cable that has live and neutral wire cores, each insulated and bundled together. We recommend using a dual-core wire to help keep the wiring clean, so each meter only has one cable. We divided the cable into four 25cm pieces (one for each meter) and stripped both ends - 10mm on one end, 30mm on the other. The shorter stripped end will be connected to the screw terminals, and the longer will be split apart to connect to the voltmeters. If you choose to make the project for yourself, make the wire lengths shorter than we did – we had trouble packing everything into the finished enclosure.

To add the fork connectors, we need a crimping tool – you can find the one we used in the part list. Using eye connectors, if you have them available, is most likely a better option than fork connectors - they won’t slide out on the meter thread if the nuts aren’t tight. After stripping each of the wires to expose about 5mm of copper, push them into the fork connectors and crimp them. They should form a crimped joint similar to the way rivets work, which prevents them from falling out without any solder. If you find that the leads are coming out of the crimp lugs, they may not be crimped as tightly as required, or there is not enough copper wire filling the holes. Strip about 12mm of wire, twist it tight and fold it over before inserting into a fresh crimp lug and crimping tightly.

Each of the voltmeters comes with a small bag of washers and nuts. The assembly order shown in the image above will hold the fork connector tight onto the thread: Washer, fork connector, washer and nut. Each of the meters will now have a wire attached to it, which will lead back to the main circuit board and can be screwed into the terminals.

ADDING BACKLIGHT

If you want to add an additional retro look to this project, you can add some LEDs into the meters themselves. By drilling a 3mm hole into the back of each meter, being careful to just drill through the plastic, we can insert a white or yellow LED beneath the base of the needle which, when illuminated, will add a soft backlight for viewing in the dark. We didn’t do this in our build, but it’s a cool addition if you work in the dark a lot. Just make sure to add a resistor in series with each LED!

FLASHING LEDS

The next step is to prepare the two LEDs that will be added to the faceplate, one either side of the DIYODE logo. We cut the two leads on each LED short, leaving about half a centimeter to solder wires to. Make sure to use a thin wire for this, as you don’t want to be putting too much stress on the leads of the LEDs. We used a dual-core audio cable. We also slid a couple of centimeters of heatshrink over both wire ends and used a heat gun to protect the leads from short-circuiting. It’s easy to forget this step, so make sure to put the heatshrink on before soldering! We also added a wider piece of heatshrink over the first two to keep the wires together.

Be extra careful when handling the LEDs, the legs on the LED won’t hesitate to break off if you bend them too much – and then you’ll have to do this all over again!

We repeated this process on the other end of the wire, soldering in two pins of a female header and using heatshrink to hold it all together.

FINAL ASSEMBLY

With all the components done, it’s time to place everything inside our 3D-printed enclosure. We started by inserting the meters into the faceplate. The meters themselves have two 3mm threads at the bottom left and bottom right corners for securing onto the enclosure. The faceplate includes these holes and so the meters should slide right in. We used a washer and nut on each thread to secure the meters in place on the faceplate.

To add the LEDs we prepared in the previous step, we pushed the LEDs into the 5mm holes either side of the faceplate. If, like us, you have tolerance problems pushing them in, use a hand drill with a 5mm bit to enlarge the holes. The LEDs should then fit comfortably into the holes.

The next step is to put the main circuit board in the enclosure. We snapped off the blank 40mm of our main circuit board, leaving the top half of 90mm × 30mm. Be careful when doing this! It’s very easy to accidentally snap off parts of the board you want to keep. You could also do this with a pair of strong scissors.

Grab a hand drill and make two 3mm holes in the board, 30mm beneath the two top ones. They should line up with the four holes on the back of the enclosure.

Slot four 10mm M3 screws through the holes from the back of the enclosure, and screw two M3 nuts over each. These will act as standoffs for our circuit board - although you could use actual PCB standoffs if you have them on hand. Lock the circuit board in by placing another M3 nut over each of the screw threads. To add the Mini-USB extension, align it over the hole on the enclosure, and secure it with two M3 screws from the back. It should now be locked into the enclosure and can be plugged into the Nano.

All that’s left to do is connect the meters to the screw terminals if you haven’t already, and close the enclosure by connecting the faceplate to the enclosure. With the physical build itself all done, it’s time to move onto the code that drives the whole operation.

THE CODE

The code for this project is not just a simple Arduino sketch. Rather, it has three different parts that work together to get, process, and display the performance info from the computer. All of the code can be downloaded from our website.

For the Arduino to get the performance data from the host system, we need some data to begin with! Getting this data is harder than you might expect. The issue is, it’s not as simple as just getting the CPU temperature or any other performance figure from a system library. The motherboard of a computer has sensors, and there are many different variations of these sensors and chipsets that control them. Some computers may not even have these sensors at all! So, to make this work, we need to write code that interfaces with and reads data from the sensors in our specific computer, which inherently prevents the code from working on other systems. Not fun.

Fortunately, the program Open Hardware Monitor already has code that picks up on a huge variety of computer sensors and displays them on graphs over time. It’s open source, so we are free to interface with it and comb through its code. After we download Open Hardware Monitor from its website: openhardwaremonitor.org and extract it, we run the executable and check out the sensors listed in the main window.

Notice the program picks up data from specific sensors, including our Nvidia GPU’s (GTX 960) temperature. Open Hardware Monitor can pick up most sensors in modern hardware, so all we need to do is decide on the information that we want and collect it in our own program. We’ve chosen the CPU Package Temperature, CPU Total Load, RAM Usage, and the GPU Core temperature.

To collect this data, we will be using the OpenHardwareMonitorLib.dll library, which should be included alongside the executable file. This library will allow us to use features implemented in Open Hardware Monitor in our own executable program. This is exactly what we want and will make the entire programming process a lot easier!

WINDOWS CONSOLE PROGRAM

Note: Don’t worry if you aren’t running Windows. We’ll talk about how to send data to the Arduino in any programming language or on any OS later in this article.

It’s now time to write the program to use the data from the OHM library to relay to the Arduino through Serial over USB. You’ll need to install Microsoft Visual Studio for this, so head to https://visualstudio.microsoft.com/ and download it. After it’s installed, create a new project and, under the Visual C# category, select Console Application and click OK.

You should be greeted with an empty Program.cs file.

To import the OHM library, right click on the References tab in your Solution Explorer and click Add Reference. We’re going to be importing the OpenHardwareMonitor.dll file, so find it on your disk and import it using the Browse button. This is the reason why we haven’t included an .exe in our project files, as the location of the DLL on the drive we need will vary depending on the computer. Importing the DLL will allow us to use the functions from the library OpenHardwareMonitor in our Program.cs file. Notice we only need the hardware functionality of the library.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Diagnostics;
using System.IO.Ports;
using OpenHardwareMonitor.Hardware;

There is a fair amount of code required to set up and initialise the interaction with the library, so we’re only going to be looking at the Main method used in the program. You can read through the entirety of Program.cs in the project files.

static void Main(string[] args) {
  Console.Write("Input COM port 
to output serial data (e.g. COM3): ");
  string portInput = Console.ReadLine();
  Console.WriteLine("---------------");
  int baud = 9600;
  port = new SerialPort(portInput, baud);
  port.Open();
  Program p = new Program();
  computer = new Computer();
  computer.Open();
  computer.CPUEnabled = true;
  computer.RAMEnabled = true;
  computer.GPUEnabled = true;
  while (true) {
    computer.Accept(p);
    byte cpuUsage = (byte)GetCPUUsage();
    byte memoryUsage = (byte)GetMemoryUsage();
    byte gpuTemp = (byte)GetGPUTemperature();
    byte cpuTemp = (byte)GetCPUTemperature();
     Console.WriteLine(cpuUsage.ToString() + 
"% CPU Usage | " + memoryUsage.ToString() + 
"% RAM Usage | " + gpuTemp.ToString() + 
"°C GPU Temp. | " + cpuTemp.ToString() + 
"°C CPU Temp.");
    byte[] packet = { 
      cpuUsage, memoryUsage, gpuTemp, cpuTemp 
    };
    port.Write(packet, 0, 4);
    Thread.Sleep(250);
  }
}

The program first asks the user for a COM port to output Serial data on. In this case, it’ll be the COM port the Arduino is connected to. It then, using the System.IO.Ports library, opens a new Serial port on the COM port requested.

After some code is run to set up the interface with OpenHardwareMonitor, it begins the loop that continuously provides the connected Arduino with Serial data. The first line of the loop tells the Computer object to accept new information from OpenHardwareMonitor. We then gather the byte (0-255) of data from each sensor we are using and create a variable called ‘packet’. ‘packet’ is an array that contains four bytes that we are going to send through the Serial connection to the Arduino. Once we’ve written the four-byte packet to the serial port, we wait a quarter of a second and then loop again.

We mentioned at the beginning of this section that if you aren’t on Windows or want to use a different programming language, this project can still be done. Just gather your sensor information (either through OpenHardwareMonitor or a way of your own) and send it through the serial port with four bytes, one for each sensor value.

The program should now run and transmit Serial data!

If you have trouble getting the program to work, make sure you set the program to run with elevated administrator rights – sometimes the Serial IO doesn’t work properly if the program isn’t run as an administrator. You can do this by opening the app.manifest file auto-created by Visual Studio and changing the requestedExecutionLevel line to the following:

<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />

Arduino Code

The main purpose of this Arduino code is to accept serial data from our host program, output the data to the voltmeters and turn on the flashing lights if necessary. With a Mini-USB cable connected to the back of the enclosure, open the Arduino IDE and set the correct COM port. You can find the code we wrote in the project files.

The first couple of lines simply declare the output pins were using for our meters and parameters for the program. That is – pins 3,5,6, and 9 for the meters and pins 7 and 8 for our LEDs. The warning threshold is what threshold one or more values must be above for the flashing lights to illuminate – i.e. 90%. Warning speed is the speed at which the lights flash (in milliseconds), and lightsFlashing is the current state of the lights.

After we setup output pins and a serial connection in the setup function, we run the loop function continuously. We wait until the serial buffer has four bytes in it – the ones we received from our host program – and output the byte value as an analogue PWM output on each of the meter pins. If any meter is above 90% of the maximum value (255), we set lightsFlashing to true. In the next part of the loop, we handle displaying the flashing lights if currently enabled.

int meterPins[4] = {9,6,5,3};
int leftLight = 7;
int rightLight = 8;
float warningThreshold = 0.9;
float warningSpeed = 500;
bool lightsFlashing = false;
void setup() {
  Serial.begin(9600);
  //Set pins to output mode.
  for(int i = 0; i < 3; i++) { 
    pinMode(meterPins[i], OUTPUT);
  }
  pinMode(leftLight, OUTPUT);
  pinMode(rightLight, OUTPUT);
}
void loop() {
  //Wait until buffer has four bytes.
  if(Serial.available() >= 4) {
    lightsFlashing = false;
    for(int i = 0; i < 4; i++) {
      int serialByte = Serial.read();
      byte val = (byte)(serialByte * 
(float)2.55);
      int meter = meterPins[i];
      analogWrite(meter, val);
      if(val >= warningThreshold * (float)255) {
        lightsFlashing = true;
      }
    }
  }
  //If any meter is above warning threshold
  if(lightsFlashing) {
    //Manage flashing lights
    //lightStep increases by one every 
    //warningSpeed in ms.
    int lightStep = (int)(millis() / 
warningSpeed);
    //Even lightStep values turn left light on.
    //odd lightStep values turn right light on.
    digitalWrite(leftLight,lightStep % 2 == 0);
    digitalWrite(rightLight,lightStep % 2 == 1);
  } else {
    digitalWrite(leftLight, LOW);
    digitalWrite(rightLight, LOW);
  }
}

By dividing the current time in milliseconds by the warningSpeed, we end up with an increasing counter in steps of warningSpeed milliseconds – in our case, 500. In order to get an alternating output between each of the LEDs, we modulo (meaning divide by, and get remainder) this counter by 2. If it’s 0, we turn the left LED on, if it’s 1, we turn the right LED on. This results in an alternating set of LEDs that are “chasing” each other. This is a handy trick that can be used for any number of “chasing” LEDs – just mod a counter by the number of LEDs you have.

If you have trouble uploading the Arduino code, keep in mind the host program can’t be running. It’ll be using the Serial port which must be free for the Arduino IDE to upload the sketch.

TROUBLESHOOTING

There’s a number of possible issues this project can run into, so if you do encounter any, this section might help you solve them.

A common problem we had was particular meters not moving at all when the program was running. This was usually the result of a dodgy screw terminal connection – the wires like to fall out if they aren’t screwed in properly. Take the entire circuit board out and reinsert the copper strands into the terminals. If you’re still having problems with the cables falling out, restrip them and try again.

Did you know some Mini-USB cables don’t have a data line? We didn’t, until we spent about half an hour wondering why the code wouldn’t upload! Some Mini-USB cables only have a power rail so make sure your cable does support data transfer – this goes for any project.

However, it can also be software related. Check the initialisation and data getting code (See the GetCPUUsage function) in the Windows program – you need to ensure that the sensors that you are accessing are actually detected in OHM, otherwise the program will just return zero as the data value. Also check you have correctly set the pins in the Arduino IDE. It’s easy enough to accidentally define a meter pin as a pin it’s not meant to be on.

If none of your meters are moving, check you entered the correct COM port into the Windows program and the Nano is receiving power from the USB port. There is a small light (RX LED) on the Nano that blinks momentarily when Serial data is received, so check that illuminates repeatedly as the data from the program is sent.

Finally, check the Windows program is running in the first place! To upload any changes to the Arduino code requires closing the host program, and thus the display won’t work at all until you start it again.

TESTING

Once the sketch is uploaded and the host program is running, the meter should now be working! We sat it on our desk and ran some benchmarks on our computer with the meter connected. Sure enough, the needles crept upwards as we increased the load. The meters, as we expected, were more inaccurate than at first expected. Some meters were more inaccurate than others – The GPU temperature meter, for example, displays around 5-10°C above the actual value reported by the computer. Nonetheless, the dashboard accomplishes its purpose – to give us an overview of our system’s performance at a glance. It’s very noticeable when a new program opens in the background, as the RAM usage needle creeps slowly up.

Having the two red flashing LEDs in the faceplate is a surprisingly very effective feature too – you become instantly aware when an application has decided to start eating up your PCs resources without your permission!

WHERE TO FROM HERE?

An interesting area to look at with this project is displaying specialised information on the gauges. If you’re handy with online programming APIs, you could hook up a gauge to display information related to local weather temperature, social media followers, stock prices, or just about anything else you might be interested in! It’s worth noting the Arduino Nano has 6 PWM outputs, allowing room for adding another two analogue gauges.

If a video game you play has a programming interface that allows external tools to get information about the game state, you could have an awesome physical Heads Up Display! A speedometer for a racing game? A health meter for a roguelike dungeon game? There’s a lot of possibilities for HUDs with this project.

Old-style analogue gauges – like the look we’ve emulated in this project - aren’t the limit either. By adding some code in the Windows program to accept incoming serial data from the Arduino, you could trigger functions on your computer with physical inputs. If a program you use has a lot of shortcuts, how about a custom keypad that has labelled buttons with your most used macros? What about a rotary encoder with buttons that cycles through running Windows on your computer so you can multitask between programs? We encourage you to come up with your own designs and uses for variations of this project.

Liam Davies

Liam Davies

17-year old high school student.