Hey there!
Here's an update on the project progress.
Firstly, my Arduino firmware.
The host script, that collects CPU and RAM load data and pushes it to /dev/ttyUSBn does not exist, yet. I'll publish it in this thread, once it's done.
/*
Serial Analogue Duty Cycle Meter
Arduino firmware
Author: faekjarz
Version: 20161124.2
License: WTF-DNSM (Public Domain -ish)
> Do Whatever The Funk you want with it, but
> Do Not Sue Me if it burns your house and/or kills your cat!
Developed and tested on an Arduino Nano 3 clone w/ CH340G USB tty
The communication protocol is simple. One line per dataset,
terminated by a line feed char (\n). A dataset comprises of an integer
channel identifier, a colon, and a duty cycle integer of max 3 digits.
e.g. 0:42\n1:69\n0:100\1:0
Datasets will be somewhat validated, and the duty cycle values will be
constrain()ed to the range of 0 to 100 (%). The duty cycle values will
then be map()ed (translated) to the calibrated full scale PWM values.
For full scale PWM calibration, i used the Fade example,
from the Arduino IDE: File > Examples > 01.Basics > Fade.
I adjusted fadeAmount to 1 and played with the 255 in the if statement.
I used an initial maximum of 100, and a 22k resistor between pin and meter,
then incremented my way up to full scale, until the needle didn't move further.
Channel data is identified by the array index.
i.e. chPin[0], calPWMfs[0], ...[0] relate to channel 0 (1st),
chPin[1], calPWMfs[1], ...[1] relate to channel 1 (2nd), ...
If your setup has more than two meters, well then, just add more channels. ;D
Only the first 3 variables, chCount, chPin, and calPWMfs, have to be altered.
*/
// the amount of channels: 2 meters = 2 channels = 2
// afaik, there is no method to count array elements, must set manually
const int chCount = 2;
// to wich pins the meters are connected
const int chPin[] = {3, 5};
// calibrate max PWM for full scale deflection
// These are MY values, for MY meters, and MY 22k resistors
// Your cal may vary.
// 0, right, yellow, 152
// 1, left, red, 177
const int calPWMfs[] = {152, 177};
// miscellanious initialisation
const boolean d = true; // serial debugging
const int loopDelay = 50; // milliseconds (1/1000)
boolean inputReady = false;
String inputString;
int seppos;
int ch;
int duty;
int valDuty[chCount]; // an array with chCount elements
int valPWM[chCount]; // an array with chCount elements
void setup ()
{
// initialise UART
Serial.begin(9600);
Serial.println("begin");
if(d)Serial.println("debug output is enabled");
if(d){Serial.print("channels: ");Serial.println(chCount);}
// set meter pin mode
for (int i = 0; i < chCount; i++)
{
pinMode(chPin[i], OUTPUT);
if(d){Serial.print("channel ");Serial.print(i);Serial.print(" pin ");Serial.print(chPin[i]);Serial.println(" mode: OUTPUT");}
}
}
void loop ()
{
// handle input when ready
if (inputReady)
{
if(d){Serial.println("inputReady");Serial.print("inputString: '");Serial.print(inputString);Serial.println("'");}
// find separator
seppos = inputString.indexOf(':');
if(d){Serial.print("seppos: ");Serial.println(seppos);}
// validate separator position
if (seppos < 1)
{
if(d){Serial.println("nope: invalid input");}
}
else
{
// extract channel id field
ch = inputString.substring(0, seppos).toInt();
if(d){Serial.print("ch: ");Serial.println(ch);}
// extract duty cycle field
duty = inputString.substring(seppos + 1).toInt();
if(d){Serial.print("duty: ");Serial.println(duty);}
// constrain duty cyle value (0 - 100%)
duty = constrain(duty, 0, 100);
if(d){Serial.print("constrained duty: ");Serial.println(duty);}
// update memory and meters only if changed
if (duty == valDuty[ch]) {
if(d){Serial.println("nope: no changes");}
}
else
{
if(d){Serial.print("old valDuty[ch]: ");Serial.println(valDuty[ch]);}
valDuty[ch] = duty;
if(d){Serial.print("new valDuty[ch]: ");Serial.println(valDuty[ch]);}
// map value to calibrated PWM value
valPWM[ch] = map(valDuty[ch], 0, 100, 0, calPWMfs[ch]);
if(d){Serial.print("mapped valPWM[ch]: ");Serial.println(valPWM[ch]);}
// update meter pin, set new PWM value
analogWrite(chPin[ch], valPWM[ch]);
}
}
// handling done reset input vars
inputString = "";
inputReady = false;
}
// everyone loves a little nap, right?
delay(loopDelay);
}
void serialEvent ()
{
while (Serial.available())
{
// collect new byte
char newb = (char)Serial.read();
// check for newline (\n), end of dataset
if (newb == '\n')
{
inputReady = true;
}
else
{
// append to string variable
inputString += newb;
}
}
}
Secondly, a picture of the disassembled dual meter, that arrived from China the other day.
(https://pbs.twimg.com/media/Cx8664OWQAABFmt.jpg:large)
…and a screen shot of the Serial Monitor with some debug output
(https://pbs.twimg.com/media/CyAI4rIWQAUwMgZ.jpg:large)