I'm building a new high end desktop PC, and due to a delay in getting the processor shipped to me I've been wasting time thinking of what accessories to fill up those unused 5.25" bays.
I saw some widgets with LCDs to display temperature and fan speeds, etc. However after reading reviews I'm not thrilled with any of them. Additionally they don't read the real temperatures, they have probes you glue on.
That got me thinking of a quickie project that would be fun. I'll make a panel LCD myself, I'd like to display the CPU load, or other parameters, and temperatures if I can. I know it's fairly hard to pull the temperatures from motherboards due to the wide variety of designs.
The basic design will be this. I'll use an Arduino with an LCD plugged into either a USB port or onto a USB header on the mother board. It will be a fairly simple serial client that displays whatever text you send it.
Running on the PC will be a Java program feeding info to the USB serial com port. The Java program will pull the CPU load and System temperatures and format it for display. I could do color changes, whatever to make it fancy.
The first task is to access the desired information from the Java program running on the Windows PC.
Some useful posts
- http://stackoverflow.com/questions/47177/how-to-monitor-the-computers-cpu-memory-and-disk-usage-in-java
- http://stackoverflow.com/questions/634580/cpu-load-from-java
- http://sellmic.com/blog/2011/07/21/hidden-java-7-features-cpu-load-monitoring/
Some info can be pulled from within Java, but it is fairly limited. I tried this code pasted into a little netbeans program
OperatingSystemMXBean OS = ManagementFactory.getOperatingSystemMXBean();
jLabelCPUs.setText("Number of CPUs: "+ Integer.toString(OS.getAvailableProcessors())+ " " +OS.getArch());;
jLabelLoad.setText("CPU load: "+ Double.toString(OS.getSystemLoadAverage()));
The OS.getSystemLoadAverage() always Returns -1. A little more reading reveals that this doesn't work on Windows. Not definitive but discouraging. The CPU architecture commands do work though.
Instead I thought I'd run a windows command line program from within Java and pull the output. This approach worked much better.
http://stackoverflow.com/questions/9097067/get-cpu-usage-from-windows-command-prompt
There are two basic approaches. wmic and typeperf. Entered these commands into a cmd window and got back a string of the CPU load. Both have some pretty obscure command arguments.
wmic cpu get loadpercentage
typeperf -qx "\Process" > config.txt typeperf -cf config.txt -o perf.csv -f CSV -y -si 10 -sc 60
Now to embed this in Java and get the output back to the Java program.
This Java code runs the cmd line wmic.
try {
Process p = Runtime.getRuntime().exec("wmic cpu get loadpercentage");
} catch (IOException ex) {
System.out.println("cmd line failed");
Logger.getLogger(BlingGui.class.getName()).log(Level.SEVERE, null, ex);
}
Looking for how to get the output back, I see I just gotta use buffered stream to read it:
Back to polishing up the windows cmd line commands to get the data I want.
Wmic is awesome! I can get more than cpu load. All sorts of process and machine info.
wmic cpu get currentClockSpeed
wmic cpu get loadpercentage
Typeperf is also very useful.
http://technet.microsoft.com/en-us/library/bb490960.aspx
This command gives processor and memory usage in running 1 second intervals. Awesome.
typeperf "\Memory\Available bytes" "\processor(_total)\% processor time"
This makes just one sample, also seems a little slow to respond
typeperf -sc 1 "\processor(_total)\% processor time"
typeperf -sc 1 "\processor(_total)\% processor time"
typeperf command format is a mess to escape in Java, but got it to work like this:
Process p = Runtime.getRuntime().exec("typeperf \"\\processor(_total)\\% processor time\" ");
Process p = Runtime.getRuntime().exec("typeperf \"\\processor(_total)\\% processor time\" ");
This makes just one sample at a time.
typeperf -sc 1 "\processor(_total)\% processor time"
typeperf -sc 1 "\processor(_total)\% processor time"
Here is the output of typeperf writing to a hack GUI in Java. The yellow is the CPU%. Obviously haven't done the formatting yet. Making progress!
I wasted some more time looking for how to get the temperature command line, and it is not easy. I'm avoiding using somebody else's freeware program like CPUID or speedfan. Both of which work but won't get me to my goal. I'm going to stick with CPU load, memory and frequency data for the prototype.A little more work and I have a Java performance meter program. Grabbed the cmd line output, did some string manipulation and formatting. I haven't added the serial client stuff yet to talk to the Arduino yet. This demos all three methods. Java commands, wmic and tyeperf commands. The typeperf is the one running the progress bar.
The executable is here: https://code.google.com/p/arduino-java-xyzcnc/downloads/list
This is the gist of the code, minus the GUI stuff.
public BlingGui() {
initComponents();
this.setVisible(true);
OperatingSystemMXBean OS = ManagementFactory.getOperatingSystemMXBean();
jLabelCPUs.setText("Number of CPUs: "+ Integer.toString(OS.getAvailableProcessors())+ " " +OS.getArch());;
Timer t_update = new Timer(10000, new ActionListener(){
private String t1;
@Override
public void actionPerformed(ActionEvent e){
try {
Process w1 = Runtime.getRuntime().exec("wmic cpu get CurrentClockSpeed");
BufferedReader stdInput1 = new BufferedReader(new InputStreamReader(w1.getInputStream()));
BufferedReader stdError1 = new BufferedReader(new InputStreamReader(w1.getErrorStream()));
while ((t1 = stdInput1.readLine()) != null) {
if(t1.length()!=0)
if( Character.isDigit( t1.charAt( 0 ) )) jLabelFreq.setText("Clock: "+ t1.trim() +" MHz");
}
} catch (IOException ex) {
System.out.println("cmd line failed");
Logger.getLogger(BlingGui.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
t_update.start();
try {
// execute windows command line: typeperf -sc 1 "\processor(_total)\% processor time"
Process p = Runtime.getRuntime().exec("typeperf \"\\processor(_total)\\% processor time\" ");
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
// read the output from the command
System.out.println("Here is the standard output of the command:\n");
String s;
while ((s = stdInput.readLine()) != null) {
s = s.replace("\"", "");
String[] sArray = s.split(",");
s = sArray[sArray.length-1].trim();
jLabelLoad.setText("CPU Load: " + s + "%");
try {
jProgressBarCPU.setValue( Integer.valueOf(s.indexOf('.') ));
double dd = Double.valueOf(s);
int gg = (int) dd;
jProgressBarCPU.setValue( gg);
if (gg<33) jProgressBarCPU.setForeground(Color.green);
else if (gg<66) jProgressBarCPU.setForeground(Color.orange);
else jProgressBarCPU.setForeground(Color.red);
} catch (Exception e) {
//Sometimes this is not a number
}
}
// read any errors from the attempted command
System.out.println("Here is the standard error of the command (if any):\n");
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
} catch (IOException ex) {
System.out.println("cmd line failed");
Logger.getLogger(BlingGui.class.getName()).log(Level.SEVERE, null, ex);
}
}
Next step is to combine this with my Arduino serial communication program to send the CPU load data to an external Arduino with LCD shown in this post:
http://blog.workingsi.com/2013/01/revisiting-arduino-control-from-pc.html
This is just for prototyping, I'll build a custom LCD unit that fits in a drive bay once I get the s/w working.
For proof of concept I did a Frankenstein and simply pasted the CPU monitor GUI class right into my serial comm tool. That way I use that tool to find the Arduino comm port and connect, and then the CPU monitor kicks in and sends the CPU load string information as if I were pushing the send button on the GUI.
The Arduino is just running the Examples->Liquid Crystal->SerialDisplay sketch right out of the box.
The hardware is an Ardino with a large 4x20 LCD connected just like the Arduino example says. I won't repeat all that here. I reused this from http://blog.workingsi.com/2011/02/arduino-lcd-countdown-clock.html. Everybody should have an Arduino with an LCD on it lying around for emergencies.
W00t! It works!. Here is the PC running the serial comm tool, with the new CPU GUI below it. On top of the screen is the Arduino/LCD displaying the CPU load every second.
Now to clean up the code and make the LCD display a bar graph instead of just number.
The Arduino code need some upgrades.
- Sleep whenever it hasn't gotten data in a while. Turn off the LCD backlight and blank the display.
- Initially send a character like "AAAAA" until it's connected so the Java GUI can find it and initialize communication
- Eventual features using the Analog pins to control some LEDs brightness or color
/*
LiquidCrystal Library - Serial Input
This sketch displays text sent over the
serial port
(e.g. from the Serial Monitor) on an attached
LCD.
The circuit:
*
LCD RS pin to digital pin 7
*
LCD Enable pin to digital pin 6
*
LCD D4 pin to digital pin 5
*
LCD D5 pin to digital pin 4
*
LCD D6 pin to digital pin 3
*
LCD D7 pin to digital pin 2
*
LCD R/W pin to ground
*
10K resistor:
*
ends to +5V and ground
*
wiper to LCD VO pin (pin 3)
http://arduino.cc/en/Tutorial/LiquidCrystalSerial
*/
// include the library code:
#include <LiquidCrystal.h>
const int backlight = 8; // the LED backlight is wired to pin 8
long previousMillis = 0; //stores the last time the display
got data
// initialize the library with the
numbers of the interface pins
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);
void setup(){
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// set up the LCD backlight
pinMode(backlight, OUTPUT);
digitalWrite(backlight, LOW);
// initialize the serial communications:
Serial.begin(9600);
establishContact(); // send a
byte to establish contact until receiver responds
}
void loop()
{
// when characters arrive over the serial port...
if (Serial.available()) {
// wait a bit for the entire message to arrive
delay(100);
// clear the screen
lcd.clear();
// wake up and turn on the backlight
digitalWrite(backlight, HIGH);
previousMillis = millis();
// read all the available characters
while (Serial.available() > 0) {
// display each character to the LCD
lcd.write(Serial.read());
}
} else if (millis() - previousMillis > 10000) {
//turn off the backlight and clear the display
digitalWrite(backlight, LOW);
lcd.clear();
}
}
void establishContact() {
while (Serial.available() <= 0) {
Serial.println("Z");
// send an initial string
delay(300);
}
}
It is also clear the Arduino itself is too tall and I will have to use a right angle header to connect to the LCD.
It occurred to me that I would also like to have some connector/header on the front I can use to access a few of the pins of the Arduino so I can use it for development and whatever GPIO project I dream up.
This vacuum fluorescent one looks cool, a bit pricey at $29
http://www.adafruit.com/products/347
http://www.adafruit.com/datasheets/20T202DA2JA.pdf
It also has a serial interface. That will save pins but require the code to be changed.
Outer dimensions are 37mm x 116mm. It will just barely fit.
http://www.adafruit.com/products/399#Downloads
This one is 36x80mm and has a three color backlight. $14. Only 2x16 chars
$31, 116mm x 37mm, 20x2, parallel interface like I'm used to. However price is a bit steep, not sure if VF is worth it.
Searched a while, decided the VF displays are too expensive and I like the multicolor backlight price and convenience of LCD.
Digikey has this one, looks similar to the one on Adafruit.
http://www.digikey.com/product-detail/en/NHD-0216K1Z-NS(RGB)-FBW-REV1/NHD-0216K1Z-NS(RGB)-FBW-REV1-ND/2172436
I decided to get the Adafruit display, they say they have resistors onboard for the backlight, and it comes with a trim pot.
The display came. I'm going to mount it in an old 5.25 bay blank plastic cover from an old PC. Here is the display sitting on top of the plastic blank bay cover.
My plan is to wire it up just like the Adafruit tutorial
Plugged in the IDE ribbon cable to the headers. I used an ohm meter to double check the wiring. I found no mistakes. First time that ever happened.
Attached the Arduino to the protoboard, plugged in the USB. I copied the code directly from the Adafruit page since the hardware was exactly the same as they show. http://learn.adafruit.com/character-lcds/rgb-backlit-lcds. Plugged in the USB, uploaded the sketch, twisted the pot until the contrast showed the words. Win on the first try!
Rather than remake the front panel, I put some electrical tape on the edges of the display to stop the light leakage, and used foam tape to mount the display in the panel blank. I decided to forge ahead and throw it together to see if there were any issues and polish up the software. It does look a tad ratty. LCD is crooked and the cutout is ragged. The picture even makes it look worse than it does in real life.
Hopefully I'll go back and remake the front panel and mount the LCD better later.
while (Serial.available() > 0) {
// display each character to the LCD
//lcd.write(Serial.read());
char temp;
temp = Serial.read();
if (temp=='^') setBacklight(0, 255 , 0);
else if (temp=='<') setBacklight(255 , 0, 0);
else if (temp=='>') setBacklight(0, 0 , 255);
else if (temp=='@') lcd.setCursor(0,0);
else if (temp=='$') lcd.setCursor(0,1);
else lcd.write(temp);
}
This chart shoes how to combine the RGB to get different colors
http://dba.med.sc.edu/price/irf/Adobe_tg/models/rgbcmy.html
I also found that many of the combinations, at reduced brightness have a bad flicker. That is probably due to the PWM on the arduino being too low. Since I don't want to mess up the delay timers, I'm just going to pop the brightness on those colors.
if (temp=='^') setBacklight(0, 255 , 0); //green
else if (temp=='<') setBacklight(255 , 0, 0); //red
else if (temp=='>') setBacklight(0, 0 , 255); //blue
else if (temp=='{') setBacklight(0, 255 , 128); //cyan
else if (temp=='}') {
brightness = 255; //must max out to prevent flicker
setBacklight(255, 100 , 0); //orange
}
else if (temp=='|') {
brightness = 255; //must max out to prevent flicker
setBacklight(128, 0 , 255); //purple
}
else if (temp=='~') {
brightness = 255; //must max out to prevent flicker
setBacklight(255, 0 , 255); //magenta
}
else if (temp=='&') {
brightness = 255; //must max out to prevent flicker
setBacklight(255, 255 , 255); //grey
}
else if (temp=='_') {
brightness = 255; //must max out to prevent flicker
setBacklight(255, 255 , 0); //yellow
}
else if (temp=='@') lcd.setCursor(0,0);
else if (temp=='$') lcd.setCursor(0,1);
else lcd.write(temp);
some juicy lines....I marked the ones that I liked in red. Some didn't seem to work and gave back 0.
\Processor Information(0,_Total)\% of Maximum Frequency
\Processor Information(0,1)\% of Maximum Frequency
\Processor Information(0,0)\% of Maximum Frequency
\Processor Information(_Total)\Processor Frequency
\Processor Information(0,_Total)\Processor Frequency
\Processor Information(0,1)\Processor Frequency
\Processor Information(0,0)\Processor Frequency
\Processor(0)\% Processor Time
\Processor(1)\% Processor Time
\Processor(_Total)\% Processor Time
\Memory\Page Faults/sec
\Memory\% Committed Bytes In Use
\Memory\Available KBytes
\Memory\Available MBytes
\PhysicalDisk(0 C: D:)\Disk Transfers/sec
\PhysicalDisk(_Total)\Disk Transfers/sec
\PhysicalDisk(0 C: D:)\Disk Reads/sec
\PhysicalDisk(_Total)\Disk Reads/sec
\PhysicalDisk(0 C: D:)\Disk Writes/sec
\PhysicalDisk(_Total)\Disk Writes/sec
\PhysicalDisk(0 C: D:)\Disk Bytes/sec
\PhysicalDisk(_Total)\Disk Bytes/sec
To dump all the ones I want, I used this command:
Funny, using this command I discovered on my work laptop that the power management settings were running the CPU capped at 800MHz. Turning up the slider to "performance" got the CPU speed up to 2534. It is much peppier now. A nice Easter egg.
Here is the typeperf command in Java with all the escapes
final Process p = Runtime.getRuntime().exec("typeperf "
+ "\"\\Processor Information(0,0)\\Processor Frequency\" "
+ "\"\\processor(_total)\\% processor time\" "
+ "\"\\Memory\\% Committed Bytes In Use\" "
+ "\"\\PhysicalDisk(_Total)\\Disk Bytes/sec\" "
+ "");
I wrote some code to slice up the response and pull out the numbers, and change color depending on load. Ha ha funny part is the new machine is so bloody fast it is almost impossible to max out the CPU. I finally had to download Sisoftware sandra benchmark tool. No amount of running youtube videos even got me to 10% CPU load.
Here is a snippet of the Java that decodes the typeperf response, makes a bar graph and changes the color of the display using the control characters.
String sp;
while ((sp = stdInputp.readLine()) != null) {
//Parse and clean up the typeperf response
jMessageArea.setText(sp);
sp = sp.replace("\"", "");
String[] spArray = sp.split("\\s*,\\s*");
try {
//System.out.println(spArray[1]+" "+ spArray[2]+" "+ spArray[3]+" "+ spArray[4]);
float CPUfreq = Float.valueOf(spArray[1]);
float CPUload = Float.valueOf(spArray[2]);
float MemUsed = Float.valueOf(spArray[3]);
float diskBytes = Float.valueOf(spArray[4]);
int CPUf = (int) CPUfreq;
int CPUl = (int) CPUload;
int memu = (int) MemUsed;
int bargraph = (int) (CPUload*16/100 + 0.5);
String bars = "";
for (int jj=0; jj<bargraph; jj++) {
bars=bars.concat("=");
}
String displayString = bars + "$" + Integer.toString(CPUf) + "MHz Mem" + Integer.toString(memu)+"%";
// add color control characters based on load
if (CPUload>79) displayString = "<" + displayString; //red
else if (CPUload>49) displayString = "}" + displayString; //orange
else if (CPUload>24) displayString = "_" + displayString; //yellow
else if (CPUload>14) displayString = "^" + displayString; //green
else displayString = ">" + displayString; //blue
send(displayString);
}
catch (Exception e) {
System.out.println("Exception "+ e.toString());
}
}
I left the Java GUI fairly rough, since it will run in hidden mode most of the time. The Hide button sets the form to run invisibly. This is detecting several Arduinos on the system at once, and automatically picking the one that is sending the QQQQQ stream identifying itself.
I need to put the .jar file somewhere it will start when the computer starts, so I put the .jar executable into the startup folder.
The video is a bit like a minute of watching paint dry, but you can see the processor benchmark test finish and ramp down the processor load. In these videos I wasn't showing the Memory load yet.
http://code.google.com/p/arduino-java-xyzcnc/downloads/detail?name=SifishCPUMonitor.jar
If you try to run this, the usual caution that you need Java JRE installed on your machine, plus you have to copy the rxtx jar and dll to the proper places from the Arduino directory. The java program will prompt you to do it if you don't do it right. It's covered in my other posts.
This comment has been removed by a blog administrator.
ReplyDeleteA delightful scrutinizing for any person who values examining on the web diaries.
ReplyDeletebest ultra wide monitor for gaming
This is an incredible rousing article.I am basically satisfied with your great work.You put truly exceptionally accommodating data... 4k compute rmonitor
ReplyDeleteThere are two forms of LED backlighting techniques that are currently used. One is RGB dynamic LED along with the other one is edge LED. Visit Site
ReplyDeleteFinally, it is absolutely forbidden to touch your LCD monitor with your bare hands as the pressure applied on the screen will cause damage to the delicate pixels and that in turn would make that pixel turn black and not work.
ReplyDeleteRead 144hz Monitor Reviews
When shopping for a monitor for gaming or multimedia you will see manufactures brag about their response time. Although response rate or latency is extremely important when it comes to games, the manufactures derive this number in various ways. here
ReplyDeleteCrucial online marketing you just it applies seek before submission. It will probably be simple and easy to jot down advanced write-up which. https://gecey.com/24-inch-tv
ReplyDeleteIf more people that write articles really concerned themselves with writing great content like you, more readers would be interested in their writings. Thank you for caring about your content. Best 240HZ Monitor 2019
ReplyDeleteThe expenses of supplanting a windshield costs considerably more and differs, contingent upon the vehicle. computer upgrade service
ReplyDeleteThe biggest advantage of playing Escape from Tarkov is that you are virtually playing in real time and it provides for extremely high replay value. For more ideal details about escape from tarkov, visit this link
ReplyDelete.
someone to write your essay is a great way of relieving your academic stress. Homework Help Online Despite this fact, many students are still skeptical about hiring someone to do their assignment and homework.
ReplyDelete