Remote Temperature Sensor
tomcrawford
Posts: 1,129
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.
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.
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.



Comments
*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