This circuit uses the PIC16F628 microcontroller to provide 4 timed outputs that can be programmed from 1 minute to 1 week. An extra 8 bit shift register (74HC164) is used for the 4 timer outputs and to display four additional indicator lights.On bootup, the display will show current time of 2:57 AM and all timer settings will be set to zero. One toggle and four momentary switches are used to enter and display data. A SPST toggle switch (A/B) is used to select the setup or Run mode and the other four switches can be momentary push buttons used to enter data or manually toggle timer outputs on and off.
Switch functions are as follows: Run/Setup (A/B) - Selects run or setup mode. (A = Run) Time (C) - Displays current time, active in both setup and run modes. Hours (E) - Increments Hours data. Active in Setup mode. Minutes (F) - Increments Minutes data. Active in Setup mode. Snooze Timer (E) - Toggles timer #1 on for selected time. Active in run mode. Manual select (F) - Toggles selected timers on or off. Active in run mode. Advance (D) - Advances display to next data. Active in both setup and run modes.There are 19 displays. The first 3 indicate current time, AMPM and day of week, and options and seconds. The remaining 16 displays indicate start and stop times, AMPM and day of week for the 4 timers. AMPM is indicated with a 1 or 0 in the hours digit (1=PM) and day of week is indicated in the minutes digit (1-7) (1 = Sunday). The current display is indicated by the 4 LEDs attached to the lower 4 bits of the 74HC164 shift register (bits 0 to 3). This makes it a little easier to figure out what is being displayed rather than counting from 1 to 19. The timer outputs are controlled by the upper 4 bits of the register (bits 4 to 7). The current display is the binary value of the 4 LEDs so that 0000 is the start time for timer 1 and 0001 is the AMPM and day of week setting for the start time of timer 1. The last display will be 1111 which indicates AMPM and day of week for the stop time of timer 4. However, since there are 19 displays, the first 4 are indicated by binary 0000. The sequence goes as follows:
0000 - Current Time 0000 - Current AMPM and day of week 0000 - Options and seconds 0000 - Start time for timer 1 0001 - AMPM and day of week for start time of timer 1 0010 - Stop time for timer 1 0011 - AMPM and day of week for stop time of timer 1 0100 - Start time for timer 2 0101 - AMPM and day of week for start time of timer 2 0110 - Stop time for timer 2 0111 - AMPM and day of week for stop time of timer 2 1000 - Start time for timer 3 1001 - AMPM and day of week for start time of timer 3 1010 - Stop time for timer 3 1011 - AMPM and day of week for stop time of timer 3 1100 - Start time for timer 4 1101 - AMPM and day of week for start time of timer 4 1110 - Stop time for timer 4 1111 - AMPM and day of week for stop time of timer 4Some examples are listed here:
To set timer 2 for 7:00AM to 8:00AM every day, first set the setup/run switch to the setup mode. Then press the time switch to get to the top of the stack. Next press the advance switch until 0100 is displayed. Next use the hours and minutes switches to set the time to 7:00. Then press the advance switch once so the display is 0101 and set the display for 0:00 which means AM and every day of the week. If you wanted PM, the hours digit would be set to '1' and if you wanted the event to occur only on Mondays, the minutes digit would be set to '2' (Sunday=1)
Parallel Mode:
In the parallel mode, all events are sent to timer #1 so that four timed intervals can be obtained from timer 1. So, if you set timer 2 to start at 8:00AM, both timer 1 and 2 will start at 8:00AM. The parallel mode is activated by entering a '1' in the options field, which is the hours digit of the third display (0000). This same display shows the current seconds in the minutes digit.
Snooze function:
The snooze feature allows timer 1 to be set for periods of 5 to 75 minutes in 5 minute steps. To use it, first select the desired time by advancing the LED display to the binary value divided by 5. So, if you want 5 minutes, set the display to 0001. 10 minutes is 0010 and so forth. When the correct value is displayed, press the hours switch to begin. Note that using a settimg of 0000 will turn on timer 1 indefinetly until a stop time is encountered or the timer is manually switched off with the minutes key.
Manual control:
The state of all 4 timers can be set manually by advancing the LED display to the desired state and then pressing the minutes key. For example, to engage timer 1 and 3, the LED display will be set to 0101. To reset the timers press the time key so the LED display is 0000 and then press the minutes key.
----------------------Program Listing --------------------------- ;--------------------- Clock2.asm 09/19/07 ------------------- LIST P=16F628 ; Device number (PIC16F628) ERRORLEVEL -224 ; suppress annoying message because of tris ERRORLEVEL -302 ; suppress message because of page change ;--------------------- Configuration ---------------------------- _BODEN_OFF equ H'3FBF' ; Brown out detection off _CP_OFF equ H'3FFF' ; Code protection off _PWRTE_ON equ H'3FF7' ; Power-on reset enabled _WDT_OFF equ H'3FFB' ; Watch dog timer off _LVP_OFF equ H'3F7F' ; Low Voltage programming off _INTRC_OSC_NOCLKOUT equ H'3FFC' ; Use Internal RC Oscillator _MCLRE_OFF equ H'3FDF' ; Use RA5 as functional input __CONFIG _CP_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT & _PWRTE_ON & _LVP_OFF & _BODEN_OFF & _MCLRE_OFF ;--------------------- Define Variables ------------------------------- INDF equ 00h FSR equ 04h CMCON equ 1Fh ; Comparator Control Address INTCON equ 0Bh ; Interrupt control register OPTION_REG equ 81h ; Option register STATUS equ 03h ; Status register TRISA equ 85h ; I/O control for port A TRISB equ 86h ; I/O control for port B PORTB equ 06h ; Address of port B PORTA equ 05h ; Address of port A PC equ 02h ; Program counter COUNTER equ 20h ; Addresses 20H-7FH = general RAM HOURS equ 21h ; Current Time MINUTES equ 22h AMPM equ 23h WEEKDAY equ 24h OPTIONS equ 25h SECONDS equ 26h HOURS_START1 equ 27h ; Timer 1 0000 MINUTES_START1 equ 28h AMPM_START1 equ 29h ; 0001 WEEKDAY_START1 equ 2ah HOURS_STOP1 equ 2bh ; 0010 MINUTES_STOP1 equ 2ch AMPM_STOP1 equ 2dh ; 0011 WEEKDAY_STOP1 equ 2eh HOURS_START2 equ 2fh ; Timer 2 0100 MINUTES_START2 equ 30h AMPM_START2 equ 31h ; 0101 WEEKDAY_START2 equ 32h HOURS_STOP2 equ 33h ; 0110 MINUTES_STOP2 equ 34h AMPM_STOP2 equ 35h ; 0111 WEEKDAY_STOP2 equ 36h HOURS_START3 equ 37h ; Timer 3 1000 MINUTES_START3 equ 38h AMPM_START3 equ 39h ; 1001 WEEKDAY_START3 equ 3ah HOURS_STOP3 equ 3bh ; 1010 MINUTES_STOP3 equ 3ch AMPM_STOP3 equ 3dh ; 1011 WEEKDAY_STOP3 equ 3eh HOURS_START4 equ 3fh ; Timer 4 1100 MINUTES_START4 equ 40h AMPM_START4 equ 41h ; 1101 WEEKDAY_START4 equ 42h HOURS_STOP4 equ 43h ; 1110 MINUTES_STOP4 equ 44h AMPM_STOP4 equ 45h ; 1111 WEEKDAY_STOP4 equ 46h TEMP equ 47h ; Value passed to Digits routine TENS equ 48h ; Value returned from Digits routine TEMPW equ 49h ; Used in interrupt to save w SWITCH equ 4ah ; Value returned from switches STATUS_SAVE equ 4bh ; Interrupt (save status) TEMP1 equ 4ch ; Part of delay routine ALARM equ 4dh ; Alarm on/off (bit 7 set =on) TEMP_SAVE equ 4eh ; Saves a copy of TEMP TIMER equ 4fh AMPM_LED equ 50h FLAG equ 51h PORTC equ 52h ; Current state of 74HC164 register PORTC_OUT equ 53h ; Copy of PORTC to output COUNTER1 equ 54h TEMP2 equ 55h STEPS equ 56h ; Current state of the 4 LED indicators FLAG1 equ 57h ;--------------------- Program Starts here -------------------------- goto INIT ;--------------------- Interrupt routine to update time ------------- org 0x04 movwf TEMPW ; Save w swapf STATUS,0 ; Get status register into w movwf STATUS_SAVE ; Save status register bcf STATUS,5 ; Go to bank 0 (00) incf SECONDS,f ; Advance seconds movlw d'60' xorwf SECONDS,0 btfss STATUS,2 ; Check for 60 seconds goto Done ; Jump out if not 60 clrf SECONDS incf MINUTES,f call Check_events ; Check events where minutes are not 0 call Snooze_Timer movlw d'60' xorwf MINUTES,0 btfss STATUS,2 ; Check for 60 minutes goto Done ; Jump out if not 60 clrf MINUTES incf HOURS,f call Check_events ; Check events where minutes = 0 movlw d'13' xorwf HOURS,0 btfss STATUS,2 ; Check for 13 hours goto Noon ; Jump out if not 13 clrf HOURS incf HOURS,f ; Set hours to 1:00 Noon movlw d'12' xorwf HOURS,0 btfss STATUS,2 ; Check for 12 hours goto Done ; Jump out if not 12 incf AMPM,f bcf AMPM,1 ; Clear Bit 1 to stop overflow btfsc AMPM,0 ; AM = Bit 0 clear Goto Done WeekDay incf WEEKDAY,f movlw d'8' xorwf WEEKDAY,0 btfss STATUS,2 ; Check for new week goto Done clrf WEEKDAY incf WEEKDAY,f ; Set weekday to 1 = Sunday Done bcf INTCON,2 swapf STATUS_SAVE,0 movwf STATUS swapf TEMPW,f swapf TEMPW,0 retfie ;--------------------- End Interrupt Procedure ---------------------- INIT ; Initialize variables bsf STATUS,5 ; Select memory bank 1 (01) bcf STATUS,6 ; Select memory bank 1 (01) movlw b'00000000' movwf TRISB ; Set port B as output movlw b'01110000' ; movwf TRISA ; Set port A as output, RA4,5,6=Input bsf OPTION_REG,5 ; Select Timer0 (TOCS=1) bcf OPTION_REG,3 ; Assign prescaler to timer0 bcf OPTION_REG,0 ; Set prescaler to 128 bcf STATUS,5 ; Reset to bank 0 bcf STATUS,0 ; Clear carry bit bcf STATUS,2 ; Clear zero flag bcf STATUS,1 ; bsf INTCON,5 ; Enable timer0 interrupt bcf INTCON,2 ; Clear interrupt flag bsf INTCON,7 ; Enable global interrupt movlw 07h movwf CMCON ; Comparators off movlw h'22' movwf FSR Load_Defaults ; Set all values to 0 movlw d'0' incf FSR,f ; Increment Pointer movwf INDF movlw h'5a' xorwf FSR,0 btfss STATUS,2 goto Load_Defaults movlw h'21' movwf FSR ; Set Pointer to Time display movlw d'2' movwf HOURS movlw d'57' movwf MINUTES call Write_PortC ; Clear shift register goto Main Timer_Table ; Set or Reset 1 bit of portC call Parallel bsf FLAG,1 ; Write port C if flag set movfw COUNTER1 addwf PC,1 bsf PORTC,4 return bcf PORTC,4 return bsf PORTC,5 return bcf PORTC,5 return bsf PORTC,6 return bcf PORTC,6 return bsf PORTC,7 return bcf PORTC,7 return Parallel ; Set or reset bit 4 of portC if parallel option selected movlw d'0' xorwf OPTIONS,0 btfsc STATUS,2 return movfw COUNTER1 addwf PC,1 bsf PORTC,4 return bcf PORTC,4 return bsf PORTC,4 return bcf PORTC,4 return bsf PORTC,4 return bcf PORTC,4 return bsf PORTC,4 return bcf PORTC,4 return Array ; Data for 7 segment digits addwf PC,1 retlw b'01000000' ; "0" retlw b'01111001' ; "1" retlw b'00100100' ; "2" retlw b'00110000' ; "3" retlw b'00011001' ; "4" retlw b'00010010' ; "5" retlw b'00000010' ; "6" retlw b'01111000' ; "7" retlw b'00000000' ; "8" retlw b'00010000' ; "9" Main ; ------------ Main Loop ---------------------- call Display ; Display data call Read_Port ; Check for switch closed movlw d'14' ; Check for time switch closed xorwf SWITCH,0 btfss STATUS,2 goto Set_Time movlw h'21' movwf FSR clrf STEPS clrf FLAG1 call Update_PortC call Wait Set_Time movlw d'46' ; Check for time switch and RA5 closed xorwf SWITCH,0 btfss STATUS,2 goto Increment_Display movlw h'21' movwf FSR clrf STEPS clrf FLAG1 call Update_PortC call Wait Increment_Display movlw d'13' ; Check for advance key pressed in run mode xorwf SWITCH,0 btfss STATUS,2 goto Function ; Function key not hit (13) call Wait ; Wait for switch to open call Increment_Pointer Function movlw d'45' ; Ckeck for advance key pressed in setup mode xorwf SWITCH,0 btfss STATUS,2 goto Increment_100s ; Function key not hit (13) call Wait ; Wait for switch to open call Increment_Pointer Increment_100s ; On plus RA5 = 32 + 11 = 43 movlw d'43' ; Check for hours key pressed xorwf SWITCH,0 btfss STATUS,2 goto Increment_10s call Wait incf INDF,f movlw d'13' ; Rollover to 0 at 13 xorwf INDF,0 btfsc STATUS,2 clrf INDF Increment_10s ; RA5 + alarm off = 39 movlw d'39' ; Check for minutes key pressed xorwf SWITCH,0 btfss STATUS,2 goto Timer_Toggle call Wait incf FSR,f incf INDF,f movlw d'60' ; Rollover to 0 at 60 xorwf INDF,0 btfsc STATUS,2 clrf INDF decf FSR,f Timer_Toggle ; Copy LED states to timer output movlw d'7' xorwf SWITCH,0 btfss STATUS,2 goto Snooze movfw STEPS movwf TEMP rlf TEMP,f rlf TEMP,f rlf TEMP,f rlf TEMP,f clrf PORTC movfw TEMP iorwf PORTC,f call Update_PortC call Wait Snooze ; Set snooze timer for 5 to 75 minutes movlw d'11' xorwf SWITCH,0 btfss STATUS,2 goto Main bsf PORTC,4 call Update_PortC movfw STEPS clrf TIMER movwf COUNTER movlw d'5' Add addwf TIMER,f ; Multiply timer by counter decfsz COUNTER,f goto Add Repeat movlw d'11' xorwf SWITCH,0 btfss STATUS,2 goto Main movfw TIMER movwf TEMP call Digits movfw TENS call Output ; Display snooze timer setting (tens digit) movlw d'11' movwf PORTA call Delay movfw TEMP call Output ; Display snooze timer setting (ones digit) movlw d'7' movwf PORTA call Delay call Read_Port ; Look for switch open goto Repeat ; Continue to display until switch open ;-------------------------- End of Main Loop ------------------------ Snooze_Timer ; Decrement timer from preset value movlw d'0' xorwf TIMER,0 btfsc STATUS,2 return decf TIMER,f movlw d'0' xorwf TIMER,0 btfss STATUS,2 goto $ +3 bcf PORTC,4 call Update_PortC return Output ; Write data to port B call Array movwf PORTB return Delay ;------------------------ Delay ---- about 600 uS ------------ movlw d'25' Delay_0 movwf TEMP1 Delay_1 movwf COUNTER Delay_2 decfsz COUNTER,f goto Delay_2 decfsz TEMP1,f goto Delay_1 return Digits ; Converts value in TEMP to 2 single digits - TENS and TEMP clrf TENS movlw d'10' Loop incf TENS,f subwf TEMP,f btfss STATUS,0 goto Ones goto Loop Ones decf TENS,f addwf TEMP,f return Read_Port ; Look to see if switch is closed movlw d'127' movwf PORTA movwf PORTB ; Set port B to high level bsf STATUS,5 ; Select bank 1 (01) movlw b'01111111' movwf TRISA ; Set port A as input, RA7=output movlw b'00111111' movwf TRISA ; Set RA6 to output bcf STATUS,5 ; Return to bank 0 (00) bcf PORTA,6 ; Low level on RA6 movlw d'10' call Delay_0 ; Wait movfw PORTA ; Read the pins movwf SWITCH bsf STATUS,5 ; Select Bank 1 movlw b'01111111' movwf TRISA ; Set port A to input movlw b'01110000' movwf TRISA ; Set porta,0,1,2,3 to output bcf STATUS,5 ; Return to Bank 0 movlw b'00101111' ; RA5 is normally 0 andwf SWITCH,f ; Switch returns value 0 to 47 return Check_events ;Check data for timers 1 to 8 --- Start at address h27 movfw FSR movwf TEMP2 ; Save pointer clrf COUNTER1 bcf FLAG,0 movlw h'27' movwf FSR Timer_Loop ; Check current time against all events movfw HOURS xorwf INDF,0 btfss STATUS,2 bsf FLAG,0 ; No Good incf FSR,f movfw MINUTES xorwf INDF,0 btfss STATUS,2 bsf FLAG,0 incf FSR,f movfw AMPM xorwf INDF,0 btfss STATUS,2 bsf FLAG,0 incf FSR,f ; Weekday movlw d'0' xorwf INDF,0 btfsc STATUS,2 goto $ +5 ; skip test if weekday =0 movfw WEEKDAY xorwf INDF,0 btfss STATUS,2 bsf FLAG,0 btfss FLAG,0 ; data no good, jump call Timer_Table incf COUNTER1,f incf COUNTER1,f incf FSR,f bcf FLAG,0 movlw d'16' xorwf COUNTER1,0 btfss STATUS,2 goto Timer_Loop movfw PORTC movwf PORTC_OUT clrf COUNTER1 btfss FLAG,1 goto $ +2 call Write_PortC movfw TEMP2 movwf FSR ; Restore pointer clrf FLAG return Write_PortC ; RB7 = clock RA7 = Data btfsc PORTC_OUT,0 bsf PORTA,7 btfss PORTC_OUT,0 bcf PORTA,7 rrf PORTC_OUT,f bsf PORTB,7 ; Move clock up bcf PORTB,7 ; Move clock down incf COUNTER1,f movlw d'8' xorwf COUNTER1,0 btfss STATUS,2 goto Write_PortC ; Next bit of 8 return Display ; -------------------- Display Data ----------------------- clrf AMPM_LED ; AMPM off movlw h'21' xorwf FSR,0 btfss STATUS,2 goto $ +3 btfsc AMPM,0 bsf AMPM_LED,7 ; Add AMPM light (time) movfw INDF ; Get 100s data movwf TEMP call Digits btfss TENS,0 goto Ones_Hours movfw TENS ; Light 10s Hours LED call Output movlw d'14' iorwf AMPM_LED,0 ; Add AMPM light if time or alarm movwf PORTA call Delay Ones_Hours movfw TEMP call Output movlw d'13' iorwf AMPM_LED,0 ; Add AMPM light if time or alarm movwf PORTA call Delay incf FSR,f movfw INDF movwf TEMP call Digits movfw TENS call Output movlw d'11' iorwf AMPM_LED,0 ; Add AMPM light if time or alarm movwf PORTA call Delay movfw TEMP call Output movlw d'7' iorwf AMPM_LED,0 ; Add AMPM light if time or alarm movwf PORTA call Delay decf FSR,f return Wait ; Wait until switches are open call Display call Read_Port movlw d'15' ; Switches open in run mode xorwf SWITCH,0 btfsc STATUS,2 return movlw d'47' ; Switches open in program mode xorwf SWITCH,0 btfsc STATUS,2 return goto Wait Increment_Pointer incf FSR,f ; Increment Pointer 2 steps incf FSR,f call Step movlw h'47' xorwf FSR,0 btfss STATUS,2 return movlw h'21' movwf FSR ; Set Pointer to Time display return Step ; Increment step for LED display (range 0 to 15) movlw h'29' subwf FSR,0 btfsc STATUS,2 bsf FLAG1,0 btfss FLAG1,0 return incf STEPS,f movlw h'47' xorwf FSR,0 btfsc STATUS,2 goto $ +2 goto Update_PortC clrf STEPS clrf FLAG1 Update_PortC ; Load LED display data into lower 4 bits of portc clrf COUNTER1 bcf PORTC,0 bcf PORTC,1 bcf PORTC,2 bcf PORTC,3 movfw STEPS iorwf PORTC,f ; add timer data (upper 4 bits) movfw PORTC movwf PORTC_OUT ; Move portc to output byte call Write_PortC return end --------------------- Compiled Hex code ----------------------- :020000003328A3 :08000800C900030ECB008312B6 :10001000A60A3C302606031D2D28A601A20A2A2185 :10002000F2203C302206031D2D28A201A10A2A211C :100030000D302106031D1E28A101A10A0C30210646 :10004000031D2D28A30AA31023182D28A40A083065 :100050002406031D2D28A401A40A0B114B0E8300B6 :10006000C90E490E09008316031300308600703054 :100070008500811681110110831203100311831072 :100080008B160B118B1707309F0022308400003035 :10009000840A80005A300406031D4728213084005A :1000A0000230A1003930A2005B218B286A20D114D4 :1000B000540882075216080052120800D21608008F :1000C000D21208005217080052130800D217080075 :1000D000D2130800003025060319080054088207CF :1000E0005216080052120800521608005212080058 :1000F0005216080052120800521608005212080048 :1001000082074034793424343034193412340234C0 :10011000783400341034682113210E304A06031D50 :10012000972821308400D601D701B52192212E30A5 :100130004A06031DA12821308400D601D701B5212C :1001400092210D304A06031DA72892219D212D30B2 :100150004A06031DAD2892219D212B304A06031D1E :10016000B7289221800A0D3000060319800127303C :100170004A06031DC3289221840A800A3C300006E7 :1001800003198001840307304A06031DD22856084C :10019000C700C70DC70DC70DC70DD2014708D20450 :1001A000B52192210B304A06031D8B285216B5212A :1001B0005608CF01A0000530CF07A00BDC280B307C :1001C0004A06031D8B284F08C70009214808FE2056 :1001D0000B30850001214708FE20073085000121F2 :1001E0001321DF2800304F0603190800CF03003029 :1001F0004F06031DFD285212B521080080208600FD :1002000008001930CC00A000A00B0429CC0B032956 :100210000800C8010A30C80AC702031C10290B29AC :10022000C803C70708007F308500860083167F302B :1002300085003F308500831205130A30022105082E :10024000CA0083167F3085007030850083122F30FE :10025000CA0508000408D500D401511027308400D5 :1002600021080006031D5114840A22080006031DFC :100270005114840A23080006031D5114840A003017 :1002800000060319472924080006031D5114511CB8 :100290005620D40AD40A840A511010305406031D83 :1002A00030295208D300D401D11C57295B215508AD :1002B0008400D101080053188517531C8513D30CF3 :1002C00086178613D40A08305406031D5B290800DC :1002D000D00121300406031D6F292318D017000810 :1002E000C7000921481C7A294808FE200E30500416 :1002F000850001214708FE200D30500485000121B2 :10030000840A0008C70009214808FE200B30500469 :10031000850001214708FE20073050048500012197 :1003200084030800682113210F304A0603190800CE :100330002F304A06031908009229840A840AA7214B :1003400047300406031D08002130840008002930CE :10035000040203195714571C0800D60A4730040634 :100360000319B329B529D601D701D4015210D210EF :100370005211D2115608D2045208D3005B21080052 :02400E00103F61 :00000001FFMenu