Forum Update - Announcement about May 10th, 2018 update and your password.

HDC1080 Try

I've been trying to get some simple data from a new chip I got. The temp data never changes and I'm doing something wrong with the math. I've attached a picture of the TV screen and code.
Thanks for looking.
CON       
  _clkmode = xtal1 + pll16x      '80 MHz system clock
  _xinfreq = 5_000_000

    'I2C pins
scl  =  20
sda  =  21
Bitrate = 10000  'I2C @ 50Khz    for longish cables

HDC     = $40           'I2C 7 bit address
Config_reg  = $02       'config register address
trigger     = $00       'Trigger byte &  temperature output register
Hum_out     = $01       'humidity output register                                

Config_params = %1001_0000_0000_0000  'see pg 15      

OBJ
   TV : "TV_TEXT"
   I2C  : "I2C PASM driver v1.8OD"
VAR
   byte data[4]  '0 & 1 temp output, 2 & 3 hum output
   word temper, humid ,RH
   long temp_C
PUB main
  TV.start(0)
  WaitMS(100)
  I2C.start(SCL,SDA,bitrate)
  WaitMS(100)
  
  I2C.writeWordB(HDC,Config_reg,Config_params)   'configure device
  WaitMS(100)

  
  
   repeat
     I2C.command(HDC,trigger)   'start a temp, hum measurement
      WaitMS(100)                 'allow time for measurement

     
     tv.home
     temper := (I2C.ReadByte(HDC,$00) << 8)   
     temper |= I2C.ReadNext(HDC)
     temper := temper <<= 2
     humid := (I2C.ReadByte(HDC,$01) << 8)
     humid  |= I2C.ReadNext(HDC)
     humid := humid <<= 2
     tv.cr
     tv.str(string ("temp in bin = "))
     tv.bin(temper,14)
     tv.cr
     tv.dec(temper)
     tv.cr
     tv.str(string("hum in bin = "))
     tv.bin(humid,14)
     tv.cr
     tv.dec(humid)
     waitms(1000)

     temp_C := (((temper/65536)*165)-40)
     RH:=((humid/65536)*100)
     tv.cr
     tv.str(string("temp in c = "))     
     tv.dec(temp_c)
     tv.cr
     tv.str(string("RH = "))
     tv.dec(RH)
     WaitMS(1000) 

    


PUB  WaitMS(millisec) |time
  time := clkfreq/1000 * millisec
  waitcnt(time + cnt)

[img][/img]
3072 x 2304 - 2M

Comments

  • 6 Comments sorted by Date Added Votes
  • On the math part, you need to do multiplication BEFORE division. Otherwise you will get zero.

    temp_C := ((temper*165)/65536)-40)

    But the temper value looks way too large. 65028 will be 123.72°C ???

    Bean
    logo.png?91518163160380889
    Esterline Research & Design
    thitt@esterlineresearch.com

    We offer consulting on the following areas of expertise:
    Frequency Control - Micro-Controller/Processor Projects
    Test and Automation - General Programming and Coding
    Circuit Design - Board Layouts
  • ChrisGaddChrisGadd Posts: 257
    edited April 30 Vote Up0Vote Down
    I'm not sure if you need the configuration RST bit-15 set, as the datasheet examples never touch it, and you're shifting the returned temperature and humidity values in the wrong direction; bits [01:00] are unused, so you need to shift right by 2 to get the 14-bit value.

    Bean is correct that dividing a 14-bit number by 2^16 results in loss of all digits, but even with multiplying before dividing you still lose fractional digits.
    The temperature ranges from -40 to +125, a span of 165. With 14-bit resolution, each lsb equals 0.0107 degrees. The operation temper := temper >> 2 - 4000 gets you degrees x 100; 1 = -3999, 16383 = 12383.

    If you don't need that resolution, keep temper and humid at 16-bits and use; temper := temper * 165 / 65536 - 40 and humid := humid * 100 / 65536.

    If I'm reading the datasheet properly, the measurements are triggered with a write to register $00. Then after waiting for the HDC1080 to complete, the measurements are read from $00 and $01.
    A possible problem that I see here is re-addressing the register for the read begins another sample. If it's not a problem, then the i2c method readWordB can be used instead of the readByte and readNexts with shifting and or'ing. I also don't know if the readNext method even works with this device, as the HDC1080 returns 16 bits from a single register address; I've never seen that before.

    I included an arbitrary method for non-standard devices, to use: i2c.arbitrary(@local_long,1,@local_long,4). You'll have to declare local_long and load local_long := HDC << 1 | 1 into it before executing, the temperature will be in bits[31:18] and humidity in bits[15:02] afterward.

    Lastly, the PASM version of that I2C driver is intended for high speeds. The Spin version of that driver runs at about 20Kbps and uses the same methods without consuming a cog.

    Edited because I forgot how my own code works
  • Thanks Bean & Chris
    I'll make some mods and have another go of it
  • Getting closer. Thanks Chris for the ARBITRARY method!
    BUT, although the 32 bit value from the HDC keeps updating every 3 seconds as it should. everything else stays the same and the temper and humid BIN read nothing. I've tried other ways of masking but I think BITWISE AND(&) is the right way.
    PUB main |  local_long
      TV.start(0)
      WaitMS(100)
      I2C.init(SCL,SDA)
      WaitMS(100)
      
      
      I2C.writeWordB(HDC,Config_reg,Config_params)   'configure device
      WaitMS(100)
        humid~
        temper~
      
      
       repeat
         local_long := HDC << 1 | 1
         I2C.command(HDC,$00)   'start a temp, hum measurement
          WaitMS(100)                 'allow time for measurement
         temper:=humid:=0
        
         tv.home
         i2c.arbitrary(@local_long,1,@local_long,4)
         WaitMS(100)
         tv.str(string("32 bit output from HDC"))
         tv.cr
         tv.bin(local_long,32)
         tv.cr
         WaitMS(100)
         
         temper:= @local_long & %1111_1111_1111_1111_0000_0000_0000_0000  'AND to mask all except 31:18
         
         tv.cr
         tv.str(string("Temp in decimal  "))
         tv.dec(temper)
         tv.cr
        
         tv.str(string ("temp in bin = "))
         tv.bin(temper,14)
         
         tv.cr
         tv.cr
         tv.str(string("hum in bin = "))
         tv.bin(humid,14)
         humid:=@local_long & %0000_0000_0000_0000_1111_1111_1111_1111 'AND to mask all except 15:02
         tv.cr
         tv.str(string("Hum in decimal  "))
         tv.dec(humid)
         waitms(1000)
    
         temp_C := ((temper*165/65536)-40)
         RH:=(humid*100/65536)
         tv.cr
         tv.cr
         tv.str(string("temp in c = "))     
         tv.dec(temp_c)
         tv.cr
         tv.str(string("RH = "))
         tv.dec(RH)
         WaitMS(3000) 
    
    3072 x 2304 - 2M
  • Hey AGCB did you get the code for the BME280 to work successfully?
  • You are correctly using the immediate value of local_long when you display the binary value, but are using the address of local_long when applying the masks.
    I tried converting the returned binary value into temp and humidity and discovered another problem in that the i2c.arbitrary method reads little-endian.
    The easiest/laziest fix is:
    tempC := local_long.byte[0] << 8 | local_long.byte[1]
    tempC := tempC * 165 / 65536 - 40
    
    RH := local_long.byte[2] << 8 | local_long.byte[3]
    RH := RH * 100 / 65536
    
    Looks like it's about 19c and 43% RH there.
Sign In or Register to comment.