/* control and access functions for Sensirion SHT15 temperature and humidity sensor. Buy one on a nice little breakout board from www.sparkfun.com. eric volpe 4/22/2010 http://heepy.net */ #include #include #include "sht15.h" // send the initial reset, which should be done before use void sht_reset(void) { uint8_t i; DATA_OUTPUT(); DATA_HI(); for(i=0; i<=9; i++) { CLK_HI(); CLK_LO(); } DATA_LO(); } // this is the "attention" signal that must precede // all other accesses. static void sht_start(void) { // nfi. DATA_OUTPUT(); DATA_HI(); CLK_HI(); DATA_LO(); CLK_LO(); CLK_HI(); DATA_HI(); CLK_LO(); } // this actually sends a command byte and initiates // a measurement, and waits for it to complete. void sht_send_byte(uint8_t byte) { uint8_t i, n; sht_start(); // shift out the bits to send DATA_OUTPUT(); for(i=0; i<8; i++) { CLK_LO(); if (byte & 0x80) { DATA_HI(); } else { DATA_LO(); } CLK_HI(); byte <<= 1; } CLK_LO(); // wait for ack DATA_INPUT(); while(DATA == 1); CLK_HI(); CLK_LO(); while(DATA == 0); n=0; // count how long it takes while((DATA == 1) && (n != 255)) { n++; _delay_ms(1); } // printf("took %u loops\n", n); } // this reads the result of the preceding measurement. // The measurement is stored until you read it, so there // isn't a timing requirement. uint16_t sht_read(void) { uint8_t i,j; uint8_t res[3]; uint16_t val; CLK_LO(); DATA_INPUT(); for(j=0; j<3; j++) { res[j]=0; for(i=0; i<7; i++) { _delay_us(10); CLK_HI(); res[j] |= DATA; CLK_LO(); res[j]<<=1; } _delay_us(10); CLK_HI(); res[j] |= DATA; CLK_LO(); DATA_OUTPUT(); DATA_LO(); _delay_us(10); CLK_HI(); _delay_us(10); CLK_LO(); DATA_INPUT(); } // res[2] is a checksum. we could check it, i guess. return((res[0]<<8)|res[1]); } // This reads the SHT15's status byte, which is described // in the data sheet. There's not much in it. uint8_t sht_readstatus(void) { uint8_t i,j; uint8_t res[2]; uint16_t val; uint8_t byte = 0x07; // read status reg command sht_start(); // shift out the bits to send DATA_OUTPUT(); for(i=0; i<8; i++) { CLK_LO(); if (byte & 0x80) { DATA_HI(); } else { DATA_LO(); } CLK_HI(); byte <<= 1; } CLK_LO(); // wait for ack DATA_INPUT(); while(DATA == 1); CLK_HI(); CLK_LO(); for(j=0; j<2; j++) { res[j]=0; for(i=0; i<7; i++) { _delay_us(10); CLK_HI(); res[j] |= DATA; CLK_LO(); res[j]<<=1; } _delay_us(10); CLK_HI(); res[j] |= DATA; CLK_LO(); DATA_OUTPUT(); DATA_LO(); _delay_us(10); CLK_HI(); _delay_us(10); CLK_LO(); DATA_INPUT(); } // res[1] is checksum, i guess we could check it. return(res[0]); } // This writes to the SHT15's status byte, which lets you // do a couple of things like switch resolution or turn on // the internal heater. void sht_writestatus(uint8_t val) { uint8_t i, byte; sht_start(); byte = 0x06; // write status register cmd DATA_OUTPUT(); for(i=0; i<8; i++) { CLK_LO(); if (byte & (1<<7)) { DATA_HI(); } else { DATA_LO(); } CLK_HI(); byte <<= 1; } CLK_LO(); // wait for ack DATA_INPUT(); while(DATA == 1); CLK_HI(); byte = val; // send desired value DATA_OUTPUT(); for(i=0; i<8; i++) { CLK_LO(); if (byte & (1<<7)) { DATA_HI(); } else { DATA_LO(); } CLK_HI(); byte <<= 1; } CLK_LO(); } // these functions take measurements and then do the // floating point math to convert the output into actual // units like degrees or percent humidity. #ifdef SHT15_FLOAT_FUNCS // returns temperature in degrees C. double sht_temp(void) { uint16_t rawtemp; sht_send_byte(0x03); rawtemp=sht_read(); return ((0.01 * rawtemp) - 39.7); } // returns relative humidity, not temperature compensated double sht_humidity(void) { uint16_t rawhum; sht_send_byte(0x05); rawhum=sht_read(); return ((-0.0000015955*rawhum*rawhum) + (0.0367*rawhum) - 2.0468); } // temperature compensated humidity reading - read temp first, then // pass the result to this for a more accurate humidity measurement. double sht_humidity_comp(double temp) { uint16_t rawhum; double uncomp; sht_send_byte(0x05); rawhum=sht_read(); uncomp = (-0.0000015955*rawhum*rawhum) + (0.0367*rawhum) - 2.0468; return (((temp - 25.0) * (0.01 + (0.00008 * rawhum))) + uncomp); } #endif /* SHT15_FLOAT_FUNCS */