
The buttons are momentary push to make types.
I have tested the program on the following PIC® chips, 16F84, 16F628(7), 18F1320(1220) and 18F452(252).
It should work on any part with 1k or more memory.
Read the notes in the program for more details.
The software is called “84_1307_1.bas” and is fully commented with each routine having its own explanation.
I have used versions of this code for two years now and it has proved to be very reliable.
'Program "84_1307_1.bas" written by Mark Rodgers 18,07,04.
'mark@rodgers.fsworld.co.uk
'Compiled in Proton+ 2.1.4
'Tested on 16F84,16F628,18F1320 and 18F452
'It is presented as is with no guarantees or responsibilities implied.
'It is not for any comercial use(I wish!) or to copy and pass any part as
'your own, I would be happy if it was used to develop your own comercial free
'code or as the basis for a club project with inclusion of author recognition.
'Please feel free to contact me if you wish to use this code/hardware for any reason.
Device 16F84 'better than an OC71
XTAL 4
LCD_RSPIN PORTA.0
LCD_ENPIN PORTB.0
SDA_PIN PORTA.4
SCL_PIN PORTA.3
WARNINGS off
Dim bcd_to_bin_byte 'variable used in BCD and Binary conversion routines
Dim low_bits 'low byte for Binary to BCD routine
Dim high_bits 'high byte for Binary to BCD routine
Dim ds1307_address 'DS1307 internal registers address(0=seconds,1=minutes etc.)
Dim second 'seconds variable
Dim minute 'minutes variable
Dim hour 'hours variable
Dim day 'days variable
Dim date 'dates variable
Dim month 'months variable
Dim year 'years variable
Dim buttonvalue 'variable used for "up" and "down" buttons values
Dim maxvalue 'variable holding highest allowable current value in button routine
Dim minvalue 'variable holding lowest current allowable value in button routine
Dim leap 'variable used to set "maxvalue" in leapyear
Dim monthlength 'variable used to set maximum number of days in the selected month
Dim index 'variable used to select display options in "setup"
Dim character 'variable holding data selected from eeprom or ldata tables to be printed on display
Dim printposition 'start position on the LCD of first "character" in print routine
Dim printend 'last "character" position to be printed on LCD
Dim printaddress 'start position of data in eeprom or ldata table
Dim row 'the line number you wish to display the info on the LCD
Dim read_data 'tells the print routine,"print_eeprom" to use eeprom(0) or ldata(1) for its data reading
WARNINGS On
Symbol up=PORTA.2 'use porta.2 for the "up" button
Symbol down=PORTA.1 'use porta.1 for the "down" button
Symbol setup=PORTB.3 'use portb.3 for the "setup" buton
Symbol clockout=%11010000 'set the 1307 to receive data
Symbol clockin=%11010001 'set the 1307 to transmit data
TRISA=%00110 'set porta to use 2 bits as input
TRISB.3=1 'set portb to input for "setup" button
PORTA=0 'make sure porta is clear
PORTB=0 'make sure portb is clear
year=0
month=1
date=1
day=0
hour=0
minute=0
'*****************************************
'*****************************************
'this is the main routine that reads the time from the DS1307 and then displays it on the LCD
start:
Cls
If setup=0 Then GoTo start 'debounce setup button on return from setting time
display_time:
GoSub get_time 'read time from DS1307
GoSub print_time 'print the clock display
If setup=0 Then GoTo time_set 'if the setup button is pressed then goto the time setting routine
GoTo display_time
'*****************************************
'*****************************************
'This section of code is dealing with data from the DS1307 and converting it from the BCD used by
'the chip, to Binary used by the real world.
'These routines have been heavily borrowed from LES JOHNSON'S book "The L.E.T. PIC® basic Compiler
'Unleashed" that was originaly provided with the old compiler. I have changed them to suit my own
'conventions and re-written them to use purely Proton Basic commands (none of that horrid assembler
'here thank you!!).
'I have included the original assembler versions of the BCD to Binary conversion routines.
'You can change the routines and see the different size of code produced when using the original
'routines and my fat Basic ones.
'I wrote the Basic versions in order to understand the conversion process and to keep a flag
'flying for my "Basic Rules!" crusade!!.
'Thanks for the inspiration LES.
'*****************************************
'*****************************************
'This routine starts the clock running.
'"clockout" is the alias for the DS1307 I2C buss address, the first zero is the DS1307 internal
'register that holds the "seconds" data, and the second zero is the value to put in that register.
'In this case, [0] will start the clock (reseting the seconds to zero)
'and [1] (the default) will stop the clock.
start_clock:
BusOut clockout,0,[0]
Return
'*****************************************
'*****************************************
'This routine uses the variable "bcd_to_bin_byte" to send the Binary data from the time variables minute,
'hours etc.(set during the "time_set" routine) to the "convert_to_bcd" routine.
'When the conversion is done the time variables, minutes, hours etc., will hold BCD values ready
'to be sent to the DS1307 chip.
'The "busout" line works in the following manner:
'"clockout" is the alias used in setting the I2C of the DS1307 to receive data from the PIC®.
'"1" is the address in the 1307 of the "minute" register, (the start of the data to follow).
'[minute,hour,day,date,month,year] is the data sent to the 1307, the address is incremented by one
'(as the values are bytes). Hour=address 2 etc.
'The line "busout clockout,1,[minute,hour,day,date,month,year]" can be more easily understood
'(by me at least) when written "busout clockout,1,[minute]" followed by "busout clockout,2,[hour]",
'"busout clockout,3,[day]", and so on.
'The "second" register can not be set to a value, it is set to zero when the clock is re-initialised
'with the "start_clock" routine.
set_time:
bcd_to_bin_byte=minute:GoSub convert_to_bcd:minute=bcd_to_bin_byte
bcd_to_bin_byte=hour:GoSub convert_to_bcd:hour=bcd_to_bin_byte
bcd_to_bin_byte=day:GoSub convert_to_bcd:day=bcd_to_bin_byte
bcd_to_bin_byte=date:GoSub convert_to_bcd:date=bcd_to_bin_byte
bcd_to_bin_byte=month:GoSub convert_to_bcd:month=bcd_to_bin_byte
bcd_to_bin_byte=year:GoSub convert_to_bcd:year=bcd_to_bin_byte
BusOut clockout,1,[minute,hour,day,date,month,year]
Return
'*****************************************
'*****************************************
get_time:
ds1307_address=0:GoSub read_time 'read seconds data from 1307
second=bcd_to_bin_byte 'convert to binary
'if a back up battery is missing use this line to stop the routine from locking up when power is switched off then on again
'if second>59 then gosub start_clock:goto get_time
ds1307_address=1:GoSub read_time 'read minute data from 1307
minute=bcd_to_bin_byte 'convert to binary
ds1307_address=2:GoSub read_time 'read hour data from 1307
hour=bcd_to_bin_byte 'convert to binary
ds1307_address=3:GoSub read_time 'read day data from 1307
day=bcd_to_bin_byte 'convert to binary
ds1307_address=4:GoSub read_time 'read date data from 1307
date=bcd_to_bin_byte 'convert to binary
ds1307_address=5:GoSub read_time 'read month data from 1307
month=bcd_to_bin_byte 'convert to binary
ds1307_address=6:GoSub read_time 'read year data from 1307
year=bcd_to_bin_byte 'convert to binary
Return
'Read the data from address pointed to by "ds1307_address"
'The data read is stored in the variable "bcd_to_bin_byte"
read_time:
BusIn clockin,ds1307_address,[bcd_to_bin_byte]
GoSub convert_to_bin
Return
'BCD to BINARY conversion
'The byte to be converted is loaded into the variable "bcd_to_bin_byte"
'and is returned in the same variable "bcd_to_bin_byte."
'if the value of bcd_to_bin_byte is 9 or less then do nothing,(Bin and BCD are equal at 9 and below)
convert_to_bin:
Select bcd_to_bin_byte
Case 16 To 25
bcd_to_bin_byte=bcd_to_bin_byte-6
Case 32 To 41
bcd_to_bin_byte=bcd_to_bin_byte-12
Case 48 To 57
bcd_to_bin_byte=bcd_to_bin_byte-18
Case 64 To 73
bcd_to_bin_byte=bcd_to_bin_byte-24
Case 80 To 89
bcd_to_bin_byte=bcd_to_bin_byte-30
Case 96 To 105
bcd_to_bin_byte=bcd_to_bin_byte-36
Case 112 To 121
bcd_to_bin_byte=bcd_to_bin_byte-42
Case 128 To 137
bcd_to_bin_byte=bcd_to_bin_byte-48
Case 144 To 153
bcd_to_bin_byte=bcd_to_bin_byte-54
EndSelect
'This following code does the same thing but in assembler
'Movlw 0
'Btfsc bcd_to_bin_byte,0
'Addlw 1
'Btfsc bcd_to_bin_byte,1
'Addlw 2
'Btfsc bcd_to_bin_byte,2
'Addlw 4
'Btfsc bcd_to_bin_byte,3
'Addlw 8
'Btfsc bcd_to_bin_byte,4
'Addlw 10
'Btfsc bcd_to_bin_byte,5
'Addlw 20
'Btfsc bcd_to_bin_byte,6
'Addlw 40
'Btfsc bcd_to_bin_byte,7
'Addlw 80
'Movwf bcd_to_bin_byte
Return
' BINARY to BCD conversion
' The byte to be converted is loaded into the variable bcd_to_bin_byte
' and is returned in the same variable bcd_to_bin_byte
convert_to_bcd:
low_bits=bcd_to_bin_byte//10 'get lsb,same for Bin and BCD
high_bits=bcd_to_bin_byte/10 'get msb
bcd_to_bin_byte=high_bits*16 'covert msb to BCD
bcd_to_bin_byte=bcd_to_bin_byte+low_bits 'add BCD msb and lsb together
'This following code does the same thing but in assembler
'Movf bcd_to_bin_byte,w
'Clrf MSD
'Movwf LSD
'gtenth:
'Movlw 10
'Subwf LSD,w
'Btfss 3,0
'Goto Over
'Movwf LSD
'Incf MSD,f
'Goto Gtenth
'over:
'Swapf MSD,F
'Movf LSD,w
'Iorwf MSD,w
'Movwf bcd_to_bin_byte
Return
'*****************************************
'*****************************************
'this routine uses values set in other routines to print on the LCD a set of characters from either the eeprom or a ldata table
'the ldata table is used in order to get the program into a 16F84, if you use a bigger chip the eedata can be used instead.
'it is very simple, first it selects where to look for the data and then puts the data at the "printaddress" into the
'"character" variable, that character is printed at the initial position ("row","printposition") on the LCD, this is repeated
'until the "printposition" reaches the "printend" value.
'All the required characters are now printed on the LCD and the routine is exited.
print_eeprom:
Repeat
If read_data=0 Then character=ERead printaddress 'use eeprom for data retrieval
If read_data=1 Then character=LRead menu_list+printaddress 'use ldata for data retrieval
Print At row,printposition,character 'print to the LCD
Inc printposition 'move print position one to the right
Inc printaddress 'point to the next position in the table
Until printposition=printend+1 'end loop when all characters have been printed
Return
'*****************************************
'*****************************************
'this routine formats the screen display, it is set out in order to allow the same routine to be used (gosub print_time)
'when displaying the time when the clock is running, and as the six diferent subroutines needed to display the time
'options during the clock setting routine.
print_time:
Print At 1,11,DEC2 second
print_min:
Print At 1,8,DEC2 minute,":"
print_hour:
Print At 1,5,DEC2 hour,":"
print_day:
read_data=0 'use eeprom for data reading
row=2 'print on line 2 of LCD
printposition=1 'initial position of "day" on LCD
printend=3 'position of last letter to be printed
printaddress=day*3 'work out address of data in the eeprom(minimum is 3)
GoSub print_eeprom 'goto LCD print routine
print_date:
Print At 2,5,DEC2 date
print_month:
read_data=0 'use eeprom for data reading
row=2 'print on line 2 of LCD
printposition=8 'initial position of "month" on LCD
printend=10 'position of last letter to be printed
printaddress=month*3 'work out address of data in the eeprom(minimum is 3)
printaddress=printaddress+21 'first month data is at address 24 (21+3)in eeprom
GoSub print_eeprom 'goto LCD print routine
print_year:
Print At 2,12,"20",DEC2 year
Return
'*****************************************
'*****************************************
'This routine sets the time.
'variables "minvalue" and "maxvalue" set the low and high values for year(0-99),month(1-12),
'date(1-31,1-30,1-28 and leap year 1-29),day(1-7,mon to sun),hour(0-23)and minute(0-59).
time_set:
If setup=0 Then GoTo time_set 'debounce button if still pressed from previous routine
Cls
second=0 'clears second display at end of setup
Print At 1,1,"Set"
'the setting of the clock is done "year" first and ends with the "minute", seconds can not be set by the user
'the 1307 will start the clock with zero seconds whenever it is initialised after the time is sent to it.
buttonvalue=year:index=0:maxvalue=99:minvalue=0:Go Sub buttons:year=buttonvalue 'work on the YEAR first
buttonvalue=month:index=1:maxvalue=12:minvalue=1:G oSub buttons:month=buttonvalue 'next to the MONTH
'before changing the date we must set the maximum number of days in the selected month and if we need
'to wory about the leap year when it is February.
monthlength=31 'if the months are JAN,MAR,MAY,JUL,AUG,OCT and DEC then "monthlength" will be 31
Select month
Case 4,6,9,11 'if the months are APR,JUN,SEP or NOV then "monthlength" will be 30
monthlength=30
Case 2 'if it is FEB then set "monthlength" to 28
monthlength=28
leap=year//4 'tests for a leap year
If leap=0 Then monthlength=29 'if it is a leap year then set FEB "monthlength" to 29
EndSelect
buttonvalue=date:index=2:maxvalue=monthlength:minv alue=1:GoSub buttons:date=buttonvalue 'change the DATE
buttonvalue=day:index=3:maxvalue=7:minvalue=1:GoSu b buttons:day=buttonvalue 'change the DAY
buttonvalue=hour:index=4:maxvalue=23:minvalue=0:Go Sub buttons:hour=buttonvalue 'change the HOUR
buttonvalue=minute:index=5:maxvalue=59:minvalue=0: GoSub buttons:minute=buttonvalue 'change the MINUTE
'restart system with new settings
'NOTE:the SECONDS value is always set to zero when the clock is restarted,
'always set the time 1 minute in advance and press "setup" when the reference clock gets to the displayed time!
Print At 1,11,"00 " ,At 2,1,"'Setup' to Start"
restart:
'wait until the "setup" button is pressed before starting the clock
If setup=0 Then Cls:GoSub set_time:GoSub start_clock:GoTo start
GoTo restart
'*****************************************
'*****************************************
'this routine uses the "up" and "down" buttons to select the values you require when setting the clock and prints the setup menu
buttons:
If up=0 Then Inc buttonvalue
elayMS 200 'if up button is pressed then increase "buttonvalue" by one
If buttonvalue>maxvalue Then buttonvalue=minvalue 'if "buttonvalue" goes above its maximum then make it equal to "minvalue"
If down=0 Then Dec buttonvalue
elayMS 200 'if down button is pressed then decrease "buttonvalue" by one
If buttonvalue<minvalue Or buttonvalue=255 Then buttonvalue=maxvalue 'if "buttonvalue" goes below its minimum, or 255 if the minimum is 0, then make it equal to "maxvalue"
'print the time setting menu
read_data=1 'use ldata table for print routine
row=1 'print on line 1 of LCD
printposition=13 'start position on LCD for the menu
printend=16 'last character position on LCD for the menu
printaddress=index*4 'work out start position of data in ldata table
GoSub print_eeprom 'jump to LCD print routine
'choose what is to be displayed on the LCD and which variable is to be changed by this "buttons" routine.
'using if-then rather than case as it uses less memory in this routine
If index=0 Then year=buttonvalue:GoSub print_year
If index=1 Then month=buttonvalue:GoSub print_month
If index=2 Then date=buttonvalue:GoSub print_date
If index=3 Then day=buttonvalue:GoSub print_day
If index=4 Then hour=buttonvalue:GoSub print_hour
If index=5 Then minute=buttonvalue:GoSub print_min
If setup=0 Then DelayMS 200:Return
GoTo buttons
'*****************************************
'*****************************************
EData 0,0,0,"MonTueWedThuFriSatSunJanFebMarAprMayJunJulA ugSepOctNovDec"
menu_list:LData "YearMnthDateDay HourMin "
'*****************************************
'*****************************************
End
'mark@rodgers.fsworld.co.uk
'Compiled in Proton+ 2.1.4
'Tested on 16F84,16F628,18F1320 and 18F452
'It is presented as is with no guarantees or responsibilities implied.
'It is not for any comercial use(I wish!) or to copy and pass any part as
'your own, I would be happy if it was used to develop your own comercial free
'code or as the basis for a club project with inclusion of author recognition.
'Please feel free to contact me if you wish to use this code/hardware for any reason.
Device 16F84 'better than an OC71
XTAL 4
LCD_RSPIN PORTA.0
LCD_ENPIN PORTB.0
SDA_PIN PORTA.4
SCL_PIN PORTA.3
WARNINGS off
Dim bcd_to_bin_byte 'variable used in BCD and Binary conversion routines
Dim low_bits 'low byte for Binary to BCD routine
Dim high_bits 'high byte for Binary to BCD routine
Dim ds1307_address 'DS1307 internal registers address(0=seconds,1=minutes etc.)
Dim second 'seconds variable
Dim minute 'minutes variable
Dim hour 'hours variable
Dim day 'days variable
Dim date 'dates variable
Dim month 'months variable
Dim year 'years variable
Dim buttonvalue 'variable used for "up" and "down" buttons values
Dim maxvalue 'variable holding highest allowable current value in button routine
Dim minvalue 'variable holding lowest current allowable value in button routine
Dim leap 'variable used to set "maxvalue" in leapyear
Dim monthlength 'variable used to set maximum number of days in the selected month
Dim index 'variable used to select display options in "setup"
Dim character 'variable holding data selected from eeprom or ldata tables to be printed on display
Dim printposition 'start position on the LCD of first "character" in print routine
Dim printend 'last "character" position to be printed on LCD
Dim printaddress 'start position of data in eeprom or ldata table
Dim row 'the line number you wish to display the info on the LCD
Dim read_data 'tells the print routine,"print_eeprom" to use eeprom(0) or ldata(1) for its data reading
WARNINGS On
Symbol up=PORTA.2 'use porta.2 for the "up" button
Symbol down=PORTA.1 'use porta.1 for the "down" button
Symbol setup=PORTB.3 'use portb.3 for the "setup" buton
Symbol clockout=%11010000 'set the 1307 to receive data
Symbol clockin=%11010001 'set the 1307 to transmit data
TRISA=%00110 'set porta to use 2 bits as input
TRISB.3=1 'set portb to input for "setup" button
PORTA=0 'make sure porta is clear
PORTB=0 'make sure portb is clear
year=0
month=1
date=1
day=0
hour=0
minute=0
'*****************************************
'*****************************************
'this is the main routine that reads the time from the DS1307 and then displays it on the LCD
start:
Cls
If setup=0 Then GoTo start 'debounce setup button on return from setting time
display_time:
GoSub get_time 'read time from DS1307
GoSub print_time 'print the clock display
If setup=0 Then GoTo time_set 'if the setup button is pressed then goto the time setting routine
GoTo display_time
'*****************************************
'*****************************************
'This section of code is dealing with data from the DS1307 and converting it from the BCD used by
'the chip, to Binary used by the real world.
'These routines have been heavily borrowed from LES JOHNSON'S book "The L.E.T. PIC® basic Compiler
'Unleashed" that was originaly provided with the old compiler. I have changed them to suit my own
'conventions and re-written them to use purely Proton Basic commands (none of that horrid assembler
'here thank you!!).
'I have included the original assembler versions of the BCD to Binary conversion routines.
'You can change the routines and see the different size of code produced when using the original
'routines and my fat Basic ones.
'I wrote the Basic versions in order to understand the conversion process and to keep a flag
'flying for my "Basic Rules!" crusade!!.
'Thanks for the inspiration LES.
'*****************************************
'*****************************************
'This routine starts the clock running.
'"clockout" is the alias for the DS1307 I2C buss address, the first zero is the DS1307 internal
'register that holds the "seconds" data, and the second zero is the value to put in that register.
'In this case, [0] will start the clock (reseting the seconds to zero)
'and [1] (the default) will stop the clock.
start_clock:
BusOut clockout,0,[0]
Return
'*****************************************
'*****************************************
'This routine uses the variable "bcd_to_bin_byte" to send the Binary data from the time variables minute,
'hours etc.(set during the "time_set" routine) to the "convert_to_bcd" routine.
'When the conversion is done the time variables, minutes, hours etc., will hold BCD values ready
'to be sent to the DS1307 chip.
'The "busout" line works in the following manner:
'"clockout" is the alias used in setting the I2C of the DS1307 to receive data from the PIC®.
'"1" is the address in the 1307 of the "minute" register, (the start of the data to follow).
'[minute,hour,day,date,month,year] is the data sent to the 1307, the address is incremented by one
'(as the values are bytes). Hour=address 2 etc.
'The line "busout clockout,1,[minute,hour,day,date,month,year]" can be more easily understood
'(by me at least) when written "busout clockout,1,[minute]" followed by "busout clockout,2,[hour]",
'"busout clockout,3,[day]", and so on.
'The "second" register can not be set to a value, it is set to zero when the clock is re-initialised
'with the "start_clock" routine.
set_time:
bcd_to_bin_byte=minute:GoSub convert_to_bcd:minute=bcd_to_bin_byte
bcd_to_bin_byte=hour:GoSub convert_to_bcd:hour=bcd_to_bin_byte
bcd_to_bin_byte=day:GoSub convert_to_bcd:day=bcd_to_bin_byte
bcd_to_bin_byte=date:GoSub convert_to_bcd:date=bcd_to_bin_byte
bcd_to_bin_byte=month:GoSub convert_to_bcd:month=bcd_to_bin_byte
bcd_to_bin_byte=year:GoSub convert_to_bcd:year=bcd_to_bin_byte
BusOut clockout,1,[minute,hour,day,date,month,year]
Return
'*****************************************
'*****************************************
get_time:
ds1307_address=0:GoSub read_time 'read seconds data from 1307
second=bcd_to_bin_byte 'convert to binary
'if a back up battery is missing use this line to stop the routine from locking up when power is switched off then on again
'if second>59 then gosub start_clock:goto get_time
ds1307_address=1:GoSub read_time 'read minute data from 1307
minute=bcd_to_bin_byte 'convert to binary
ds1307_address=2:GoSub read_time 'read hour data from 1307
hour=bcd_to_bin_byte 'convert to binary
ds1307_address=3:GoSub read_time 'read day data from 1307
day=bcd_to_bin_byte 'convert to binary
ds1307_address=4:GoSub read_time 'read date data from 1307
date=bcd_to_bin_byte 'convert to binary
ds1307_address=5:GoSub read_time 'read month data from 1307
month=bcd_to_bin_byte 'convert to binary
ds1307_address=6:GoSub read_time 'read year data from 1307
year=bcd_to_bin_byte 'convert to binary
Return
'Read the data from address pointed to by "ds1307_address"
'The data read is stored in the variable "bcd_to_bin_byte"
read_time:
BusIn clockin,ds1307_address,[bcd_to_bin_byte]
GoSub convert_to_bin
Return
'BCD to BINARY conversion
'The byte to be converted is loaded into the variable "bcd_to_bin_byte"
'and is returned in the same variable "bcd_to_bin_byte."
'if the value of bcd_to_bin_byte is 9 or less then do nothing,(Bin and BCD are equal at 9 and below)
convert_to_bin:
Select bcd_to_bin_byte
Case 16 To 25
bcd_to_bin_byte=bcd_to_bin_byte-6
Case 32 To 41
bcd_to_bin_byte=bcd_to_bin_byte-12
Case 48 To 57
bcd_to_bin_byte=bcd_to_bin_byte-18
Case 64 To 73
bcd_to_bin_byte=bcd_to_bin_byte-24
Case 80 To 89
bcd_to_bin_byte=bcd_to_bin_byte-30
Case 96 To 105
bcd_to_bin_byte=bcd_to_bin_byte-36
Case 112 To 121
bcd_to_bin_byte=bcd_to_bin_byte-42
Case 128 To 137
bcd_to_bin_byte=bcd_to_bin_byte-48
Case 144 To 153
bcd_to_bin_byte=bcd_to_bin_byte-54
EndSelect
'This following code does the same thing but in assembler
'Movlw 0
'Btfsc bcd_to_bin_byte,0
'Addlw 1
'Btfsc bcd_to_bin_byte,1
'Addlw 2
'Btfsc bcd_to_bin_byte,2
'Addlw 4
'Btfsc bcd_to_bin_byte,3
'Addlw 8
'Btfsc bcd_to_bin_byte,4
'Addlw 10
'Btfsc bcd_to_bin_byte,5
'Addlw 20
'Btfsc bcd_to_bin_byte,6
'Addlw 40
'Btfsc bcd_to_bin_byte,7
'Addlw 80
'Movwf bcd_to_bin_byte
Return
' BINARY to BCD conversion
' The byte to be converted is loaded into the variable bcd_to_bin_byte
' and is returned in the same variable bcd_to_bin_byte
convert_to_bcd:
low_bits=bcd_to_bin_byte//10 'get lsb,same for Bin and BCD
high_bits=bcd_to_bin_byte/10 'get msb
bcd_to_bin_byte=high_bits*16 'covert msb to BCD
bcd_to_bin_byte=bcd_to_bin_byte+low_bits 'add BCD msb and lsb together
'This following code does the same thing but in assembler
'Movf bcd_to_bin_byte,w
'Clrf MSD
'Movwf LSD
'gtenth:
'Movlw 10
'Subwf LSD,w
'Btfss 3,0
'Goto Over
'Movwf LSD
'Incf MSD,f
'Goto Gtenth
'over:
'Swapf MSD,F
'Movf LSD,w
'Iorwf MSD,w
'Movwf bcd_to_bin_byte
Return
'*****************************************
'*****************************************
'this routine uses values set in other routines to print on the LCD a set of characters from either the eeprom or a ldata table
'the ldata table is used in order to get the program into a 16F84, if you use a bigger chip the eedata can be used instead.
'it is very simple, first it selects where to look for the data and then puts the data at the "printaddress" into the
'"character" variable, that character is printed at the initial position ("row","printposition") on the LCD, this is repeated
'until the "printposition" reaches the "printend" value.
'All the required characters are now printed on the LCD and the routine is exited.
print_eeprom:
Repeat
If read_data=0 Then character=ERead printaddress 'use eeprom for data retrieval
If read_data=1 Then character=LRead menu_list+printaddress 'use ldata for data retrieval
Print At row,printposition,character 'print to the LCD
Inc printposition 'move print position one to the right
Inc printaddress 'point to the next position in the table
Until printposition=printend+1 'end loop when all characters have been printed
Return
'*****************************************
'*****************************************
'this routine formats the screen display, it is set out in order to allow the same routine to be used (gosub print_time)
'when displaying the time when the clock is running, and as the six diferent subroutines needed to display the time
'options during the clock setting routine.
print_time:
Print At 1,11,DEC2 second
print_min:
Print At 1,8,DEC2 minute,":"
print_hour:
Print At 1,5,DEC2 hour,":"
print_day:
read_data=0 'use eeprom for data reading
row=2 'print on line 2 of LCD
printposition=1 'initial position of "day" on LCD
printend=3 'position of last letter to be printed
printaddress=day*3 'work out address of data in the eeprom(minimum is 3)
GoSub print_eeprom 'goto LCD print routine
print_date:
Print At 2,5,DEC2 date
print_month:
read_data=0 'use eeprom for data reading
row=2 'print on line 2 of LCD
printposition=8 'initial position of "month" on LCD
printend=10 'position of last letter to be printed
printaddress=month*3 'work out address of data in the eeprom(minimum is 3)
printaddress=printaddress+21 'first month data is at address 24 (21+3)in eeprom
GoSub print_eeprom 'goto LCD print routine
print_year:
Print At 2,12,"20",DEC2 year
Return
'*****************************************
'*****************************************
'This routine sets the time.
'variables "minvalue" and "maxvalue" set the low and high values for year(0-99),month(1-12),
'date(1-31,1-30,1-28 and leap year 1-29),day(1-7,mon to sun),hour(0-23)and minute(0-59).
time_set:
If setup=0 Then GoTo time_set 'debounce button if still pressed from previous routine
Cls
second=0 'clears second display at end of setup
Print At 1,1,"Set"
'the setting of the clock is done "year" first and ends with the "minute", seconds can not be set by the user
'the 1307 will start the clock with zero seconds whenever it is initialised after the time is sent to it.
buttonvalue=year:index=0:maxvalue=99:minvalue=0:Go Sub buttons:year=buttonvalue 'work on the YEAR first
buttonvalue=month:index=1:maxvalue=12:minvalue=1:G oSub buttons:month=buttonvalue 'next to the MONTH
'before changing the date we must set the maximum number of days in the selected month and if we need
'to wory about the leap year when it is February.
monthlength=31 'if the months are JAN,MAR,MAY,JUL,AUG,OCT and DEC then "monthlength" will be 31
Select month
Case 4,6,9,11 'if the months are APR,JUN,SEP or NOV then "monthlength" will be 30
monthlength=30
Case 2 'if it is FEB then set "monthlength" to 28
monthlength=28
leap=year//4 'tests for a leap year
If leap=0 Then monthlength=29 'if it is a leap year then set FEB "monthlength" to 29
EndSelect
buttonvalue=date:index=2:maxvalue=monthlength:minv alue=1:GoSub buttons:date=buttonvalue 'change the DATE
buttonvalue=day:index=3:maxvalue=7:minvalue=1:GoSu b buttons:day=buttonvalue 'change the DAY
buttonvalue=hour:index=4:maxvalue=23:minvalue=0:Go Sub buttons:hour=buttonvalue 'change the HOUR
buttonvalue=minute:index=5:maxvalue=59:minvalue=0: GoSub buttons:minute=buttonvalue 'change the MINUTE
'restart system with new settings
'NOTE:the SECONDS value is always set to zero when the clock is restarted,
'always set the time 1 minute in advance and press "setup" when the reference clock gets to the displayed time!
Print At 1,11,"00 " ,At 2,1,"'Setup' to Start"
restart:
'wait until the "setup" button is pressed before starting the clock
If setup=0 Then Cls:GoSub set_time:GoSub start_clock:GoTo start
GoTo restart
'*****************************************
'*****************************************
'this routine uses the "up" and "down" buttons to select the values you require when setting the clock and prints the setup menu
buttons:
If up=0 Then Inc buttonvalue
elayMS 200 'if up button is pressed then increase "buttonvalue" by oneIf buttonvalue>maxvalue Then buttonvalue=minvalue 'if "buttonvalue" goes above its maximum then make it equal to "minvalue"
If down=0 Then Dec buttonvalue
elayMS 200 'if down button is pressed then decrease "buttonvalue" by oneIf buttonvalue<minvalue Or buttonvalue=255 Then buttonvalue=maxvalue 'if "buttonvalue" goes below its minimum, or 255 if the minimum is 0, then make it equal to "maxvalue"
'print the time setting menu
read_data=1 'use ldata table for print routine
row=1 'print on line 1 of LCD
printposition=13 'start position on LCD for the menu
printend=16 'last character position on LCD for the menu
printaddress=index*4 'work out start position of data in ldata table
GoSub print_eeprom 'jump to LCD print routine
'choose what is to be displayed on the LCD and which variable is to be changed by this "buttons" routine.
'using if-then rather than case as it uses less memory in this routine
If index=0 Then year=buttonvalue:GoSub print_year
If index=1 Then month=buttonvalue:GoSub print_month
If index=2 Then date=buttonvalue:GoSub print_date
If index=3 Then day=buttonvalue:GoSub print_day
If index=4 Then hour=buttonvalue:GoSub print_hour
If index=5 Then minute=buttonvalue:GoSub print_min
If setup=0 Then DelayMS 200:Return
GoTo buttons
'*****************************************
'*****************************************
EData 0,0,0,"MonTueWedThuFriSatSunJanFebMarAprMayJunJulA ugSepOctNovDec"
menu_list:LData "YearMnthDateDay HourMin "
'*****************************************
'*****************************************
End
contributed by Mark Rodgers.


Menu
Recent Articles


Using PDS with SPI GLCD based on ST7565R Controller
Graphic LCDs based on the ST7565 are cheaper then GLCDs with other controllers. SPI requires only four pins. If the circuit