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