| Master Clock
Atomic Time Synchronisation Circuit
Slave Clocks Pulse controlled Slave Calendar and Tide clock
|
||
|
The clock displays the Month day and tide using 3 analogue dials. The day hand is driven by a 30 sec slave clock motor and the month and tide hands by standard 1 second quartz motors. The tide clock is pulsed from the Master Clocks 1 second alternating pulse output while the Month and days are controlled by a PIC microprocessor on receipt of the 24 hour midnight pulse also from the Master Clock.
The PIC microprocessor calculates how many days in the current month including leap years and will automatically step the day and month hand to the next month at midnight on the last day of that month.
|
||
|
Pulse controlled Slave Calendar and Tide clock
|
Download full documentation as word file | Download full documentation as a pdf |
| Split screen demo showing
the calendar clock stepping from 29th Feb
(leap year) to 01 March. The lower screen is the PC display showing
the com port data as the calendar steps. The calendar is setup using the same connection.
|
||
| Calendar Clock connected to a Laptop The date in the calendar microprocessor can be set on power up or via the serial port. The date is stored on the microprocessor in case of power failure. As long as power is restored just before midnight the calendar will still work.
The dial is held in place by a brass catch and folds back giving access to the control switches and serial port socket.
The microprocessor used in this calendar clock is a PIC18F1320. The serial interface is provided by a MAX232 IC.
|
Case open to show circut board and controls
|
|
|
Flow Chart for the 18F1320 microprocessor code
|
Calendar Clock Controls &
Serial Port
The Calendar has manual controls for date and month setting via a row of switches behind the hinged dial.
The Calendar clock is setup and monitored via the serial port of a PC and has a 9pin socket also mounted behind the dial.
|
|
| Output from
Calendar Clock Serial Port
|
||
| Calendar dial showing number of pulses required to step month and day hands The month display uses the seconds hand of a standard quartz movement. This will do 1 revolution per 60 pulses from the clock driver. To get the display to stop on each month the clock driver will need to send out 5 alternate polarity pulses (60/12=5) at midnight on the last day of the month.
The day display uses a 30 sec clock movement and uses the minute hand to show days. Each revolution of the min hand requires 120 pulses. Each month has a max of 31 days so each day mark requires 3 pulses to step the the next day. In total this would be 93 pulses for a 31 day month, 90 pulses for a 30 day month, 87 pulses for a 29 day month and 84 pulses for a 28 day month. Therefore in order to get back to day 1 at the beginning of a month a variable number of pulses depending on the last day of the month will need to be sent at midnight on the last day of the month. The pic chip algorithms take into account each different month including leap years.
below. 3 pulses to step the day hand forward to the next day and 5 pulses to step the month hand to the next month. At the end of each month the number of pulses required will depend on the month and year and will be from 30 to 39.
|
||
|
. Example of the serial output from the calendar clock on a laptop connected to the clock serial port.
In this example the calendar was set to 28/02 in the 4th year of a leap year. On receipt of the 24 hour midnight pulse the calendar is pulsed 33 times from the 29 position on the dial to set the hands to the first day of March.
|
||
|
Setup & Operation Ensure all switches are in their normal positions see fig 7 below and a programmed PIC is in place.
Power up your PC and run a terminal program like Putty. Configure the serial connection. See diagram below (Putty) .
Plug in the serial or USB to serial lead into your computer. Plug the other end of the lead into the Calendar Clock serial port behind the dial. To check the stored settings press and release the “PIC Date Check” button. If the connection is OK the PIC should send the settings over the serial port to your PC screen and should be as follows. “Month toggle x” where x is 0 or 1. “D=xx:yy:zz” where xx is the day, yy is the month, and zz is the leap year number from 1 to 4 On first setting up the calendar the month movement must be setup in sync with the pulses from the PIC. The month movement requires an alternating pulse to step it on so if the correct polarity pulse is not received it will step the month 4 times instead of the 5 required each month. To sync the month movement set the calendar to the last day of any month as follows.
Put on caps lock and type the following. D31:01:01:00 and “Enter” this sets the date to the 31st Jan, 1st year of a leap year with toggle 0. The screen should show the date set “Echo Date=31:01:01:00”
Move the “PIC Date” switch to the “Step” position and wait for the day hand to start stepping before returning to the “Auto” position. The PC screen should show 3 pulses as the hand is driven to the next day. Note it does not matter for now where the hands are set.
As the end of Jan is set the screen will now show “31 day month” and show the extra 30 pulses counting up from 1. After pulse 30 the month pulses start and the display shows Mth1, Mth2 etc as the month pulse are sent followed by “Month toggle 0” and then “Month toggle now 1”. Make sure the month hand moves on the first pulse and steps 5 times to move 1 full month segment.
If the month hand does not move 5 times when the date is resent to the PIC you must use toggle 0, if it moves OK you must send toggle 1 to the pic.
Before setting the final date set the month hand to the correct month by setting the Month Ctrl switch to “Man” and operate the “Step Month” button up and down to the two “step” position repeatedly. When the correct month is indicated return the “Month Ctrl” switch to “Auto” Now set the day hand to the correct date using the armature or by spinning the drive cog. The final working date can now be sent to the PIC using the format “Dday:month:leap year:toggle” Eg for 20th September in a leap year with toggle at 0 ie the above test failed enter “D20:09:04:00” Or if the above test worked and the month stepped correctly type. “D20:09:04:01”
When complete the screen should confirm the correct date has been sent. Pressing the “PIC Date check” button will confirm the correct date has been stored.
Shut down the terminal program and disconnect the serial cable from the calendar clock, close the calendar clock and lock the dial into place.
When inserting a new PIC turn the power off using the “PIC PWR” button then set up the new PIC as above.
Note when setting the Master clock forward past midnight (when clocks go back) switch the “Pic Date” switch to off. This prevents the Calendar clock stepping as the Master steps past midnight.
|
||
Circuit Operation Tide Clock
|
||
|
The Tide movement is a standard quartz type tide clock and is driven from the 2 sec quartz driving pulse from the master via a repeater circuit. The repeater circuit uses 4 Nand Schmitt triggers to repeat the alternating pulse from the master. Each pair can drive 3 movements but 1 pair is used to drive the Tide movement only. The other pair is spare and not used.
|
||
![]()
|
||
Circuit Operation 18F1320
|
||
|
The 18F1320 is configured as follows. PORTA are inputs and PORTB are outputs. PORTA.4 is the midnight pulse input, PORTA.5 if held at 1 enables divide by 2 not used in this circuit. PORTA.6 if held at 1 enables the divide by 30 input also not used in this circuit. PORTA.7 if held at 0 by the reset switch SW3 loads stored date data from the EEPROM. If held at 1 on power up loads date data from the software upload .
|
||
![]() |
||
|
PORTB.5 is the output for the day hand and drives Q3 then Q1. PORTB.0 & PORTB.3 drive the month hand and are always inverted with respect to each other when the month hand is being driven. When not being driven they are both set to 0 to ensure no current passes through the month coil. The month is driven via SW2 Mth Ctrl set to Auto (Step Mth set to off). To manual step the Month SW2 is set to Man and the Mth Switch SW1 is operated alternately to the Step positions.
The PIC Date Switch SW5 is used to control Auto & Manual date stepping of the PIC and also to turn off receiving midnight pulses when for example setting the master for winter time.
|
||
![]()
|
||
Circuit Operation Max232A MAX232 IC is used as an RS232 driver & receiver. Only 1 half of this IC is used. Connection to the RS232 I/P & O/P is via a standard 9 Pin connector. |
||
![]()
|
||
|
Vero layout with Max232 highlighted .
|
||
|
Max232cpe pin outs
|
||
| The PIC code
Note The pic code and circuit for this calendar clock was supplied to me by members of the Electro Tech Online Forum and they have kindly given me permission to post it online. Where I have added extra code or added more notes, I have added a note in the comments field thus " 'Brett " . The Calendar Clock uses a PIC microprocessor IC to step the days and month movements the correct amount. This circuit uses a 18F1320 PIC chip and the code is written in OshonSoft basic and then compiled and loaded into the PIC. Code Define CONFIG1L = 0x00 Define CONFIG1H = 0xc8 '11001000 int RC osc RA6/7 ports Define CONFIG2L = 0x0c '00001100 Define CONFIG2H = 0x1e '00011110 Define CONFIG3L = 0x00 Define CONFIG3H = 0x00 '00000000 Define CONFIG4L = 0x81 '10000001 Define CONFIG4H = 0x00 Define CONFIG5L = 0x03 '00000011 Define CONFIG5H = 0xc0 '11000000 Define CONFIG6L = 0x03 '00000011 Define CONFIG6H = 0xe0 '11100000 Define CONFIG7L = 0x03 '00000011 Define CONFIG7H = 0x40 '01000000
'********* 18FPulsar V1 ******************
'PulsarVer3 Date Wheel Driver for Mark Basic #1 '29/11/2007 Using 16F628A converted to 18F1320 30/09/2009 '1st off Oshonsoft Version for Brett 31/08/2009 '**************************************************** 'the Date input from the PC is at 9600baud, no parity, 1 start/stop bit [normal usage] 'the pic expects Ddd:mm:yy:tt format,, if a number is less than 10 add a leading zero 'eg: D07:02:09:01 Brett the last 2 digits are the month toggle 'when the Date is received OK by the PIC, it retransmits it back on the uart.
'the uart outputs at midnight, the new date also the extra pulse markers.
Define CLOCK_FREQUENCY = 4
AllDigital
'Define SIMULATION_WAITMS_VALUE = 1 'make=0 before prog a PIC **************** 'Define SEROUT_DELAYUS = 1000
Dim ascbfr0 As Byte Dim ascbfr1 As Byte Dim ascbfr2 As Byte Dim ascbfr3 As Byte Dim ascbfr4 As Byte Dim ascbfr5 As Byte Dim ascbfr6 As Byte Dim ascbfr7 As Byte Dim ascbfr8 As Byte 'Brett Dim ascbfr9 As Byte 'Brett Dim ascbfr10 As Byte 'Brett
Dim day_end_cntr As Byte Dim month_cntr As Byte 'months count on T0CK inputs [days inp] Dim year_cntr As Byte 'years count Dim roll_over_cnt As Byte Dim leap As Byte Dim pulse As Byte Dim sec_cntr As Byte Dim temp1 As Byte Dim temp2 As Byte Dim month As Byte 'Brett '' Dim aschigh As Byte Dim asclow As Byte Dim b2a_value As Byte Dim units As Byte Dim tens As Byte
OSCCON = %01100000
TRISA = 0xf0 'PORTA high pins 1nputs, low 4 are outputs TRISB = 0 'makes all PORTB pins 0utputs
'''''''''''''''''' timer0 changes for 1320 T0CON.T08BIT = 1 T0CON.TMR0ON = 1 T0CON.T0CS = 1 T0CON.T0SE = 0 T0CON.PSA = 1 T0CON.T0PS2 = 0 T0CON.T0PS1 = 0 T0CON.T0PS0 = 0
TMR0L = 255 'this is the number day inputs To make the t0 timer overflow INTCON.TMR0IE = 1 'enables the T0 timer to Interrupt, when timer overflows
RCON.IPEN = 0
Hseropen 9600 ''enable uart serial output at 9600 baud
If PORTA.5 = 1 Then Goto div2 Endif
If PORTA.6 = 1 Then Goto div30 Endif
If PORTA.7 = 0 Then 'Reset button NOT pressed 'recall values from EEPROM if RA7, pin16 is LOW Read 0, day_end_cntr Read 1, month_cntr Read 2, year_cntr Read 3, month Goto skip_init Endif
'if RA7 pin16 is HIGH at power up read these values 'reinitialise all counters to these settings 'Mark you can change these values, save testing waiting! 'put them back to current TODAY's values when you have done testing 'when you program a PIC these are the values it will save and use.
'TODAY is 31/08/09.... 27day, 11mon[30days in month].. 1st year of a 4 year cycle 'Brett set month to 0 for month movement init_loop: day_end_cntr = 27 month_cntr = 09 year_cntr = 1 month = 0 'Brett
'save values to EEPROM Write 0, day_end_cntr Write 1, month_cntr Write 2, year_cntr Write 3, month 'Brett
skip_init: 'serial output header at power up b2a_value = day_end_cntr Gosub byte2asc2 Hserout "Init Date=", aschigh, asclow, ":" b2a_value = month_cntr Gosub byte2asc2 Hserout aschigh, asclow, ":" temp1 = year_cntr Or 0x30 Hserout temp1, CrLf WaitMs 500 If PORTA.7 = 1 Then Goto init_loop Endif
INTCON.TMR0IE = 1 'enables the T0 timer to Interrupt, when timer overflows Enable High 'this enables the Interrrupts
'==============================================================================
'just keep looping until a day input pulse causes an Interrupt loop:
If PIR1.RCIF = 0 Then Goto skip1 Endif
Hserin temp1
If temp1 = "D" Then 'Brett note keyboard input Goto rx_date Else Goto skip1 Endif
rx_date:
Hserin ascbfr0 ' Brett note defines 10 keys in order Hserin ascbfr1 Hserin ascbfr2 Hserin ascbfr3 Hserin ascbfr4 Hserin ascbfr5 Hserin ascbfr6 Hserin ascbfr7 Hserin ascbfr8 'Brett Hserin ascbfr9 'Brett Hserin ascbfr10 'Brett
'' Hserout CrLf temp1 = ascbfr0 temp1 = temp1 And 0x0f temp2 = ShiftLeft(temp1, 4)
temp1 = ascbfr1 temp1 = temp1 And 0x0f temp1 = temp1 Or temp2 Gosub bcd2bin If temp1 = 0 Then temp1 = 1 Endif Write 0x0, temp1 day_end_cntr = temp1 '''''''''''''''''''''''''''''''''''' temp1 = ascbfr3 temp1 = temp1 And 0x0f temp2 = ShiftLeft(temp1, 4) temp1 = ascbfr4 temp1 = temp1 And 0x0f temp1 = temp1 Or temp2 Gosub bcd2bin If temp1 = 0 Then temp1 = 1 Endif Write 0x1, temp1 month_cntr = temp1 '''''''''''''''''''''''''''''''''''' temp1 = ascbfr6 temp1 = temp1 And 0x0f temp2 = ShiftLeft(temp1, 4) temp1 = ascbfr7 temp1 = temp1 And 0x0f temp1 = temp1 Or temp2 Gosub bcd2bin temp1 = temp1 Mod 4
If temp1 = 0 Then temp1 = 4 Endif
Write 0x2, temp1 year_cntr = temp1 '''''''''''''''''''''''''''''''''''' 'Brett temp1 = ascbfr9 temp1 = temp1 And 0x0f temp2 = ShiftLeft(temp1, 4) temp1 = ascbfr10 temp1 = temp1 And 0x0f temp1 = temp1 Or temp2 Gosub bcd2bin temp1 = temp1 'Mod 4
Write 0x3, temp1 month = temp1 'end Brett '''''''''''''''''''''''''''''''''''' Hserout CrLf Hserout "Echo Date=" Hserout ascbfr0, ascbfr1, ascbfr2 Hserout ascbfr3, ascbfr4, ascbfr5 Hserout ascbfr6, ascbfr7, ascbfr8, ascbfr9, ascbfr10, CrLf 'Brett ascbfr9, ascbfr10
temp1 = 0 temp2 = 0
skip1: Enable High '========================================
If PORTA.7 = 1 Then Disable Low
'serial output current dates if use presses button, after power up. Hserout CrLf 'Brett Hserout "Month toggle " #month 'Brett Hserout CrLf b2a_value = day_end_cntr Gosub byte2asc2 Hserout "Date Check=", aschigh, asclow, ":"
b2a_value = month_cntr Gosub byte2asc2 Hserout aschigh, asclow, ":" temp1 = year_cntr Or 0x30 Hserout temp1, " of 4" CrLf Endif
If PORTA.7 = 1 Then WaitMs 500 Goto loop Endif
Enable High Goto loop
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 'divide by 30, from 1sec input,to give a pulse every 30sec div30: INTCON.TMR0IE = 1 'enables the T0 timer to Interrupt, when timer overflows TMR0L = 255
div30a: If PORTA.7 = 1 Then sec_cntr = 0 Endif If PORTA.7 = 1 Then Goto div30a Endif Enable Low 'this enables the Interrrupts
div_loop: Goto div30a
'''''''''''''''''''''''''''''''''''''''''''''''''''''''' 'divide by 2, from 1sec input,crystal clock drive div2:
INTCON.TMR0IE = 1 'enables the T0 timer to Interrupt, when timer overflows TMR0L = 255
div2a: If PORTA.7 = 1 Then sec_cntr = 0 Endif
If PORTA.7 = 1 Then Goto div2a Endif Enable Low 'this enables the Interrrupts
div2_loop: Goto div2a
End 'sub routines MUST go after this END
'convert hex to decimal [99max] byte2asc2:
temp1 = b2a_value Mod 10 asclow = temp1 Or 0x30 temp2 = 0 While b2a_value > 9 b2a_value = b2a_value - 10 temp2 = temp2 + 1 Wend aschigh = temp2 Or 0x30
Return
'convt rtc packed bcd to a bin number for inc/dec usage bcd2bin: units = temp1 And 0x0f tens = temp1 And 0xf0 tens = ShiftRight(tens, 4) tens = tens * 10 temp1 = tens + units Return
'***************************************************************************
'any interrupts MUST go at the END On High Interrupt 'occurs at midnight every night
Save System
INTCON.TMR0IF = 0 'clears the Interrupt flag, set by T0 timer day count INTCON.TMR0IE = 0 'disables the T0 timer to Interrupt
If PORTA.5 = 1 Then Goto int2 Endif
If PORTA.6 = 1 Then Goto int30 Endif
'always send 1 pulse at midnight
'************ Brett pulse 3 times at midnight WaitMs 1000 'waits for 30sec slaves to pulse For pulse = 1 To 3 PORTB.5 = 1 'set PORTB.5 high, PULSE OUT WaitMs 400 'a 50mSec, this will be [waitms 400] PORTB.5 = 0 'sets PORTB.5 low, this simulates the pulse to the Slave WaitMs 400 Hserout " " #pulse Next pulse Hserout CrLf
day_end_cntr = day_end_cntr + 1 'inc day counter
If day_end_cntr > 33 Then '''''''''' day_end_cntr = 1 Endif
'table of months +1 day , NOTE: a '0' in position '0'. roll_over_cnt = LookUp(0, 32, 29, 32, 31, 32, 31, 32, 32, 31, 32, 31, 32), month_cntr
If year_cntr = 4 And roll_over_cnt = 29 Then roll_over_cnt = 30 Endif
If day_end_cntr = roll_over_cnt Then 'compare day count with number of days in month+1
'do action for month length Select Case roll_over_cnt
Case 29, 30 'do this if its a 28 day month [feb] leap = 36 'Brett steps to 1 from 28 Hserout "28 day month " 'Brett Hserout CrLf If year_cntr = 4 Then leap = 33 'Brett steps to 1 from 29 Hserout "Leap year so 29 day month " 'Brett Hserout CrLf Endif
For pulse = 1 To leap PORTB.5 = 1 'set PORTB.5 high, PULSE OUT WaitMs 400 'a 50mSec, this will be [waitms 400] PORTB.5 = 0 'sets PORTB.5 low, this simulates the pulse to the Slave WaitMs 400 'for serial output Hserout " " #pulse 'Brett Next pulse Hserout CrLf
'************Brett start of 5 pulse month stepping If month > 1 Then month = 1 Endif If month = 0 Then 'Alternates polarity of start pulse for quartz movement PORTB.0 = 1 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 0 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 'delay, this will be [waitms 400] Hserout " Mth1" Hserout CrLf PORTB.0 = 0 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 1 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 Hserout " Mth2" Hserout CrLf PORTB.0 = 1 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 0 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 Hserout " Mth3" Hserout CrLf PORTB.0 = 0 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 1 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 Hserout " Mth4" Hserout CrLf PORTB.0 = 1 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 0 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 Hserout " Mth5" Hserout CrLf Endif
If month = 1 Then 'Alternates polarity of start pulse for quartz movement PORTB.0 = 0 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 1 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 'delay, this will be [waitms 400] Hserout " Mth1" Hserout CrLf PORTB.0 = 1 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 0 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 Hserout " Mth2" Hserout CrLf PORTB.0 = 0 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 1 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 Hserout " Mth3" Hserout CrLf PORTB.0 = 1 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 0 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 Hserout " Mth4" Hserout CrLf PORTB.0 = 0 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 1 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 Hserout " Mth5" Hserout CrLf Endif
PORTB.0 = 0 'sets PORTB.0 low 'Brett turns off power to quartz motor until next month PORTB.3 = 0 'setsPORTB.3 low
Hserout "Month toggle " #month Hserout CrLf
If month = 0 Then 'Toggles month from 0 to 1 or 1 to 0 month = 1 Else month = 0 Endif Hserout " Month toggle now " #month Hserout CrLf
month_cntr = month_cntr + 1 'inc monthr counter day_end_cntr = 1 'reset day counter to zero b2a_value = day_end_cntr Gosub byte2asc2
Case 31 'do this if its a 30 day month? Hserout "30 day month " Hserout CrLf For pulse = 1 To 30 'Brett steps to 1 from 30 PORTB.5 = 1 'setsPORTB.5 high, PULSE OUT WaitMs 400 'delay, this will be [waitms 400] PORTB.5 = 0 'sets PORTB.5 low, this simulates the pulse to the Slave WaitMs 400 'for serial output Hserout " " #pulse Next pulse Hserout CrLf
'************Brett start of 5 pulse month stepping If month > 1 Then month = 1 Endif If month = 0 Then 'Alternates polarity of start pulse for quartz movement PORTB.0 = 1 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 0 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 'delay, this will be [waitms 400] Hserout " Mth1" Hserout CrLf PORTB.0 = 0 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 1 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 Hserout " Mth2" Hserout CrLf PORTB.0 = 1 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 0 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 Hserout " Mth3" Hserout CrLf PORTB.0 = 0 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 1 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 Hserout " Mth4" Hserout CrLf PORTB.0 = 1 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 0 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 Hserout " Mth5" Hserout CrLf Endif
If month = 1 Then 'Alternates polarity of start pulse for quartz movement PORTB.0 = 0 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 1 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 'delay, this will be [waitms 400] Hserout " Mth1" Hserout CrLf PORTB.0 = 1 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 0 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 Hserout " Mth2" Hserout CrLf PORTB.0 = 0 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 1 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 Hserout " Mth3" Hserout CrLf PORTB.0 = 1 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 0 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 Hserout " Mth4" Hserout CrLf PORTB.0 = 0 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 1 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 Hserout " Mth5" Hserout CrLf Endif
PORTB.0 = 0 'sets PORTB.0 low 'Brett turns off power to quartz motor until next month PORTB.3 = 0 'setsPORTB.3 low
Hserout "Month toggle " #month Hserout CrLf
If month = 0 Then 'Toggles month from 0 to 1 or 1 to 0 month = 1 Else month = 0 Endif Hserout " Month toggle now " #month Hserout CrLf
month_cntr = month_cntr + 1 'inc monthr counter day_end_cntr = 1 'reset day counter to zero b2a_value = day_end_cntr Gosub byte2asc2 'Hserout "d=", aschigh, asclow, ":" 'serial out
Case 32 'do this if its a 31 day month? Hserout "31 day month " Hserout CrLf For pulse = 1 To 27 '27 'Brett steps to 1 from 31 PORTB.5 = 1 'setsPORTB.5 high, PULSE OUT WaitMs 400 'delay, this will be [waitms 400] PORTB.5 = 0 'sets PORTB.5 low, this simulates the pulse to the Slave WaitMs 400 'for serial output Hserout " " #pulse Next pulse Hserout CrLf
'************Brett start of 5 pulse month stepping If month > 1 Then month = 1 Endif If month = 0 Then 'Alternates polarity of start pulse for quartz movement PORTB.0 = 1 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 0 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 'delay, this will be [waitms 400] Hserout " Mth1" Hserout CrLf PORTB.0 = 0 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 1 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 Hserout " Mth2" Hserout CrLf PORTB.0 = 1 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 0 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 Hserout " Mth3" Hserout CrLf PORTB.0 = 0 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 1 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 Hserout " Mth4" Hserout CrLf PORTB.0 = 1 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 0 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 Hserout " Mth5" Hserout CrLf Endif
If month = 1 Then 'Alternates polarity of start pulse for quartz movement PORTB.0 = 0 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 1 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 'delay, this will be [waitms 400] Hserout " Mth1" Hserout CrLf PORTB.0 = 1 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 0 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 Hserout " Mth2" Hserout CrLf PORTB.0 = 0 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 1 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 Hserout " Mth3" Hserout CrLf PORTB.0 = 1 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 0 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 Hserout " Mth4" Hserout CrLf PORTB.0 = 0 'setsPORTB.0 high, PULSE OUT for quartz motor PORTB.3 = 1 'setsPORTB.3 low, PULSE OUT for quartz motor WaitMs 1000 Hserout " Mth5" Hserout CrLf Endif
PORTB.0 = 0 'sets PORTB.0 low 'Brett turns off power to quartz motor until next month PORTB.3 = 0 'setsPORTB.3 low
Hserout "Month toggle " #month Hserout CrLf
If month = 0 Then 'Toggles month from 0 to 1 or 1 to 0 month = 1 Else month = 0 Endif Hserout " Month toggle now " #month Hserout CrLf
month_cntr = month_cntr + 1 'inc monthr counter day_end_cntr = 1 'reset day counter to zero b2a_value = day_end_cntr Gosub byte2asc2
EndSelect
'----------------------------------------------------------------------------------- Endif
If month_cntr = 13 Then 'overflow so reset to 1 month_cntr = 1 'reset month counter to 1[jan] year_cntr = year_cntr + 1 'inc year counter Endif
If year_cntr = 5 Then 'overflow so reset to year 1, its a 4 year cycle year_cntr = 1 Endif
'convert binary To ascii For uart b2a_value = day_end_cntr Gosub byte2asc2 Hserout "D=", aschigh, asclow, ":" 'serial out
b2a_value = month_cntr Gosub byte2asc2 Hserout aschigh, asclow, ":" temp1 = year_cntr Or 0x30 Hserout temp1, CrLf
TMR0L = 255 'you must reload the t0 timer Count
'they temporarily NOT used during Simulation, slows the Sim down 'save values in EEPROM, in case of power failure Write 0, day_end_cntr Write 1, month_cntr Write 2, year_cntr Write 3, month 'Brett Goto skip30
''''''''''''''''''''''''''''''''''''''''''''''' int30: sec_cntr = sec_cntr + 1 b2a_value = sec_cntr Gosub byte2asc2 Hserout aschigh, asclow, ","
If sec_cntr > 29 Then PORTB.5 = 1 'set PORTB.5 high, PULSE OUT WaitMs 40 '''0 'this will be [waitms 400] PORTB.5 = 0 'sets PORTB.5 low, this simulates the pulse to the Slave sec_cntr = 0 Hserout CrLf Endif TMR0L = 255 Goto skip30 '''''''''''''''''''''''''''''''''''''''''''''' int2: Toggle PORTB.5 If PORTB.5 = 1 Then PORTB.4 = 0 Else PORTB.4 = 1 Endif TMR0L = 255 If PORTB.5 = 1 Then Hserout "^5,", Else Hserout "^4," Endif
skip30: INTCON.TMR0IE = 1 'enables the T0 timer to Interrupt, when timer overflows Resume
|
||
|
Subroutines and code explanations
Green REM
Blue
Code Explanation In order to understand and also remember for the future the code used in this clock I have written out explanations for the code. byte2asc2: 'convt hex to decimal to ASCII e.g. if b2a_value = 27 in this case the day numbertemp1 = b2a_value Mod 10 temp1 = remainder of 27/10 = 7 (Mod 10 means divide by 10 & show remainder)asclow = temp1 Or 0x30 asclow = 7 in binary (0000 0111) OR’d with 0x30 in binary (0011 0000)this is00000111 OR 00110000 = 0011011100110111 in ASC11 displays 7temp2 = 0 resets temp2 to 0While b2a_value > 9 b2a_value = b2a_value - 10 temp2 = temp2 + 1 27-10 = 17temp2 = 117-10 = 7Temp2 = 2Wend aschigh = temp2 Or 0x30 aschigh = 2 in binary (0000 0010) OR’d with 0x30 in binary (0011 0000)this is00000010 OR 00110000 = 0011001000110010 in ASCII displays 2Return Used to display the day, month and year number over the serial port see skip_int
bcd2bin: see rx_date below 'convt rtc packed bcd to a bin number for inc/dec usage
units = temp1 And 0x0f tens = temp1 And 0xf0 tens = ShiftRight(tens, 4) tens = tens * 10 temp1 = tens + units Return
init_loop: 'if RA7 pin16 is HIGH at power up read these values 'reinitialise all counters to these settings 'Mark you can change these values, save testing waiting! 'put them back to current TODAY's values when you have done testing 'when you program a PIC these are the values it will save and use. 'TODAY is 31/08/09.... 27day, 11mon[30days in month].. 1st year of a 4 year cycle 'Brett set month to 0 for month movement day_end_cntr = 27 month_cntr = 09 year_cntr = 1 month = 0 'Brett 'save values to EEPROM Write 0, day_end_cntr Write 1, month_cntr Write 2, year_cntr Write 3, month 'Brett
skip_init: 'serial output header at power up b2a_value = day_end_cntr Gosub byte2asc2 **************************************************************byte2asc2: 'convt hex to decimal to ASCII e.g. if b2a_value = 27 in this case the day numbertemp1 = b2a_value Mod 10 temp1 = remainder of 27/10 = 7 (Mod 10 means divide by 10 & show remainder)asclow = temp1 Or 0x30 asclow = 7 in binary (0000 0111) OR’d with 0x30 in binary (0011 0000)this is00000111 OR 00110000 = 0011011100110111 in ASC11 displays 7temp2 = 0 resets temp2 to 0While b2a_value > 9 b2a_value = b2a_value - 10 temp2 = temp2 + 1 27-10 = 17temp2 = 117-10 = 7Temp2 = 2Wend aschigh = temp2 Or 0x30aschigh = 2 in binary (0000 0010) OR’d with 0x30 in binary (0011 0000)this is00000010 OR 00110000 = 0011001000110010 in ASCII displays 2Return **************************************************************Hserout "Init Date=", aschigh, asclow, ":" Outputs 2 and 7 from byte2asc2: above
b2a_value = month_cntr Gosub byte2asc2 see above Hserout aschigh, asclow, ":" temp1 = year_cntr Or 0x30 Hserout temp1, CrLf WaitMs 500 If PORTA.7 = 1 Then Goto init_loop Endif
rx_date: presume 27:09:01 entered Hserin ascbfr0 ' Brett note defines 10 keys in order Hserin ascbfr1 Hserin ascbfr2 Hserin ascbfr3 Hserin ascbfr4 Hserin ascbfr5 Hserin ascbfr6 Hserin ascbfr7 Hserin ascbfr8 'Brett Hserin ascbfr9 'Brett Hserin ascbfr10 'Brett
'' Hserout CrLf temp1 = ascbfr0 temp1 is ASCII code for 2 and is 00110010temp1 = temp1 And 0x0f this is temp 1 ANDed with 0x0f (00001111)this = 0000010 or 2temp2 = ShiftLeft(temp1, 4) so temp2 = 00100000temp1 = ascbfr1 temp1 is ASCII code for 2 and is 00110111temp1 = temp1 And 0x0f this is temp 1 ANDed with 0x0f (00001111) this = 00000111 or 7 temp1 = temp1 Or temp2 this = 00000111 OR 00100000so temp 1 = 00100111Gosub bcd2bin **************************************************bcd2bin: 'convt rtc packed bcd to a bin number for inc/dec usage
units = temp1 And 0x0f from above temp1 = 00100111, 0x0f = 00001111so units = 00100111 AND 00001111units = 00000111 or 7tens = temp1 And 0xf0 from above temp1 = 00100111, 0xf0 = 11110000so tens = 00100111 AND 11110000tens = 00100000tens = ShiftRight(tens, 4) tens = 00000010tens = tens * 10 tens = 00010100 temp1 = tens + units temp1 = 00011011Return **************************************************If temp1 = 0 Then temp1 = 1 Endif Write 0x0, temp1 0x0 = 00011011 or 27day_end_cntr = temp1 day_end_cntr = 00011011 or 27This is repeated for ascbf3, 4, 6, 7, 9 & 10 below.'''''''''''''''''''''''''''''''''''' temp1 = ascbfr3 temp1 = temp1 And 0x0f temp2 = ShiftLeft(temp1, 4) temp1 = ascbfr4 temp1 = temp1 And 0x0f temp1 = temp1 Or temp2 Gosub bcd2bin If temp1 = 0 Then temp1 = 1 Endif Write 0x1, temp1 month_cntr = temp1 '''''''''''''''''''''''''''''''''''' temp1 = ascbfr6 temp1 = temp1 And 0x0f temp2 = ShiftLeft(temp1, 4) temp1 = ascbfr7 temp1 = temp1 And 0x0f temp1 = temp1 Or temp2 Gosub bcd2bin temp1 = temp1 Mod 4
If temp1 = 0 Then temp1 = 4 Endif
Write 0x2, temp1 year_cntr = temp1 '''''''''''''''''''''''''''''''''''' 'Brett temp1 = ascbfr9 temp1 = temp1 And 0x0f temp2 = ShiftLeft(temp1, 4) temp1 = ascbfr10 temp1 = temp1 And 0x0f temp1 = temp1 Or temp2 Gosub bcd2bin temp1 = temp1 'Mod 4
Write 0x3, temp1 month = temp1 'end Brett '''''''''''''''''''''''''''''''''''' Hserout CrLf Hserout "Echo Date=" Hserout ascbfr0, ascbfr1, ascbfr2 Hserout ascbfr3, ascbfr4, ascbfr5 Hserout ascbfr6, ascbfr7, ascbfr8, ascbfr9, ascbfr10, CrLf 'Brett ascbfr9, ascbfr10
temp1 = 0 temp2 = 0
|
||