	; // ----------------------------------------------------- //
	; // PIC16F873 based 8 channel sequencer for relay ctrl.   //
	; //                                                       //
	; //                  Copyright 2014,  Wolkensdorfer Peter //
	; // ----------------------------------------------------- //

	list	p=16f873
	#include p16f873.inc

	; // Device configuration bits ---------------------------------------

	__CONFIG _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_ON & _HS_OSC & _WRT_ENABLE_ON & _LVP_OFF & _CPD_OFF

	; // Variables -------------------------------------------------------

temp_WREG	equ	0x20		; // Context saving
temp_STATUS	equ	0x21
temp_PCLATH	equ	0x22
temp_FSR	equ	0x23

Flags		equ	0x24      	; // Own status bits Flags
TickCount	equ	0x25		; // Timer0 IT count
PulseCount	equ	0x26		; // Heartbeat LED counter
EventDelay	equ	0x27		; // Timebase count till next event
Index		equ	0x28		; // Index into data table

	; // Flags register bits ---------------------------------------------

#define		MYCLOCK	Flags,0		; // Timebase tick flag
#define		PULSE	Flags,1		; // Status of heartbeat LED
#define		SEQTYPE	Flags,2		; // 0: startup, 1: shutdown
#define		INSEQ	Flags,3		; // 1: within sequence
#define		PLSMASK	0x02		; // To invert LED state

		; // Port bits -----------------------------------------------

#define		POWERED	PORTA,0		; // Detect +12V
#define		PULSLED	PORTA,5		; // PIC heartbeat LED

	org	0x0000			; // RESET vector

		CLRF	PCLATH
		GOTO    Main

		; // Timer interrupt handler ---------------------------------

	org	0x0004

IT_handler	MOVWF  	temp_WREG   	; // Goes to 0x20 or 0xA0
		SWAPF  	STATUS,W        ; // Get STATUS
		BCF    	STATUS,RP0      ; // Switch to bank 0
		MOVWF  	temp_STATUS 	; // Save STATUS
		MOVF   	PCLATH, W     	; // Get PCLATH
		MOVWF  	temp_PCLATH 	; // Save PCLATH
		CLRF   	PCLATH		; // Clear PCLATH
		MOVF	FSR,W
		MOVWF	temp_FSR

		BCF	INTCON,T0IF	; // Clear timer IT flag
		INCF	TickCount	; // Count (76 Hz at 10 MHz)
		MOVF	TickCount,W	; // Check counter
		SUBLW	0x08		; // Compare to maximum
		BTFSS	STATUS,Z	; // Reached?
		GOTO	ith1		; // Not yet

		CLRF	TickCount	; // Reset counter
		BSF	MYCLOCK		; // Set tick flag (105 ms timebase)

ith1		MOVF	temp_PCLATH,W	; // Restore context
		MOVWF	PCLATH
		MOVF	temp_FSR,W
		MOVWF	FSR
		SWAPF	temp_STATUS,W
		MOVWF	STATUS
		SWAPF	temp_WREG
		SWAPF	temp_WREG,W
		RETFIE

		; // Main program --------------------------------------------
		
Main		BCF	STATUS,RP0
		MOVLW	0x1F		; // Set TRIS and PORT defaults ...
		BSF	STATUS,RP0	; // ... for PORTA
		MOVWF	TRISA		; // Only RA5 is output
		CLRF	TRISB		; // ... for PORTB
		MOVLW	0xFF
		CLRF	TRISC      	; // ... for PORTC

		BCF	STATUS,RP0	; // Initialize ports
		CLRF	PORTA
		CLRF	PORTB
		CLRF	PORTC

		MOVLW	0xC6		; // Set configuration
		BSF	STATUS,RP0
		MOVWF	OPTION_REG	; // Prescaler assigned to TMR0
					; // Clock is 2.5 MHz, so w/o
					; // prescaler we get ca. 9,8 kHz IT
					; // With 1:128 prescaler we get 76 Hz
					; // Every 8th IT gives a timebase of
					; // 105 ms.
		MOVLW	0x81		; // A/D module ON at Osc/32
		BCF	STATUS,RP0
		MOVWF	ADCON0
		MOVLW	0x0E		; // One analog channel
		BSF	STATUS,RP0	; // Result is left justified
		MOVWF	ADCON1

		MOVLW	0xA0		; // Enable Timer0 IT only
		MOVWF	INTCON
		BCF	STATUS,RP0

		CLRF    Flags		; // Initialize variables
		CLRF	TickCount
		CLRF	PulseCount
		CLRF	Index
		BSF	INSEQ		; // Initiate startup sequence

		; // Main program loop ---------------------------------------

main_loop	CLRWDT			; // Clear watchdog
		BTFSS	MYCLOCK		; // Timebase tick?
		GOTO	main_loop	; // No, continue

		; // Heartbeat LED -------------------------------------------

		BCF	MYCLOCK		; // Clear timebase flag
		INCF	PulseCount	; // Increment counter
		MOVF	PulseCount,W	; // Read counter
		SUBLW	5		; // Half second passed?
		BTFSS	STATUS,Z
		GOTO	sequencing	; // No

		MOVLW	PLSMASK		; // Invert heartbeat flag
		XORWF	Flags
		CLRF	PulseCount	; // Reset counter
		BTFSS	PULSE		; // Copy flag state to LED
		BCF	PULSLED
		BTFSC	PULSE
		BSF	PULSLED

		; // Output sequencer ----------------------------------------

sequencing	BTFSC	INSEQ		; // Within sequence?
		GOTO	sequer		; // Yes

		BTFSC	POWERED		; // +12V still present?
		GOTO	main_loop	; // Yes, nothing to do

		BSF	SEQTYPE		; // Set type to shutdown sequence
		NOP
		BSF	INSEQ		; // Start sequence

sequer

end_seq		BCF	INSEQ		; // Stop sequencing

done		GOTO	main_loop

	end	; // of code =================================================

