Shop OBEX P1 Docs P2 Docs Learn Events
Remote Temperature Sensor — Parallax Forums

Remote Temperature Sensor

tomcrawfordtomcrawford Posts: 1,126
edited 2013-08-15 14:25 in Robotics
This note describes a remote temperature sensor based on Propellor, DS1620, and XBee. Power consumption is an issue.

The code is attached. No schematic was ever drawn; the connections are implicit in the CON section of the code.

CON
        _clkmode = xtal1 + pll8x        'Standard clock mode 
        _xinfreq = 5_000_000            ' * crystal frequency = 80 MHz
       

'DS1620 constants
        CS1620 = 14, CK1620 = 13, D1620 = 12
        WrCfg = $0C, StartC = $EE, RdTmp = $AA

'XBee Constants
        XBSer = 1, XBSleep = 2

'Define the LED
         Led = 15                                             
VAR
  long  SnoozeCount, SerializerCnt
  long  OldRaw, Raw, BitTime 
  byte  Debug             'execute the debuggging code
  byte  Ascii, Parity
   
OBJ
  pst      : "parallax serial terminal"


  
PUB main
  BitTime := Clkfreq/9600                              'clock tics per serial bit time
  dira[XBSer]~~                                        'an output
  outa[XBSer]~~                                        'high
  dira[XBSleep]~~                                      'XBee Sleep Pin
  outa[XBSleep]~                                       'Not sleep
  debug := $FF                                         'execute debug code
  if (debug <> 0)
    pst.Start (115_200)                                   'start up ser terminal if debugging
    pst.str(String("hello, world   "))                    'runs in cog 1
    pst.NewLine
    waitcnt(clkfreq/10+cnt)

    

  Init1620                                                'get the thermometer going
  TextString(String("+++"))                               'XBee enter command mode
  waitcnt((Clkfreq*2) + Cnt)  
  TextString(string("ATSM 1"))                             'hybernate on sleep pin
  SerialChar($0D)
  waitcnt((Clkfreq*2) + Cnt)                               'exit command mode
  TextString(String("ATCN"))
  SerialChar($0D)                                       
  waitcnt((Clkfreq*2) + Cnt)      
  dira[led]~~                                              'control the LED  

  
  repeat
    Raw := GetTemp                                       'raw temp
    if debug <> 0
        outa[LED]~~                                        'blink the led
        pst.str(String("OldRaw: "))
        pst.hex(OldRaw,3)
        Pst.str(String("   Raw: "))
        pst.hex(raw,3)                                       'display it
        pst.str(string("  SnoozeCount: "))
        pst.dec(SnoozeCount)
        pst.newline

      
    if (raw <> Oldraw) OR (SnoozeCount++ > 60)

        Parity := 0                                'Initialize the longitudinal Parity  
        outa[xbsleep]~                             'Wake up XBee 
        OldRaw := Raw                              'Save the new temperature     
        SnoozeCount := 0                           'restart the snooze count
        waitcnt(clkfreq/50 + cnt)                  'wait for XBee to wake up  
        TextString(String("X1"))                   'introductor: Inside unit looks for this
        Raw := Raw -> 8                            'put first nibble at right edge
        repeat 3                                   'will send three chars of 1620 data
            Ascii := Hex2Ascii                     'get one ascii char
            SerialChar(Ascii)                      'transmit it (and accumulate parity)
            Raw := Raw <- 4                        'get next hex digit
        SerialChar(Parity)                          'send the parity character  
        outa[XBSleep]~~                            'put XBee back to sleep    
    outa[led]~                                      'turn off the LED (even if it's not on)
    waitcnt(clkfreq*10 + cnt)                      'wait ten seconds


PUB Hex2Ascii
    Result := Raw & $F                             'scale and extract
    Result := Result + ("0")                        'ascii char
    if result > "9"                                 'see if A-F
       Result := Result + 7 
     
PUB Init1620
  dira[CS1620]~~                                         'CS is always an output
  outa[CS1620]~                                          'normally low
  dira[CK1620]~~                                         'clock
  outa[CK1620]~                                          'normally low
  outa[CS1620]~~                                         'chip select
  Write1620(WrCfg)                                       'write to config reg
  Write1620(%10)                                         'CPU, continuous conversion
  outa[CS1620]~                                          'remove CS
  outa[CS1620]~~                                         'CS back
  Write1620(StartC)                                       'start conversions
  outa[CS1620]~                                           'leave cs low


  

PUB Write1620 (Value)
  outa[D1620]~                                           'data starts out zero
  dira[D1620]~~                                          'data pin is an output
  value := value << 1                                    'pre-scale
  repeat 8                                               'always write 8 bits to 1620
    value := Value >> 1                                  'position next bit        
    outa[D1620] := (Value & 1)                           'put the bit on the data pin
    outa[CK1620]~~                                        'clock high
    outa[CK1620]~                                         'then low
  dira[D1620]~                                           'leave data pin an input   

        


PUB GetTemp 
    outa[CS1620]~~                                         ' activate sensor
    write1620(RdTmp)                                        ' send read temp command
    repeat 9                                                'will get nine bits
      result := result >> 1                                 'low order first
      if ina[D1620] <> 0                                    'see if it's a one
          result := result | $100                           'set the bit  
      outa[CK1620]~~                                        'clock the clock
      outa[CK1620]~                                         'walk the walk
    'this produces a 15 uSec pulse which is plenty
    'the period is 90-odd uSec
    outa[CS1620]~                                           'deactivate sensor
    if (result & $100) <> 0                                 'extend sign if needful
      result := result | $E00                               'return what we got
        


    

PUB TextString(TextPoint)       'send a string of text to the XBee
  repeat 
      Ascii := BYTE[TextPoint]  'get a character
      if (Ascii ==0) or (Ascii == $A) or (Ascii == $D) 
        return                   'end of string
      SerialChar(Ascii)           'send to xbee
      TextPoint ++               'on to next character



Pub SerialChar(TheByte)           'Serialize one character
  Parity := Parity ^ TheByte      'accumulate parity
  SerializerCnt := cnt            'initialize timing 
  outa[XBSer]~                    'start bit
  waitcnt(SerializerCnt+=BitTime)    'wait for start bit to complete
  repeat 8                        'going to do eight data bits
     outa[XBSer] := TheByte & %1    'set the bit to zero or one
     TheByte := TheByte >> 1       'align the next bit
     waitcnt(SerializerCnt+=BitTime)  'one bit time (Pretty much dead on)     '
  outa[XBSer]~~                     'stop bit
  waitcnt(SerializerCnt+=BitTime)   'one last bit time


I wanted to add an outdoor temperature sensor to my scrolling clock/calendar/thermometer. Here is a pointer to the project without outside temperature.

http://forums.parallax.com/showthread.php/143098-PropClock-with-Scrolling-Pithy-Sayings

Here is a pointer to a video of the new version.
http://youtu.be/NyiPvkzsf3g

The program is pretty straight-forward. Since power consumption is an issue, I needed to be able to put both the Prop and the XBee to sleep. The power consumption is about 5 ma in this case. The serial terminal is always compiled but started only if variable DEBUG is non-zero.

I put the XBee in command mode and program it to hybernate on sleep pin. Then, every ten seconds I read the thermometer. If it is different than the last time I transmitted the temperature, or if it has been ten minutes (more or less), I wake up the XBee and transmit the raw DS1620 data to the inside unit. The three characters of data are preceded by "X1" (meaning external module one). I transmit one character of longitudinal parity that is verified on the inside unit. The XBee is put back to sleep and the prop is put back to sleep for 10 seconds. Rather than use a Serializer object, I did it by hand using spin. It sends at 9600 baud with just about perfect timing.

The unit is powered with a 6 volt sealed lead-acid battery floated directly across a nominal 6 volt solar panel (from Parallax). With an average current draw of 5 ma, I figure 120 mAhr per day. The solar panel is nominally capable of 1 W or 160ma. So one hour of sun per day should do it. We'll see this winter.
1024 x 768 - 127K
1024 x 768 - 151K

Comments

  • Hal AlbachHal Albach Posts: 747
    edited 2013-08-15 13:36
    The PLL is set wrong if you want system clock to be 80MHz. Needs to be set to 16.
  • tomcrawfordtomcrawford Posts: 1,126
    edited 2013-08-15 14:25
    Hal Albach wrote: »
    The PLL is set wrong if you want system clock to be 80MHz. Needs to be set to 16.

    *Blush* Eagle-eye Albach is, of course, correct.

    I changed the PLL setting to reduce the power consumption even when the Prop was awake and neglected to fix up the boilerplate comment. Fortunately, clkfreq works as documented. tc
Sign In or Register to comment.