Humidity and pressure over SPI

I tried to put the code from humidity and from the pressure Sketch together. They are connected both over SPI.
At the moment the Sketch doesn’t work. I think I have to set one as Slave but I don’t know how.

Could you pls help me? Thx!

//humidity
#include <avr/io.h>

#define STATUS_REG_W 0x06 //000 0011 0
#define STATUS_REG_R 0x07 //000 0011 1
#define MEASURE_TEMP 0x03 //000 0001 1
#define MEASURE_HUMI 0x05 //000 0010 1
#define RESET 0x1e        //000 1111 0

// pins dat - PB4, clk - PB5
#define SETSCK1 PORTB|=(1<<PB5)
#define SETSCK0 PORTB&=~(1<<PB5)
#define SCKOUTP DDRB|=(1<<DDB5)

#define SETDAT1 PORTB|=(1<<PB4)
#define SETDAT0 PORTB&=~(1<<PB4)
#define GETDATA (PINB&(1<<PINB4))

#define DMODEIN DDRB&=~(1<<DDB4)
#define PULLUP1 PORTB|=(1<<PINB4)
#define DMODEOU DDRB|=(1<<DDB4)

#define S_PULSLONG delayMicroseconds(3) 
#define S_PULSSHORT delayMicroseconds(1)


char s_measure(unsigned int *p_value, unsigned char mode);
void calc_sth11(float *p_humidity ,float *p_temperature);
float calc_dewpoint(float h,float t);
void serialPrintFloat( float f);




//PRESSURE

#define SLAVESELECT 10
#define SPICLOCK 13
#define DATAOUT 11      //MOSI
#define DATAIN 12       //MISO

#define UBLB(a,b)  ( ( (a) << 8) | (b) )
#define UBLB19(a,b) ( ( (a) << 16 ) | (b) )


#define REVID 0x00      //ASIC Revision Number
#define OPSTATUS 0x04   //Operation Status
#define STATUS 0x07     //ASIC Status
#define START 0x0A      //Constant Readings
#define PRESSURE 0x1F   //Pressure 3 MSB
#define PRESSURE_LSB 0x20 //Pressure 16 LSB
#define TEMP 0x21       //16 bit temp

char rev_in_byte;          
int temp_in;
unsigned long pressure_lsb;
unsigned long pressure_msb;
unsigned long temp_pressure;
unsigned long pressure;








void setup(){
  //pressure  
  byte clr;
  pinMode(DATAOUT, OUTPUT);
  pinMode(DATAIN, INPUT);
  pinMode(SPICLOCK,OUTPUT);
  pinMode(SLAVESELECT,OUTPUT);
  digitalWrite(SLAVESELECT,HIGH); //disable device  

  SPCR = B01010011;
  clr=SPSR;
  clr=SPDR;
  delay(10);
  Serial.begin(9600);
  delay(500);
  write_register(0x03,0x09);


  //Humidity
  Serial.begin(19200);
}

void loop()
{
  pressure_calculate();
  delay(5000);
  humidity_calculate();
  delay(5000);
}



void pressure_calculate(){



  rev_in_byte = read_register(REVID);

  pressure_msb = read_register(PRESSURE);
  pressure_msb &= B00000111;
  pressure_lsb = read_register16(PRESSURE_LSB);
  pressure_lsb &= 0x0000FFFF;


  pressure = UBLB19(pressure_msb, pressure_lsb);
  pressure /= 4;

  Serial.print("PRESSURE ");
  Serial.println(pressure, DEC);

}



void humidity_calculate(){
  byte error;
  byte rh;
  unsigned int humival_raw,tempval_raw;
  float humival_f, tempval_f, dew_point_f;
  char str[15];

  error=s_measure( &tempval_raw,0); //measure temperature

  if (error==0){
    error=s_measure( &humival_raw,1); //measure humidity
  }

  if(error!=0){ //in case of an error
    if (error==1){
      Serial.println("SHT1x sensor communication error");
    }
    if (error==3){
      Serial.println("SHT1x sensor timeout error");
    }

    delay(5000);
    return;
  }

  humival_f = (float) humival_raw;
  tempval_f = (float) tempval_raw;

  calc_sth11(&humival_f, &tempval_f);
  dew_point_f=calc_dewpoint(humival_f,tempval_f); //calculate dew point

  Serial.print("Temperature = ");
  serialPrintFloat(tempval_f);
  Serial.print("C");        
  Serial.print(" Rel Humidity = ");
  serialPrintFloat(humival_f);
  Serial.print("%");
  Serial.print(" Dew point = ");
  serialPrintFloat(dew_point_f);
  Serial.println("C");
}


//for humidity

// writes a byte on the Sensibus and checks the acknowledge
char s_write_byte(unsigned char value)
{
  unsigned char i=0x80;
  unsigned char error=0;
  DMODEOU; 
  while(i){ //shift bit for masking
    if (i & value) {
      SETDAT1; //masking value with i , write to SENSI-BUS
    }
    else{ 
      SETDAT0;
    }
    SETSCK1; //clk for SENSI-BUS
    S_PULSLONG;
    SETSCK0;
    S_PULSSHORT;
    i=(i>>1);
  }
  DMODEIN; //release DATA-line
  PULLUP1;
  SETSCK1; //clk #9 for ack
  S_PULSLONG;
  if (GETDATA){ //check ack (DATA will be pulled down by SHT11)
    error=1;
  }
  S_PULSSHORT;
  SETSCK0;
  return(error); //error=1 in case of no acknowledge
}

// reads a byte form the Sensibus and gives an acknowledge in case of "ack=1"
unsigned char s_read_byte(unsigned char ack)
{
  unsigned char i=0x80;
  unsigned char val=0;
  DMODEIN; //release DATA-line
  PULLUP1;
  while(i){ //shift bit for masking
    SETSCK1; //clk for SENSI-BUS
    S_PULSSHORT;
    if (GETDATA){
      val=(val | i); //read bit
    }
    SETSCK0;
    S_PULSSHORT;
    i=(i>>1);
  }
  DMODEOU; 
  if (ack){
    //in case of "ack==1" pull down DATA-Line
    SETDAT0;
  }
  else{
    SETDAT1;
  }
  SETSCK1; //clk #9 for ack
  S_PULSLONG;
  SETSCK0;
  S_PULSSHORT;
  DMODEIN; //release DATA-line
  PULLUP1;
  return (val);
}

// generates a sensirion specific transmission start
// This is the point where sensirion is not I2C standard conform and the
// main reason why the AVR TWI hardware support can not be used.
//       _____         ________
// DATA:      |_______|
//           ___     ___
// SCK : ___|   |___|   |______
void s_transstart(void)
{
  //Initial state
  SCKOUTP;
  SETSCK0;
  DMODEOU; 
  SETDAT1;
  //
  S_PULSSHORT;
  SETSCK1;
  S_PULSSHORT;
  SETDAT0;
  S_PULSSHORT;
  SETSCK0;
  S_PULSLONG;
  SETSCK1;
  S_PULSSHORT;
  SETDAT1;
  S_PULSSHORT;
  SETSCK0;
  S_PULSSHORT;
  //
  DMODEIN; //release DATA-line
  PULLUP1;
}

// communication reset: DATA-line=1 and at least 9 SCK cycles followed by transstart
//      _____________________________________________________         ________
// DATA:                                                     |_______|
//          _    _    _    _    _    _    _    _    _        ___    ___
// SCK : __| |__| |__| |__| |__| |__| |__| |__| |__| |______|  |___|   |______
void s_connectionreset(void)
{
  unsigned char i;
  //Initial state
  SCKOUTP;
  SETSCK0;
  DMODEOU; 
  SETDAT1;
  for(i=0;i<9;i++){ //9 SCK cycles
    SETSCK1;
    S_PULSLONG;
    SETSCK0;
    S_PULSLONG;
  }
  s_transstart(); //transmission start
}

// resets the sensor by a softreset
char s_softreset(void)
{
  s_connectionreset(); //reset communication
  //send RESET-command to sensor:
  return (s_write_byte(RESET)); //return=1 in case of no response form the sensor
}


// makes a measurement (humidity/temperature) with checksum
// p_value returns 2 bytes
// mode: 1=humidity  0=temperature
// return value: 1=write error, 2=crc error, 3=timeout
//
char s_measure(unsigned int *p_value, unsigned char mode)
{
  unsigned error;
  unsigned char i=0;
  s_transstart(); //transmission start
  *p_value=0;
  if(mode){
    mode=MEASURE_HUMI;
  }
  else{
    mode=MEASURE_TEMP;
  }
  if(s_write_byte(mode)){
    return(1);
  }
  // normal delays: temp i=70, humi i=20
  while(i<240){
    delay(3);
    if (GETDATA==0){
      i=0;
      break;
    }
    i++;
  }
  if(i){
    // or timeout 
    return(3);
  }
  i=s_read_byte(1); //read the first byte (MSB)
  *p_value=(i<<8)|s_read_byte(0); //read the second byte (LSB) and end with no-ack
  return(0);
}

//----------------------------------------------------------------------------------------
void calc_sth11(float *p_humidity ,float *p_temperature)
//----------------------------------------------------------------------------------------
// calculates temperature [°C] and humidity [%RH] 
// input :  humi [Ticks] (12 bit) 
//          temp [Ticks] (14 bit)
// output:  humi [%RH]
//          temp [°C]
{ 
  const float C1=-4.0;              // for 12 Bit
  const float C2=+0.0405;           // for 12 Bit
  const float C3=-0.0000028;        // for 12 Bit
  const float T1=+0.01;             // for 14 Bit @ 5V
  const float T2=+0.00008;           // for 14 Bit @ 5V      

  float rh=*p_humidity;             // rh:      Humidity [Ticks] 12 Bit 
  float t=*p_temperature;           // t:       Temperature [Ticks] 14 Bit
  float rh_lin;                     // rh_lin:  Humidity linear
  float rh_true;                    // rh_true: Temperature compensated humidity
  float t_C;                        // t_C   :  Temperature [°C]

  t_C=t*0.01 - 40;                  //calc. temperature from ticks to [°C]
  rh_lin=C3*rh*rh + C2*rh + C1;     //calc. humidity from ticks to [%RH]
  rh_true=(t_C-25)*(T1+T2*rh)+rh_lin;   //calc. temperature compensated humidity [%RH]
  if(rh_true>100)rh_true=100;       //cut if the value is outside of
  if(rh_true<0.1)rh_true=0.1;       //the physical possible range

  *p_temperature=t_C;               //return temperature [°C]
  *p_humidity=rh_true;              //return humidity[%RH]
}

//--------------------------------------------------------------------
float calc_dewpoint(float h,float t)
//--------------------------------------------------------------------
// calculates dew point
// input:   humidity [%RH], temperature [°C]
// output:  dew point [°C]
{ 
  float logEx,dew_point;
  logEx=0.66077+7.5*t/(237.3+t)+(log10(h)-2);
  dew_point = (logEx - 0.66077)*237.3/(0.66077+7.5-logEx);
  return dew_point;
}
void serialPrintFloat( float f){
  Serial.print((int)f);
  Serial.print(".");
  int temp = (f - (int)f) * 100;
  Serial.print( abs(temp) );
}
//for pressure

char spi_transfer(volatile char data)
{
  SPDR = data;                    // Start the transmission
  while (!(SPSR & (1<<SPIF)))     // Wait for the end of the transmission
  {
  };
  return SPDR;                    // return the received byte
}


char read_register(char register_name)
{
    char in_byte;
    register_name <<= 2;
    register_name &= B11111100; //Read command
  
    digitalWrite(SLAVESELECT,LOW); //Select SPI Device
    spi_transfer(register_name); //Write byte to device
    in_byte = spi_transfer(0x00); //Send nothing, but we should get back the register value
    digitalWrite(SLAVESELECT,HIGH);
    delay(10);
    return(in_byte);
  
}

float read_register16(char register_name)
{
    byte in_byte1;
    byte in_byte2;
    float in_word;
    
    register_name <<= 2;
    register_name &= B11111100; //Read command

    digitalWrite(SLAVESELECT,LOW); //Select SPI Device
    spi_transfer(register_name); //Write byte to device
    in_byte1 = spi_transfer(0x00);    
    in_byte2 = spi_transfer(0x00);
    digitalWrite(SLAVESELECT,HIGH);
    in_word = UBLB(in_byte1,in_byte2);
    return(in_word);
}

void write_register(char register_name, char register_value)
{
    register_name <<= 2;
    register_name |= B00000010; //Write command

    digitalWrite(SLAVESELECT,LOW); //Select SPI device
    spi_transfer(register_name); //Send register location
    spi_transfer(register_value); //Send value to record into register
    digitalWrite(SLAVESELECT,HIGH);
}

Did you get the code to work for you?

I've got a similar problem where I want a NOKIA LCD shield and a USB port talk over SPI described at this post:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1244417398/0#0
Would be nice to find the solution for 2 slaves on one ARDUINO.
It's certainly possible but I don't know how it' done exactly.

No still trying and reading things about SPI....

You should be able to do 2 or more slaves at a time by connecting each slave device SS pin to a separate I/O pin on the Arduino. You then take which ever SS pin low to select the device you want before writing or reading the device. You may also need to change the clock phase/sample edge if the devices are different.

Even if you are using the built in SPI hardware there is nothing special about the SS pin on the ATmega168 when operating as an SPI master, you still have to set it low and high yourself.

Just remember with SPI you have to write something to read something because the slave device clocks data out only as data is clocked in. The built in SPI hardware makes it much easier and faster to use SPI devices.

What are the pressure and humidity devices you are using? Hard to give more advice without knowing....

thx for the advice I give it a try.
I do use the SCP1000 pressure sensor and the SHT15 Humidity sensor from sensirion.

I just finished a project (as "finished" as they get) using variants of those parts. I used the I2C version of the absolute pressure sensor, the SCP1000-D11 to save pins. I used the PCB3 version that comes already mounted on a DIP header.

My application uses the SHT75 because I wanted the slightly better accuracy and the leaded package was easier for me to apply.

While the SHTxx's can share the buss with I2C devices, they are not I2C compatible on the code side and will not work with the Arduino TWI library routines.

Photo at:

Imgur

hmm ok. I use the one from Sparkfun on the Bread Board.
The problem is that the SHT15 doesn't use a SS so I can't pull it High or Low.... or did I miss something

Yes, you missed the part where the SHT15 is not an SPI device, rather it is quasi-I2C.

Yes of course... So there is no possibility to connect both at the same time?

You can connect them both at the same time. You would, however, probably want to connect the SHT15 to two pins by itself as having it share the SPI bus with the SCP1000-D01 while possible will make the programming unnecessarily complicated for starters.

Study the example at:
http://wiring.org.co/learning/examples/SHT15sparkfun.html

You can use the code in Arduino and you will probably want to change the digital pins to something other than 0 and 1 so as not to conflict with Serial i/o.

Study the example at:
http://wiring.org.co/learning/examples/SHT15sparkfun.html

You can use the code in Arduino and you will probably want to change the digital pins to something other than 0 and 1 so as not to conflict with Serial i/o.

Great!!! Thx a lot now it does work!!
Thx to all of you!

Geko

All right! Enjoy, those are two really nice sensors.