Analog screen meter

Dire Straits

My favorite band from the 70s, and Mark Knoffler is still my favorite lead guitarist.

Lefty

Dear KE7GKP
OK I get that you don't like spammers. I don't like spammers. Nobody likes spammers. Their own mothers don't like spammers. I'm sorry you got disappointed that there is no real way of saving money by getting 16 bit resolution from a cheap chip. So am I !!
If I minded looking stupid I wouldn't ask stupid questions. Someeone said if you ask stupid questions you look stupid --- if you don't ask stupid questions you stay stupid.
Re differential input -- surely if it didn't do what I said the manufacturers wouldn't put it in a chip; what other reason would there be for it?
Re efficiency -- we're hobbyists, friend. We'll spend 20 hours cooking up something we could buy for $10, working in effect for 50 cents an hour because it's FUN!!
So far is one person says it's tricky and in-efficient. What I need to know is can it be done?

What I hope is final word on subject, with more risk of appearing even stupider --- when I think of it, isn't what I want to do very similar to the logic in an auto-ranging multimeter? If so, what's so damned impossible, or stupid or unreasonable about it? Here we go, KE7GKP --- lay it on me. Waiting....
Seriously, it's all very esoteric. The concept of earth seems to be relative only, and there is no absolute standard earth other than some arbitrary less than a higher potential. What I read about differential input in an adc seems to my poor old brain to push the idea of being able to select a range in which the bottom input is still higher than the chip earth. If I've got it that wrong maybe I should take up something simpler before I electrocute myself.

qmt5:
isn't what I want to do very similar to the logic in an auto-ranging multimeter?

An auto-ranging multimeter always references to ground... wait, what was the question again?

and there is no absolute standard earth other than some arbitrary less than a higher potential.

There is, it is the potential of a stake in the ground. A lot of people mix up this with the common signal point in a circuit as these are often tied together. I think you are missing the point about the accuracy you need on those potential dividers. There is a concept called Monoticity basically it means that a higher reading is given by higher voltages. A not altogether unreasonable thing to ask from an A/D.
With your scheme you need a very high order of accuracy on your resistors so that the readings made on one range map to a reading on the range next to it. With only 1% resistors you can't do that. That is why a good auto-ranging multimeter is quite expensive or rubbish.

Hi Mike, it's all pretty new to me but I had found a couple of things I didn't fully understand (quotes below) which suggested my idea was feasible. But I see what you mean about accuracy. If you're interested, the second reference below deals with the overlap problem. It's possible but not simple.
Anyhow, hope I'm not loading the forum too much. I'll stop now. Never been in a forum before.
"... have contemplated using a normal ADC with a MUX Serial/Analog Mux/Demux - 74HC4052 - COM-09907 - SparkFun Electronics and tune each section to a seperate voltage range, then scan till its in range and ADC the signal then. I didn't want to have to manipulate the data that much. Or use a 4 2.5V ADCs using relative ADC line references and scan 0 - 2.5, 2.5 - 5, 5 - 7.5 , and 7.5 - 10. Then add them together in the end to get the total ADC...."
http://electronics.stackexchange.com/questions/7597/24bit-or-better-adc-at-10v-with-at-least-100ksps
"..... prepared to make a table of values of U R which we can threshold with the
measured value to determine when to switch ranges. An ..."
http://jameskbeard.com/Rowan/Electronics_I_ECE_Materials/Microcontroller_Breath_Analyzer_Lab_Protocol_01.pdf

I totally get what you are saying, and I'm curious as to how this will pan out. I think it may be that scaling on the resistor accuracy is the inherent gotcha... certainly seems to be the kind of thing I end up learning after coming up with some grand scheme in my mind.. LOL

I've always liked the idea of measuring the charge time of a capacitor against a comparator. Not sure if this is a used method, and I suspect sample rate is the gotcha there, but I'd always thought that a comparator vs. a known quantity ought to be darn accurate. Comparators are built in to the Arduino also, but I don't think the language addresses them directly, I think you need to go under the hood for a few lines of C and fiddling to use them.. though probably worth it, if only for the fiddle factor. Kinda surprised comparator functions aren't part of the language actually, now that I think about it..

1000% on the "Of course someone else has done it better, cheaper, faster, and thirty years ago to boot!" -- I have a great passion for re-inventing the wheel, perhaps you'd be a fan of my most recent design, it's rectangular so it's easy to carry....

Arduino (in my humble opinion) is all about "doing it the wrong way" (well, at least be safe, fire is bad, ummkay?) and learning from it. Take my advice and order some spare 328's, you are going to cook a few of them. Cheap lessons at $5 each. In fact, a couple of times I've seen a decent price difference downward on 168's, and I'd think the same happens with 88's. The 32-16-8 refers to flash program memory, otherwise the chips are largely interchangable-- so if you sketches are small, and you are ending up blowing chips, might make sense to get a few of the cheaper versions if the price point is right...

A thought-- maybe you could revise the title of the post to be more clear.. swarms of broke hobbyists seeing something like "free money" or "Tech Dumpster Around Back" kinda chums the waters, lol.

As the subject is new to me my approach changes as I learn more. For instance, analog to digital converters are becoming increasingly scarce and expensive in 'thru-hole' form, whereas SMD chips seem to be becoming more available in higher specs with lower prices. Initially I developed a simple and cheap self-aligning device to connect SMD chips without having to solder them, which was fast and reliable. Great for poor old guys like me with the 'shakes'. But recently I discovered reflow soldering with solder paste, and found it to my surprise both fast, simple and reliable. Now, currently available in SOIC packaging is the MCP3422, which has software control for 12, 14, 16 and 18 bit ADC, has a built in multiplexer, full differential inputs, and built in op amp giving gains of x1, x2, x4, and x8. I can get then for about $2 !!!. Different ball game -- less need for 'stepped' input. But then I found the 74HC4052, which is a serial/analog mux/demux chip. This is analog as well, so you can pass analog values thru the IC !! It's cheap as well.
Digressing, my heading says 'money for nothing'. It meant get $50 worth of adc capacity for under $10. I still think it's possible, but I want to change the heading to something else --- it upsets people. How do I do this?

I've always liked the idea of measuring the charge time of a capacitor against a comparator.

The problem is you need to know the exact value of the components. Now if you use the dual ramp method the component values drop out.

I want to change the heading to something else

View the first post and hit the modify button. Then change the title and hit save. You can do this on all posts you made, not other peoples but the first post name is what will show up in the list of posts.

I'm changing the title of this post from 'Money for Nothing', which seems to piss people off, to 'Screen Analog Meter'. All this started when I wanted to reproduce an analogue meter on screen with software i.e. moving needle. There is a degree of inertia in a physical system that dampens out 'jitter'. I got a lot of jitter. I tried all sorts of jitter removal --- averaging & hysteresis software solutions, handshaking, slower and faster data transmission, binary data transfer instead of string transfer. I could set up a for/next loop and get smooth movement, but when I sent data over to processing the poor old needle got delusions of grandeur, thought it was a quantum particle & tried to be several places at once. I was using a pot for tests & maybe some of it was rough surface, but not all.
I was dropping a lot of data in the transfer. Reason I got off into higher resolution adc's was I thought that might be the answer, and in the process figured a way to get more bits out of a cheap adc --- hence the dumb 'Money for Nothing' heading. But higher resolution isn't the answer. I think it must be in converting the high speed & jumpy stream of data with something like a for/next loop with small steps. I'll see how that goes.

But higher resolution isn't the answer. I think it must be in converting the high speed & jumpy stream of data with something like a for/next loop with small steps. I'll see how that goes.

The jumpy needle can be calmed down by telling the needle to move only if the value that it is to represent has changed by a significant amount. If the needle represents a voltage, and the input is a value from 0 to 1023, perhaps only move the needle if the value has changed by more then 3.

In a stream of values like 456, 457, 455, 480, 481, 479, etc., draw the needle at the 456 position. Skip the 457 and 456 values, since the needle is already close enough. Draw the needle in the new position, represented by the 480, and skip the 481 and 479 values.

Since this is the first time that you mention what you are doing with the Arduino, and that Processing is involved, along with serial transmission of data, perhaps you should post some code. There could be any number of reasons for the jumpy needle that you have not considered.

I started with the built-in 10 bit ADC on a Freetronics Eleven which is an Australian Arduino Uno, then went to an external MCP3201 12 bit, then an MCP3301 12 bit and currently an MCP3422 which is 12,14,16 or 18bit. The onboard was simple , the 3201 was SPI, as was the 3301, and the 3422 has an I2C interface. None was any better than the other 'jitter-wise' so I'll post Arduino & Processing code for the on-board ADC. I notice no-one seems to post quantities of code -- is it OK? (don't want to clog the system). I used handshaking with some, and with others I sent the data as binary and assembled in Processing. None made any real difference.
Going to bed.

Here is what gives me such skittish needle movement.

/*ARDUINO CODE - Basic Data Reading with Averaging & Hysteresis.

  • Using on-board 10 bit ADC, pot onto A1, 10 or 100 uF across
  • power, 0.1 uF across pot. 5 volts in from USB bridged to Vref.
    */

float sensVal;
float previous, diff; // for calculating hysteresis
int HYSTERESIS = 2;
void setup(){
Serial.begin(9600);
}
void loop(){
for (int i=0;i<10;i++){ // averaging 10 reads
sensVal = sensVal + analogRead(0);
delay(10);
}
sensVal = sensVal/10;
diff = abs(sensVal - previous); // calculating hysteresis
if (diff <= HYSTERESIS){
sensVal = previous;
}
previous = sensVal;
Serial.println(sensVal);
}

// PROCESSING CODE

import processing.serial.;
Serial myPort;
float radius = 900; // radius of circle
float angle;
float px, py; // needle point
void setup (){
size(1000, 1000);
myPort = new Serial(this, "COM18", 9600);
myPort.bufferUntil('\n');
}
void draw(){
}
void serialEvent(Serial myPort){
String val = myPort.readStringUntil('\n');
if(val != null){
angle = float(trim(val));
angle = map(angle,0,1024,0,360);
}
ellipse(width/2, height/2, radius, radius); // dial pos/size
px = width/2 + cos(radians(angle))
(radius/2); // needle point
py = height/2 + sin(radians(angle))*(radius/2);// sets y co-ord
line(width/2, height/2, px, py);
}

As I said, tried running it faster, slower, different baud rates. Tried handshaking. Tried sending data as binary instead of a string, assembling in Processing. Tried external ADC's. Tried different chips using SPI, and I2C. Shifted hysteresis routines into Processing instead of in Arduino. Tried using 'rotate()' instead of above trig routine. Tried avoiding 'serialEvent' and put code into draw(). Took trig routine out of draw() and put it into a function. Viewed neighbours cute daughter and considered misc. heathen rites. Came back to earth with a sickening thud...... I seem to just overload Processing with data faster than it can handle. I can only think of getting a value several ms down the track & putting in a for/next loop to bridge to it in a controlled fashion somehow. I think the needle movement is jerky because it skips data. Is that it ??

int HYSTERESIS = 2;

By convention, all capital letters in the name are reserved for #define names.

sensVal = sensVal/10;
diff = abs(sensVal - previous);   // calculating hysteresis
if (diff <= HYSTERESIS){
  sensVal = previous;
}
previous = sensVal;
Serial.println(sensVal);

You could avoid all the floating point arithmetic, and simply have Processing do the divide by 10 part.

You should only send data if there is a difference. By not converting to a float, you could send the high order byte and low order byte, and have Processing re-assemble the integer value. Doing so would send just two bytes, instead of a minimum of 4 (x.xx) to a maximum of 7 (xxxx.xx).

Since the difference between 123 and 123.45 is going to be difficult to see when the value is divided by 1024/360 in Processing, anyway, I'd skip the floating point crap altogether. Just send, and receive, an int.

 myPort = new Serial(this, "COM18", 9600);

Quit dragging your feet. Get the speed up to 115200.

 void serialEvent(Serial myPort){
 String val = myPort.readStringUntil('\n');
  if(val != null){
    angle = float(trim(val));
    angle = map(angle,0,1024,0,360);
 }

You've told Processing that the serialEvent() method should be called only when a carriage return arrives. Then, reading only a part of the serial data, even though it will be all of it, wastes resources. What is there to trim? The float() function will ignore leading white space, and stop reading at any non-numeric content in the string. Ergo, the trim() call is a waste of time.

Viewed neighbours cute daughter

Always a good diversion...

I seem to just overload Processing with data faster than it can handle.

I seriously doubt that. Printing the values received in Processing (and showing the output to us) might suggest a course of action that you have not considered, if the above suggestions do not pan out.

Is it something like this your trying to do?

I had some problems getting mines nice and smooth, set a framerate in processing smooths it out a bit i set mines to 12. I made a post about this a while back and one of the forums members were good enough to point me in the right direction and now it works quite well.

Is the needle jumping around all the time, or only when you're wiping the pot? Is it just a little constant jitter or big swings to values way far away from the current actual value?

Have you actually examined the raw data stream being collected from the arduino, just as a sanity check? Is your hysteresis of 2 based on your actual "noise floor" of your readings? I've never played with the analog ins down to that resolution, but my first impression is that the value may be too low to be of any use, that's only barely more than .5 degrees

Thanks all for your suggestions --- had some emergencies to handle ---will implement them in next couple of days.

What value is your pot, it is best to use 10K.

Also put a 0.1uF from the pot wiper to ground.

PaulS --- I implemented your suggestions. The code below started off fairly 'jerky' still, but then, as you see, I dropped hysteresis value to 1, only averaged 5 instead of 10 reads, dropped the delay between the 5 readings to 5 ms insstead of 10, and cut out the 100ms delay at the end of the arduino code. I've cut out all the floating point stuff, and avoided 'serialEvent()' and now transmit data in byte form instead of strings, re-assembling in Processing'. I'm running it at 115,200. If I'm careful and slow I can check and I seem to be catching reads at intervals of 3 to 5 mainly, both in Arduino and after the Processing sketch. I did what Mike suggested -- I already had a 0.1 uF cap from pot wiper to earth, and although I couldn't find a 10K pot I had a 100K which was a lot lower than the 1 Meg I was using (top leg of the divider network was 22k i.e.
( +ve -->22k-->A0-->1 meg pot-->-ve). If I wind the pot a little faster I thought originally I was dropping reads, but on checking it still runs (say) 324,327,332,335 etc. etc. on the 10 bit on board ADC. But if I really wind it fast I get a series in Processing like the following:- 1,27,135,283,386,461.... etc. etc.
Changing framerate from the defasult of 60 doesnt improove smoothness.
Needle still doesn't look as smooth as an analog needle but I have yet to try some code to 'dampen' it --- that is, fill in the gaps of 3 to 5 steps with 1's. And that is probably as good as it's going to get. Thanks again all for your help --- much appreciated.

ARDUINO CODE
int sensVal;
int previous, diff;
int hysteresis = 2;
void setup(){
Serial.begin(115200);
}
void loop(){
Serial.print('H');
for(int i=0; i<10; i++){
sensVal = sensVal + analogRead(0);
delay(10);
}
sensVal = sensVal / 10;
diff = abs(sensVal - previous);
if(diff <= hysteresis){
sensVal = previous;
}
previous = sensVal;
// Serial.println(sensVal); // checking actual values
Serial.print(lowByte(sensVal),BYTE);
Serial.print(highByte(sensVal),BYTE);
delay(100);
}

PROCESSING CODE
import processing.serial.*;
Serial myPort;
char HEADER = 'H';
int val;
void setup(){
size(1000,50);
myPort = new Serial(this, "COM18", 115200);
}
void draw(){
if (myPort.available() >= 5){
if (myPort.read() == HEADER){
val = myPort.read(); // already gone past header, so can read data
val = myPort.read() * 256 + val;
background(255);
println(); print(val); // check values
line(val, height, val, 0); // using this instead of trig routine to save space
}
}
}

  Serial.print(lowByte(sensVal),BYTE);

I think you should spend a few minutes looking at the HardwareSerial class and the Print class (that HardwareSerial derives from). The print() functions that print a byte ultimately call the write() method. Skip the middle man.

  Serial.write(lowByte(sensVal));
  if (myPort.available() >= 5)

Each iteration of loop on the Arduino results in (an attempt being made) writing 3 bytes to the serial port. Why are you waiting for 5?