; 6 level lift control simulator. For demonstrating True lift control in PAC software
; Coded January 2011 - IanThor	   
	
		LIST    p=16F84 ; PIC16F84 is the target processor
		#include "P16F84.INC" ; Include header file
        	__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_OFF & _HS_OSC

		CBLOCK 0x10   ; Temporary storage
		state
		l1,l2,level,msdelay,destination,counter,answer,temp
		ENDC

		org	0		; Start up vector.
		goto	setports        ; Go to start up code.

		org	4		; Interrupt vector.
halt		goto	halt            

setports	clrw			; clear Working register.
		movwf	PORTA		; Ensure PORTA is zero before its enabled.
		movwf	PORTB		; Ensure PORTB is zero before its enabled.
		bsf	STATUS,RP0	; Select Bank 1
		movlw	.1          ; Mask 7 bits as outputs. 1st as input for PORTB
		movwf	TRISB		; Set TRISB register (from Working register).   
		movlw	.255		; Mask all bits as inputs for PORTA
		movwf	TRISA		; Set TRISA register.
		bcf	STATUS,RP0      ; Reselect Bank 0.
initialise	clrw			; Initial state.
		movwf   state		; Set it.
;________________________________________________________________________________________
		movlw	.0		; Initialise lift to start at level 0
		movwf	destination	; Set Destination to 0 (copy from Working register) 
		movwf	level		; Set Level also to 0 (copy from Working register)
		call	getdigit	; Go lookup code for the level to show on the 7 segment display
		movwf	PORTB		; display it on PORTB.
;main loop ______________________________________________________________________________
;scan buttons
scan		movlw	.250		; set W = 250
		movwf	temp		; temp = 250 (will cause a carry flag when addition later)
loop		btfsc   PORTA,0		; If button 0 pressed, the next instruction runs.
		movlw   0		; w=0 if above true
		btfsc   PORTA,1		; If button 1 pressed etc etc
		movlw   1		; w=1 if above true etc
		btfsc   PORTA,2
		movlw   2
		btfsc   PORTA,3
		movlw   3
		btfsc   PORTA,4
		movlw   4
		btfsc   PORTB,0
		movlw   5
		movwf   destination	; w (result) into destination	whether it changed or not

					; If a button was pressed, its value will be in W
		addwf	temp,W		; subtract temp from W. Update W with answer.  
		btfss	STATUS,C	; see if carry flag is set in W
		goto	liftdr		; if not set, this will happen
		goto	scan
;___________________________________________________________________________________________
;now we know a button has been pressed, and its value is in 'destination' we need to figure out which
;way the lift needs to travel.

liftdr		call	doneyet		; Just check same button as level were on hasn't been pressed
		movf	level,W		; Get level into Working register	         	 
		subwf	destination,W	; subtract level from destination (in W) update W with answer
					; see if the carry flag is set
		btfsc	STATUS,C	; see if carry flag is set in W
		goto	animup		; Carry flag set, lift goes up
		goto	animdown	; Carry flag clear, lift goes down
;____________________________________________________________________________________________
doneyet		movf	level,W		; Get level into Working register	         	 
		subwf	destination,W	; subtract level from destination (in W) update W with answer
		btfsc	STATUS,Z	; is the answer zero?
		goto	scan		; Yes, go back to scanning buttons
		return			; no, return to where we were
;____________________________________________________________________________________________
animup		movlw	.255		; blank display
		movwf	PORTB		; Write it to port.
		movlw	.100		; set W to 20 (10ms delay) 10 = 100ms delay
		call	wait		; call the delay routine

		movlw	.238		; bottom segment of display
		movwf	PORTB		; Write it to port.
		movlw	.100		; set W to 20 (10ms delay) 10 = 100ms delay
		call	wait		; call the delay routine

		movlw	.126		; middle segment of display
		movwf	PORTB		; Write it to port.
		movlw	.100		; set W to 20 (10ms delay) 10 = 100ms delay
		call	wait		; call the delay routine

		movlw	.253		; top segment of display
		movwf	PORTB		; Write it to port.
		movlw	.100		; set W to 20 (10ms delay) 10 = 100ms delay
		call	wait		; call the delay routine

		movlw	.255		; clear display
		movwf	PORTB		; Write it to port.
		movlw	.155		; set W to 20 (10ms delay) 10 = 100ms delay
		call	wait		; call the delay routine
		incf	level
		call    getdigit
		movwf	PORTB		; Write it to port.
		movlw	.100		; set W to 20 (10ms delay) 10 = 100ms delay
		call	wait		; call the delay routine

		call    doneyet
		goto    animup
;_____________________________________________________________________________________________
animdown	movlw	.255		; blank display
		movwf	PORTB		; Write it to port.
		movlw	.100		; set W to 20 (10ms delay) 10 = 100ms delay
		call	wait		; call the delay routine

		movlw	.253		; top segment of display
		movwf	PORTB		; Write it to port.
		movlw	.100		; set W to 20 (10ms delay) 10 = 100ms delay
		call	wait		; call the delay routine

		movlw	.126		; middle segment of display
		movwf	PORTB		; Write it to port.
		movlw	.100		; set W to 20 (10ms delay) 10 = 100ms delay
		call	wait		; call the delay routine

		movlw	.238		; bottom segment of display
		movwf   PORTB           ; Write it to port.
		movlw	.100		; set W to 20 (10ms delay) 10 = 100ms delay
		call	wait		; call the delay routine

		movlw	.255		; blank display
		movwf	PORTB		; Write it to port.
		movlw	.155		; set W to 20 (10ms delay) 10 = 100ms delay
		call	wait		; call the delay routine
		decf	level		; LEVEL -1
		call	getdigit	; update display
		movwf	PORTB		; Write it to port.
		movlw	.100		; set W to 20 (10ms delay) 10 = 100ms delay
		call	wait		; call the delay routine

		call	doneyet
		goto	animdown
;________________________________________________________________________________
; 5ms delay routine
wait	movwf	msdelay
w1		call	wait2
		decfsz	msdelay
		goto	w1
		return
wait2	movlw	.255
		movwf	l2
w2		nop
		nop
		decfsz	l2
		goto	w2
		return
________________________________________________________________________
; lookup table for displaying numbers on 7 segment display
getdigit	movf	level,W		; Get level into W.
		addwf	PCL,F		; Add offset in W to PCL to calc. goto.
		retlw	.129		; 7 seg number 0
		retlw	.243		; 7 seg number 1
		retlw	.72		; 7 seg number 2
		retlw	.97		; 7 seg number 3
		retlw	.51		; 7 seg number 4
		retlw	.36		; 7 seg number 5
		END

; 129=0 243=1  72=2 97=3 51=4 36 =5