Shop OBEX P1 Docs P2 Docs Learn Events
Prop driver for Sensirion SHT1x SHT7x, integer math. — Parallax Forums

Prop driver for Sensirion SHT1x SHT7x, integer math.

Tracy AllenTracy Allen Posts: 6,658
edited 2015-03-06 13:32 in Accessories
New obex object:
http://obex.parallax.com/object/517

I usually avoid using floating point if at all possible, and Cam's object is meant partly as an illustration of how to use his floating point library. My version uses Cam's driver code but the math is all-integer. The calls to ReadTemperature and ReadHumidity simply return the values in units of 1/100 degC and 1/10 %RH respectively.

Comments

  • varnonvarnon Posts: 184
    edited 2013-03-16 16:28
    Nice. I made something like this for myself a while back. I never had a chance to clean it up, so I never put it on the obex.
    Its annoying, but also kind of fun to work all the floats out of an equation.
  • Tracy AllenTracy Allen Posts: 6,658
    edited 2013-03-17 09:21
    Thanks Varnon. There's another object, sensirion_full, by BR, which does integer math, but only to whole degrees C and whole %RH. I'm always looking for the best possible resolution. And I want an object that is KISS interface, because I'm always forgetting what parameter or nested function goes where and what they do!

    I'm a big fan of ** as fractional multiply, ever since working on the SHT code for the BASIC Stamp. BR's integer math is different from mine, and I'm sure there are a lot of other ways to parse it too.

    Yesterday evening, I uploaded a revision. The revision is mainly in the demo, because I realized that I hadn't handled display of negative decimals quite right, and I also wanted to add code to print "NA" when the routine returns negx for timeout or range errors.
  • Tracy AllenTracy Allen Posts: 6,658
    edited 2013-03-17 19:45
    Updated again. Now does either high resolution or low resolution, depending on how you set the mode bit in the status register. A second demo program illustrates changing the resolution at run time and the effect on conversion times in milliseconds. Also tightened up the error detection.
  • tdlivingstdlivings Posts: 437
    edited 2013-03-18 21:30
    Tracy, Thank's for posting this it is perfect timing for me.
    I am experimenting with humidity sensors for a friend to monitor the enviorment for his house plants.
    My first experiment was over on the Ardunio side with a DHT11 and I purchased the Parallax SHT11
    sensor for comparison. I did not realize there was a OBEX driver and was bit banging my own, which
    has been a good exercise, but I was producing strange answers and yesterday when I saw your post I
    had something to run and see if it was me or the only sensor I had was bad. I knew there was a 99.9
    percent chance it was me but you never know. It was I forgot to cycle the clock at the ACQ bit location and
    it thru off everything.

    Tom
  • WBA ConsultingWBA Consulting Posts: 2,933
    edited 2013-03-19 10:22
    Tracy, Excellent work and beautifully executed. I have been digging through your code and I definitely acknowledge the improvements. I will be working with your code on my next batch of SHT11/SHT15 modules and will update my site's code examples page with my results. I will also start using your object as my standard moving forward. Thanks for sharing!
  • Tracy AllenTracy Allen Posts: 6,658
    edited 2013-03-19 16:59
    Wow, thanks for the endorsement Andrew! The Sensirion sensors have become hugely popular and your module is very accessible and adaptable to different purposes. Good luck with those. I was worried though when you took one down to the polar bear plunge a couple of years ago!

    I see that Parallax is currently out of stock on the #28018 module on the DIP format carrier. It still is accompanied by my original Stamp code, but for the Prop there is only a link to the generic OBEX listing for sensors. Nothing specific. There should be an easier path to follow.
  • WBA ConsultingWBA Consulting Posts: 2,933
    edited 2014-07-08 00:35
    Tracy, I was referring back to your thread for an email and noticed that for some reason, the links in your top post are incorrect. Here are the correct links:

    Tracy's Sensirion Integer Object: http://obex.parallax.com/object/517
    Cam Thompson's Sensirion Demo Object: http://obex.parallax.com/object/515
  • Tracy AllenTracy Allen Posts: 6,658
    edited 2014-07-08 10:50
    Thanks for pointing that out Andrew. Old OBEX.
  • WBA ConsultingWBA Consulting Posts: 2,933
    edited 2015-03-02 12:54
    Tracy, or others, please take a look at my messy attempt at converting C to F with this object and PST. Is there a cleaner way? What's the best method to dump the extra decimal places?
    ''=============================================================================
    '' @file     sensirion_integer_demo.spin
    ''     MODIFIED BY WBA CONSULTING, ANDREW WILLIAMS
    '' @target   Propeller with Sensirion SHT1x or SHT7x   (not SHT2x)
    '' @author   Thomas Tracy Allen, EME Systems
    '' Copyright (c) 2013 EME Systems LLC
    '' See end of file for terms of use.
    '' version 1.3
    '' uses integer math to return values directly in degC*100 and %RH*10
    '' and print to terminal screen
    '' no floating point required
    '' This is the most basic demo.
    ''=============================================================================
    
    '' version log
    '' 005  AW Added code to convert C to F
    
    
    CON
      _clkmode = xtal1 + pll8x                '
      _xinfreq = 5_000_000
    
    ' pins for data and clock.
    ' Note sht1x and sht7x protocol is like i2c, but not exactly
    ' Assumes power = 3.3V
      DPIN = 1 '13    ' needs pullup resistor
      CPIN = 0 '14    ' best use pulldown resistor for reliable startup, ~100k okay.
    
    OBJ
      pst : "parallax serial terminal"
      sht : "sensirion_integer"
    
    PUB Demo   
     sht.Init(DPIN, CPIN)
     pst.Start(9600)
     waitcnt(clkfreq/10+cnt)
    
     repeat
       pst.str(string(13,10,"Degrees F: "))
       if (result := sht.ReadTemperature) == negx
         pst.str(string("NA"))                              ' read temperature and handle possible error (negx)
       else
         result := ((result*18)+32000)                      ' sad attempt at F=C*1.8+32 in integer math
         pst.dec(result/1000)                               ' /1000 to bring it down to proper decimal position
         pst.char(".")
         pst.dec(||result//1000)                            ' grab decimal degrees
    
       pst.str(string("     %RH: "))
    
       if (result := sht.ReadHumidity) == negx              ' read RH and handle error by printing NA (not available)
         pst.str(string("NA"))
       else
         pst.dec(result/10)                                 ' %RH is in unit of tenths
         pst.char(".")
         pst.dec(||result//10)
    
       waitcnt(clkfreq*2+cnt)                               ' wait 2 seconds
       pst.clear
    
    ' Always read temperature shortly before humidity!   RH temperature compensation depends on valid temperature reading.
    ' The routines return NEGX if the sensor times out, or if the readings are grossly out of range.
    ' Due to sensor tolerances, it is still possible to get readings <0 or >100 %RH.
    
    {{
    &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
    &#9474;                                                   TERMS OF USE: MIT License                                                  &#9474;                                                            
    &#9500;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9508;
    &#9474;Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation    &#9474; 
    &#9474;files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,    &#9474;
    &#9474;modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software&#9474;
    &#9474;is furnished to do so, subject to the following conditions:                                                                   &#9474;
    &#9474;                                                                                                                              &#9474;
    &#9474;The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.&#9474;
    &#9474;                                                                                                                              &#9474;
    &#9474;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE          &#9474;
    &#9474;WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR         &#9474;
    &#9474;COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,   &#9474;
    &#9474;ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                         &#9474;
    &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
    }}
    
  • WBA ConsultingWBA Consulting Posts: 2,933
    edited 2015-03-02 17:12
    Lunchtime was productive, I figured out the decimal places and how to pull that cleanly. The C to F conversion line ends up with a number that is DegF*1000. So, a temp of 75.324F is stored in the "result" variable as 75324. This program shows the temp in three formats: 3, 2, and 1 decimal places as well as the whole number value. So, for a temp reading of 75.324F, PST will show:

    75.324
    75.32
    75.3
    75

    Anyhow, here's code:
    ''=============================================================================
    '' @file     sensirion_integer_demo.spin
    ''     MODIFIED BY WBA CONSULTING, ANDREW WILLIAMS
    '' @target   Propeller with Sensirion SHT1x or SHT7x   (not SHT2x)
    '' @author   Thomas Tracy Allen, EME Systems
    '' Copyright (c) 2013 EME Systems LLC
    '' See end of file for terms of use.
    '' version 1.3
    '' uses integer math to return values directly in degC*100 and %RH*10
    '' and print to terminal screen
    '' no floating point required
    '' This is the most basic demo.
    ''=============================================================================
    
    '' version log
    '' 005  AW Added code to convert C to F
    '' 006  AW Added code for decimal places
    
    
    CON
      _clkmode = xtal1 + pll8x                '
      _xinfreq = 5_000_000
    
    ' pins for data and clock.
    ' Note sht1x and sht7x protocol is like i2c, but not exactly
    ' Assumes power = 3.3V
      DPIN = 1 '13    ' needs pullup resistor
      CPIN = 0 '14    ' best use pulldown resistor for reliable startup, ~100k okay.
    
    OBJ
      pst : "parallax serial terminal"
      sht : "sensirion_integer"
    
    PUB Demo   
     sht.Init(DPIN, CPIN)
     pst.Start(9600)
     waitcnt(clkfreq/10+cnt)
    
     repeat
       pst.str(string(13,10,"Degrees F: "))
       if (result := sht.ReadTemperature) == negx
         pst.str(string("NA"))                              ' read temperature and handle possible error (negx)
       else
         result := ((result*18)+32000)                      ' sad attempt at F=C*1.8+32 in integer math, results in 75324 for 75.324F
         pst.newline
         
         pst.dec(result/1000)                               ' /1000 to bring it down to proper decimal position
         pst.char(".")
         pst.dec(||(result)//(1000))                        ' grab decimal degrees, 3 places, IE: 75.324
    
         pst.newline 
    
         pst.dec(result/1000)                               ' /1000 to bring it down to proper decimal position
         pst.char(".")
         pst.dec(||(result/10)//100)                        ' grab decimal degrees, 2 places, IE: 75.32 
    
         pst.newline
         
         pst.dec(result/1000)                               ' /1000 to bring it down to proper decimal position
         pst.char(".")     
         pst.dec(||(result/100)//10)                        ' grab decimal degrees, 1 place,  IE: 75.3 
    
         pst.newline
         pst.dec(result/1000)                               ' /1000 to bring it down to proper decimal position
                                                            '                                 IE: 75
    
         pst.newline  
         
         
       pst.str(string("%RH: "))
    
       if (result := sht.ReadHumidity) == negx              ' read RH and handle error by printing NA (not available)
         pst.str(string("NA"))
       else
         pst.dec(result/10)                                 ' %RH is in unit of tenths
         pst.char(".")
         pst.dec(result//10)
    
       waitcnt(clkfreq*2+cnt)                               ' wait 2 seconds
       pst.clear
    
    ' Always read temperature shortly before humidity!   RH temperature compensation depends on valid temperature reading.
    ' The routines return NEGX if the sensor times out, or if the readings are grossly out of range.
    ' Due to sensor tolerances, it is still possible to get readings <0 or >100 %RH.
    
    {{
    &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
    &#9474;                                                   TERMS OF USE: MIT License                                                  &#9474;                                                            
    &#9500;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9508;
    &#9474;Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation    &#9474; 
    &#9474;files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,    &#9474;
    &#9474;modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software&#9474;
    &#9474;is furnished to do so, subject to the following conditions:                                                                   &#9474;
    &#9474;                                                                                                                              &#9474;
    &#9474;The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.&#9474;
    &#9474;                                                                                                                              &#9474;
    &#9474;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE          &#9474;
    &#9474;WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR         &#9474;
    &#9474;COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,   &#9474;
    &#9474;ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                         &#9474;
    &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
    }}
    
  • Tracy AllenTracy Allen Posts: 6,658
    edited 2015-03-02 22:35
    That looks fine to me Andrew .

    There is possibility for roundoff, for example, 75324 --> 753 --> 75.3 and 75364 --> 754 --> 75.4.
    degF := (degC + 50) / 100 ' okay for positive only
    or better, proper rounding for either positive or negative numbers...
    degF := (degC + degC//100) / 100 ' okay for positive or negative. rounds °F*1000 off to °F*10

    Keep in mind that both operators, division / and modulus // on the Prop work correctly on both positive and negative 2s complement integers.

    Another way to convert °C*100 directly to °F*10 is to use the ** operator.

    degF :=degC ** 773094114 + 320 ' convert degC*100 to degF*10

    The multiplier is 2^32 * (18/100) = 773094114. That is okay for either positive or negative degC. Caveat: Watch out when constructing a multiplier, keep it between zero and 1/2-, that is, up to ** 2147483647.
  • WBA ConsultingWBA Consulting Posts: 2,933
    edited 2015-03-05 01:37
    Tracy, thanks, that helps me understand a bit more. Some math in SPIN is really easy, yet some is stumps me. I am also stuck with doing powers of 10 without using floating point objects. It would be nice to use a variable to set the number of decimal places such that a value of 2 would enable me to derive a value of 10 to the 2nd power, 100. Haven't found a way to do that, but I would have thought it would be easy.

    ~~~~~~~~~

    Been playing around with the Sensirion code a bit more and changed it to work with an LCD instead of PST as well as turn on the backlight if the temp changes more than 1 degree and even had a version changing the color of an WS2812B RGB LED based upon temp ranges:
    ''=============================================================================
    '' @file     sensirion_integer_demo.spin
    ''     MODIFIED BY WBA CONSULTING, ANDREW WILLIAMS
    '' @target   Propeller with Sensirion SHT1x or SHT7x   (not SHT2x)
    '' @author   Thomas Tracy Allen, EME Systems
    '' Copyright (c) 2013 EME Systems LLC
    '' See end of file for terms of use.
    '' version 1.3
    '' uses integer math to return values directly in degC*100 and %RH*10
    '' and print to terminal screen
    '' no floating point required
    '' This is the most basic demo.
    ''=============================================================================
    
    '' version log
    '' 005  AW Added code to convert C to F
    '' 006  AW Added code for decimal places
    '' 006L01 AW Changed from PST to LCD and set variable to change decimal places depending on change in temp
    '' 006L02 AW Added WS2812 RGB LED, Red if >80.0F, Green if 77.0-79.9, Blue if under 76.9
    '' 006L03 AW Changed code to just show symbol when temp changes more then 1 degree
    '' 006L03-RGB AW Removed WS2812 RGB LED code
    
    
    CON
      _clkmode = xtal1 + pll16x                '
      _xinfreq = 5_000_000
    
    ' pins for data and clock.
    ' Note sht1x and sht7x protocol is like i2c, but not exactly
    ' Assumes power = 3.3V
      DPIN = 6 '13    ' needs pullup resistor
      CPIN = 5 '14    ' best use pulldown resistor for reliable startup, ~100k okay.
      TxPin = 19
    
      
    VAR
      long  lastresult
    
    OBJ
    
      sht : "sensirion_integer"
      LCD : "FullDuplexSerial.spin"
        
    PUB Demo   
     sht.Init(DPIN, CPIN)
     LCD.start(TxPin, TxPin, %1000, 9_600)
     waitcnt(clkfreq/10+cnt)
     LCD.tx(12)                                             ' clear LCD
    
     repeat
       LCD.str(string("Deg F: "))
       if (result := sht.ReadTemperature) == negx
         LCD.str(string("NA"))                              ' read temperature and handle possible error (negx)
       else
         result := ((result*18)+32000)                      ' sad attempt at F=C*1.8+32 in integer math, results in 75324 for 75.324F
    
         if result/1000 <> lastresult                       ' if a reading changed more than 1 degree                      
           LCD.tx(17)                                       ' turn on backlight
           LCD.dec(result/1000)                               ' /1000 to bring it down to proper decimal position                     
           LCD.str(String("."))
           LCD.dec(||(result/100)//10)                        ' grab decimal degrees, 1 place,  IE: 75.3
           LCD.str(String(" *"))         
           lastresult:=result/1000                          ' store latest reading as lastresult
         else                                                ' if reading didn't change, show 1 decimal place
           LCD.tx(18)                                       ' turn off backlight 
           LCD.dec(result/1000)                               ' /1000 to bring it down to proper decimal position
           LCD.str(String("."))     
           LCD.dec(||(result/100)//10)                        ' grab decimal degrees, 1 place,  IE: 75.3 
         
         LCD.tx(13)                                           ' Line feed
         
       LCD.str(string("  %RH: "))
    
       if (result := sht.ReadHumidity) == negx              ' read RH and handle error by printing NA (not available)
         LCD.str(string("NA"))
       else
         LCD.dec(result/10)                                 ' %RH is in unit of tenths
         LCD.str(string("."))
         LCD.dec(result//10)
    
       waitcnt(clkfreq*2+cnt)                               ' wait 2 seconds
         LCD.tx(12)                                         ' Clear LCD 
    
    ' Always read temperature shortly before humidity!   RH temperature compensation depends on valid temperature reading.
    ' The routines return NEGX if the sensor times out, or if the readings are grossly out of range.
    ' Due to sensor tolerances, it is still possible to get readings <0 or >100 %RH.
    
    {{
    &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
    &#9474;                                                   TERMS OF USE: MIT License                                                  &#9474;                                                            
    &#9500;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9508;
    &#9474;Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation    &#9474; 
    &#9474;files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,    &#9474;
    &#9474;modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software&#9474;
    &#9474;is furnished to do so, subject to the following conditions:                                                                   &#9474;
    &#9474;                                                                                                                              &#9474;
    &#9474;The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.&#9474;
    &#9474;                                                                                                                              &#9474;
    &#9474;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE          &#9474;
    &#9474;WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR         &#9474;
    &#9474;COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,   &#9474;
    &#9474;ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                         &#9474;
    &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
    }}
    
  • WBA ConsultingWBA Consulting Posts: 2,933
    edited 2015-03-05 01:55
    In case anyone is interested, here is my code that also drives the WS2812 RGB LED based upon temp:
    ''=============================================================================
    '' @file     sensirion_integer_demo.spin
    ''     MODIFIED BY WBA CONSULTING, ANDREW WILLIAMS
    '' @target   Propeller with Sensirion SHT1x or SHT7x   (not SHT2x)
    '' @author   Thomas Tracy Allen, EME Systems
    '' Copyright (c) 2013 EME Systems LLC
    '' See end of file for terms of use.
    '' version 1.3
    '' uses integer math to return values directly in degC*100 and %RH*10
    '' and print to terminal screen
    '' no floating point required
    '' This is the most basic demo.
    ''=============================================================================
    
    '' version log
    '' 005  AW Added code to convert C to F
    '' 006  AW Added code for decimal places
    '' 006L01 AW Changed from PST to LCD and set variable to change decimal places depending on change in temp
    '' 006L02 AW Added WS2812 RGB LED, Red if >80.0F, Green if 77.0-79.9, Blue if under 76.9
    '' 006L03 AW Changed code to just show symbol when temp changes more then 1 degree
    
    
    CON
      _clkmode = xtal1 + pll16x                '
      _xinfreq = 5_000_000
    
    ' pins for data and clock.
    ' Note sht1x and sht7x protocol is like i2c, but not exactly
    ' Assumes power = 3.3V
      DPIN = 6 '13    ' needs pullup resistor
      CPIN = 5 '14    ' best use pulldown resistor for reliable startup, ~100k okay.
      TxPin = 19
    
    ' WS2812 CON
      CLK_FREQ = ((_clkmode - xtal1) >> 6) * _xinfreq               ' system freq as a constant
      MS_001   = CLK_FREQ / 1_000                                   ' ticks in 1ms
      US_001   = CLK_FREQ / 1_000_000                               ' ticks in 1us
      STRIP_LEN = 1                                                 ' LEDs in string
      LEDS = 18                                                     ' LED tx pin   
    
      
    VAR
      long  lastresult
    
    OBJ
    
      sht : "sensirion_integer"
      LCD : "FullDuplexSerial.spin"
      strip : "jm_ws2812"                                           ' WS2812 LED driver
        
        
    PUB Demo   
     sht.Init(DPIN, CPIN)
     LCD.start(TxPin, TxPin, %1000, 9_600)
     strip.start_b(LEDS, STRIP_LEN)                                ' start led driver
     strip.off
     waitcnt(clkfreq/10+cnt)
     LCD.tx(12)
    
     repeat
       LCD.str(string("Deg F: "))
       if (result := sht.ReadTemperature) == negx
         LCD.str(string("NA"))                              ' read temperature and handle possible error (negx)
       else
         result := ((result*18)+32000)                      ' sad attempt at F=C*1.8+32 in integer math, results in 75324 for 75.324F
    
         if result/100 > 800                                ' if over 80.0 degrees
           strip.setx(0, $FF_00_00,32)                      ' RGB LED set to red
         elseif result/100>770                              ' otherwise, if over 77.0 degrees 
           strip.setx(0, $00_FF_00,32)                      ' RGB LED set to green 
         else  
           strip.setx(0, $00_00_FF,32)                      ' last case, just set to blue
           
         if result/1000 <> lastresult                       ' if a reading changed more than 1 degree                      
           LCD.tx(17)                                       ' turn on backlight
           LCD.dec(result/1000)                               ' /1000 to bring it down to proper decimal position                     
           LCD.str(String("."))
           LCD.dec(||(result/100)//10)                        ' grab decimal degrees, 1 place,  IE: 75.3
           LCD.str(String(" *"))         
           lastresult:=result/1000                          ' store latest reading as lastresult
         else                                                ' if reading didn't change, show 1 decimal place
           LCD.tx(18)                                       ' turn off backlight 
           LCD.dec(result/1000)                               ' /1000 to bring it down to proper decimal position
           LCD.str(String("."))     
           LCD.dec(||(result/100)//10)                        ' grab decimal degrees, 1 place,  IE: 75.3 
         
         LCD.tx(13)                                           ' Line feed
         
       LCD.str(string("  %RH: "))
    
       if (result := sht.ReadHumidity) == negx              ' read RH and handle error by printing NA (not available)
         LCD.str(string("NA"))
       else
         LCD.dec(result/10)                                 ' %RH is in unit of tenths
         LCD.str(string("."))
         LCD.dec(result//10)
    
       waitcnt(clkfreq*2+cnt)                               ' wait 2 seconds
         LCD.tx(12)                                         ' Clear LCD 
    
    ' Always read temperature shortly before humidity!   RH temperature compensation depends on valid temperature reading.
    ' The routines return NEGX if the sensor times out, or if the readings are grossly out of range.
    ' Due to sensor tolerances, it is still possible to get readings <0 or >100 %RH.
    
    {{
    &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
    &#9474;                                                   TERMS OF USE: MIT License                                                  &#9474;                                                            
    &#9500;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9508;
    &#9474;Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation    &#9474; 
    &#9474;files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,    &#9474;
    &#9474;modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software&#9474;
    &#9474;is furnished to do so, subject to the following conditions:                                                                   &#9474;
    &#9474;                                                                                                                              &#9474;
    &#9474;The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.&#9474;
    &#9474;                                                                                                                              &#9474;
    &#9474;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE          &#9474;
    &#9474;WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR         &#9474;
    &#9474;COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,   &#9474;
    &#9474;ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                         &#9474;
    &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
    }}
    
  • Tracy AllenTracy Allen Posts: 6,658
    edited 2015-03-06 11:35
    That's nice. I'm onto a project now that uses the SHT71 sensors in a particulate monitor. That is the version of the sensor that comes mounted on a stalk. It has a flow-through path that gives it a very fast response to both temperature and humidity, especially when placed in the path of a small fan.
    Tracy, thanks, that helps me understand a bit more. Some math in SPIN is really easy, yet some is stumps me. I am also stuck with doing powers of 10 without using floating point objects. It would be nice to use a variable to set the number of decimal places such that a value of 2 would enable me to derive a value of 10 to the 2nd power, 100. Haven't found a way to do that, but I would have thought it would be easy.

    I think you must mean something more complicated than 102 = 10*10? Fractional powers? Those are digested by the computer using the relation z*10x = z*2x/log10(2). Then that new exponent is separated into integer and fractional parts, using the identity 2y = 2integer part of y*2fractional part of y. The integer part is saved as a shift operation to be used later. The fractional part is determined by some means, such as a lookup and interpolation in the HUB exponential table. Then multiply times z, apply the shift by the saved factor of two, and then apply the inverse of that first identity to convert back to a number with a power of 10. It is not easy in integer math, but the floating point package takes care of all of those details. Of course, floating point is at its core a number and exponent in powers of two.
  • WBA ConsultingWBA Consulting Posts: 2,933
    edited 2015-03-06 13:32
    I think you must mean something more complicated than 102 = 10*10?

    Nope, just that. In the code, to vary the number of decimal places used, you divide by 10, 100, or 1000. So it would be nice to use a variable (say "decplace") set to 1, 2, or 3 for number of decimal places and then at the beginning of my routine, I can just make decplace = 10 to the decplace power. Now in my formula, when I divide by decplace, it would be 10, 100, or 1000. I guess I could easily use a lookup table or case statement, but was hoping to just use powers of 10, but stay away from floating point objects.


    Actually, just realize that there are two values in the code that change depending on decimal places. So maybe a set of lookup tables would be clean. The three unique lines to obtain the decimal places:
         pst.dec(||(result/1)//(1000))                        ' grab decimal degrees, 3 places, IE: 75.324
    
         pst.dec(||(result/10)//100)                        ' grab decimal degrees, 2 places, IE: 75.32 
    
         pst.dec(||(result/100)//10)                        ' grab decimal degrees, 1 place,  IE: 75.3 
    

    That's nice. I'm onto a project now that uses the SHT71 sensors in a particulate monitor. That is the version of the sensor that comes mounted on a stalk. It has a flow-through path that gives it a very fast response to both temperature and humidity, especially when placed in the path of a small fan.
    Thanks for the compliment, I have been wondering if my code is ok or a mess, LOL. Agree with the SHT71 series. That concept was one of the reasons for the shape of my module. Several of my customers have told me the main value in mine is the quick response by being able to locate the module into the desired path of airflow easily.
    attachment.php?attachmentid=113410&d=1425676200
    448 x 180 - 48K
Sign In or Register to comment.