;**********************************************************************
;                                                                     *
;    Filename:	    WindowLift                                        *
;    Date:          05.01.28                                          *
;    File Version:  1.0                                               *
;                                                                     *
;    Author:        Chuck Simmers                                     *
;    Company:       Microchip Technology, Inc.                        *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Files required:                                                  *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Notes:                                                           *
;                                                                     *
;**********************************************************************

        list	p=16F688	  ; list directive to define processor
        #include <P16F688.inc>       ; processor specific variable definitions
        LIST
; P16F688.INC  Standard Header File, Version 1.00    Microchip Technology, Inc.
        LIST

        errorlevel  -302,-305	     ; suppress message 302 from list file

	__CONFIG        _CP_OFF & _WDT_OFF & _MCLRE_OFF & _PWRTE_OFF &_BOD_OFF & _INTRC_OSC_NOCLKOUT 

;***** VARIABLE DEFINITIONS
		; ***********************************************************************			
		; * Register definitions								; ***********************************************************************
		cblock	0x20
			DLY_CNT0
			DLY_CNT1
			CNT_LW	
			CNT_HI	
			ADDRESS
			w_temp		; variable used for context saving 
			status_temp	; variable used for context saving
			PENUM
			ButtonImage
			WindowLiftStatus
		endc
	#Include <UART688i.inc>

VoltageThreshold	equ	LOW(.12500 /(.50000 / .256))	; set for 1.25V
		; ***********************************************************************
		; * Other definitions							*
		; ***********************************************************************

		#define PA_ADC0CON 	B'00000001'	; channel 0, A/DC ON, Left-justified, ADCS2=0
		#define PA_ADC1CON 	B'00000101'	; channel 1, A/DC ON, Left-justified, ADCS2=0

; PORTA definitions
		#define AnalogIn0		PORTA,0
		#define AnalogIn1		PORTA,1
;		#define Button2		PORTA,2
;		#define Button1		PORTA,3
		#define UpButton		PORTA,4
		#define DwnButton		PORTA,5
		#define	TRISAset	b'11111011'

		#define ButtonMask	b'00110000'

; PORTC definitions
		#define	UpDirection		PORTC,0
		#define	DwnDirection		PORTC,1
		#define	LINCS		PORTC,2
;no connect		#define	LINfault	PORTC,3
		#define	LINTX		PORTC,4
		#define LINRX		PORTC,5
		#define	TRISCset	b'11100000'
		
;**********************************************************************
; Function ID bit definitions
;   7 6 5 4 3 2 1 0
;   | | | | |_____|___ Data Type Tag Code
;   | | |_|___________ Number of bytes in the data frame 0=2 bytes, 1=2 bytes, 2=4 bytes, 3=8 bytes
;   |_|_______________ Not Used
		#define Slave0out		0x05	;
;
;   First Data Byte : Operation Code
;   7 6 5 4 3 2 1 0
;               | |___ 1 = Window DOWN
;               |_____ 1 = Window UP
;
; *********************************************************************
		; ***********************************************************************
		; * Program Start							*
		; ***********************************************************************

		ORG 0x00
	goto	main
		
		; ***********************************************************************
		; * Interrupt Service							*
		; ***********************************************************************
		ORG     0x04	; interrupt vector location
; **** Save status and wreg ****
	movwf   w_temp            ; save off current W register contents
	movf	STATUS,w          ; move status register into W register
	bcf     STATUS,RP0        ; ensure file register bank set to 0
	bcf     STATUS,RP1        ; ensure file register bank set to 0
	movwf	status_temp       ; save off contents of STATUS register

	bsf	STATUS,RP0
	btfss	PIE1,RCIE		; is EAUSART receive interrupt enabled?
	goto	CheckXmitFlag		; no, go check transmit
	bcf	STATUS,RP0
	btfsc	PIR1,RCIF		; did a receive inerrupt happen?
	goto	LINHandler		; yes, handle it
	bsf	STATUS,RP0
CheckXmitFlag
	btfss	PIE1,TXIE		; is transmit interrupt enabled?
	goto	CheckTMR0Flag		; no, return from interrupt
	bcf	STATUS,RP0
	btfsc	PIR1,TXIF		; yes,
	goto	PutDATAbyte		;  send a byte of data
CheckTMR0Flag
	btfss	INTCON,T0IF
	goto	RestoreStatus
; **** INCREASE 16 BIT CLOCK TIMER *******
	INCF	CNT_LW,1		; INCREASE 16 COUNTER
	BTFSC	STATUS,Z		; INCR MS BYTE IF ZERO (OVERFLOW)
	INCF	CNT_HI,1
	bcf	INTCON,T0IF

RestoreStatus
; **** Restore status and wreg ****
	CLRWDT				; RESET WATCHDOG TIMER
	bcf     STATUS,RP0        ; ensure file register bank set to 0
	movf    status_temp,w     ; retrieve copy of STATUS register
	movwf	STATUS            ; restore pre-isr STATUS register contents
	swapf   w_temp,f
	swapf   w_temp,w          ; restore pre-isr W register contents
	retfie                    ; return from interrupt



		; ***********************************************************************
		; * Initialization							*
		; ***********************************************************************

main
	clrf	ADDRESS

	movlw	B'00000111'	; comparators off
	movwf	CMCON0
	bsf	STATUS,RP0
	movlw	B'00000000'	; Set calibration of internal oscillator
	movwf   OSCTUNE         ; update register with factory cal value 
	movlw	B'00000010'	; AN1 - analogue channel
	movwf	ANSEL
	movlw	B'00010000'	; ADC conversion clock - Fosc/8
	movwf	ADCON1
	movlw	B'00010011'	; pullups=ON, int=falling edge, T0=timer, T0prescale=1:256
				;  @4MHz, T0 is clocked every 64us and rollover every 16.384mS
	movwf	OPTION_REG
	movlw	TRISAset
	movwf	TRISA		; 
	movlw	TRISCset	; 
	movwf	TRISC		; 
	bcf	STATUS,RP0
	movlw	B'11111111'
	movwf	PORTA
	movlw	b'11111100'
	movwf	PORTC		; all outputs off, LINRX and TX high
	movlw	PA_ADC1CON		; Setup A/D Converter
	movwf	ADCON0
	bsf	ADCON0,GO		; start conversion
	clrf	CNT_LW			; clear long timer
	clrf	CNT_HI	

	clrf	WindowLiftStatus

	call	SetupLINUSART
	clrf	ID_TEMP
	clrf	DATAPOINTER


		; ***********************************************************************
		; * Main routine.                                       		*
		; ***********************************************************************
		
MainRoutine
	bsf	INTCON,T0IE
	bsf	INTCON,PEIE
	bsf	INTCON,GIE
MainLoop
CheckSeekID
	movfw	MESSAGE_COUNTER	; if message counter not equal to 12
	xorlw	.12
	btfss	STATUS, Z
	goto	Main_0		; then, message reception not complete, return
	movfw	ID_TEMP		; copy ID_TEMP into w-register
	andlw	0x3F
	xorlw	Slave0out	; check if this ID is acceptable
	btfss	STATUS, Z	; check zero flag
	goto	Main_0		; no, not correct ID
	movfw	DATAPOINTER	; get first data byte
	xorlw	0x02		; is this a DOWN command
	btfsc	STATUS,Z
	goto	BusWindowUp
	movfw	DATAPOINTER	; get first data byte
	xorlw	0x01		; is this a UP command
	btfsc	STATUS,Z
	goto	BusWindowDown
	goto	Main_0
BusWindowDown
	comf	DATAPOINTER,f
	goto	WindowDown
BusWindowUp
	comf	DATAPOINTER,f
	goto	WindowUp

Main_0
	call	ReadSwitchInput		;
	movfw	ButtonImage
	andlw	0x01		; is this a DOWN command
	btfss	STATUS,Z
	goto	WindowDown
	movfw	ButtonImage
	andlw	0x02		; is this a UP command
	btfss	STATUS,Z
	goto	WindowUp

StopWindow
	movfw	ButtonImage
	btfss	STATUS,Z
	goto	MainLoop
	movfw	DATAPOINTER
	btfss	STATUS,Z
	goto	MainLoop

	bcf	UpDirection
	bcf	DwnDirection
	clrf	WindowLiftStatus
	goto	MainLoop

;------------------------------------------------------------------------------
WindowUp
	bcf	DwnDirection
	bsf	UpDirection		;
	comf	WindowLiftStatus,w 	; get complement of status
	btfss	STATUS,Z		; if previus status was not up
	goto	InitialSpike		; then wait some time for current spike
	call	FastReadInput		; get current value acroos shunt
	sublw	VoltageThreshold	; subtract value from constant
	btfsc	STATUS,C		; if V <= Threshold
	goto	$+2			; then, continue
	goto	EmergencyReverse	; else, reverse motor
RunState
	movlw	0xff			; 
	movwf	WindowLiftStatus
	goto	Main_0			; return
InitialSpike
	call	Wait20			; wait until into initial ramp
	call	FastReadInput		; get current value acroos shunt
	sublw	VoltageThreshold	; subtract value from constant
	btfsc	STATUS,C		; if V <= Threshold
	goto	RunState		; then, continue
	clrf	WindowLiftStatus
	goto	Main_0			; return

EmergencyReverse
	bcf	UpDirection
	bsf	DwnDirection			; 
	call	WAIT250
	call	WAIT250
	bcf	DwnDirection		; stop motor
	bcf	UpDirection
	call	WAIT250
	call	WAIT250
	movlw	0x80			; else, continue
	movwf	WindowLiftStatus
	goto	Main_0			; return
	
;------------------------------------------------------------------------------
WindowDown
	bcf	UpDirection
	bsf	DwnDirection			; 
	goto	Main_0			; return

;------------------------------------------------------------------------------
; FUNCTION		; ReadXInput (ADRESH) X = Wreg
; DESCRIPTION		; Read X-position pot ADC channel and return value in W
; REGISTERS USED	; Wreg,ADCON0,ADRESH,ADRESL
;------------------------------------------------------------------------------
ReadXInput
	movwf	ADCON0			; Setup A/D Converter
ADCSetupDelay
	movlw	.3
	movwf	DLY_CNT0
	decfsz	DLY_CNT0,F
	goto	$-1
FastReadInput
	bsf	ADCON0,GO		; start another conversion
RXI1
	btfsc	ADCON0,GO		; wait for conversion to complete
	goto	RXI1
	movfw	ADRESH			; get conversion value
	return

;------------------------------------------------------------------------------
; FUNCTION		; ReadFastInput (ADRESH) X = Wreg
; DESCRIPTION		; Read X-position pot ADC channel and return value in W
;			; Assume channel was selected and conversion was started previously
; REGISTERS USED	; Wreg,ADCON0,ADRESH,ADRESL
;------------------------------------------------------------------------------
ReadFastInput
	btfsc	ADCON0,GO		; wait for conversion to complete
	goto	$-1
	movfw	ADRESH			; get conversion value
	bsf	ADCON0,GO		; start another conversion
	return

;------------------------------------------------------------------------------
; FUNCTION		; ReadSwitchInput (ADRESH)
; DESCRIPTION		; Read switched through ADC channel and return value in W
; REGISTERS USED	; Wreg,ADCON0,ADRESH,ADRESL
;------------------------------------------------------------------------------
ReadSwitchInput
	comf	PORTA,0
	andlw	ButtonMask
	movwf	ButtonImage
	swapf	ButtonImage,1
	movfw	ButtonImage
	btfsc	STATUS,Z	; if zero flag set,	
	retlw	0		; then, no buttons down
	return			; one or more buttons down
;------------------------------------------------------------------------------
;
; FUNCTION        : WAIT ()
;
; DESCRIPTION     : WAIT FOR DLY_CNT0 TIMES 1 MS
;			DLY_CNT1 = OSC/[4*6*1000]  [ 1MS ]
;
; PAGE		: 2
;
;------------------------------------------------------------------------------
Wait20
	MOVLW	D'20'			; DELAY COUNTER FOR 20 MS
	MOVWF	DLY_CNT0
	goto	WAIT001
Wait125
	MOVLW	D'125'			; DELAY COUNTER FOR 125 MS
	MOVWF	DLY_CNT0
	goto	WAIT001
WAIT250
	MOVLW	D'250'			; DELAY COUNTER FOR 250 MS
	MOVWF	DLY_CNT0
WAIT001
	MOVLW	D'200'			; DELAY COUNTER FOR 1 MS
	MOVWF	DLY_CNT1
WAIT1
	NOP				; [1] WASTE TIME
	CLRWDT				; [1]
	DECFSZ	DLY_CNT1,F		; [1]
	GOTO	WAIT1			; [2]

	DECFSZ	DLY_CNT0,F		; [1]
	GOTO	WAIT001			; [2]
	RETLW	0

;------------------------------------------------------------------------------
 subtitle "EEPROM Access Routines"
 page
;------------------------------------------------------------------------------
;
; FUNCTION     	: EEWRITE ()	      			
;
; DESCRIPTION  	: WRITE 8 BIT VALUE TO EEPROM 
;
;------------------------------------------------------------------------------
EE_CLEAR
	MOVLW	00H			; CLEAR 8 BIT W-REGISTER

; ******** WRITE 8-BIT WORD TO EEPROM *********

EEWRITE
	BSF	STATUS,RP0		; Select Bank 1
	MOVWF	EEDATA			; Data value to write
	BCF	STATUS,RP0		; Re-Select Bank 0
	MOVFW   ADDRESS			; GET EEPROM ADDRESS
	BSF	STATUS,RP0		; Select Bank 1
	MOVWF	EEADR			; Data memory to write

EEWRITE2
	BCF	EECON1,EEPGD		; Select Data Memory (E2)
	BSF	EECON1,WREN		; Command Write Enable
	MOVLW	55H
	MOVWF	EECON2			; Write 55H
	MOVLW	0AAH
	MOVWF	EECON2			; Write AAH
	BSF	EECON1,WR		; Command Write

WR_WAIT
	CLRWDT
	BTFSC	EECON1,WR		; Wait for write to complete
	GOTO	WR_WAIT

; ******* EEPROM WRITE DISABLE ****************

EEWRITE3
	BCF	EECON1,WREN		; Disable writes
	BCF	STATUS,RP0		; Select Bank 0
	INCF	ADDRESS,F		; Auto-increase Address Pointer
	RETLW	0H

;------------------------------------------------------------------------------
;
; FUNCTION     	: EEREAD ()	      			
;
; DESCRIPTION  	: READ 8 BIT VALUE FROM EEPROM
;
;------------------------------------------------------------------------------
EEREAD
        MOVFW   ADDRESS
	BSF	STATUS,RP0		; Select Bank 1
	MOVWF	EEADR			; Data memory address to read
	BCF	EECON1,EEPGD		; Select Data Memory (E2)
	BSF	EECON1,RD		; Command read
	MOVF	EEDATA,W		; Get data
	BCF	STATUS,RP0		; Select Bank 0
	INCF	ADDRESS,F		; Auto-increase Address Pointer
	RETURN				; Return without changing w-register

;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
		ORG ((HIGH $)+1) * 100H
	#Include <UART688i.asm>
;------------------------------------------------------------------------------
	#include <IDtable.inc>
;------------------------------------------------------------------------------
		END                      ; directive 'end of program'

