/**************************************************************************************************
*
*  Pressure SCP1000
*
*   Version:      1.0.0 - Februar 2009
*   Author:       Christoph Wartmann / chair for caad - ETH Zürich  /  wartmann[at].arch.ethz.ch
*                 Etienne Ribeiro    / tutorial assistant caad      /  eribeiro[at]ethz.ch
*
*   Desc:         This Module makes it easy to run the SCP1000 Pressure Sensor in your projects.
*
*   Protocol:     SPI
*
*   Voltage:      typical 2.7V, max 3.3V
*
*   Features implemented:
*                 - SPI Protocol
*                 - all supported Operationmodes
*
*   Not yet implemented:
*                 - I2C (supported on Sparkfun Breakout; Software addresses!)
*                 - self test
*                 - [Operationmode 4 = Triggered Mode (Not supported on Sparkfun Breakout)]
*                 - Standby Mode
*                 - Interrupt
*                 - Reset
*
*  Pins:          use any digital pin. example:
*                 DRDY = 24; (optional)
*                 CSB = 25;
*                 DATAIN (MISO) = 26;
*                 DATAOUT (MOSI) = 27;
*                 SCK = 28;
*
*  Methodes:      boolean scp1000_AppendSensor (byte drdy, byte csb, byte datain, byte dataout, byte sckclock, byte Operationmode)
*                   drdy, csb, datain, dataout, sckclock: digital Pins, drdy is not needed and can be set to -1
*                   Operationmode:  0 = High speed (15bit, 9Hz), 1 = High resolution (17bit, 1.8Hz), 2 = Ultra low power (15bit, 1Hz)
*                   return false, if sensor coud not be initialized.
*                 void scp1000_setOperationMode(int modeid)
*                   change operation mode
*                   modeid:  0 = High speed (15bit, 9Hz), 1 = High resolution (17bit, 1.8Hz), 2 = Ultra low power (15bit, 1Hz)
*                 long scp1000_Read(char which)
*                   'p' = get pressure
*                   't' = get temperature
*                   's'= get status
*                   'o' = get operation mode
*                   'n' = get operation status
*                 void scp1000_parseDegrees (int val, int *retSign, int *ret1, int *ret2)
*                   Parse value to degrees. val = scp1000_Read('t') and scp1000_parseDegrees (val,...)
*                   *retSign: Return Value (sign) -1 or 1. Access this value by &var
*                   *ret1: Return Value (upper). Access this value by &var
*                   *ret2: Return Value (lower). Access this value by &var
*                 long scp1000_parsePa (long val)
*                   Parse value to Pascal. val = scp1000_Read('p') and scp1000_parsePa (val)
*                 void scp1000_parsePa (long val, long *ret1, long *ret2)
*                   Parse value to Pascal. val = scp1000_Read('p') and scp1000_parsePa (val,...)
*                   *ret1: Return Value (upper). Access this value by &var
*                   *ret2: Return Value (lower). Access this value by &var
*                 boolean scp1000_printStatus (byte state)
*                   Print current state of sensor. state = scp1000_Read('s') and scp1000_printStatus (state)
*                 boolean scp1000_printOperation (byte operation)
*                   Print operation mode. operationmode = scp1000_Read('o') and scp1000_printOperation (operationmode)
*
***************************************************************************************************/






//
// Const

// direct access:
#define Reg_REVID 0x00
#define Reg_DATAWR 0x01
#define Reg_ADDPTR 0x02
#define Reg_OPERATION 0x03
byte const Reg_OPERATION_modes[] = {0x09, 0x0A, 0x0B, 0x0C};  // (0x0C or TRIG pin)
#define Reg_OPSTATUS 0x04
#define Reg_RSTR 0x06
#define Reg_STATUS 0x07
byte const Reg_STATUS_startupbit = 0;
#define Reg_DATARD8 0x1F
byte const Reg_DATARD8_checksumerror = 0x00;
#define Reg_DATARD16 0x20 // 16bit
#define Reg_TEMPOUT 0x21 // 16bit
// indirect access:
#define Reg_CFG 0x00
#define Reg_TWIADD 0x05
#define Reg_USERDATA1 0x29
#define Reg_USERDATA2 0x2A
#define Reg_USERDATA3 0x2B
#define Reg_USERDATA4 0x2C


// more consts
int temp_factor = 20;
int pressure_factor = 4;


//
// Var

int scp1000_DRDY;        // 24 1: availability of new measurement
int scp1000_CSB;         // 25 selects the chip on multi-chip SPI bus
int scp1000_DATAIN;      // 26 MISO (Master In Slave Out)
int scp1000_DATAOUT;     // 27 MOSI (Master Out Slave In)
int scp1000_SCKCLOCK;    // 28 Clock




// *************************
//
//  Functions
//


//
// scp1000_AppendSensor
//  -> Operationmode: 0: High speed (15bit, 9Hz), 1: High resolution (17bit, 1.8Hz), 2: Ultra low power (15bit, 1Hz), [3 Low poser but triggerd (15bit to 17bit, 1.8Hz) not supported on Sparkfun Breakout]
boolean scp1000_AppendSensor (byte drdy, byte csb, byte datain, byte dataout, byte sckclock, byte Operationmode) {

        // Variables
        scp1000_DRDY = drdy;
        scp1000_CSB = csb;
        scp1000_DATAIN = datain;
        scp1000_DATAOUT = dataout;
        scp1000_SCKCLOCK = sckclock;


        // Pins
        pinMode(scp1000_DRDY, INPUT);
        pinMode(scp1000_CSB, OUTPUT);
        pinMode(scp1000_DATAOUT, OUTPUT);
        pinMode(scp1000_DATAIN, INPUT);
        pinMode(scp1000_SCKCLOCK, OUTPUT);
        digitalWrite(scp1000_CSB, HIGH); //disable device
        digitalWrite(scp1000_DATAOUT, LOW);
        digitalWrite(scp1000_SCKCLOCK, LOW);


        // startup device
        boolean success1 = scp1000_startup();
        boolean success2 = scp1000_checksumTest();
        if (success1 == false || success2==false)
        return false;


        // Select operation mode
        if (Operationmode < 0 || Operationmode > 3) Operationmode = 0;
        scp1000_setOperationMode (Operationmode); // Values 0 to 3


        // Return
        return true;

}



//
// Startup SCP1000

boolean scp1000_startup() {

        delay (60); // 60 ms startup delay

        for (int i=0;i<6;i++) { // check if startup has finished

                int val = scp1000_SPI_read8(Reg_STATUS);
                if (int(1<<Reg_STATUS_startupbit & val) == 0) // Startup successfully
                return true;
                delay (10);

        }

        return false; // start-up has failed

}



//
// Test Checksum

boolean scp1000_checksumTest() {

        int checksum = scp1000_SPI_read8(Reg_DATARD8);
        if (Reg_DATARD8_checksumerror == checksum) {// todo
                return false;
        }


        return true;

}



//
// Set operation mode

void scp1000_setOperationMode(int modeid) {

        // Stop active Mode (if SCP1000 is already powerd up and running)
        scp1000_SPI_write(Reg_OPERATION, 0x00);
        delay (50);


        // Check if DRDY is LOW (If DRDY is HIGH it is necessary to read the output data before activating new measurement mode)
        if (scp1000_DRDY != -1) {
                if (digitalRead(scp1000_DRDY) == HIGH)
                scp1000_SPI_read16(Reg_DATARD16);
        }


        // Select an operation mode
        byte cmd = Reg_OPERATION_modes[modeid]; // Command to write to register (0C)
        scp1000_SPI_write(Reg_OPERATION, cmd);

}




//
// scp1000_Read
//   'p' -> 16bit pressure, 't' -> 16bit temperature, 's' -> status, 'o' -> operation mode, 'n' -> operation status

long scp1000_Read(char which) {

        //
        long val;
        switch(which) {

                case 'P':case 'p': // 3bit + 16bit pressure

                val = scp1000_SPI_read8(Reg_DATARD8);
                val <<= 16;
                unsigned int tmpval;
                tmpval = scp1000_SPI_read16(Reg_DATARD16);
                val += tmpval;
                return val;

                case 'T':case 't': // 16bit temperature

                val = scp1000_SPI_read16(Reg_TEMPOUT);

                // if negativ value:
                if (int(1<<13 & val) != 0) {    // bit 13 == 1
                        val ^= 16383;                 // Invert 14 bits (16 bits would be 65535)
                        val += 1;                     // plus 1
                        val *= -1;
                }

                return val;
                break;

                case 'S':case 's': // status

                return scp1000_SPI_read8(Reg_STATUS);
                break;

                case 'O':case 'o': // operation mode

                return scp1000_SPI_read8(Reg_OPERATION);
                break;

                case 'N':case 'n': // operation status

                return scp1000_SPI_read8(Reg_OPSTATUS);
                break;

        }

}



//
// scp1000_parseDegrees
//   Parse Value to Degres

void scp1000_parseDegrees (int val, int *retSign, int *ret1, int *ret2) {

        *retSign = 1;
        if (val < 0)
        *retSign = -1;
        *ret1 = abs(val / temp_factor);
        *ret2 = abs(val  % temp_factor * 100 / temp_factor);

}



//
// scp1000_parseDegrees
//   Parse Value to Pascal

long scp1000_parsePa (long val) {

        long ret1;
        long ret2;
        scp1000_parsePa (val, &ret1, &ret2);
        return ret1;

}
void scp1000_parsePa (long val, long *ret1, long *ret2) {

        *ret1 = val / pressure_factor;
        *ret2 = abs(val  % pressure_factor * 100 / pressure_factor);

}




//
// scp1000_printStatus
//   Print status in natural language

boolean scp1000_printStatus (byte state) {

        Serial.print("Status: ");
        Serial.print(state, BIN);
        Serial.print(": ");
        if (int(1<<6 & state) != 0) // byte 0100 0000
        Serial.print (" Acquisition is running."); // externally triggered
        if (int(1<<5 & state) != 0) // byte 0010 0000
        Serial.print (" New results are available.");
        if (int(1<<4 & state) != 0) // byte 0001 0000
        Serial.print (" Real time error!"); // interrupt has not been serviced in time, cleared by DATARD16 read operation
        if (int(1<<0 & state) != 0) // byte 0000 0001
        Serial.print (" Start-up procedure still running");

}


//
// scp1000_printOperation
//   Print operation-register value in natural language

boolean scp1000_printOperation (byte operation) {

        Serial.print("Operation: 0x");
        Serial.print(operation, HEX);
        Serial.print(": ");

        switch (operation) {

                case 0x00:

                Serial.print (" NO OPERATION! Select an operation mode!");
                break;

                case 0x09:

                Serial.print (" High speed acquisition mode (continuous measurement).");
                break;

                case 0x0A:

                Serial.print (" High resolution acquisition mode (continuous measurement).");
                break;

                case 0x0B:

                Serial.print (" ultra low power acquisition mode (continuous measurement).");
                break;

                case 0x0C:

                Serial.print (" low power acquisition mode. (external TRIG, NOT SUPPORTED ON SPARKFUN BREAKOUT!)");
                break;

                default:

                Serial.print (" see Datasheet on page 18 Table 11");
                break;

        }

}









// ***************************
//
//  SPI - Functions
//



//
// SPI_write

void scp1000_SPI_write (byte registerByte, byte commandByte) {

        digitalWrite(scp1000_CSB, LOW); //turn on device

        // 6 bits register address
        for (int i=5; i>=0; i--){

                // write bit
                if (int(1<<i & registerByte) == 0) digitalWrite(scp1000_DATAOUT, LOW); else digitalWrite(scp1000_DATAOUT, HIGH);
                // cycle clock
                digitalWrite(scp1000_SCKCLOCK, HIGH);
                digitalWrite(scp1000_SCKCLOCK, LOW);

        }

        digitalWrite(scp1000_DATAOUT, HIGH); // Indicate that we are Writing
        digitalWrite(scp1000_SCKCLOCK, HIGH);
        digitalWrite(scp1000_SCKCLOCK, LOW);
        digitalWrite(scp1000_DATAOUT, LOW); // LOW
        digitalWrite(scp1000_SCKCLOCK, HIGH);
        digitalWrite(scp1000_SCKCLOCK, LOW);


        // write 8 bits register content
        for (int i=7; i>=0; i--){

                // write bit
                if (int(1<<i & commandByte) == 0) digitalWrite(scp1000_DATAOUT, LOW); else digitalWrite(scp1000_DATAOUT, HIGH);
                // cycle clock
                digitalWrite(scp1000_SCKCLOCK, HIGH);
                digitalWrite(scp1000_SCKCLOCK, LOW);

        }


        digitalWrite(scp1000_CSB, HIGH); //turn off device

}



//
// SPI_read8

int scp1000_SPI_read8 (byte registerByte) {

        digitalWrite(scp1000_CSB, LOW); //turn on device

        // 6 bits register address
        for (int i=5; i>=0; i--){

                // write bit
                if (int(1<<i & registerByte) == 0) digitalWrite(scp1000_DATAOUT, LOW); else digitalWrite(scp1000_DATAOUT, HIGH);
                // cycle clock
                digitalWrite(scp1000_SCKCLOCK, HIGH);
                digitalWrite(scp1000_SCKCLOCK, LOW);

        }

        digitalWrite(scp1000_DATAOUT, LOW); // Indicate that we are Reading
        digitalWrite(scp1000_SCKCLOCK, HIGH);
        digitalWrite(scp1000_SCKCLOCK, LOW);
        digitalWrite(scp1000_SCKCLOCK, HIGH);
        digitalWrite(scp1000_SCKCLOCK, LOW);

        // read 8 bits register content
        int returnValue = 0;
        for (int i=7; i>=0; i--){

                // read bit
                returnValue += digitalRead (scp1000_DATAIN) << i;
                // cycle clock
                digitalWrite(scp1000_SCKCLOCK, HIGH);
                digitalWrite(scp1000_SCKCLOCK, LOW);

        }


        digitalWrite(scp1000_CSB, HIGH); //turn off device

        return returnValue;

}



//
// SPI_read16

int scp1000_SPI_read16 (byte registerByte) {

        digitalWrite(scp1000_CSB, LOW); //turn on device

        // 6 bits register address
        for (int i=5; i>=0; i--){

                // write bit
                if (int(1<<i & registerByte) == 0) digitalWrite(scp1000_DATAOUT, LOW); else digitalWrite(scp1000_DATAOUT, HIGH);
                // cycle clock
                digitalWrite(scp1000_SCKCLOCK, HIGH);
                digitalWrite(scp1000_SCKCLOCK, LOW);

        }

        digitalWrite(scp1000_DATAOUT, LOW); // Indicate that we are Reading
        digitalWrite(scp1000_SCKCLOCK, HIGH);
        digitalWrite(scp1000_SCKCLOCK, LOW);
        digitalWrite(scp1000_SCKCLOCK, HIGH);
        digitalWrite(scp1000_SCKCLOCK, LOW);


        // read 8 bits register content
        int returnValue = 0;
        for (int i=15; i>=0; i--){

                // read bit
                returnValue += digitalRead (scp1000_DATAIN) << i;
                // cycle clock
                digitalWrite(scp1000_SCKCLOCK, HIGH);
                digitalWrite(scp1000_SCKCLOCK, LOW);

        }

        digitalWrite(scp1000_CSB, HIGH); //turn off device

        return returnValue;

}

This website has been archived and is no longer maintained.