At some point while researching microcontroller projects, I came across several people who had used Arduinos and PICs to drive analog panel meters so they would display computer stats such as CPU load, memory usage, etc. It immediately struck me as something I just had to do. Here it is. My PC meter uses an Arduino microcontroller and receives the stats from a .NET Framework application I wrote in C#.Net. It’s housed in a plastic enclosure and looks quite professional IMHO. It was a fun project, and something I think most any computer/electronics geek would enjoy. I love mine, and I look forward to building more.
Here it is in action:
Read on for details on the parts and tools I used, some info on the process of building the device (and the problems I ran into) and links to download the source code and meter templates.
- Microcontroller – Arduino Leonardo (w/o headers). It’s easy to learn, has plenty of outputs (this project requires 6), and has a built-in virtual serial port for communication with the PC to be monitored. I picked the version w/o headers since this is a permanent build.
- Enclosure – Serpac 17s case in black. It’s just about the right size to house the meters I selected, and the price is right.
- Meters – There’s lots of options here. I personally chose to go with 1ma ammeters, as I saw other examples that used them. The specific ones I ordered came from Uxcell, a Hong Kong based company that sells factory-direct items from China. I don’t know how accurate the meters are, but they’re good enough for this project, and they were cheap. I ordered them through Uxcell on Amazon.com. The listing is gone now, but they were described as model #85C1-A, Class 2.5 accuracy 0-1ma ammeters. If you search Amazon.com or Ebay they’re pretty easy to find. One caveat: some reviewers indicate quality issues with these imported meters. Of the three I purchased, I did have one that I could not adjust to zero w/o opening it up. Besides that though, they all work fine, and I think the quality matches the price I paid for them.
- Resistors for meters – With 1ma ammeters, the correct resistor is 5kΩ ohm (to get 1ma of current at 5 volts.) 4.7kΩ (which I used) is more common, and will work just find as long as the code is adjusted accordingly. I get into more detail about this in the code section.
- LEDs – These are used to indicate when either the CPU load or memory usage is peaking (above 80%). I used two 5mm red/green bicolor LEDs from Radio Shack (#276-0012) which are held in place with two snap-in panel mount LED holders, also from Radio Shack (#276-0079).
- Resistors for LEDs – The LEDs I used are good for 30ma, and they seem to need it for optimal brightness in my opinion. The resistor to do this at 5v is 100Ω. Note that 30ma is getting close to the Leonardo’s maximum 40ma current per pin, but I haven’t had any problems so it seems to be safe. I don’t know if all ‘duinos can source/sink 30ma, so if using another board, you’ll want to verify this.
- Panel mount USB cable – The Leonardo has a USB micro connector, and I was concerned about durability as my meter device is plugged and unplugged over time. So I installed a panel mount cable that brings the micro connector out to a USB B female connector. I got mine from Adafruit.
Software I used
- Arduino IDE – For developing the Arduino program. Also includes the necessary drivers for the Arduino’s virtual serial port.
- Microsoft Visual C# 2010 Express – For developing the desktop application. It’s a free (as in beer) version of Microsoft’s Visual Studio IDE that supports the C#.Net 2010 language.
- Inkscape – Open source vector graphic editor that I used to design the new meter faces.
Download the files
All of the code I wrote and the meter faces I created can be downloaded in one big ZIP archive here. The meter faces are released under a CC license and the Arduino code is public domain. The desktop application is copyrighted, however it is released under a BSD license so you may use, modify and redistribute the code freely as long as credit is given. See the license.txt file for more details.
If you’re not interested in the desktop application’s source code and just want the executable, you can find it in the ZIP archive in the PcMeterSln\PcMeter\bin\Release folder. You’ll need the PcMeter.exe file which is the actual executable and the PcMeter.exe.config file which stores the configuration settings. The program requires the Microsoft .NET Framework 4.0 to be installed on your computer, which is freely available here.
Building the Device
Cutting and drilling the enclosure
For me, this was the hardest part, and the least forgiving. I bought two enclosures to be safe, but fortunately I only needed one. I used a Dremel with the Circle Cutter & Straight Edge Guide accessory to cut the large circles needed to mount the meters. I measured carefully, double-checked my measurements, and cut two perfect holes. Somehow though, they ended up being just a little too small. I don’t know if I messed up the circle cutter adjustment somehow, but that’s my best guess as to what went wrong. Next time I’ll triple check it. I ended up having to cut the holes larger “freestyle”, so now they don’t look so perfect. But with the meters installed, it doesn’t show.
I had trouble figuring out how to determine the mounting location of the two bolts that hold the meter in place, so I made a template from some scrap wood to use as a guide. It’s not perfect, but it did the job.
Creating the custom meter faces
The meters ship with metal faces that indicate a reading from 0 to 1ma. Disassembling the meters is very easy using a small screwdriver, allowing for the faces to be replaced with custom ones. I scanned one of the original meters faces, imported it into Inkscape, and then drew new faces for CPU% and MEM% based on the scanned image. The designs I came up with are pretty basic as I don’t have much experience with Inkscape but I’m pretty happy with them. I printed the faces on card stock and used a hobby knife to cut them out and trim them to fit inside the meters.
Putting it all together
The Arduino Leonardo and USB cable are mounted to the bottom portion of the Serpac enclosure, and the meters and LEDs are mounted to the top portion. The position of the USB cable was carefully chosen so the cable runs in between the two terminals attached to the meter that’s mounted above it. Somewhat of a tight fit, but it worked out.
The circuit is simple, so I skipped breadboarding the four resistors and just soldering them in with the wiring. The resistors for the meters are soldered directly to the ring terminals which made them easy to implement. The wiring going the Arduino is soldered as well since this is a permanent build.
The assembled unit looks great and is definitely one of the more “professional” looking projects I’ve build from scratch. The size is a good fit for having it sitting on top of a desk or PC case.
Writing the code
This is just a quick overview of what the programs are doing, and some points of interest.
The desktop application
The desktop application is written in C#.Net and was developed using Microsoft Visual C# 2010 Express. The program is a little “heavy”, as it requires .NET Framework 4.0 to be installed on the computer and it’s not particularly lean given the small task it has. I’m a VB/C# developer by trade though so it was the most comfortable environment for me the develop the desktop application in.
I designed the program so it can be used by anyone without having to modify the source code. All of the options you might need to change can be modified via the user interface. You can specify the COM port to use, and choose to have the program connect to the COM port when it opens. The program can also be set to start minimized. This way, you can have it start when Windows loads and it will be out of the way. When connected to the COM port, the application reads the CPU and memory usage (utilizing the System.Diagnostics.PerformanceCounter class) every 500ms and display the readings on the form and send them to the selected COM port. CPU usage comes from the System.Diagnostics.PerformanceCounter class, and memory usage is calculated using GetPerformanceInfo by Antonio Bakula.
The Arduino program
The Arduino program continuously reads the virtual COM port and when it receives data in the correct format, it parses it and sets the meters and LEDs accordingly. Th reading for CPU% is “smoothed” over the last four readings to prevent drastic jumps in the displayed value. This is not done for Memory usage, since it’s typically a more stable value. If no data in the correct format is found for more than three seconds, the device enters a “screen saver” mode where it moves the needles on the meters back and forth in opposite directions to show it’s running but not receiving data.
Several constants are used to indicate which pins are used for the various outputs and other settings, so it’s easy to change them if necessary. And actually, there are two that will almost always need to be changed for each specific device, which are METER_A_MAX and METER_B_MAX. Let’s look at why this is.
The Arduino’s analogWrite function uses a maximum value of 255 which results in the max voltage (typically 5v) being output on the specified pin. However, the “true” max value may be less than this, depending on the accuracy of the meters used and the value/accuracy of the resistors. In the device I built, 5kΩ resistors were required to achieve 1ma of current at 5v, which would put the meters at the 100% position. I could purchase precision 5kΩ resistors and have the current be really accurate, but its more convenient (and cheaper) to use 4.7kΩ 5% tolerance resistors instead, which are very common. To compensate, I adjusted the two MAX constants to the necessary values to display 100% on the meters correctly. Even with the correct precision resistors, this may still have been necessary as the inexpensive meters I used are probably not high precision.
Overall the meter works great, but there are a few issues.
- The desktop applications hangs on Windows shutdown – This is because of how I developed the program, and a bug in .Net applications that causes programs to lose track of their forms when they’re hidden from the taskbar. I need to change the way I have the application setup to fix this, but since it’s not a huge issue it hasn’t been a priority.
- The desktop application reports CPU activity when there is none, at least on one computer – I’ve seen this on a PC running Windows 7 Professional. Other machines running Windows 7 and XP don’t do this. I’m not sure it’s my implementation of the PerformanceCounter class, or if the class it just giving bad values, but I can’t see anything wrong in the code that would cause this. I need to test it further.
- The 100% position of the meters is affected by the input voltage – The typical USB voltage is 5v, but it can (and does) vary. After finishing the project, and ensuring everything was working great, I moved the PC Meter from my laptop to a desktop PC, and I noticed right away that on the desktop PC, the needles weren’t quite hitting 100% when they should. I suspected the voltage, so got my meter out and checked both machines. Sure enough, they varied. The laptop is right around 5v, and the desktop PC is about 4.9v. It’s a small difference, and the needle position is not affected that much, but I still found it bothersome. One fix would be to use the voltage regulator built into the Arduino, but then I would lose the convenience of plugging in just one cable for power and data. Another idea is adding a potentiometer to the circuit and using it as an adjustment to account for voltage differences.
- Meters for additional statistics – Besides CPU and memory usage, it might be nice to also monitor network bandwidth utilization, individual CPU cores, etc. The PerformanceCounter class supports several stats, and the programs could be modified to support additional values with some simple modifications.
- More aesthetically pleasing meter – I’m happy with how the device looks, but it is fairly simple and a bit “industrial” looking. It might be nice to do something in a wood enclosure with some vintage meters.
Links/Sources of inspiration
The idea for this project and the information needed to complete it came from several sources, some of which I share here.
- Show pc stats on analog gauges – great article with lots of info on interfacing with analog gauges. It’s based on a PIC microcontroller, but much of the info applies regardless of the microcontroller used. It uses the LCD Smartie application to send data over the serial port to the microcontroller. I considered doing this myself before writing my own application. However, development on LCD Smartie appears to have stalled which concerned me, and I wanted to try out the PerformanceCounter class anyways.
- Arduino Analog Gauge – Project that drives meters based on PC stats using an Arduino microcontroller. It is based on the previously mentioned article and also uses LCD Smartie.
- Arduino: Showing CPU load with 9 LEDs! – This project uses LEDs to display CPU load rather than a meter, but it uses a C#.Net application to drive the meter, which I referred to as I learned to do it myself.
- GetPerformanceInfo by Antonio Bakula – this is the code I use to get the memory stats. See this stack overflow post as well.
- mnedix brought the memory% issue in my original application to my attention. Check out his CPU/memory indicator that runs off my C# application but uses nixie tubes instead of panel meters as indicators. Very cool!