Help with Voltage to Pressure

I am trying to write a function/procedure that returns the pressure from a MAP (Manifold Aboslute Pressure) sensor It is a analog sensor. I want to convert the ADC value to Psi or kpa.

Here is the start of the code with the sensor range values,
Can someone please help me with a formula

Ray.

/*

  • *********** Manifold pressure sensor ***************
  • MIN VOLTS 0.5 V = 0 Psi Gauge
  • MAX VOLTS 4.5 V = 15 Psi Gauge

*/

//---------------------- get Map Pressure ------------------------------
uint16_t getMapPressure(uint16_t adcVal)
{

uint16_t map;


map = acdVal ????????????

return map

You have to provide some more information
You are working on an informatic project. Your code will process information and what is most needed in an informatic project is - guess what ? information.

What is the reference-voltage that your ADC is using 5V? 3,3V?
what resolution does your ADC have? 8bit?, 10bit?, 12bit?, 16bit?, 24bit?
depends on the ADC / the microcontroller that you are using

So what microcontroller are you using?
Do you use an ADC-input of this microcontroller or are you using an external ADC?

as an example calculation for reference-voltage 5V = 5000 mV and 10 bit ADC-resolution

LibreOffice-caclulation-sheet.
The sheet creates even the code with the calculated numbers

ADC_digits = analogRead(ADC_Pin);
upScaledDigits = ADC_Digits * 1000
measured_milli_PSI = map(upScaledDigits,102000,921000,0,15000);

as function maps uses integers and as floats are unprecise on microcontrollers me personally I prefer upscaling integer-values.

I guess milli-PSI 1 PSI = 1000 milliPSI will be precise enough.
You could even go up to microPSI with a scaling-factor of 1.000.000 but that is not really precise on a 10bit ADC because 1 digit is

PSI-range / voltage-difference * Ref-voltage/max-ADC
15 PSI / 4000 mV * 5000 mV / 1023 digits= 0.0183 PSI / digit

So on a 10bit ADC the real resolution is 18,3 milli-PSI

calculate-map-values.zip (31.7 KB)

best regards Stefan

Can you also provide a link to the data sheet ?
Also important to know if there is a linear relationship between pressure and voltage output.

Hello, I am looking for a math formula to convert the raw ADC value read from sensor into Psi or Kpa
This is the procedure that I am trying to write
Ray.

/*
*   ***********  Manifold pressure sensor ***************
* 
*    MIN VOLTS 0.5 V = 0 Psi Gauge
*    MAX VOLTS 4.5 V = 15 Psi Gauge
* 
*/

//---------------------- get Map Pressure ------------------------------
uint16_t getMapPressure(uint16_t adcVal)
{

    uint16_t map;

    map = acdVal ????????????

   return map

}

Hi,
What model sensor are you using?
Can you please post a link to data/specs?

What model Arduino are you using?

You can use the map function;

Thanks.. Tom.. :smiley: :+1: :coffee: :australia:

This is the sensor DataSheet

Here is all the code. I think it just compliates my inquire


*/
#include <Stepper.h>
#include "StepperAneroid.h"
#include <Wire.h>



// Give the motor control pins names:
#define pwmA 3
#define pwmB 11
#define brakeA 9
#define brakeB 8
#define dirA 12
#define dirB 13

ECU_Cal ecu;
// Define number of steps per revolution:
const int stepsPerRevolution = 200;
uint8_t RxData[RXPACKET];
uint8_t TxData[TXPACKET];
uint8_t gotRx = false;
unsigned char* ptr_g;   //global pointer to data
unsigned int packet_lenght;
uint8_t reply[6] = {0x24,0x00,0x06,0x00,0x00,0x00 };
int sensorPin = A0;    // select the input pin for the potentiometer
int sensorValue = 0;  // variable to store the value coming from the sensor
// constants won't change. They're used here to set pin numbers:
const int buttonPin = 2;         // the number of the pushbutton pin
uint8_t buttonState = 0;         // variable for reading the pushbutton status


void loadTableDate(void);
void CheckCommsActivity(void);
void changeOfValueRequested(void);
void sendWholeMap(void);
void sendReply(uint8_t id, uint8_t flag);
uint16_t CalculateCheckSum(uint8_t* StructurePointer, uint16_t pkt);
uint8_t CheckSum16bit(void);

// Initialize the stepper library on the motor shield:
Stepper myStepper = Stepper(stepsPerRevolution, dirA, dirB);

void setup() {
    loadTableDate();

    Serial.begin(9600);           // set up Serial library at 115200 bps
    while (!Serial);
    Serial.println("Stepper test!");

    Serial.println("Motor Shield found.");
    ecu.data.stepPos = 129;

    
    // initialize the pushbutton pin as an input:
    pinMode(buttonPin, INPUT);
    pinMode(buttonPin, INPUT_PULLUP);
    buttonState = 0;
    ecu.data.stepPos = 100;

    // Set the PWM and brake pins so that the direction pins can be used to control the motor:
    pinMode(pwmA, OUTPUT);
    pinMode(pwmB, OUTPUT);
    pinMode(brakeA, OUTPUT);
    pinMode(brakeB, OUTPUT);
    EnableStepper();
 
    //Set the motor speed (RPMs):
   
    myStepper.setSpeed(350);
    
    //zeroStepperMotor();
    //setStepperPos();
    DisableStepper();
    
}

void loop() {
    // read the value from the sensor:
    int16_t rawADC = analogRead(sensorPin);
    ecu.data.mapRaw = rawADC;
    ecu.data.map = rawADCtoPsi(rawADC);


    // read the state of the pushbutton value:
    ecu.data.stepStopSw = digitalRead(buttonPin);
    
  /*
    // Step one revolution in one direction:
    myStepper.step(200);

    delay(2000);

    //Step on revolution in the other direction:
    myStepper.step(-200);

    delay(2000);
  */
    delay(10);
    //sendWholeMap();

    //Serial.println("Hello Ray");
    if (gotRx == true) {
        gotRx = false;
      // CheckCommsActivity();
    }
    //


}

/*
  SerialEvent occurs whenever a new data comes in the hardware serial RX. This
  routine is run between each time loop() runs, so using delay inside loop can
  delay response. Multiple bytes of data may be available.
*/
void serialEvent() {
    static uint16_t pkt = 0;
    static uint16_t x = 0;
    static uint8_t Schar = false;    // Start char for comms
    uint8_t RxByte;
    static uint16_t i = 0;

    while (Serial.available()) {
        RxByte = Serial.read();

        switch (RxByte) {

        case 0x24: RxData[x++] = RxByte; // $ Start char                 
            Schar = true;
            break;
        default: if (Schar == true) {
            RxData[x++] = RxByte;
        }
               break;
        } // End Switch

        if (x == 3) {
            pkt = (RxData[x - 2] << 8);
            pkt = pkt + (RxByte & 0xFF);

        }

        if (x == pkt) {   // Last byte received      
            x = 0;
            pkt = 0;
            Schar = false;
            gotRx = true;
            CheckCommsActivity();
        }
    }

}

//------------------ Check Comms Activity ---------------------------

void CheckCommsActivity(void) {

    uint8_t cmd;

    if (gotRx == true) {

        cmd = RxData[3];  // Read the forth byte which is the command

        switch (cmd) {
        case 0x01: sendRealTimeData();
            break;
        case 0x02:// receiveWholeMap();
            break;
            //case 0x03: WriteStructureToEEprom((uint8_t*)&ecu, sizeof(ecu));   // Lock changes into flash
             //   sendReply(0x03, true); // Okay
              //  break;
        case 0x04: sendWholeMap();
            break;
        case 0x05: changeOfValueRequested();
            break;
        }

        gotRx = false;
    }
}

//------------------- Change Of Value Requested --------------------  
void changeOfValueRequested(void)
{
    uint16_t dataID;
    uint16_t wordVal;
    uint16_t pos;


    if (CheckSum16bit() == true) {

        dataID = (RxData[4] << 8);
        dataID = dataID + (uint8_t)(RxData[5]);


        switch (dataID) {

        case 1001: 
            pos = RxData[8];    // Fuel Pump PWM Table
            wordVal = (RxData[6] << 8);
            wordVal = wordVal + RxData[7];
            ecu.setup.table[1][pos] = wordVal;
            sendReply(0x05, true);
            break;
        }

    }
    else {
        sendReply(0x05, false);
    }

}

//---------------------------- Send Real Time Data -----------------------
void sendRealTimeData(void) {

    uint16_t pkt = sizeof(ecu.data);
    uint8_t x;
    ecu.data.startChar = 0x24;
    ecu.data.PacketHi = (pkt >> 8);
    ecu.data.PacketLo = (uint8_t)pkt;
    ecu.data.PacketID = 0x01;
    ecu.data.crcCnt = CalculateCheckSum((uint8_t*)&ecu.data, pkt);
    (void)memcpy(&TxData, (uint8_t*)&ecu.data, pkt);

    for (x = 0; x < pkt; x++) {
        Serial.write(TxData[x]);
    }
    packet_lenght = pkt;
    // SCI0CR2_TIE = 1;                  //TDRE interrupt requests enabled   
}

//---------------------------- Send Whole Map ----------------------------
void sendWholeMap(void)
{
    uint16_t pkt = sizeof(ecu);
    uint8_t x;

    ecu.startChar = 0x24;
    ecu.PacketHi = (pkt >> 8);
    ecu.PacketLo = (uint8_t)pkt;
    ecu.PacketID = 0x04;
    ecu.crcCnt = CalculateCheckSum((uint8_t*)&ecu, pkt);
    (void)memcpy(&TxData, (uint8_t*)&ecu, pkt);

    for (x = 0; x < pkt; x++) {
        Serial.write(TxData[x]);
    }

    gotRx = false;

    packet_lenght = pkt;
    //  SCI0CR2_TIE = 1;                  //TDRE interrupt requests enabled   

}

//----------------------------- Send Reply to PC --------------------------
void sendReply(uint8_t id, uint8_t flag)
{
    uint8_t x;

    reply[3] = id;
    reply[4] = flag;  // True or False
    (void)memcpy(&TxData, (uint8_t*)&reply, 6U);
    packet_lenght = 6U;

    for (x = 0; x < packet_lenght; x++) {
        Serial.write(TxData[x]);
    }

}

//------------------ Calculate Structure Check Sum --------------------------

uint16_t CalculateCheckSum(uint8_t* StructurePointer, uint16_t pkt)
{
    uint16_t x;
    uint16_t cnt;

    pkt = pkt - 0x0002;
    cnt = 0;
    for (x = 0; x < pkt; x++) {
        cnt = cnt + StructurePointer[x];
    }

    cnt = (uint16_t)(65535 - cnt) + 1;


    return(cnt);
}


//------------------------ Check Sum 16 bit -------------------------
uint8_t CheckSum16bit(void)
{
    uint8_t result;
    uint16_t x;

    uint16_t pkt;
    uint16_t cnt, cs;


    pkt = (RxData[1] << 8);
    pkt = pkt + RxData[2];
    pkt = pkt - 0x0002;

    cnt = 0;
    for (x = 0; x < pkt; x++) {
        cnt = cnt + (RxData[x] & 0xFF);
    }

    cs = (uint16_t)(RxData[pkt] << 8) + (uint16_t)RxData[pkt + 1];


    result = (uint8_t)(cnt - (65535 - cs));

    return(result);
}

//------------------------------- Zero Stepper Motor ------------------------------
uint8_t zeroStepperMotor(void)
{
    uint8_t x = 1;
    do {
        myStepper.step(-5);
        delay(50);          // wait for sensors to stabilize
        x = digitalRead(buttonPin);
    } while (x == 1);
    ecu.data.stepPos = 0;
    return x;
}

//------------------------ Set Stepper Pos ------------------------------------------
void setStepperPos(void)
{
    uint16_t pos;
   
    pos = Interpolate2D((uint16_t*)&ecu.setup.table  , STEPSTABLEX, ecu.data.map);
    myStepper.step(pos);
}


//----------------------------- Interpolate 2D ---------------------------
uint16_t Interpolate2D(uint16_t* table, uint8_t axisXCnt, int16_t xAxis)
{
    uint8_t x;
    int16_t val = 0;
    int16_t o_low;  /* Output (table) low value */
    int16_t i_low;  /* Input (X-axis) low value */
    int16_t o_delta; /* Spread between the two adjacent table output values */
    int16_t i_delta; /* Spead between the two adjacent input values */


    if (xAxis > table[axisXCnt - 1]) {

        val = table[(axisXCnt << 1) - 1];
        return val;

    }
    else

        if (xAxis < table[0]) {
            val = table[axisXCnt];
            return val;
        }

    for (x = 0; x < axisXCnt - 1; ++x) {
        if (table[x] <= xAxis && xAxis < table[x + 1]) {

            i_low = table[x];	          /* Input (X-axis) low value */
            o_low = table[x + axisXCnt]; /* Output (table) low value */

            i_delta = table[x + 1] - table[x];
            o_delta = table[x + axisXCnt + 1] - table[x + axisXCnt];

            /* Prevent division by zero.  We could get here if two consecutive
          input values in the table are the same. */
            if (o_delta == 0)
            {
                val = o_low;
                return val;;
            }

            val = (uint16_t)(o_low + ((xAxis - i_low) * (long)o_delta) / i_delta);

            return val;

        }
    }

    /* Didn't find it (we shouldn't ever get here). */
    return val;
}

//------------------------------ Raw ADC to Psi ---------------------------------
uint16_t rawADCtoPsi(uint16_t adc)
{
   float psi;
 
   float voltage = (float)adc/ 1024.0 * 5.0;
    psi = (voltage - 0.5) / 4.5 * 100.0;
    psi = psi * 100;
    return psi;
}
//------------------------------ Disable Stepper ------------------------------
void DisableStepper(void)
{
    digitalWrite(pwmA, LOW);
    digitalWrite(pwmB, LOW);
    digitalWrite(brakeA, LOW);
    digitalWrite(brakeB, LOW);
}
//----------------------------- Enable Stepper ----------------------------------
void EnableStepper(void)
{
    digitalWrite(pwmA, HIGH);
    digitalWrite(pwmB, HIGH);
    digitalWrite(brakeA, LOW);
    digitalWrite(brakeB, LOW);
}
//---------------------------------------------------------------------------
void loadTableDate(void)
{
    ecu.setup.table[0][0] = 0;
    ecu.setup.table[0][1] = 2;
    ecu.setup.table[0][2] = 4;
    ecu.setup.table[0][3] = 6;
    ecu.setup.table[0][4] = 8;
    ecu.setup.table[0][5] = 10;
    ecu.setup.table[0][6] = 12;
    ecu.setup.table[0][7] = 14;
    ecu.setup.table[0][8] = 16;
    ecu.setup.table[0][9] = 18;
    ecu.setup.table[0][10] = 20;
    ecu.setup.table[0][11] = 22;
    ecu.setup.table[0][12] = 25;


    ecu.setup.table[1][0] = 0;
    ecu.setup.table[1][1] = 5;
    ecu.setup.table[1][2] = 20;
    ecu.setup.table[1][3] = 40;
    ecu.setup.table[1][4] = 80;
    ecu.setup.table[1][5] = 120;
    ecu.setup.table[1][6] = 160;
    ecu.setup.table[1][7] = 180;
    ecu.setup.table[1][8] = 220;
    ecu.setup.table[1][9] = 250;
    ecu.setup.table[1][10] = 275;
    ecu.setup.table[1][11] = 310;
    ecu.setup.table[1][12] = 320;

    ecu.setup.mapPressMin = 0;
    ecu.setup.mapPressMax = 200;
    ecu.setup.mapVoltsMin = 102;
    ecu.setup.mapVoltsMax = 921;
}

Sometimes there is a formula in the datasheet.
I map the range of the input onto the range of the output and solve the offsets.
When starting with a voltage, then dividing by the voltage range removes the voltage.
If multiplying that with the pressure range, then the result is a pressure.

Have you heard of "ratiometric".
When the sensor is powered with the same voltage as the Arduino board (5V or 3.3V), then you get the maximum accuracy. If the voltage of the Arduino board changes, you still get the right pressure. So if the 5V drops to 4.5V, the analogRead() still returns the same value because the analogRead() returns a value relative to the voltage reference.

Assuming that you have a Arduino Uno or Mega or Nano and the pressure sensor is connected to A0:

// Get the raw ADC value
int rawADC = analogRead(A0);

// Calculate the voltage.
// Warning : Do not change the 5.0, even if the voltage is 4.6V.
//       The "5.0" is just a helper value, it drops out of the formula.
float voltage = float(rawADC) / 1024.0 * 5.0;

float voltage_range = 4.5 - 0.5;
float pressure_range = 15.0;
float voltage_offset = 0.5;
float pressure_offset = 0.0;

float pressure = ((voltage - voltage_offset) / voltage_range * pressure_range) + pressure_offset;

Or the short version:

// Warning : Do not change the 5.0, even if the voltage is 4.6V.
int rawADC = analogRead(A0);
float voltage = float(rawADC) / 1024.0 * 5.0;
float pressure = (voltage - 0.5) / 4.0 * 15.0;

I have merged your cross-posts @rayhall.

Cross-posting is against the Arduino forum rules. The reason is that duplicate posts can waste the time of the people trying to help. Someone might spend a lot of time investigating and writing a detailed answer on one topic, without knowing that someone else already did the same in the other topic.

Repeated cross-posting can result in a suspension from the forum.

In the future, please only create one topic for each distinct subject matter. This is basic forum etiquette, as explained in the "How to get the best out of this forum" guide. It contains a lot of other useful information. Please read it.

Thanks in advance for your cooperation.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.