PDA

View Full Version : OT: Displaying the output of a vacuum gauge



macona
04-20-2010, 06:15 AM
I have a Pfeiffer cold cathode vacuum gauge just off the turbo pump on my RGA system. Simple to use, 24v in and it gives a signal out depending on pressure. I want to build a display to connect to it. Heres the thing, the output is linear, in a way. Anything over 8.5v is over pressure. 8.5means 1 Pa, 7.5 is 1e-1, 6.5 is 1e-2. Simple, every volt is a decade down to 1.8v where it peters out at 2x10^-7 Pa. If the output is below .5v that means there is something wrong with the gauge.

Now the problem is that between each decade the voltage is logarithmic to the pressure. So at 6.5v the pressure is 1e-2, 6.8 is 2e-2, 6.97v is 3e-2, 7.2v is 4e-2, and so on.

Any ideas how to deal with this? I am figuring using the analog input on something like an Arduino or Teensy++. On the arduino it will give me 10 bit resolution between 0-5v. Use a voltage divider to scale it and output the info on a LCD.

But how do I process the data on something like this. I suppose I could do a lookup table where it subtracts the number that determines the decade and then does and inverse log of the resulting number to determine the pressure in that range. So if it saw a voltage of 5.92v it would set the range to e-3, subtract 5.5 to get .42v, calculate 10^.42 to get 2.63 and then display 2.63e-3Pa on the LCD. Also do an option to show mbar or torr.

I really have no clue how to program something like this. Or even if I am doing it close to the right way. I do not want to do this on a PC!

Any ideas?

-Jerry

http://farm5.static.flickr.com/4051/4536876621_f59ea95693_o.png

Holycross
04-20-2010, 06:54 AM
Macona,

Have you checked to see if Pfeiffer offer a readout/controller. Installed similar units made by varian at a cyclotron years ago.

Mark


I have a Pfeiffer cold cathode vacuum gauge just off the turbo pump on my RGA system. Simple to use, 24v in and it gives a signal out depending on pressure. I want to build a display to connect to it. Heres the thing, the output is linear, in a way. Anything over 8.5v is over pressure. 8.5means 1 Pa, 7.5 is 1e-1, 6.5 is 1e-2. Simple, every volt is a decade down to 1.8v where it peters out at 2x10^-7 Pa. If the output is below .5v that means there is something wrong with the gauge.

Now the problem is that between each decade the voltage is logarithmic to the pressure. So at 6.5v the pressure is 1e-2, 6.8 is 2e-2, 6.97v is 3e-2, 7.2v is 4e-2, and so on.

Any ideas how to deal with this? I am figuring using the analog input on something like an Arduino or Teensy++. On the arduino it will give me 10 bit resolution between 0-5v. Use a voltage divider to scale it and output the info on a LCD.

But how do I process the data on something like this. I suppose I could do a lookup table where it subtracts the number that determines the decade and then does and inverse log of the resulting number to determine the pressure in that range. So if it saw a voltage of 5.92v it would set the range to e-3, subtract 5.5 to get .42v, calculate 10^.42 to get 2.63 and then display 2.63e-3Pa on the LCD. Also do an option to show mbar or torr.

I really have no clue how to program something like this. Or even if I am doing it close to the right way. I do not want to do this on a PC!

Any ideas?

-Jerry

beanbag
04-20-2010, 07:07 AM
Am I missing something here? Isn't the voltage always logarithmic to the pressure? There's nothing special that happens at every decade.

This might sound really stupid, but there are analog gauges/dials that already have a log scale printed on them. They're typically marked for pressure or volume.

oldtiffie
04-20-2010, 07:16 AM
I take bb's points here.

If a standard pressure guage is accurate enough over the required range, the scale can be re-plotted/calibrated from linear to log.

Perhaps the mechanical arm can be replaced with a rotary potentiometer/resistor that is wound for a log output and read off directly by a meter (volts? amps?). I guess the output could be used to illuminate an LCD display.

Stuart Br
04-20-2010, 07:56 AM
Jerry, the big question here is what resolution are you looking for?

A Nat Semi LM3915N-1 will drive a 10 segment LED bar/dot display very simply.
See http://docs-europe.origin.electrocomponents.com/webdocs/06e8/0900766b806e8b6c.pdf for details

If you need a higher resolution than this, then you need to look at a different solution.

Stuart

P.S. Data sheet also shows that you can cascade 2 units with a bit of work, giving you a 60dB range over 20 segments.

macona
04-20-2010, 08:58 AM
Pfeiffer does sell a readout for it. Used they are at least $400.

A meter won't do it. You can have a log scale on it but the meter is still linear in response.

The output is logrithmic only between decades. I did find a math library for arduino so I might give that a try.

This is a fully electronic cold cathode ion gauge. No moving parts.

Stuart Br
04-20-2010, 09:35 AM
Jerry,

I'm with beanbag here, the chart shows a "straight" logarithmic relationship between pressure and voltage across the whole range, I don't see anything strange going on between decades.

8.5V = 1Pa Log10(1) = 0
7.5V = 0.1Pa Log10(0.1) = -1
6.5V = 0.01Pa Log10(0.01) = -2
5.5V = 0.001Pa Log10(0.001) = -3
4.5V = 0.0001Pa Log10(0.0001) = -4
5.5V = 0.00001Pa Log10(0.00001) = -5
6.5V = 0.000001Pa Log10(0.000001) = -6

macona
04-20-2010, 10:07 AM
Yes, that shows the rough vacuum. To get the fine reading I have to take that to figure out the rest. So 4.8v would be 2x10^-4Pa (.0002Pa) 5.1v would be .0004Pa.

Stuart Br
04-20-2010, 11:00 AM
Its actually a lot easier than that.

if you take your reference voltage as 8.5 V giving 1 Pa
Pressure for any voltage is
pa= 10^(InputV -8.5)

So for 5.1V

5.1-8.5 =-3.4
10^-3.4= .0004 Pa

back to my original question, what sort of resolution are you looking for and what is the tolerance on the sensor?

MrSleepy
04-20-2010, 01:02 PM
Hi Jerry

I would use a table if you intend to use a microcontroller...they give you speed at the expense of rom. You can achieve your results via calculation and math librarys...but they normally eat cpu cycles and are not that memory friendly either...Cordic routines may save on memory if thats an issue.

If your looking at that atmel based teensy..its 10 bit ad will give you 1024 elements (minus the error zones) in the table..so it shouldnt be that big if you keep to ints. depending on how you want to display the data.

Once you have the raw data in each table element its quite easy to convert from binary to decimal...then convert to ascii for the LCD..the web is full of C code for this...8052.com has plenty that I and other have posted over the years.

ST micro are currently selling the discovery package (http://www.st.com/mcu/contentid-130-...DISCOVERY.html) that includes a ARM based usb front end programming chip and a ST8 (http://www.st.com/stonline/products/literature/ds/14771.pdf) rear end that can be snapped in half..You also get a free IDE and 16k limit cosmic C compiler...all for $7 ..so you would have everything you'd need to get started.

The silabs 8051 kits are a great alternative aswell..

Rob

Evan
04-20-2010, 01:33 PM
Use an antilog amplifier.

Datasheet here:

http://www.datasheetarchive.com/datasheet-pdf/028/DSA00501563.html

Weston Bye
04-20-2010, 02:00 PM
...Now the problem is that between each decade the voltage is logarithmic to the pressure. So at 6.5v the pressure is 1e-2, 6.8 is 2e-2, 6.97v is 3e-2, 7.2v is 4e-2, and so on...

-Jerry

http://farm5.static.flickr.com/4051/4536876621_f59ea95693_o.png

So, if you redrew the graph with linear spacing between the grid lines, the voltage traces would roughly resemble a staircase? Seems strange. Such an output would cause a lot of extra work for the circuitry it was feeding. Sounds like what might happen with a defective R2R ladder. Have you been able to actually look at the output with a scope whild sweeping the vacuum?

macona
04-20-2010, 03:58 PM
Stuart, wow, you hit that one. Didnt even see that. Geesh. the 10 bit of a microcontroller would be good. Accuracy of one of these gauges is not great (30% in the range) but its nice to have the resolution to see trends in pressure.

Rob, I am looking at using the teensy because I have one lying around that I never got around to using intended for another project. I only need it to update a few times a second. I think it ought to handle that. Nice thing about microcontrollers, if it does not work just reprogram it. The teensy will take up to 2.59v in so I will have to use a voltage divider. What would be the easiest way to make a 1024 entry lookup table?

Evan, that looks like a possibility as well. I would have to convert to a current output to get the range.

Weston, you have it exactly. My guess one of the reasons they do this is to make it more difficult to make a display. The only thing is my other ion gauge outputs in a similar fashion. As they put it in their manual, 1v to 9v out (1v per decade) and is proportional to the logarithm of the pressure. 1v at 1x10^-10 and 9v 1x10-2 torr. So its very similar, maybe a throwback from old time fully analog gauges.

The gauge is the white thing sticking up in this picture:

http://farm5.static.flickr.com/4004/4310510553_6bdec383e1_b.jpg

Stuart Br
04-20-2010, 06:22 PM
I have spent far too much time doing loss calcs on optical fibre for data transmission, so I get the whole logarithmic scale stuff.
You have opened my eyes onto these low cost micro-controllers, I never knew you could pick them up at such a low cost. Not much good to me though, I never got my head round "C". I can read some of the simple constructs, but I have never tried writing any code with it.

MaxHeadRoom
04-20-2010, 06:32 PM
I can read some of the simple constructs, but I have never tried writing any code with it.

You can do alot in the native assembly, the PicMicro site host alot of applications with code, also free assembler and debugger etc.
If you need an intro see Nigel Goodwins site
http://www.winpicprog.co.uk/pic_tutorial.htm

(My daughter is 'marooned' in Oxfordshire right now due to the closing of Heathrow A.P) !!:(
M.

macona
04-20-2010, 06:38 PM
That's why the arduino is so popular. They made is very easy to use. All sorts of plug in software modules and hardware shields make it so easy to use that even artists can use them.

MrSleepy
04-20-2010, 07:24 PM
Hi Jerry

As Stuart Br noted..it does seem possible to calculated the value without needing lookup tables (as you would need to linearise a thermistor etc).

You have a 10 bit resolution of 1024 divisions and (I'm assuming) a AD Vref of 2.5v and the 0-10v from the sensor can be scaled for a Vref of 2.5

So 8.5v Vsensor becomes 2.125v ADC input
so 8.5v Vsensor = adcIn/Vref x 1024 = 2.125/2.5 x 1024 = 870


for high end
870/1024 x vref x scaling = 870/1024 x 2.5 x 4 = 8.5
So Pa = 10^ (input - 8.5) = 8.5 - 8.5 = 1

for low end

184/1024 x vref x scaling = 184/1024 x 2.5 x 4 = 1.8
So Pa = 10^ (input - 8.5) = 1.8 - 8.5 = 1.99e-7


If you calculate as above you may havce to use the floating point libs...which are a real speed killer due to the amount of clock cycles needed and library sizes are an issue..
most mcu users try to avoid them and use fixed point math scaling the values in the 16bit range of 0-65535



Rob

macona
04-20-2010, 10:49 PM
What do you consider a speed killer?

I have a bunch of displays to choose from. VFD's and LCD. The VFDs have serial input as an option.

Microcontrollers are totally new to me. Never messed with them before.

macona
04-21-2010, 01:09 AM
I breadboarded the little teensy++ board I have to a 4x20 LCD and that works. Ill add a pot to the analog input to simulate the gauge input.

Paul Alciatore
04-21-2010, 01:55 AM
As Evan said, you need an anti-log function. The modern way would be to use one of the single chip micros like the Basic Stamp or the PICAxe or a generic PIC device. You would use an A-D input on the device to input the Voltage and then use it as the exponent of 10 to derive the actual reading. One or two constants would allow calibration.

Reading = A * 10^(B * V)

V is the input Voltage from your sensor, A and B are the calibration constants.

The output value would be displayed on a serial style LCD readout.

Of course, you will need some electronic construction and programming skills. The cost should be under $100 or so.

macona
04-21-2010, 01:59 AM
Thats what I am doing with the teensy++ It uses an atmel microcontroller, http://www.pjrc.com/store/teensypp_pins.html

Evan
04-21-2010, 03:17 AM
There was a bumper sticker that was popular in Silicon Valley early in the IC age. It read "One OP Amp is worth a thousand gates". That is still true in many analog situations. Calculating the eponential term of a digitized input will exaggerate the quantatization error by the same exponential factor. You will achieve an order of magnitude better resolution by using an analog antilog amplifier and then digitizing the output from it.

macona
04-21-2010, 03:27 AM
The antilog amp does not have enough decades of range.

Evan
04-21-2010, 05:03 AM
This one can do up to 10 decades in current ratio mode.

http://www.ka-electronics.com/images/SSM/SSM2100.pdf

RB211
04-21-2010, 06:13 AM
The 10bit resolution will be much closer to 8 bit res due to noise in the ADC circuit.

macona
04-21-2010, 06:39 AM
Evan, any idea where to find one of those? The usual suspects dont have them. Looks like that company is long gone.

Looks like I can do all the math in the uC with the basic arduino library. The analog input has a averaging option which should knock down some of the noise.

macona
04-21-2010, 06:56 AM
It seems almost every one of these antilog amps are no longer made. Guess everyone is doing it with ADC's and DSPs.

Evan
04-21-2010, 08:40 AM
There are plenty of circuits on line for building an antilog amp using a dual or quad FET op amp. Just search on antilog op amp circuit. Another name for the same thing is a root extractor.

batt-man
04-21-2010, 09:12 AM
Can't help but think that this is being made more complex than it needs to be

Simply take the output from the vacuum gauge and bung into an adc connected to a microcontroller connected in turn to a display of some sort, possibly through a simple resistor divider or similar and write a bit of c code to do the calculations.

pseudo-code would be something like this:

start-loop

read adc value
if value =>7.5 and < 8.5
set decade = 1e -1
calculate log of (value - 7.5)
print log of value + decade
end if

if value =>6.5 and < 7.5
set decade = 1e -2
calculate log of (value - 6.5)
print log of value + decade
end if

<a few more if statements...>

<maybe a goto sleep for a few miliseconds or so...>

goto start-loop

May not be the most "elegant" solution but it'd certainly work with a fair degree of accuracy and any relatively recent microcontroller would quite likely have a built-in adc and certainly more than enough memory for such a simple task...

Batt

macona
04-21-2010, 03:41 PM
Batt, thats exactly what I am doing with the Teensy++/Arduino.

Barrington
04-21-2010, 04:12 PM
I really don't see an anti-log amp is at all suitable for this application. Let's suppose you scale it so that 1e+00 Pa gives 10v out, then 1e-07 Pa would give 1 microvolt out - what are you going to do next :confused: .......That's why the sensor is provided with a log output in the first place ...


Just throwing in a few ideas - a microcontroller implementation depends a lot on what language you prefer to use:-

1: Crudest - If your microcontroller memory/ language allows it, you could just store the complete display required (including the decimal point etc. !) for every input value in a large string array.

e.g. each element of the array would be a string such as "1.23e-02" - 8 bytes per entry . This would be effective for the display of a single unit but would require three large separate tables for Pa, mbar and torr.

-OR-

2: Less Crude - Store the display value as BCD digits only - 2 bytes per entry. One table per unit is now more reasonable, just a little more effort to display.

-OR-

3: Less memory - Scale the sensor voltage / A-D output in software, such that 1.5 volts converts to 0000000000 and 8.5 volts converts to 1110000000 . This means the exponent and significand are nicely separated, so:-

-For a 'Pa' output use the top 3 bits inverted to give the 'exponent' (just add the minus sign on the display).

-Use the bottom 7 bits to address a 128 entry look up table for the significand, requiring only 256 bytes (at 4 BCD digits per entry).

-For a 'mbar' output just add 2 to the 'exponent' display.

-For a 'torr' output subtract a further 17 from the A-D value (with the above scaling this represents a division by 1.358 - close enough) and add 2 to the exponent as for mbar.

This approach uses significantly less memory.

-OR-

4: Even less memory - If you want to use simple assembler and would prefer to avoid any multiply/divide libraries:-

Use an op-amp to scale the sensor output to 0.625*(Vin-1.5), i.e. 1.5V in -> 0V out, 8.5V in -> 4.375V out.

Convert this using a 5v range, 10bit A-D in the microcontroller, : i.e. 0000000000 to 1110000000, and continue as above.

More circuitry, but provides an easy route to fit trimmers for offset/gain.



Look-up table Generation

There are many ways to generate a lookup table - here's an example of a single decade 128 entry table with a 4 digit output using a spreadsheet:-

Column A: numbers 0 to 127
Column B: =A1/128
Column C: =10^B1
Column D: =INT(1000*C1)

Then either simply copy and paste the output values from column D into your code and edit in whatever assembler/compiler directives required., or format the cells in column D with the required assembler text added - e.g. a custom number format "dw "0000"h" and then copy and paste the result.

-OR-

Much more flexible - dig out that old copy of QBASIC and use it to generate the text file:-

e.g for option 2: above you could generate the table thus:-

OPEN "c:\testab.txt" FOR OUTPUT AS #1

'A-D: if 8.5v (1.0e+00 Pa) -> 1023, then 1.5v (1.0e-07 Pa) -> 181
'- i.e. 7 decades over 843 counts

FOR N = 0 TO 842

logvalue = (7 * (N / 842) - 7)
exponent = INT(logvalue)
significand = 10 ^ (logvalue - exponent)

PRINT #1, "table("; N; ") = &H";
PRINT #1, USING "###"; 100 * significand;
PRINT #1, USING "#"; -exponent;

NEXT N
CLOSE #1
- which produces a text file of array values:-

table( 0 ) = &H1007
table( 1 ) = &H1027
table( 2 ) = &H1047
table( 3 ) = &H1067
table( 4 ) = &H1087
table( 5 ) = &H1107
table( 6 ) = &H1127
table( 7 ) = &H1147
table( 8 ) = &H1177
...
table( 833 ) = &H8421
table( 834 ) = &H8581
table( 835 ) = &H8751
table( 836 ) = &H8911
table( 837 ) = &H9091
table( 838 ) = &H9261
table( 839 ) = &H9441
table( 840 ) = &H9621
table( 841 ) = &H9811
table( 842 ) = &H1000

- Simply subtract 181 from the A-D output and retrieve that array value, a 16 bit word of 4 BCD digits, where e.g. 1234 should be displayed as 1.23e-4


For the single decade (128 entry) look up tables in option 3: and 4: above - examples for assembler and high level:-


OPEN "c:\testab.txt" FOR OUTPUT AS #1

' e.g. for use with an assembler:-

FOR N = 1 TO 127
IF N MOD 8 = 0 THEN PRINT #1, " DW ";
entry = INT(1000 * (10 ^ (N / 128)))
PRINT #1, STR$(entry); "h";
IF N MOD 8 <> 7 THEN PRINT #1, ","; ELSE PRINT #1,
NEXT N

PRINT #1, : PRINT #1,

' -OR- e.g. for use with a higher level language:-

FOR N = 0 TO 127
PRINT #1, "look_up_array("; N; ") = ";
PRINT #1, USING "#.##"; (10 ^ (N / 128))
NEXT N

CLOSE #1
Produces a text file containing:-

dw 1000h, 1018h, 1036h, 1055h, 1074h, 1094h, 1113h, 1134h
dw 1154h, 1175h, 1197h, 1218h, 1240h, 1263h, 1286h, 1309h
dw 1333h, 1357h, 1382h, 1407h, 1433h, 1459h, 1485h, 1512h
dw 1539h, 1567h, 1596h, 1625h, 1654h, 1684h, 1715h, 1746h
dw 1778h, 1810h, 1843h, 1876h, 1910h, 1945h, 1980h, 2016h
dw 2053h, 2090h, 2128h, 2167h, 2206h, 2246h, 2287h, 2329h
dw 2371h, 2414h, 2458h, 2502h, 2548h, 2594h, 2641h, 2689h
dw 2738h, 2788h, 2838h, 2890h, 2942h, 2996h, 3050h, 3105h
dw 3162h, 3219h, 3278h, 3337h, 3398h, 3459h, 3522h, 3586h
dw 3651h, 3718h, 3785h, 3854h, 3924h, 3995h, 4067h, 4141h
dw 4216h, 4293h, 4371h, 4450h, 4531h, 4613h, 4697h, 4782h
dw 4869h, 4958h, 5048h, 5139h, 5232h, 5327h, 5424h, 5523h
dw 5623h, 5725h, 5829h, 5935h, 6042h, 6152h, 6264h, 6378h
dw 6493h, 6611h, 6731h, 6853h, 6978h, 7104h, 7233h, 7365h
dw 7498h, 7635h, 7773h, 7914h, 8058h, 8204h, 8353h, 8505h
dw 8659h, 8816h, 8976h, 9139h, 9305h, 9474h, 9646h, 9821h


look_up_array( 0 ) = 1.00
look_up_array( 1 ) = 1.02
look_up_array( 2 ) = 1.04
look_up_array( 3 ) = 1.06
look_up_array( 4 ) = 1.07
look_up_array( 5 ) = 1.09
...
look_up_array( 121 ) = 8.82
look_up_array( 122 ) = 8.98
look_up_array( 123 ) = 9.14
look_up_array( 124 ) = 9.31
look_up_array( 125 ) = 9.47
look_up_array( 126 ) = 9.65
look_up_array( 127 ) = 9.82


Vary a few details to suit whatever assembler/compiler is used, and adjust to taste...

Cheers

.

macona
04-21-2010, 05:35 PM
Oh boy.. I need to take some classes in programming. I understand some of it but not enough to be able to use it.

Weston Bye
04-21-2010, 05:45 PM
Oh boy.. I need to take some classes in programming. I understand some of it but not enough to be able to use it.

Why bother with a class. If you dive in and muddle your way through your particular problem, you will find that you will maybe spend as much time as sitting in the class, but when you're done you will know more about it than the instructor. And everything you learn will be practical, not theoretical.

RB211
04-21-2010, 06:47 PM
I know Arduino's are insanely popular. I don't know WHY they are.. What is wrong with the ATMEL chip by itself with its free IDE and GCC compiler? Arduino seams like surfing the web with AOL.

Anyhow, the ADC on the atmel or atmel/arduino should be good enough, even at 8 bit res. Those extra 2 bits are just filled with noise. Have to use the function described in the sheet for reducing noise levels while doing an adc conversion. With the use of interrupts, will be a piece of cake.

Evan
04-21-2010, 07:43 PM
what are you going to do next ?

You switch to current mode. The leakage current on a good FET op amp is in the nanoamps so there is plenty of room to fit enough decades of linear output within the required range.

The problem with digitizing the log output is that because it is exponential, at the high end of each range the linear distance between the digital values also grows exponentially. The result is that a 1 bit error produces a very large change in the final reported linear value after an antilog algorithm has been applied in software.

By using linear amplifiers in non-linear mode the resolution is entirely preserved and the output, which has been converted to linear, is then sampled at the same resolution across the entire range.

There is no easy way to do this digitally. The only option that is all digital is to use brute force A/D conversion with an order of magnitude greater resolution than is required if an antilog amplifier is used.

BTW, a good example of how digital isn't always better is the digital oscilloscope, and for the same reasons.

macona
04-22-2010, 12:23 AM
We had a really nice new Tektronix digital scope with built in logic analyzer. Great scope. Annoying thing was it took something like 2 minutes to boot up.

Anyway. Got the programming done. Cant display exponents or get much past decimal points doing it the easy way so I had to do a lot with if statements. I still need to do the voltage divider for the input but it looks good so far. I also added some extras like interlocks to prevent valves from opening. It runs very fast. I even slowed it down with a 50ms delay between loops.

http://www.youtube.com/v/yJwfnCFOJm0&hl

Here'e the mess I call code:


#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 10, 0, 1, 2, 3, 4, 5, 6, 7);
const int numReadings = 10;

int readings[numReadings]; // the readings from the analog input
int index = 0; // the index of the current reading
int total = 0; // the running total
int average = 0; // the average

int inputPin = 0;
int exponent;
float torr = .0075;
float pa;
float volts;
float pressure;
float offset;
int error;

void setup()
{
// initialize serial communication with computer:
Serial.begin(9600);
// initialize all the readings to 0:
for (int thisReading = 0; thisReading < numReadings; thisReading++)
readings[thisReading] = 0;
pinMode (PIN_C6, OUTPUT);
pinMode (PIN_C7, OUTPUT);
lcd.begin(20, 4);
lcd.clear();
lcd.setCursor(1, 0);
// Print a message to the LCD.
lcd.print("Turbopump Pressure");
lcd.setCursor(0, 2);
// Print a message to the LCD.
lcd.print("Probe Valve");
lcd.setCursor(0, 3);
// Print a message to the LCD.
lcd.print("Main Valve");
}

void loop() {
// subtract the last reading:
total= total - readings[index];
// read from the sensor:
readings[index] = analogRead(inputPin);
// add the reading to the total:
total= total + readings[index];
// advance to the next position in the array:
index = index + 1;

// if we're at the end of the array...
if (index >= numReadings)
// ...wrap around to the beginning:
index = 0;

// calculate the average:
average = total / numReadings;
float volts = average * .0097;

float pa = pow(10.0000, offset);
// send it to the computer (as ASCII digits)
if (volts <= 8.5 && volts > 7.62) {
exponent = -3;
offset = volts - 7.62;
}
if (volts <= 7.62 && volts > 6.62) {
exponent = -4;
offset = volts - 6.62;
}
if (volts <= 6.62 && volts > 5.62) {
exponent = -5;
offset = volts - 5.62;
}
if (volts <= 5.62 && volts > 4.62) {
exponent = -6;
offset = volts - 4.62;
}
if (volts <= 4.62 && volts > 3.62) {
exponent = -7;
offset = volts - 3.62;
}
if (volts <= 3.62 && volts > 2.62) {
exponent = -8;
offset = volts - 2.62;
}
if (volts <= 2.62 && volts > 1.8) {
exponent = -9;
offset = volts - 1.62;
}
float torr = pow(10, offset);
Serial.println(exponent);
Serial.println(volts);
Serial.println(offset);
Serial.println(torr);
if (volts > 8.5) {
lcd.setCursor(4, 1);
lcd.print(" Overrange ");
error = 1;
}
if (volts < 1.8 && volts > 0.5) {
lcd.setCursor(4, 1);
lcd.print(" Underrange ");
error = 0;
}
if (volts < 0.5) {
lcd.setCursor(4, 1);
lcd.print("Sensor Error ");
error = 1;
}
if (volts >= 1.8 && volts <= 8.5) {
lcd.setCursor(8, 1);
// Print a message to the LCD.
lcd.print("e Torr");
lcd.setCursor(4, 1);
lcd.print(torr);
lcd.setCursor(9, 1);
lcd.print(exponent);
error = 0;
}
if (volts < 6.5 && error == 0) {digitalWrite (PIN_C6, HIGH);
lcd.setCursor(12, 2);
lcd.print("ENABLED "); }
else {
digitalWrite (PIN_C6, LOW);
lcd.setCursor(12, 2);
lcd.print("DISABLED"); }


if (volts < 5.5 && error == 0) {digitalWrite (PIN_C7, HIGH);
lcd.setCursor(12, 3);
lcd.print("ENABLED "); }
else {
digitalWrite (PIN_C7, LOW);
lcd.setCursor(12, 3);
lcd.print("DISABLED"); }

delay(50);
}

Evan
04-22-2010, 12:52 AM
exp=int(11-volts+.38)*-1 will handle the five cases between the limits.

macona
04-22-2010, 01:05 AM
Hmm. Looks like you are right.

macona
04-22-2010, 03:08 AM
Made up a little voltage divider and hooked it up. It works. Needed a bit of calibration but it seems to be there. Now to come up with a power supply and some perf board to mount everything to.

http://farm3.static.flickr.com/2717/4542163723_9e1338dec4_o.jpg

Barrington
04-22-2010, 07:54 AM
Macona, nicely done. I was coming at it from a very different background. I think you've shown why these modules are so popular for quick one-offs !

Now thinking in fully floating point...

For Pa display the exponent and significand can be more simply calculated from:-

x = volts - 1.5
decade = int(x)
exponent = decade - 7
significand = pow(10,(x - decade))


Scaling for mbar and torr is easy because the log input means that division is simply equivalent to a voltage shift:-

- for mbar display (Pa/100) just subtract:-
volts = volts - 2.000 // equivalent to dividing by 100

- for torr display (Pa/133.32) just subtract:-
volts = volts - 2.1249 // equivalent to dividing by 133.32


It doesn't matter that the numbers can go negative...

e.g. the mbar reading for 2volt input:-

volts = volts - 2.000 = 0
x = volts - 1.5 = -1.5
decade = int(-1.5) = -2
exponent = -2 - 7 = -9
significand = pow(10,(x - decade)) = (pow(10,0.5)) = 3.01

e.g. the torr reading for 2volt input:-

volts = volts - 2.1249 = -0.1249
x = volts - 1.5 = -1.6249
decade = int(-1.6249) = -2
exponent = -2 - 7 = -9
significand = pow(10,(x - decade)) = pow(10,0.3751) = 2.37

Cheers

.

Barrington
04-22-2010, 08:28 AM
You switch to current mode. The leakage current on a good FET op amp is in the nanoamps so there is plenty of room to fit enough decades of linear output within the required range.
The problem with digitizing the log output is that because it is exponential, at the high end of each range the linear distance between the digital values also grows exponentially. The result is that a 1 bit error produces a very large change in the final reported linear value after an antilog algorithm has been applied in software.
I understand the point of using currents to represent wide dynamic ranges, but there are problems.

The beauty of the quantising the logarithmic value is that each A-D step is a fixed percentage of the reading, unlike a linear scale where each step is a fixed percentage of full scale.

Using the earlier numbers using a 10 bit A-D, each step is ~2% of reading everywhere over the full sensor range.

If you manage to linearise the output and want to keep a similar resolution at the low end you're going to need a something like a 28 bit A-D... Now at the top end, with a perfect and noiseless sensor, you still have 2e-9 Pa per step, but so what ? Are you going to display a large number of digits of imaginary precision, autorange, or display the result in exponential form - probably the last option !!

The sensor in question barely demands more than a couple of digits of precision. 2% is way beyond it's accuracy and, even more significantly, beyond it's repeatablity.

Cheers

.

Evan
04-22-2010, 11:23 AM
If you manage to linearise the output and want to keep a similar resolution at the low end you're going to need a something like a 28 bit A-D...

That applies regardless of whether the signal is log or linear. The bottom of the range is subject to strong quantization noise cause by the low effective number of bits used to represent it.

lazlo
04-22-2010, 11:30 AM
I know Arduino's are insanely popular. I don't know WHY they are.. What is wrong with the ATMEL chip by itself with its free IDE and GCC compiler? Arduino seams like surfing the web with AOL.

AOL is a good analogy, I've described Arduino as training wheels for AVR. Arduino hides the AVR bootloader from you. So you can learn the AVR with the Arduino, and then transition to the full gcc environment when you're ready.

Barrington
04-22-2010, 11:55 AM
Quote:

If you manage to linearise the output and want to keep a similar resolution at the low end you're going to need a something like a 28 bit A-D...
That applies regardless of whether the signal is log or linear. The bottom of the range is subject to strong quantization noise cause by the low effective number of bits used to represent it.

Er - no, I don't think so. ???

If you manage to linearise the output and want to keep a similar resolution at the low end...

With the 10bit conversion of the log signal, it works out at about 2e-9 Pa per step at the low end. To achieve 2e-9 Pa per step after linearisation requires a 28bit conversion.

The whole point is that the logarithmic nature of the signal mitigates against the quantisation errors for low values of the measured parameter !

Cheers

.

macona
04-22-2010, 03:41 PM
Macona, nicely done. I was coming at it from a very different background. I think you've shown why these modules are so popular for quick one-offs !

Now thinking in fully floating point...

For Pa display the exponent and significand can be more simply calculated from:-

x = volts - 1.5
decade = int(x)
exponent = decade - 7
significand = pow(10,(x - decade))


Scaling for mbar and torr is easy because the log input means that division is simply equivalent to a voltage shift:-

- for mbar display (Pa/100) just subtract:-
volts = volts - 2.000 // equivalent to dividing by 100

- for torr display (Pa/133.32) just subtract:-
volts = volts - 2.1249 // equivalent to dividing by 133.32


It doesn't matter that the numbers can go negative...

e.g. the mbar reading for 2volt input:-

volts = volts - 2.000 = 0
x = volts - 1.5 = -1.5
decade = int(-1.5) = -2
exponent = -2 - 7 = -9
significand = pow(10,(x - decade)) = (pow(10,0.5)) = 3.01

e.g. the torr reading for 2volt input:-

volts = volts - 2.1249 = -0.1249
x = volts - 1.5 = -1.6249
decade = int(-1.6249) = -2
exponent = -2 - 7 = -9
significand = pow(10,(x - decade)) = pow(10,0.3751) = 2.37

Cheers

.

Wow, you are right. I am stealing your code! ;)

The last programming I did was RPL for my HP48GX probably 15 years ago. Took a class on it and it turned out I knew more than the teacher.

-Jerry

macona
04-23-2010, 12:03 AM
Got the code mostly done now. With all the extra IO available I made it do more things. It now will turn on and off the fore and turbo pump. It also controls the two valves between the turbo pump and the chamber with safeties that shut the valves down if pressure gets too high to protect the turbo pump and RGA. I can also switch between torr and mbar with the press of a button thanks to Barringtons info.

Still barely takes up 1/8 of the ROM on the uC. Did have some trouble finding code to allow on/off action from a momentary pushbutton.

-Jerry




#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 10, 0, 1, 2, 3, 4, 5, 6, 7);
const int numReadings = 10;
int readings[numReadings]; // the readings from the analog input
int index = 0; // the index of the current reading
int total = 0; // the running total
int average = 0; // the average
int decade;
int inputPin = 0;
int exponent;
float torr;
float pa;
float volts;
float pressure;
float significand;
int error;
int state = HIGH; // the current state of the output pin
int reading; // the current reading from the input pin
int previous = LOW; // the previous reading from the input pin
int state1 = HIGH; // the current state of the output pin
int reading1; // the current reading from the input pin
int previous1 = LOW; // the previous reading from the input pin
// the follow variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long time = 0; // the last time the output pin was toggled
long time1 = 0; // the last time the output pin was toggled
long debounce = 200; // the debounce time, increase if the output flickers
int state2 = HIGH; // the current state of the output pin
int reading2; // the current reading from the input pin
int previous2 = LOW; // the previous reading from the input pin
long time2 = 0; // the last time the output pin was toggled
int state3 = HIGH; // the current state of the output pin
int reading3; // the current reading from the input pin
int previous3 = LOW; // the previous reading from the input pin
long time3 = 0; // the last time the output pin was toggled
int state4 = HIGH; // the current state of the output pin
int reading4; // the current reading from the input pin
int previous4 = LOW; // the previous reading from the input pin
long time4 = 0; // the last time the output pin was toggled
int mvenab;
int pvenab;
int override = LOW;
int overridden = LOW;
void setup()
{
// initialize serial communication with computer:
Serial.begin(9600);

// initialize all the readings to 0:
for (int thisReading = 0; thisReading < numReadings; thisReading++)
readings[thisReading] = 0;
pinMode (PIN_C4, OUTPUT); //Turbo Pump
pinMode (PIN_C5, OUTPUT); //Fore Pump
pinMode (PIN_C6, OUTPUT); //Main Valve
pinMode (PIN_C7, OUTPUT); //Probe Valve
pinMode (PIN_B0, INPUT_PULLUP); //Override Input
pinMode (PIN_B1, INPUT_PULLUP); //Main Valve Input
pinMode (PIN_B2, INPUT_PULLUP); //Probe Valve Input
pinMode (PIN_B3, INPUT_PULLUP); //Turbo In
pinMode (PIN_B4, INPUT_PULLUP); //Fore In
pinMode (PIN_B5, INPUT_PULLUP); //Mode Switch
lcd.begin(20, 4);
lcd.clear();
lcd.setCursor(0, 0);
// Print a message to the LCD.
lcd.print("Fore: Turbo: ");
lcd.setCursor(0, 2);
// Print a message to the LCD.
lcd.print("Main Valve");
lcd.setCursor(0, 3);
// Print a message to the LCD.
lcd.print("Probe Valve");
}

void loop() {
reading = digitalRead(PIN_B3); // Turbo Control
if (reading == HIGH && previous == LOW && millis() - time > debounce) {
if (state == HIGH)
state = LOW;
else
state = HIGH;
time = millis();
}
digitalWrite(PIN_C5, state);
previous = reading;
reading1 = digitalRead(PIN_B4); // Fore Control
if (reading1 == HIGH && previous1 == LOW && millis() - time1 > debounce) {
if (state1 == HIGH)
state1 = LOW;
else
state1 = HIGH;
time1 = millis();
}
previous1 = reading1;
digitalWrite(PIN_C4, state1);
if (state == 0) {
lcd.setCursor(17, 0);
lcd.print("OFF");
}
else {
lcd.setCursor(17, 0);
lcd.print("ON ");
}
if (state1 == 0) {
lcd.setCursor(6, 0);
lcd.print("OFF");
}
else {
lcd.setCursor(6, 0);
lcd.print("ON ");
}
reading2 = digitalRead(PIN_B5); // Pressure Mode Switch
if (reading2 == HIGH && previous2 == LOW && millis() - time2 > debounce) {
if (state2 == HIGH)
state2 = LOW;

else
state2 = HIGH;

time2 = millis();
}
previous2 = reading2;
if (state2 == 0) {

lcd.setCursor(7, 1);
float torr = volts - 2.1249;
lcd.print(" Torr");
}
else {
lcd.setCursor(7, 1);
float torr = volts - 2.0;
lcd.print(" mBar");
}

// subtract the last reading:
total= total - readings[index];
// read from the sensor:
readings[index] = analogRead(inputPin);
// add the reading to the total:
total= total + readings[index];
// advance to the next position in the array:
index = index + 1;

// if we're at the end of the array...
if (index >= numReadings)
// ...wrap around to the beginning:
index = 0;

// calculate the average:
average = total / numReadings;
float volts = average * .0097;
if (state2 == 0) torr = volts - 2.1249;
else torr = volts - 2.0;

float x = torr - 1.5;
decade = int(x);
exponent = decade - 7;
float significand = pow(10,(x - decade));


Serial.println(exponent);
Serial.println(volts);
Serial.println(decade);
Serial.println(torr);
if (volts > 8.5) {
lcd.setCursor(0, 1);
lcd.print(" Overrange ");
error = 1;
}
if (volts < 1.8 && volts > 0.5) {
lcd.setCursor(0, 1);
lcd.print(" Underrange ");
error = 0;
}
if (volts < 0.5) {
lcd.setCursor(0, 1);
lcd.print("Sensor Error ");
error = 1;
}
if (volts >= 1.8 && volts <= 8.5) {
lcd.setCursor(4, 1);
// Print a message to the LCD.
lcd.print("e");
lcd.setCursor(0, 1);
lcd.print(significand);
lcd.setCursor(5, 1);
lcd.print(exponent);
error = 0;
}
if (volts < 6.5 && error == 0) pvenab = 1;
else pvenab = 0;
if (volts < 5.5 && error == 0) mvenab = 1;
else mvenab = 0;
override = digitalRead(PIN_B0);
reading3 = digitalRead(PIN_B1); // Main Valve Switch
if (reading3 == HIGH && previous3 == LOW && millis() - time3 > debounce) {
if (state3 == HIGH)
state3 = LOW;
else
state3 = HIGH;
time3 = millis();
}
previous3 = reading3;
//if (mvenab == 0 && override == 1) overridden = 1;
if (override == 0 || mvenab == 1) digitalWrite(PIN_C6, state3);
else {
digitalWrite(PIN_C6, LOW);
state3 = 0;
}
reading4 = digitalRead(PIN_B2); // Probe Valve Switch
if (reading4 == HIGH && previous4 == LOW && millis() - time4 > debounce) {
if (state4 == HIGH)
state4 = LOW;
else
state4 = HIGH;
time4 = millis();
}
previous4 = reading4;
if (pvenab == 1) digitalWrite(PIN_C7, state4);
else {
digitalWrite(PIN_C7, LOW);
state4 = 0;
}
if ( state3 == HIGH && override == LOW) {
lcd.setCursor(12,2);
lcd.print("OVERRIDE");
}
else {
if (state3 == HIGH && mvenab == 1) {
lcd.setCursor(12,2);
lcd.print("OPEN ");
}
else {
lcd.setCursor(12,2);
lcd.print("CLOSED ");
}
}
if (state4 == HIGH) {
lcd.setCursor(12,3);
lcd.print("OPEN ");
}
else {
lcd.setCursor(12,3);
lcd.print("CLOSED ");
}


delay(50);
}

Fasttrack
04-23-2010, 12:29 AM
I'm sorry I missed this thread. Good solution, Jerry. Full-fledged vacuum controls are readily available, but they tend to be pricey. We make all of ours in house, although we're still in the dark ages, in some respects. Some of our controls still have tubes ;)

So, iirc, you've gone to a completely oilless vacuum system, correct? So you don't have too much to worry about - most turbo pumps will handle atm without a problem, even if you have a massive failure. But if you can think of any important safety interlocks for the proposed useage of your system, now would seem an appropriate time to incorporate them! Maybe a beam/pressure interlock or something of the kind?

macona
04-23-2010, 01:49 AM
I have a small alcatel 2002 rotary pump backing the turbo. I can use a good diaphragm pump but I dont have one. It is a turbo drag pump.

Turbos can start up at ATM but they will never reach speed. The controller will sense too much load or it will time out. I dont know of any turbo that can handle being dumped to ATM though. This little one I have runs at 90,000 RPM. The vanes will start melting if it was suddenly exposed to ATM.

macona
04-24-2010, 02:18 AM
Macona, nicely done. I was coming at it from a very different background. I think you've shown why these modules are so popular for quick one-offs !

Now thinking in fully floating point...

For Pa display the exponent and significand can be more simply calculated from:-

x = volts - 1.5
decade = int(x)
exponent = decade - 7
significand = pow(10,(x - decade))


Scaling for mbar and torr is easy because the log input means that division is simply equivalent to a voltage shift:-

- for mbar display (Pa/100) just subtract:-
volts = volts - 2.000 // equivalent to dividing by 100

- for torr display (Pa/133.32) just subtract:-
volts = volts - 2.1249 // equivalent to dividing by 133.32


It doesn't matter that the numbers can go negative...

e.g. the mbar reading for 2volt input:-

volts = volts - 2.000 = 0
x = volts - 1.5 = -1.5
decade = int(-1.5) = -2
exponent = -2 - 7 = -9
significand = pow(10,(x - decade)) = (pow(10,0.5)) = 3.01

e.g. the torr reading for 2volt input:-

volts = volts - 2.1249 = -0.1249
x = volts - 1.5 = -1.6249
decade = int(-1.6249) = -2
exponent = -2 - 7 = -9
significand = pow(10,(x - decade)) = pow(10,0.3751) = 2.37

Cheers

.

Ugh, it dosnt work after all. It see int(-1.64) as -1 and not -2 like you have it.

Edit. Got it fixed.

New code:

if (state2 == 0) torr = volts - .1249;
else torr = volts;
x = torr - 1.5;
decade = (int(x) - 2);
exponent = decade - 7;
significand = pow(10,((x - 2) - decade));

Barrington
04-24-2010, 06:04 AM
Ugh, it dosnt work after all. It see int(-1.64) as -1 and not -2 like you have it.
Many apologies - thinking in the wrong language. :o Haven't used any 'C' for a long time.

In 'C' the function is floor(x), which returns the largest integer not greater than x .

Sorry about that.

Cheers

.

P.S. However, I'm afraid your new code won't work either !

- because the 'C' int introduces a problem at zero which you cant get rid of - i.e. decade will = -2 over a two decade range.

I think this should now be o.k. :) :-

x = volts - 1.5;
decade = floor(x);
exponent = decade - 7;
significand = pow(10,(x - decade));

Again, many apologies...

Cheers

.

macona
04-24-2010, 03:23 PM
My "Fix" just offset the problem two decades which was OK since I cant go below e-9 anyway.

But you real fix works. I couldnt even find the floor instruction in the arduino reference but it seems to be supported.

Thanks!

macona
06-23-2010, 06:51 AM
Finally got around to finishing this thing last night. Somewhere around 4:30AM. :D

Used a box from an bad Runco video processor. Already had buttons on the front and a 2x24 line VFD display. The box is incredibly well built. The front plate is milled from solid 3/8" aluminum.

I point to point wired the board. Used four reed relays since their coil current was under the max out on the uC. No transistors needed. I used a little switcher instead of a 7805 so I wouldnt have to deal with heat dissipation from dropping the 24v down to 5v. I need 24v to power the turbo pump and solenoid valves on the vacuum valves.

Found one nasty, the converter put out a 10v pulse on startup which killed the first uC. I think it has something to do with too small of a load. I put a 5.1v zener across the rails and that clamps it right down. Also stuck the teensy in a ZIF to make future reprogramming simpler. I got a bunch of Hirose circular connectors off some Japanese process controls for the back. Still need to relabel the buttons.

It seems to work. I need to get a tank of helium to check for leaks in the system now.

http://farm2.static.flickr.com/1378/4725753861_13826786f1_b.jpg

http://farm2.static.flickr.com/1179/4726401796_8956138b4e_b.jpg

http://farm2.static.flickr.com/1063/4726402022_febac93913_b.jpg