BlueCore Tech PC System Monitor — Arduino Mega, 3.2-inch TFT and Windows App

by vandenbrande in Circuits > Arduino

52 Views, 0 Favorites, 0 Comments

BlueCore Tech PC System Monitor — Arduino Mega, 3.2-inch TFT and Windows App

Finished-TFT.jpg
Windows-System-Monitor.png
Arduino PC System Monitor | CPU, GPU & RAM on a TFT Display | BlueCore Tech

Hello world! Today i made a PC System Monitor with an Arduino Mega 2560, a 3.2-inch TFT screen and my own BlueCore Tech Windows software!

This is one complete project: the Windows application collects the computer's statistics, sends them over USB, and the Arduino displays them over custom graphics loaded from a microSD card. The screen shows CPU and GPU temperatures and load, RAM usage, SSD temperature and capacity usage, download/upload rates, uptime, time and date.

I tested two nearly identical HUGA 480x320 TFT shields: an older board without a V2.0 marking and a board marked V2.0. They need separate initialization settings, so both working sketches are included. The comparison photo and instructions below explain which one to use.

The finished design uses a READY handshake to keep Windows and the Arduino synchronized, and updates changed text without reloading the entire background. Follow the steps in order for the hardware, SD files, Arduino code and Windows software.

Created by Danny van den Brande — BlueCore Tech.

Supplies

Hardware

  1. Arduino Mega 2560 or compatible Mega 2560 board.
  2. HUGA 3.2-inch 480x320 TFT LCD shield for Arduino Mega2560, matching either of the two boards pictured below.
  3. microSD card and a card reader. Use FAT32 for this build.
  4. USB data cable matching your Mega and a Windows PC.

Software and files

  1. Arduino IDE with Arduino AVR Boards and the UTFT, UTFT_SdRaw and SdFat libraries.
  2. One of the two supplied Arduino sketches.
  3. SPLASH.RAW and SYSTEM.RAW on the SD card.
  4. BlueCore_System_Monitor_Control.pyw, the Windows companion application.
  5. Python 3.10 (the tested installation was 3.10.11, 64-bit), psutil, pyserial and pythonnet.
  6. LibreHardwareMonitor 0.9.6 .NET Framework runtime DLLs, downloaded from its official release.
  7. Windows administrator access for the application's hardware sensor readings.

No separate temperature sensor or RTC module is required: these readings and the clock come from the PC. This is a Mega shield project; an Uno or a different 2.4-inch shield is not a drop-in substitute.

Understand the Complete System

The USB cable carries both power and serial data between the Mega and the PC. The TFT shield plugs onto the Mega. Its microSD slot holds the graphics; it does not hold the Python program.

  1. Windows reads CPU/RAM/network/uptime data with psutil and hardware sensors through LibreHardwareMonitor.
  2. The Python app waits until the Arduino says READY.
  3. The app sends one line of statistics at 115200 baud.
  4. The Mega updates the text on the TFT and announces READY again.

The Windows app must be running for live PC readings. The Arduino does not measure the CPU or GPU directly, and this version displays statistics rather than controlling PC fans or other hardware.

Identify Your TFT: Older Board or V2.0

Two-Screen-Versions.jpg

Look at the rear of the TFT before fitting it. In the comparison photo, the upper board is the older version without the V2.0 marking; the lower board has V2.0 printed near the Mega2560 text.

  1. Older screen: use BlueCore_System_Monitor_V1.ino.
  2. Screen marked V2.0: use BlueCore_System_Monitor_V2.ino.

Both tested sketches use the same UTFT constructor:

UTFT myGLCD(ILI9481, 38, 39, 40, 41);

The V2 sketch additionally sends display command 0x21 after InitLCD, with chip select asserted:

digitalWrite(40, LOW);
myGLCD.LCD_Write_COM(0x21);
digitalWrite(40, HIGH);

This was the tested correction for the V2 panel. It is not a different RAW file format or a reason to randomly swap drivers. Both sketches retain RAW_SWAP = 0 and use the same graphics. Use the supplied sketch as a whole; the screenshots do not establish compatibility with every similarly advertised shield.

Fit the Shield to the Mega

  1. Disconnect USB power.
  2. Check that your display is the Mega2560 shield shown in the comparison, with matching headers.
  3. Align all header rows carefully and press the shield straight onto the Mega. Check both ends for a one-pin offset or bent pins.
  4. Insert the prepared SD card as described in the next step.
  5. Connect the Mega to the PC using a USB data cable.

No extra signal wires are needed for this tested shield arrangement. The sketches use the Mega parallel TFT connection, control pins 38–41, and SD chip select 53. Do not add a second shield sharing those signals without checking its pin use.

Prepare the MicroSD Card and RAW Graphics

SPLASH_480x320.png
SYSTEM_480x320.png
  1. Back up anything you need from the card before formatting. Prepare a FAT32 card using your normal SD-card tool.
  2. Download the two attached RAW files.
  3. Copy SPLASH.RAW and SYSTEM.RAW directly to the card root, not inside a folder.
  4. If your browser gives a download an unfamiliar extension, restore the exact filenames. In Windows Explorer enable file-name extensions so you do not accidentally create SYSTEM.RAW.txt.
  5. Eject the card safely and insert it into the TFT shield's SD slot while power is disconnected.
SD card root
├── SPLASH.RAW
└── SYSTEM.RAW

Each file is 480 × 320 pixels × 2 bytes = 307,200 bytes, containing the project's RGB565 RAW pixel data. These are not BMP or PNG files. Renaming a PNG to .RAW does not convert it.

Use these final graphics with both sketches. The included PNG images are previews for reference; the Arduino loads the RAW files. The final SSD temperature artwork uses °C and the capacity field uses %.

Install the Arduino Libraries

  1. Open Arduino IDE and install Arduino AVR Boards if it is not already available.
  2. Install UTFT by Henning Karlsen / Rinky-Dink Electronics. UTFT_SdRaw is an add-on, not a replacement for UTFT.
  3. Install UTFT_SdRaw and SdFat.
  4. Restart the IDE if it does not recognize a newly installed library.
  5. Select Arduino Mega or Mega 2560 as the board.

The supplied sketches were compiled with the installed UTFT library, UTFT_SdRaw 1.2.4 and SdFat 2.3.0. SPI is supplied by the Arduino AVR board package. If a header is missing, install that library rather than deleting the include line.

UTFT source and information: Rinky-Dink Electronics UTFT. Use Library Manager for available packages, or Arduino IDE's Add .ZIP Library option for the library author's ZIP.

Download and Upload the Correct Sketch

  1. Download the V1 or V2 sketch for your screen. You only upload one sketch at a time.
  2. Save it inside a folder with the same name as the sketch: BlueCore_System_Monitor_V1/BlueCore_System_Monitor_V1.ino, or the equivalent V2 folder.
  3. Open the .ino file in Arduino IDE.
  4. Select Arduino Mega or Mega 2560 and the COM port assigned to your board.
  5. Stop the BlueCore Windows app and close other programs using that COM port.
  6. Click Verify, then Upload.

Both supplied versions compile for the Mega. They use SD chip select 53 and SPI_HALF_SPEED. Keep these tested settings for the first run.

On startup the sketch initializes the TFT and SD card, displays SPLASH.RAW for approximately 2.5 seconds, then loads SYSTEM.RAW and sends READY. If SD initialization fails, the serial diagnostic is SD INIT FAILED. Open Serial Monitor at 115200 only for diagnosis, then close it before using the Windows application.

Install the Tested Python Environment

The Windows application was tested with 64-bit Python 3.10.11. If you have several Python versions installed, use the version selector explicitly instead of assuming that python starts the right one.

  1. Install Python from the official Python 3.10.11 release page, including the Windows launcher.
  2. Open a Command Prompt or PowerShell window.
  3. Check the selected interpreter, then install the dependencies:
py -3.10 --version
py -3.10 -m pip install psutil==7.2.2 pyserial==3.5 pythonnet==3.1.0

These are the versions used for the publication check. pythonnet connects Python to the .NET LibreHardwareMonitor library. The current program uses direct DLL access; it does not require the older WMI-based setup.

Do not use an old requirements file that omits pythonnet, and do not assume an older launcher selects Python 3.10. The explicit commands in this tutorial avoid that ambiguity.

Create the Windows Application Folder

BlueCore_Header.png
  1. Create a folder such as C:\BlueCore_System_Monitor.
  2. Instructables accepts .py source but not .pyw. Download BlueCore_System_Monitor_Control.py and rename it to BlueCore_System_Monitor_Control.pyw in that folder. Enable file-name extensions in Explorer first. The attachment is byte-for-byte identical to the tested .pyw source; only its download extension differs.
  3. Place BlueCore_Header.png beside it if you want the separate header image available. The program also contains its embedded header.
  4. The settings file BlueCore_System_Monitor_Settings.json can be created by SAVE SETTINGS; choose your own COM port rather than copying COM8 blindly.
  5. Add the runtime DLLs in the next step before starting live monitoring.

The .pyw filename is deliberate: the finished program can run without a spare console window. Do not paste the full application into an Arduino sketch—the Python program runs on Windows and the .ino runs on the Mega.

Add the Correct LibreHardwareMonitor DLLs

Download LibreHardwareMonitor.zip from the official LibreHardwareMonitor 0.9.6 release. Choose that .NET Framework archive, not LibreHardwareMonitor.NET.10.zip and not the source-code archive.

  1. Extract the archive into a separate folder.
  2. Copy the following nine DLLs beside BlueCore_System_Monitor_Control.pyw.
  3. Keep matching versions from the same archive; do not collect unrelated DLL versions from download sites.
LibreHardwareMonitorLib.dll
BlackSharp.Core.dll
DiskInfoToolkit.dll
HidSharp.dll
RAMSPDToolkit-NDD.dll
System.Buffers.dll
System.Memory.dll
System.Numerics.Vectors.dll
System.Runtime.CompilerServices.Unsafe.dll

The nine files from this official archive were checked byte for byte against the working project's runtime files. The clean copy also initialized LibreHardwareMonitor successfully. Hardware sensor availability still depends on Windows privileges, driver support and the PC.

If Windows marks a downloaded trusted file as blocked, use its Properties → Unblock option. Do this only for files you downloaded from the official source. The BlueCore program looks for LibreHardwareMonitorLib.dll next to its own .pyw file and adds that folder to the DLL search path.

There is no need to keep the standalone LibreHardwareMonitor GUI open for BlueCore: the application loads its library directly. If hardware access still fails when elevated, consult the official release's driver requirements rather than replacing the Arduino sketch.

Start the Windows App and Select Your COM Port

  1. Close Arduino Serial Monitor and any other serial terminal.
  2. Open a terminal in your BlueCore application folder.
  3. For the first diagnostic launch, run the command below so error messages remain visible.
  4. Select the COM port assigned to your Mega, set baud to 115200 and start with a 1000 ms refresh interval.
  5. Click START MONITOR. The program requests administrator elevation for hardware sensor access; approve the Windows prompt for your trusted local copy. If it relaunches, click START MONITOR in the elevated window.
  6. Click SAVE SETTINGS after selecting the correct values.
py -3.10 BlueCore_System_Monitor_Control.pyw

For a console-free launch after setup, use the Windows launcher:

pyw -3.10 BlueCore_System_Monitor_Control.pyw

COM8 is the port in my demonstration, not a requirement. The activity log should show the serial connection, Arduino startup/READY messages and transmitted SYS packets. CPU and SSD temperatures may be unavailable without administrator access even when other values work.

Check the Layout With SEND TEST PACKET

  1. Start the connection and wait for the Arduino to finish loading its graphics.
  2. Click SEND TEST PACKET.
  3. Check that the fixed example numbers appear in the correct panels.
  4. Allow the next live update to replace the test values.

The test packet is deliberately queued until the Arduino sends READY. It does not bypass the handshake. The example contains CPU 47°C / 38%, GPU 54°C / 71%, RAM 62% and 19.8/32.0, SSD 39°C / 61%, download 18.4, upload 2.1, uptime 03d 17h, time 03:52 and date 13-10-26.

These are example values for checking placement, not measurements. A successful test proves the serial/display route works; it does not prove that Windows can read every hardware sensor.

Understand the Live Measurements

  1. CPU: temperature from LibreHardwareMonitor; total CPU load from psutil.
  2. GPU: temperature and load from LibreHardwareMonitor, with an NVIDIA nvidia-smi fallback when available. NVIDIA hardware is not mandatory for the entire application.
  3. RAM: percentage used and used/total memory from psutil.
  4. SSD temperature: a storage temperature sensor from LibreHardwareMonitor.
  5. SSD usage: percentage of C:\ capacity filled, not disk activity or read/write speed. On a PC with multiple drives, the temperature sensor and C: may need matching to the intended device.
  6. Download/upload: rates calculated from changes in Windows network byte counters, not an internet speed test.
  7. Uptime: time since the Windows boot time reported by psutil.
  8. Clock/date: local Windows time, HH:MM and DD-MM-YY. No RTC is used.

The program uses binary divisors for memory and network rates although the artwork labels them GB and MB/s. Small idle traffic may round to 0.0. Sleep/hibernation can preserve uptime; a Windows restart gives a fresh boot session.

Unavailable hardware temperature/load readings are shown as N/A rather than invented temperatures. Sensor coverage varies between computers.

Why the READY Handshake Matters

During development, sending packets while the Mega was busy with large RAW images corrupted received data; a date could even contain text like 13-10-SYS. The final implementation synchronizes the sender with the display.

  1. Arduino boots and finishes loading both graphics.
  2. Arduino sends a line containing exactly READY.
  3. Windows waits until it has that READY signal and the refresh interval has elapsed.
  4. Windows consumes the signal and sends exactly one SYS line.
  5. Arduino parses the line and updates the display.
  6. Arduino sends READY for the next update.

A 1000 ms refresh setting means an interval between permitted updates, not permission to send every second regardless of Arduino state. Both normal readings and queued test packets obey READY. Keep this behavior if you extend the project.

The Serial Packet Format

Each packet is one comma-separated line with 15 fields including SYS, terminated with a newline:

SYS,CPU_TEMP,CPU_LOAD,GPU_TEMP,GPU_LOAD,RAM_PERCENT,RAM_USED,RAM_TOTAL,SSD_TEMP,SSD_USAGE,DOWNLOAD,UPLOAD,UPTIME,TIME,DATE

Example:

SYS,47,38,54,71,62,19.8,32.0,39,61,18.4,2.1,03d 17h,03:52,13-10-26

The sender appends the newline character after the date. The Arduino ignores carriage returns, checks the SYS prefix and collects the expected fields into bounded text buffers. It is designed for the included sender, not arbitrary unvalidated CSV input.

If you write another sender, preserve the field order, 115200 baud, newline termination and READY handshake. Do not insert commas into a value or stream multiple lines ahead of the display.

Smooth Text Updates Without Reloading the Background

SYSTEM.RAW is loaded during startup. The final sketches compare each incoming value with its previously displayed text. If a value has not changed, they leave it alone.

For a changed field, the code erases the old character pixels using that panel's calibrated background color, then draws the new text. It does not reload the entire 307,200-byte image for every packet, and it does not paint a large black rectangle over the artwork.

This approach depends on the flat background under each text field. If you design a new background with detailed artwork directly beneath the numbers, simple color erasing will not reconstruct that artwork. Keep the text areas suitable or deliberately redesign the rendering method.

The supplied files contain the final working method; earlier experimental refresh versions are not needed.

Center Anchors, Fonts and Screen-Specific Layout

The saved X coordinates are the centers of fields, not the left edges. UTFT print positions therefore need a width adjustment:

startX = anchorX - (strlen(text) * fontWidth) / 2;

Drawing directly at anchorX shifts the text too far right. The old and new text must each be centered using their own widths when a value changes.

Large temperatures, RAM percentage, network rates and time use white BigFont. CPU/GPU load and SSD capacity use green SmallFont; RAM used/total and uptime use cyan SmallFont; the date uses white SmallFont.

The two attached sketches preserve their tested coordinates. For example, RAM_USED_X is 291 in V1 and 289 in V2. Do not overwrite one version with the other's coordinates just to make the source files identical. Start with the matching sketch and supplied artwork before customizing placement.

Using the Monitor on a Different Windows PC

The application contains preferred sensor identifiers from the development PC, plus fallback selection. Another motherboard, processor, GPU or drive may expose different identifiers.

  1. First verify the test packet so you know the Arduino/display connection is working.
  2. Run the app elevated and confirm that LibreHardwareMonitor initializes.
  3. If a particular reading is N/A or appears to refer to another device, inspect that PC's sensors using the official LibreHardwareMonitor application.
  4. Compare the appropriate sensor identifiers and the preferred IDs/fallback logic in a separate copy of the Python source.
  5. If monitoring a drive other than C:, adjust SYSTEM_DRIVE in that copy and select a matching temperature sensor.

Keep the original working download as a reference. A missing sensor is a Windows/hardware support issue; changing the TFT driver will not create it.

Troubleshooting

White screen or incorrect colors: check the exact shield revision and use its matching V1/V2 sketch. V2 includes 0x21; both use ILI9481 and RAW_SWAP = 0. Check shield alignment with power disconnected.

SD INIT FAILED or missing background: check the card, FAT32 preparation, root filenames, file sizes and seating. Keep CS 53 and SPI_HALF_SPEED. Do not substitute PNGs or add the old sd.exists experiments—the supplied direct-load code is the working version.

App cannot open COM port: close Serial Monitor and other serial programs, select the actual Mega port, then STOP and START after reconnecting. A charge-only USB cable will not provide a serial connection.

App will not launch: run it from a terminal with py -3.10 to see the error. Install all three Python dependencies into that interpreter.

DLL load error: confirm all nine matching DLLs are beside the .pyw file, use the .NET Framework archive and check trusted-file blocking. Do not mix the .NET 10 archive into this setup.

CPU/SSD N/A: confirm administrator mode and supported hardware access. GPU-only readings do not prove CPU/SSD sensor access works. Consult LibreHardwareMonitor's hardware/driver support for that PC.

Connected but no changing values: check for an exact READY line after startup. Do not fix it by flooding the port; verify the sketch, SD loading and baud rate.

Corrupted date or merged packets: use the supplied app and its READY handshake. Close any second sender.

Text shifted or remnants behind values: retain the center-anchor calculation and the matching background colors. Verify the original graphics before editing the layout.

SSD 95% while PC is idle: that is occupied storage capacity, not disk load. Network 0.0 can simply mean very little traffic.

Downloads, Credits and Next Ideas

The Arduino sketches, SD graphics and Windows source belong to this single project. Use one matching sketch, both RAW files and the Windows application with its dependencies. Keep the downloaded original files as a reference before experimenting.

The photos show the finished display and Windows app, and the two physical TFT revisions. Both screen versions were tested during the build. The publication checks compiled both sketches and verified the clean runtime's DLL loading and packet format; sensor availability on your PC must still be checked during setup.

Thanks to the authors of UTFT, UTFT_SdRaw, SdFat, psutil, pyserial, pythonnet and LibreHardwareMonitor. Third-party libraries retain their own licenses; download their files from the original projects.

Possible future additions include a custom enclosure, alternative dashboard artwork and more configurable sensor selection. They are ideas for extending the build, not features required for this version.

Have fun building it! — Danny van den Brande / BlueCore Tech