Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: onewire.cpp
- Revision:
- 0:1197076b78f4
- Child:
- 1:f8aa0ff8d04a
diff -r 000000000000 -r 1197076b78f4 onewire.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/onewire.cpp Mon May 10 08:14:32 2010 +0000
@@ -0,0 +1,367 @@
+#include "mbed.h"
+#include "onewire.h"
+#include "crc8.h"
+
+
+
+// DS18B20 converted to run on mbed
+
+
+
+
+
+DigitalInOut ow_pin(ONEWIRE_PIN);
+
+
+
+BYTE ow_reset(void) { // reset. Should improve to act as a presence pulse
+ BYTE err;
+
+ ow_pin.output();
+ ow_pin = 0; // bring low for 500 us
+ wait_us(500);
+ ow_pin.input();
+ wait_us(60);
+ err = ow_pin;
+ wait_us(240);
+ if ( ow_pin == 0 ) { // short circuit
+ err = OW_SHORT_CIRCUIT;
+#ifdef DEBUG
+ printf("Error. Short circut!!!\n");
+#endif
+ }
+ return err;
+}
+
+BYTE ow_bit_io( BYTE b ) {
+
+ ow_pin.output(); // drive bus low
+ ow_pin = 0;
+ wait_us(1); // Recovery-Time wuffwuff was 1
+ //ow_pin.input();
+ if ( b ) ow_pin.input(); // if bit is 1 set bus high (by ext. pull-up)
+
+ // delay was 15uS-1 see comment above
+ wait_us(15-1);
+ // ???ow_pin.input();
+ if ( ow_pin == 0 ) b = 0; // sample at end of read-timeslot
+
+ wait_us(60-15);
+ ow_pin.input();
+
+ return b;
+}
+
+BYTE ow_byte_wr( uint8_t b ) {
+ uint8_t i = 8, j;
+
+ do {
+ j = ow_bit_io( b & 1 );
+ b >>= 1;
+ if ( j ) b |= 0x80;
+ } while ( --i );
+
+ return b;
+}
+
+
+uint8_t ow_byte_rd( void ) {
+ // read by sending 0xff (a dontcare?)
+ return ow_byte_wr( 0xFF );
+}
+
+
+
+BYTE ow_rom_search( BYTE diff, BYTE *id ) {
+ BYTE i, j, next_diff;
+ BYTE b;
+
+ if ( ow_reset() ) return OW_PRESENCE_ERR; // error, no device found
+
+ ow_byte_wr( OW_SEARCH_ROM ); // ROM search command
+ next_diff = OW_LAST_DEVICE; // unchanged on last device
+
+ i = OW_ROMCODE_SIZE * 8; // 8 bytes
+
+ do {
+ j = 8; // 8 bits
+ do {
+ b = ow_bit_io( 1 ); // read bit
+ if ( ow_bit_io( 1 ) ) { // read complement bit
+ if ( b ) // 11
+ return OW_DATA_ERR; // data error
+ } else {
+ if ( !b ) { // 00 = 2 devices
+ if ( diff > i || ((*id & 1) && diff != i) ) {
+ b = 1; // now 1
+ next_diff = i; // next pass 0
+ }
+ }
+ }
+ ow_bit_io( b ); // write bit
+ *id >>= 1;
+ if ( b ) *id |= 0x80; // store bit
+
+ i--;
+
+ } while ( --j );
+
+ id++; // next byte
+
+ } while ( i );
+
+ return next_diff; // to continue search
+}
+
+void ow_command( BYTE command, BYTE *id ) {
+ BYTE i;
+
+ ow_reset();
+
+ if ( id ) {
+ ow_byte_wr( OW_MATCH_ROM ); // to a single device
+ i = OW_ROMCODE_SIZE;
+ do {
+ ow_byte_wr( *id );
+ id++;
+ } while ( --i );
+ } else {
+ ow_byte_wr( OW_SKIP_ROM ); // to all devices
+ }
+
+ ow_byte_wr( command );
+}
+
+void ow_parasite_enable(void) {
+ ow_pin.output();
+ ow_pin = 1;
+}
+
+void ow_parasite_disable(void) {
+
+ ow_pin.input();
+}
+
+
+/* find DS18X20 Sensors on 1-Wire-Bus
+ input/ouput: diff is the result of the last rom-search
+ output: id is the rom-code of the sensor found */
+void DS18X20_find_sensor(BYTE *diff, BYTE id[]) {
+ for (;;) {
+ *diff = ow_rom_search( *diff, &id[0] );
+ if ( *diff==OW_PRESENCE_ERR || *diff==OW_DATA_ERR ||
+ *diff == OW_LAST_DEVICE ) return;
+ if ( id[0] == DS18B20_ID || id[0] == DS18S20_ID ) return;
+ }
+}
+
+/* get power status of DS18x20
+ input : id = rom_code
+ returns: DS18X20_POWER_EXTERN or DS18X20_POWER_PARASITE
+*/
+BYTE DS18X20_get_power_status(uint8_t id[]) {
+ uint8_t pstat;
+ ow_reset();
+ ow_command(DS18X20_READ_POWER_SUPPLY, id);
+ pstat=ow_bit_io(1); // pstat 0=is parasite/ !=0 ext. powered
+ ow_reset();
+ return (pstat) ? DS18X20_POWER_EXTERN:DS18X20_POWER_PARASITE;
+}
+
+void DS18X20_show_id_uart( BYTE *id, size_t n ) {
+ size_t i;
+ for ( i = 0; i < n; i++ ) {
+ if ( i == 0 ) printf( "FC: " );
+ else if ( i == n-1 ) printf( "CRC: " );
+ if ( i == 1 ) printf( " SN: " );
+ printf("%X ",id[i]);
+ if ( i == 0 ) {
+ if ( id[0] == DS18S20_ID ) printf("(18S)");
+ else if ( id[0] == DS18B20_ID ) printf("(18B)");
+ else printf("( ? )");
+ }
+ }
+ if ( crc8( id, OW_ROMCODE_SIZE) )
+ printf( " CRC FAIL\n " );
+ else
+ printf( " CRC O.K.\n" );
+}
+
+/* start measurement (CONVERT_T) for all sensors if input id==NULL
+ or for single sensor. then id is the rom-code */
+uint8_t DS18X20_start_meas( uint8_t with_power_extern, uint8_t id[]) {
+ ow_reset(); //**
+ if ( ow_pin ) { // only send if bus is "idle" = high
+ ow_command( DS18X20_CONVERT_T, id );
+ if (with_power_extern != DS18X20_POWER_EXTERN)
+ ow_parasite_enable();
+ return DS18X20_OK;
+ } else {
+#ifdef DEBUG
+ printf( "DS18X20_start_meas: Short Circuit !\n" );
+#endif
+ return DS18X20_START_FAIL;
+ }
+}
+
+/* reads temperature (scratchpad) of sensor with rom-code id
+ output: subzero==1 if temp.<0, cel: full celsius, mcel: frac
+ in millicelsius*0.1
+ i.e.: subzero=1, cel=18, millicel=5000 = -18,5000°C */
+uint8_t DS18X20_read_meas(uint8_t id[], uint8_t *subzero,
+ uint8_t *cel, uint8_t *cel_frac_bits) {
+ uint8_t i;
+ uint8_t sp[DS18X20_SP_SIZE];
+
+ ow_reset(); //**
+ ow_command(DS18X20_READ, id);
+ for ( i=0 ; i< DS18X20_SP_SIZE; i++ ) sp[i]=ow_byte_rd();
+ if ( crc8( &sp[0], DS18X20_SP_SIZE ) )
+ return DS18X20_ERROR_CRC;
+ DS18X20_meas_to_cel(id[0], sp, subzero, cel, cel_frac_bits);
+ return DS18X20_OK;
+}
+
+/*
+ convert raw value from DS18x20 to Celsius
+ input is:
+ - familycode fc (0x10/0x28 see header)
+ - scratchpad-buffer
+ output is:
+ - cel full celsius
+ - fractions of celsius in millicelsius*(10^-1)/625 (the 4 LS-Bits)
+ - subzero =0 positiv / 1 negativ
+ always returns DS18X20_OK
+ TODO invalid-values detection (but should be covered by CRC)
+*/
+uint8_t DS18X20_meas_to_cel( uint8_t fc, uint8_t *sp,
+ uint8_t* subzero, uint8_t* cel, uint8_t* cel_frac_bits) {
+ uint16_t meas;
+ uint8_t i;
+
+ meas = sp[0]; // LSB
+ meas |= ((uint16_t)sp[1])<<8; // MSB
+ //meas = 0xff5e; meas = 0xfe6f;
+
+ // only work on 12bit-base
+ if ( fc == DS18S20_ID ) { // 9 -> 12 bit if 18S20
+ /* Extended measurements for DS18S20 contributed by Carsten Foss */
+ meas &= (uint16_t) 0xfffe; // Discard LSB , needed for later extended precicion calc
+ meas <<= 3; // Convert to 12-bit , now degrees are in 1/16 degrees units
+ meas += (16 - sp[6]) - 4; // Add the compensation , and remember to subtract 0.25 degree (4/16)
+ }
+
+ // check for negative
+ if ( meas & 0x8000 ) {
+ *subzero=1; // mark negative
+ meas ^= 0xffff; // convert to positive => (twos complement)++
+ meas++;
+ } else *subzero=0;
+
+ // clear undefined bits for B != 12bit
+ if ( fc == DS18B20_ID ) { // check resolution 18B20
+ i = sp[DS18B20_CONF_REG];
+ if ( (i & DS18B20_12_BIT) == DS18B20_12_BIT ) ;
+ else if ( (i & DS18B20_11_BIT) == DS18B20_11_BIT )
+ meas &= ~(DS18B20_11_BIT_UNDF);
+ else if ( (i & DS18B20_10_BIT) == DS18B20_10_BIT )
+ meas &= ~(DS18B20_10_BIT_UNDF);
+ else { // if ( (i & DS18B20_9_BIT) == DS18B20_9_BIT ) {
+ meas &= ~(DS18B20_9_BIT_UNDF);
+ }
+ }
+
+ *cel = (uint8_t)(meas >> 4);
+ *cel_frac_bits = (uint8_t)(meas & 0x000F);
+
+ return DS18X20_OK;
+}
+
+/* converts to decicelsius
+ input is ouput from meas_to_cel
+ returns absolute value of temperatur in decicelsius
+ i.e.: sz=0, c=28, frac=15 returns 289 (=28.9°C)
+0 0 0
+1 625 625 1
+2 1250 250
+3 1875 875 3
+4 2500 500 4
+5 3125 125
+6 3750 750 6
+7 4375 375
+8 5000 0
+9 5625 625 9
+10 6250 250
+11 6875 875 11
+12 7500 500 12
+13 8125 125
+14 8750 750 14
+15 9375 375 */
+uint16_t DS18X20_temp_to_decicel(uint8_t subzero, uint8_t cel,
+ uint8_t cel_frac_bits) {
+ uint16_t h;
+ uint8_t i;
+ uint8_t need_rounding[] = { 1, 3, 4, 6, 9, 11, 12, 14 };
+
+ h = cel_frac_bits*DS18X20_FRACCONV/1000;
+ h += cel*10;
+ if (!subzero) {
+ for (i=0; i<sizeof(need_rounding); i++) {
+ if ( cel_frac_bits == need_rounding[i] ) {
+ h++;
+ break;
+ }
+ }
+ }
+ return h;
+}
+
+/* compare temperature values (full celsius only)
+ returns -1 if param-pair1 < param-pair2
+ 0 if ==
+ 1 if > */
+int8_t DS18X20_temp_cmp(uint8_t subzero1, uint16_t cel1,
+ uint8_t subzero2, uint16_t cel2) {
+ int16_t t1 = (subzero1) ? (cel1*(-1)) : (cel1);
+ int16_t t2 = (subzero2) ? (cel2*(-1)) : (cel2);
+
+ if (t1<t2) return -1;
+ if (t1>t2) return 1;
+ return 0;
+}
+
+void OneWireOutByte(unsigned char d) { // output byte d (least sig bit first).
+ for (int n=8; n!=0; n--) {
+ if ((d & 0x01) == 1) { // test least sig bit
+ ow_pin.output();
+ ow_pin = 0;
+ wait_us(5);
+ ow_pin.input();
+ wait_us(80);
+ } else {
+ ow_pin.output();
+ ow_pin = 0;
+ wait_us(80);
+ ow_pin.input();
+ }
+
+ d=d>>1; // now the next bit is in the least sig bit position.
+ }
+
+}
+
+unsigned char OneWireInByte() { // read byte, least sig byte first
+ unsigned char d = 0, b;
+ for (int n=0; n<8; n++) {
+ ow_pin.output();
+ ow_pin = 0;
+ wait_us(5);
+ ow_pin.input();
+ wait_us(5);
+ b =ow_pin;
+ wait_us(50);
+ d = (d >> 1) | (b << 7); // shift d to right and insert b in most sig bit position
+ }
+ return d;
+}
+