Basic Stamp 2 (BS2) RTC DS1302 & Temp DS1620 on an LCD, Buttons and Alarm
To my surprise there was no Basic Stamp 2 method to display both date/time and temperature on an LCD and control it with buttons. With DEBUG, yes but buttons no. I built something similar sometime back using a BS2 and an SX Video Module (Hitt Consulting - Bean) using only a DS1302 RTC and buttons.
http://forums.parallax.com/showthread.php?p=553426
I also did something similar using an SX-28 and an LCD with a DS1302 RTC and buttons.
http://forums.parallax.com/showthread.php?p=643780
However, there was nothing I could find for the BS2 that used an LCD, buttons, DS1302 RTC and a DS1620 Temperature IC as well as having an alarm mode. So I saw the need in the forums and decided to meet the need on some level.
The code is pretty much self explainatory with comments. I am not a programmer by trade just hobby so there are probably better ways to do this - but I used what I could find and modified it to get it to work.
It does use 8 buttons (I used the professional development board by Parallax).
The temp is displayed in Celsius or Fahrenheit but I suggest commenting out either of the tempC or tempF WORD to free up a word. If you use both, there is only a "bit" of variable space left. So it is good to comment one out.
The code you have seen before as it is a compilation of other DS1302, DS1620 and other programs combined to get it to work together.
There is also only 1 available BS2 pin left as well as having 1 bit to 1 word left.
The LCD displays (but you can change it to what you want):
Su 06:00:00A xxC· (xx is the temperature)
12:00PM 12/31/08
One last question that I am not sure about is I thought I remember reading that you must set the Date (eg. Sunday, Monday, etc..) because it affects the year 2 digit code. The DS1302 has an algorythm that uses this Date to figure out if the year is actually 2008, or 1908, 1808 (based on if the year 2 digits are 08). I think this is correct so I have a button for setting the Date. The top line is very tight on data displayed so the Date is only 2 characters (e.g. Su, Mo, Tu, etc..)
Another thing is that the Alarm time (2nd line) is·set by holding down Button6 and Button0 (for minutes forward) or Button1 (for Hours forward). I did not utilize the Backward button (Button7) as this would be too many buttons to·press or hold.
Comments?
PS: I found a small bug in the alarm setting and fixed it (6/29/08)
[/code][/size]
Post Edited (T&E Engineer) : 6/29/2008 4:20:17 AM GMT
http://forums.parallax.com/showthread.php?p=553426
I also did something similar using an SX-28 and an LCD with a DS1302 RTC and buttons.
http://forums.parallax.com/showthread.php?p=643780
However, there was nothing I could find for the BS2 that used an LCD, buttons, DS1302 RTC and a DS1620 Temperature IC as well as having an alarm mode. So I saw the need in the forums and decided to meet the need on some level.
The code is pretty much self explainatory with comments. I am not a programmer by trade just hobby so there are probably better ways to do this - but I used what I could find and modified it to get it to work.
It does use 8 buttons (I used the professional development board by Parallax).
The temp is displayed in Celsius or Fahrenheit but I suggest commenting out either of the tempC or tempF WORD to free up a word. If you use both, there is only a "bit" of variable space left. So it is good to comment one out.
The code you have seen before as it is a compilation of other DS1302, DS1620 and other programs combined to get it to work together.
There is also only 1 available BS2 pin left as well as having 1 bit to 1 word left.
The LCD displays (but you can change it to what you want):
Su 06:00:00A xxC· (xx is the temperature)
12:00PM 12/31/08
One last question that I am not sure about is I thought I remember reading that you must set the Date (eg. Sunday, Monday, etc..) because it affects the year 2 digit code. The DS1302 has an algorythm that uses this Date to figure out if the year is actually 2008, or 1908, 1808 (based on if the year 2 digits are 08). I think this is correct so I have a button for setting the Date. The top line is very tight on data displayed so the Date is only 2 characters (e.g. Su, Mo, Tu, etc..)
Another thing is that the Alarm time (2nd line) is·set by holding down Button6 and Button0 (for minutes forward) or Button1 (for Hours forward). I did not utilize the Backward button (Button7) as this would be too many buttons to·press or hold.
Comments?
PS: I found a small bug in the alarm setting and fixed it (6/29/08)
[size=2][code]
' ==============================================================================
'
' File...... DS1302_DS1620_LCD_8BTN.BS2
' Purpose... RTC Control
' Author.... Tim Gilmore
' E-mail.... [url=mailto:gilmoret@us.saic.com]gilmoret@us.saic.com[/url]
' Started... 27 June 2008
' Updated... 29 June 2008
'
' {$STAMP BS2}
' {$PBASIC 2.5}
'
'
' ==============================================================================
' ------------------------------------------------------------------------------
' Program Description
' ------------------------------------------------------------------------------
' This program demonstrates the control and use of an external real-time clock
' chip, the DS1302 and a real-time temperature chip, the DS1620 both from Dallas Semiconductor.
'
' It has 8 buttons tied high with 10K resistors. The other side of the button goes to ground.
' Also recommend a 220 ohm resistor between each BUTTON BIN AND each BUTTON.
'
' 5 vdc
' ^
' |
' |
' (10K ohm)
' |
' | --|--
' BS2 Pin (x) <--(220 ohm resistor)-------o o--|
' |
' -----
' (Repeat for all 8 switch assemblies) ---
' (x is a BS2 Pin from 8 to 15) -
'
' Pin Assignments
' 0 DS1302 DataIO
' 1 DS1302 Clock
' 2 DS1302 Chip Select
' 3 Parallax Serial LCD RX Line
'
' 4 DS1620 DQ (use a 1K resistor between DQ {DS1620) and pin 4 (BS2))
' 5 DS1620 Clock2
' 6 DS1620 Reset
' 7 ???
' 8 Button 0
' 9 Button 1
' 10 Button 2
' 11 Button 3
' 12 Button 4
' 13 Button 5
' 14 Button 6
' 15 Button 7
'
' BE SURE TO "RESET" THE BASIC STAMP 2 CIRCUIT AFTER POWER UP.
' ------------------------------------------------------------------------------
' I/O Definitions
' ------------------------------------------------------------------------------
DataIO CON 0 ' DS1302.6
Clock CON 1 ' DS1302.7
CS1302 CON 2 ' DS1302.5
LCD CON 3 ' Parallax Serial LCD Display (Rx line)
DQ CON 4 ' DS1620.1 (data I/O)
Clock2 CON 5 ' DS1620.2
Reset CON 6 ' DS1620.3
BtnsIn VAR INH ' button input (pins 8 - 15)
' ------------------------------------------------------------------------------
' Constants
' ------------------------------------------------------------------------------
WrSecs CON $80 ' write seconds
RdSecs CON $81 ' read seconds
WrMins CON $82 ' write minutes
RdMins CON $83 ' read minutes
WrHrs CON $84 ' write hours
RdHrs CON $85 ' read hours
CWPr CON $8E ' write protect register
WPr1 CON $80 ' set write protect
WPr0 CON $00 ' clear write protect
WrBurst CON $BE ' write burst of data
RdBurst CON $BF ' read burst of data
WrRam CON $C0 ' RAM address control
RdRam CON $C1
Yes CON 1
No CON 0
Hr24 CON 0
Hr12 CON 1
ClockMode CON Hr12 ' use AM/PM mode
Baud CON 32 ' 19K2 bps
LcdBkSpc CON $08 ' move cursor left
LcdRt CON $09 ' move cursor right
LcdLF CON $0A ' move cursor down 1 line
LcdCls CON $0C ' clear LCD (use PAUSE 5 after)
LcdCR CON $0D ' move pos 0 of next line
LcdBLon CON $11 ' backlight on
LcdBLoff CON $12 ' backlight off
LcdOff CON $15 ' LCD off
LcdOn1 CON $16 ' LCD on; cursor off, blink off
LcdOn2 CON $17 ' LCD on; cursor off, blink on
LcdOn3 CON $18 ' LCD on; cursor on, blink off
LcdOn4 CON $19 ' LCD on; cursor on, blink on
LcdLine1 CON $80 ' move to line 1, column 0
LcdLine2 CON $94 ' move to line 2, column 0
LcdCC0 CON $F8 ' define custom char 0
LcdCC1 CON $F9 ' define custom char 1
LcdCC2 CON $FA ' define custom char 2
LcdCC3 CON $FB ' define custom char 3
LcdCC4 CON $FC ' define custom char 4
LcdCC5 CON $FD ' define custom char 5
LcdCC6 CON $FE ' define custom char 6
LcdCC7 CON $FF ' define custom char 7
RdTmp CON $AA ' read temperature
WrHi CON $01 ' write TH (high temp)
WrLo CON $02 ' write TL (low temp)
RdHi CON $A1 ' read TH
RdLo CON $A2 ' read TL
StartC CON $EE ' start conversion
StopC CON $22 ' stop conversion
WrCfg CON $0C ' write config register
RdCfg CON $AC ' read config register
' ------------------------------------------------------------------------------
' Variables
' ------------------------------------------------------------------------------
index VAR Byte ' loop counter
reg VAR Byte ' DS1302 address to read/write
ioByte VAR Byte ' data to/from DS1302
secs VAR Byte ' seconds
secs01 VAR secs.LOWNIB
secs10 VAR secs.HIGHNIB
mins VAR Byte ' minutes
mins01 VAR mins.LOWNIB
mins10 VAR mins.HIGHNIB
hrs VAR Byte ' hours
hrs01 VAR hrs.LOWNIB
hrs10 VAR hrs.HIGHNIB
day VAR Byte '1 - 7 for Sunday through Saturday (Used for determining if the year is 2008 or 1908).
month VAR Byte
month01 VAR month.LOWNIB
month10 VAR month.HIGHNIB
date VAR Byte ' Date (0 - 31)
date01 VAR date.LOWNIB
date10 VAR date.HIGHNIB
year VAR Byte ' Year (00 - 99) - up to the year 2100 (or really 2099).
year01 VAR year.LOWNIB
year10 VAR year.HIGHNIB
ampm VAR hrs.BIT5 ' 0 = AM, 1 = PM
tMode VAR hrs.BIT7 ' 0 = 24, 1 = 12
rawTime VAR Word ' raw storage of time values
work VAR Byte ' work variable for display output
oldSecs VAR Byte ' previous seconds value
apChar VAR Byte ' "A" or "P"
ampmFlag VAR Bit ' 0 = AM, 1 = PM
btns VAR Byte
btnMin VAR btns.BIT0 ' update minutes
btnHrs VAR btns.BIT1 ' update hours
btnDay VAR btns.BIT2 ' update day
btnMonth VAR btns.BIT3 ' update month
btnDate VAR btns.BIT4 ' update date
btnYear VAR btns.BIT5 ' update year
btnAlarm VAR btns.BIT6 ' Set alarm
btnBack VAR btns.BIT7 ' go backward for everything except alarm.
mins_alarm VAR Byte
hrs_alarm VAR Byte
ampmflag_alarm VAR Bit
alarmbit_alarm VAR Bit
tempIn VAR Word ' raw temperature
sign VAR tempIn.BIT8 ' 1 = negative temperature
tSign VAR Bit
tempC VAR Word ' Celsius
'tempF VAR Word ' Fahrenheit
'
'Comment out tempF to free up a Word of variable space (if not using Fahrenheit)
idx VAR Byte
' ------------------------------------------------------------------------------
' EEPROM Data
' ------------------------------------------------------------------------------
Su DATA "Su ", 0
Mo DATA "Mo ", 0
Tu DATA "Tu ", 0
We DATA "We ", 0
Th DATA "Th ", 0
Fr DATA "Fr ", 0
Sa DATA "Sa ", 0
' ------------------------------------------------------------------------------
' Initialization
' ------------------------------------------------------------------------------
Initialize:
DIRL = %00111111 ' switches are ins, others outs
DIRH = %00000000
reg = CWPr ' clear write protect register
ioByte = WPr0
GOSUB RTC_Out
HIGH LCD ' Setup Serial Output Pin
SEROUT LCD, Baud, [noparse][[/noparse]LcdOn1, LcdBLon] ' Turn LCD Display & Backlight On
HIGH Reset ' alert the DS1620
SHIFTOUT DQ, Clock2, LSBFIRST, [noparse][[/noparse]WrCfg, %10] ' use with CPU; free-run
LOW Reset
PAUSE 10
HIGH Reset
SHIFTOUT DQ, Clock2, LSBFIRST, [noparse][[/noparse]StartC] ' start conversions
LOW Reset
alarmbit_alarm = 1
oldSecs = $99 ' set the display flag
hrs = $06 ' preset time to 6:00 AM
month = $12
date = $31
year = $08
mins_Alarm = 0
hrs_Alarm = $12
GOSUB Set_Time
' ------------------------------------------------------------------------------
' Program Code
' ------------------------------------------------------------------------------
Main1:
IF 12 - (24 - (hrs10 * 10 + hrs01) // 12) = hrs_alarm THEN
IF mins = mins_alarm THEN
IF ampmflag = ampmflag_alarm THEN
IF alarmbit_alarm = 1 THEN
GOSUB Action_alarm
ENDIF
ENDIF
ENDIF
ENDIF
GOSUB Get_Temperature ' read the DS1620
GOSUB Get_Time ' read the DS1302
IF (secs = oldSecs) THEN Check_Buttons ' time for update?
Main2:
GOSUB Show_Time ' yes, show it
oldSecs = secs ' mark it
IF alarmbit_alarm = 0 THEN
alarmbit_alarm = 1
ENDIF
Check_Buttons:
GOSUB Get_Buttons
IF (btns = 0) THEN Do_Some_Task ' let Stamp do other work
IF (btnAlarm=Yes) AND (btnMin=Yes) THEN AlarmSet
IF (btnAlarm=Yes) AND (btnHrs=Yes) THEN AlarmSet
IF (btnBack = Yes) THEN Go_Back ' back button pressed?
Go_Forward:
rawTime = rawTime + btnMin ' add one minute
rawTime = rawTime + (btnHrs * 60) ' add one hour
day = (day + btnDay) // 7 ' next day
month = month + btnMonth
IF month = $A THEN
month = $10
ELSEIF month > $12 THEN
month = 1
ENDIF
date = date + btnDate
IF date = $A THEN
date = $10
ELSEIF date = $1A THEN
date = $20
ELSEIF date = $2A THEN
date = $30
ELSEIF date > $31 THEN
date = 1
ENDIF
year = year + btnYear
IF year = $A THEN
year = $10
ELSEIF year = $1A THEN
year = $20
ELSEIF year = $2A THEN
year = $30
ELSEIF year = $3A THEN
year = $40
ELSEIF year = $4A THEN
year = $50
ELSEIF year = $5A THEN
year = $60
ELSEIF year = $6A THEN
year = $70
ELSEIF year = $7A THEN
year = $80
ELSEIF year = $8A THEN
year = $90
ELSEIF year > $99 THEN
year = 0
ENDIF
GOTO Update_Clock
Go_Back:
IF (btns <= %0000000) THEN Do_Some_Task ' no update button pressed
rawTime = rawTime + (btnMin * 1439) ' subtract one minute
rawTime = rawTime + (btnHrs * 1380) ' subtract one hour
day = (day + (btnDay * 6)) // 7 ' previous day
month = month - btnMonth
IF month = 0 THEN
month = $12
ELSEIF month = $F THEN
month = $9
ENDIF
date = date - btnDate
IF date = $2F THEN
date = $29
ELSEIF date = $1F THEN
date = $19
ELSEIF date = $F THEN
date = $9
ELSEIF date = 0 THEN
date = $31
ENDIF
year = year - btnYear
IF year = $9F THEN
year = $99
ELSEIF year = $8F THEN
year = $89
ELSEIF year = $7F THEN
year = $79
ELSEIF year = $6F THEN
year = $69
ELSEIF year = $5F THEN
year = $59
ELSEIF year = $4F THEN
year = $49
ELSEIF year = $3F THEN
year = $39
ELSEIF year = $2F THEN
year = $29
ELSEIF year = $1F THEN
year = $19
ELSEIF year = $F THEN
year = $9
ELSEIF year = $FF THEN
year = $99
ENDIF
GOTO Update_Clock
AlarmSet:
mins_Alarm = mins_Alarm + btnMin
IF mins_alarm = $A THEN
mins_alarm = $10
ELSEIF mins_alarm = $1A THEN
mins_alarm = $20
ELSEIF mins_alarm = $2A THEN
mins_alarm = $30
ELSEIF mins_alarm = $3A THEN
mins_alarm = $40
ELSEIF mins_alarm = $4A THEN
mins_alarm = $50
ELSEIF mins_alarm = $5A THEN
mins_alarm = 0
ENDIF
hrs_Alarm = hrs_Alarm + btnHrs
IF hrs_alarm = $A THEN
hrs_alarm = $10
ELSEIF (ampmFlag_alarm = 0) AND (hrs_alarm > $12) THEN
hrs_alarm = 1
ampmFlag_alarm = 1
ELSEIF (ampmFlag_alarm = 1) AND (hrs_alarm > $12) THEN
hrs_alarm = 1
ampmFlag_alarm = 0
ENDIF
Update_Clock: ' send updated value to DS1302
rawTime = rawTime // 1440 ' clean-up time mods
GOSUB Set_Raw_Time ' set the clock with rawTime
GOTO Main2
Do_Some_Task: ' work when not setting clock
' other code here
GOTO Main1
' ------------------------------------------------------------------------------
' Subroutines
' ------------------------------------------------------------------------------
Action_alarm:
'Do any alarm actions here (for example:)
'
' DO something while the time is waiting to clear (< 1 minute)
FOR idx = 1 TO 3
SEROUT LCD, Baud, [noparse][[/noparse]LcdCls] ' Clear The LCD Display
PAUSE 1000
SEROUT LCD, Baud, [noparse][[/noparse]"ALARM ", HEX2 hrs_alarm, ":", HEX2 mins_alarm]
IF ampmFlag_alarm = 0 THEN
SEROUT LCD, Baud, [noparse][[/noparse]"AM", LcdCR]
ELSE
SEROUT LCD, Baud, [noparse][[/noparse]"PM", LcdCR]
ENDIF
SEROUT LCD, Baud, [noparse][[/noparse]"Take Action"]
PAUSE 2000
NEXT
alarmbit_alarm = 0
RETURN
Show_Time:
'DEBUG HOME
LOOKUP day,[noparse][[/noparse]Su,Mo,Tu,We,Th,Fr,Sa],work ' get address of day string
SEROUT LCD, Baud, [noparse][[/noparse]LcdLine1] ' LCD Home Position
Get_Day_Char:
READ work, ioByte ' grab a character
IF (ioByte = 0) THEN Check_Clock_Mode ' if 0, string is complete
'DEBUG ioByte ' print the character
SEROUT LCD, Baud, [noparse][[/noparse]ioByte]
work = work + 1 ' point to next
GOTO Get_Day_Char
Check_Clock_Mode:
'DEBUG " ", CR ' clear day name debris
' SEROUT LCD, Baud, [noparse][[/noparse]" ", CR]
IF (ClockMode = Hr24) THEN Show24
Show12:
SEROUT LCD, Baud, [noparse][[/noparse]DEC2 12 - (24 - (hrs10 * 10 + hrs01) // 12)]
SEROUT LCD, Baud, [noparse][[/noparse]":", HEX2 mins, ":", HEX2 secs]
ampmFlag = 0
apChar = "A" ' assume AM
IF (hrs < $12) THEN Show_AMPM ' check time
ampmFlag = 1
apChar = "P" ' hrs was >= $12
Show_AMPM:
'SEROUT LCD, Baud, [noparse][[/noparse]apChar, "M"] ' Un-comment to show the "M" on the display
SEROUT LCD, Baud, [noparse][[/noparse]apChar, " "]
GOTO Show_Time_Done
Show24:
SEROUT LCD, Baud, [noparse][[/noparse]HEX2 hrs, ":", HEX2 mins, ":", HEX2 secs]
Show_Time_Done:
SEROUT LCD, Baud, [noparse][[/noparse]SDEC tempC, "C"]
SEROUT LCD, Baud, [noparse][[/noparse]HEX2 hrs_alarm, ":", HEX2 mins_alarm]
IF ampmFlag_alarm = 0 THEN
SEROUT LCD, Baud, [noparse][[/noparse]"AM"]
ELSE
SEROUT LCD, Baud, [noparse][[/noparse]"PM"]
ENDIF
SEROUT LCD, Baud, [noparse][[/noparse]" ", HEX2 month, "/", HEX2 date, "/", HEX2 year]
RETURN
Get_Buttons:
btns = %11111111 ' enable all button inputs
FOR index = 1 TO 10
btns = btns & ~BtnsIn ' test inputs
PAUSE 5 ' delay between tests
NEXT
PAUSE 200 ' slow held button(s)
RETURN
RTC_Out: ' send ioByte to reg in DS1302
HIGH CS1302
SHIFTOUT DataIO, Clock, LSBFIRST, [noparse][[/noparse]reg, ioByte]
LOW CS1302
RETURN
RTC_In: ' read ioByte from reg in DS1302
HIGH CS1302
SHIFTOUT DataIO, Clock, LSBFIRST, [noparse][[/noparse]reg]
SHIFTIN DataIO, Clock, LSBPRE, [noparse][[/noparse]ioByte]
LOW CS1302
RETURN
Set_Raw_Time: ' convert rawTime to BCD
hrs10 = rawTime / 600
hrs01 = (rawTime // 600) / 60
mins10 = (rawTime // 60) / 10
mins01 = rawTime // 10
Set_Time: ' DS1302 Burst Write
HIGH CS1302 ' Select DS1302
SHIFTOUT DataIO, Clock, LSBFIRST, [noparse][[/noparse]WrBurst]
SHIFTOUT DataIO, Clock, LSBFIRST, [noparse][[/noparse]secs, mins, hrs, date, month, day, year, 0]
LOW CS1302 ' Deselect DS1302
RETURN
Get_Time: ' read data with burst mode
HIGH CS1302
SHIFTOUT DataIO, Clock, LSBFIRST, [noparse][[/noparse]RdBurst]
SHIFTIN DataIO, Clock, LSBPRE, [noparse][[/noparse]secs, mins, hrs, date, month, day, year, idx]
LOW CS1302
rawTime = ((hrs10 & %11) * 600) + (hrs01 * 60)
rawTime = rawTime + (mins10 * 10) + mins01
RETURN
Get_Temperature:
HIGH Reset ' alert the DS1620
SHIFTOUT DQ, Clock2, LSBFIRST, [noparse][[/noparse]RdTmp] ' give command to read temp
SHIFTIN DQ, Clock2, LSBPRE, [noparse][[/noparse]tempIn\9] ' read it in
LOW Reset ' release the DS1620
tSign = sign ' save sign bit
tempIn = tempIn / 2 ' round to whole degrees
IF (tSign = 0) THEN No_Neg1
tempIn = tempIn | $FF00 ' extend sign bits for negative
No_Neg1:
tempC = tempIn ' save Celsius value
tempIn = tempIn */ $01CC ' multiply by 1.8
IF (tSign = 0) THEN No_Neg2 ' if negative, extend sign bits
tempIn = tempIn | $FF00
No_Neg2:
tempIn = tempIn + 32 ' finish C -> F conversion
'tempF = tempIn ' save Fahrenheit value
RETURN
[/code][/size]
Post Edited (T&E Engineer) : 6/29/2008 4:20:17 AM GMT

Comments
http://forums.parallax.com/showthread.php?p=552892
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Chris Savage
Parallax Engineering
Also I supose, I could have freed up 2 extra I/O lines but it wasn't immediately obvious to me when I put this together and had enough pins anyway on the BS2.
But yes Chris has shown this is possible.
Thanks Chris.