Basic Stamp 2 (BS2) RTC DS1302 & Temp DS1620 on an LCD, Buttons and Alarm
T&E Engineer
Posts: 1,396
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.