Interpolating logarithmic vacuum sensor table

Soooo, Im really new to writing code, and I’m trying to make a display readout for an ultra high vacuum gauge. The gauge has a logarithmic curve for the pressure/voltage, as the manual states, from 0-10V. I know arduino can only use 0-5v, so I’ll use a voltage divider, issue is, now I’m not sure how to make it all work.

Here is the pressure table:

interpolatepressureTable (1 - 9 =V | 10^-10 - 10^-2 =Torr)
1 {1, 0.0000000001},
1.5 {2, 0.000000001},
2 {3, 0.00000001},
2.5 {4, -7},
3 {5, 0.000001},
3.5 {6, 0.00001},
4 {7, 0.0001},
4.5 {8, 0.001},
5 {9, 0.01},

The manual gives you an equation to calculate the pressure. P=10^v-11, where P is pressure, v is voltage, so if my sensor gives me 4 volts i know the pressure reading is 1x10-7 torr. and so on.

Question is, when i send it through a voltage divider, how do I then either have the arduino solve an equation, or interpolate a lookup table. I have no idea how to do the lookup table, here is my uber basic code for the equation, however still based on 0-10V rather than 0-5 like it should be.

#include <LiquidCrystal.h>
#include <math.h>


// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

// the setup routine runs once when you press reset:

    void setup() {
      // initialize serial communication at 9600 bits per second:
      Serial.begin(9600);
      
      lcd.begin(16, 2);
      lcd.print("MKS  Instruments");
      lcd.setCursor(0, 1);
      lcd.print("IMT Cold Cathode");
      delay(6500);
      lcd.clear();
      lcd.print("Gauge Pressure:");
      
    }

// the loop routine runs over and over again forever:
   
    void loop() {
      
      pinMode(A0, INPUT);              //A0 is set as input
      float v = analogRead(A0);        //v is input voltage set as floating point unit on analogRead
      v = map(v, 0, 1023, 0, 10);      //v is voltage measured from 0 to 1023 mapped from 0v to 10v (needs to be 5)
      float p = pow(10, v - 11.000);   //p is pressure in torr, represented by k in the equation [P=10^(v-k)] which is represented-
                                       // -by 11.000 (K  = 11.000 for Torr, 10.875 for mbar, 8.000 for microns, 8.875 for Pascal)

       Serial.print(v);

       char pressureE[5];
       dtostre(p, pressureE, 1, 0);        // scientific format with 1 decimal places
      
       lcd.setCursor(0, 1);
       lcd.print(pressureE);
       lcd.print(" Torr");

    }

CCVacuumGaugebase.ino (1.36 KB)

MKS903.pdf (264 KB)

You don't need to worry about the 5V vs 10V thing. The input to the voltage divider is 0-10V. The analogRead() gives you a corresponding value 0-1023. The fact that it went through a stage when it was 0-5V is irrelevant.

But this is a problem:

The map() function uses integer math so will not generate fractions, when the math might indicate that it should do so. Fractional remainders are truncated, and are not rounded or averaged.

So map() will only give you 0,1,2,3...,9. It will never give you 3.88 for example.

You need something more like:

v = v * 10.0 / 1024.0;

PaulRB:
So... does your code work or not?

You don't need to worry about the 5V vs 10V thing. The input to the voltage divider is 0-10V. The analogRead() gives you a corresponding value 0-1023. The fact that it went through a stage when it was 0-5V is irrelevant.

oh, really? :sweat_smile: I didn't know that, as I said, I'm super new, basically just read a bunch of other forum posts that all said something about only 0-5v, like this one Arduino Mega 0 - 10V analog input? - Electrical Engineering Stack Exchange

Oh, you still need the voltage divider. 10V would otherwise damage the analog pin. But, think about it: an output of, for example, 7.4V from the sensor would get reduced to 3.7V by the voltage divider. This would give a reading of around 757 or 758 from analogRead(). You could then calculate the input voltage as 757 / 1024 * 5. But you would still need to translate that back to the 0-10V range by multiplying the result by 10 / 5. So the formula would be 757 / 1024 * 5 * 10 / 5 and, voilá, the 5s cancel each other out.

PS. I updated my previous reply before I realised you had responded. Please re-read.

PaulRB:
PS. I updated my previous reply before I realised you had responded. Please re-read.

ok, I'm beginning to follow, issue is also I wrote the original code several months ago so i'm trying to remeber all the stuff from then.

So, instead of using the map function i would have?:

void loop() {

pinMode(A0, INPUT);
float v = analogRead(A0);
v = v * 10.0 / 1024;

float p = pow(10, v - 11.000);

So, Im basically taking the divided input of the 3.7v and calculating back to the 7.4, giving me 2.5*10^-4 torr? That looks like it will work, unless im missing it completely... is there anything else in the code that needs fixing? Thanks btw!! :slight_smile:

Nothing wrong as far as I can see. Except normally pinMode() would be in setup() not loop(). But all pins default to INPUT anyway, so not really needed. Would be good to give pin A0 a name:

#define PRESSURE_SENSOR A0

then you can use analogRead(PRESSURE_SENSOR).

Oh, I'm not sure 5 chars is enough:

char pressureE[5];

I think you will need 7, as in "2.5E-10", plus one extra for the /0 that terminates a string in C.

Alright, here is the final code

#include <LiquidCrystal.h>
#include <math.h>


// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

// the setup routine runs once when you press reset:

    void setup() {
      // initialize serial communication at 9600 bits per second:
      Serial.begin(9600);
      pinMode(A0, INPUT);              //A0 is set as input
      #define PRESSURE_SENSOR A0;
      
      lcd.begin(16, 2);
      lcd.print("MKS  Instruments");
      lcd.setCursor(0, 1);
      lcd.print("IMT Cold Cathode");
      delay(6500);
      lcd.clear();
      lcd.print("Gauge Pressure:");
      
    }

// the loop routine runs over and over again forever:
   
    void loop() {

      float v = analogRead(A0);        //v is input voltage set as floating point unit on analogRead
      v = v * 10.0 / 1024;             //v is 0-5v divider voltage measured from 0 to 1024 calculated to 0v to 10v scale
      float p = pow(10, v - 11.000);   //p is pressure in torr, which is represented by k in the equation [P=10^(v-k)] which is-
                                       // -11.000 (K  = 11.000 for Torr, 10.875 for mbar, 8.000 for microns, 8.875 for Pascal)

       Serial.print(v);

       char pressureE[8];
       dtostre(p, pressureE, 1, 0);        // scientific format with 1 decimal places
      
       lcd.setCursor(0, 1);
       lcd.print(pressureE);
       lcd.print(" Torr");

    }

I uploaded it to my test platform and booted it up, connecting A0 to the 5v aref and gnd respectively. GND shows 1.0e-11 torr, and the 5v shows 9.8e-02, (close enough) seems pretty spot on to me! Curious though, is there any reason it is reading the top of the range slightly off? Is that just an accuracy thing?

Also, you have been a massive help, I got majorly hung up on this for some reason even though it seems it was right under my nose lol. When I first started this project it seemed so daunting. This is my first program BTW! :3

Sources of error could include:

  1. The supply not being exactly 5V. Usb power is often 4.7-4.8V in practice. Powering the Arduino through its barrel jack with 7.5-12V may give something closer to 5V.

  2. The resistors in your voltage divider. If they have gold bands, they should be within 1% tolerance, but you could measure them to check.

If that does not get you close enough, there are other ways such as using the Arduino's internal voltage reference, or an external voltage reference (but never connect anything to AREF that is higher than Vcc).

Also, the AREF pin is an input, not an output. You can attach an external voltage reference there (less than 5V on Uno) and, in the code, instruct the Arduino to measure the analog inputs against that. Normally they are compared to Vcc, which is the voltage at the 5V pin on an Arduino.

I linked a video of it working with an external power supply, starting at 1 volt and incrementing up to 5 volts. It seems to be consistently off by two tenths of the correct value, so 9.8e10-4 instead of 1e10-5. This really isnt a big deal for me I don't think, just curious. Thanks :slight_smile:

So what is the Arduino's supply voltage at the 5V pin?

Also, if I make two posts in a row, do you only read the second? E.g. post #5, #8

Apologies. I'm always very scatter brained, and also sleep deprived if you must know, heh.

I meant to write that it is being powered by the barrel jack with a 9 volt, not usb. I don't have the gauge connected so no voltage divider, just my bench power supply.

I just measured 5 volt pin and everything is accurate, btw this is one of those chinese knockoff arduino boards, I have some genuinos that I will use for the real thing, this is just a test arduino for code prototypes