;**********************************************************************
;    Filename:        lampctr.asm                                     *
;    Date:            2003-02-22                                      *
;    File Version:    1.0                                             *
;                                                                     *
;    Author:          Per Zander                                      *
;**********************************************************************
;    Files required:  p16c505.inc                                     *
;********************************************************************** 
;   Description:                                                     
;
;    This is a program for turning 8 different lamps on and off in 
;    different sequences. There are four alternative sequences, that are
;    selected by the inputs RB4 and RB5. 
;
;    Sequence 0 (RB5 and RB4 low). Total 20 s:
;      
;    On:  L0 (5s) L1 (2s) L2 (4s) L3 (1s) L4 (3s) L5 (4s) L6 (1s) L7 
;    Off: L4 (2s) L2 (5s) L6 (3s) L1 (2s) L7 (1s) L0 (5s) L5 (2s) L3
;
;    Sequence 1 (RB5 low, RB4 high). Total 11 s on, 13 s off:
;
;    On:  L0 (2s) L1 (1s) L2 (2s) L3 (1s) L4 (2s) L5 (2s) L6 (1s) L7
;    Off: L4 (1s) L2 (3s) L6 (3s) L1 (1s) L7 (1s) L0 (3s) L5 (1s) L3
;
;    Sequence 2 (RB5 high, RB4 low). Total 20 s: 
;
;    On:  L4 (2s) L2 (5s) L6 (3s) L1 (2s) L7 (1s) L0 (5s) L5 (2s) L3
;    Off: L0 (5s) L1 (2s) L2 (4s) L3 (1s) L4 (3s) L5 (4s) L6 (1s) L7
;
;    Sequence 3 (RB5 and RB4 high). Total 13 s on, 11 s off: 
;
;    On:  L4 (1s) L2 (3s) L6 (3s) L1 (1s) L7 (1s) L0 (3s) L5 (1s) L3
;    Off: L0 (2s) L1 (1s) L2 (2s) L3 (1s) L4 (2s) L5 (2s) L6 (1s) L7
;
;    The selected sequence is started by a positive pulse on RC5. The 
;    first pulse after reset will start an "on" sequence, next one starts
;    an "off" sequence etc.
;
;**********************************************************************

;*---------- Device select. ----------*

	  list      p=16c505            ; List directive to define processor
	  #include <p16c505.inc>        ; Processor specific variable definitions

;*---------- Configuration specification. ----------*

	  __CONFIG   _CP_OFF & _WDT_OFF & _MCLRE_ON & _IntRC_OSC_RB4EN

;*---------- Port definitions. ----------*

sel0    EQU     0x04               ; Select0 on RB4
sel1    EQU     0x05               ; Select1 on RB5  
din     EQU     0x05               ; Data in on RC5     
p0      EQU     0x00               ; Port 0  on RB0                 
p1      EQU     0x01               ; Port 1  on RB1
p2      EQU     0x02               ; Port 2  on RB2
p3      EQU     0x00               ; Port 3  on RC0 
p4      EQU     0x01               ; Port 4  on RC1
p5      EQU     0x02               ; Port 5  on RC2
p6      EQU     0x04               ; Port 6  on RC4
p7      EQU     0x03               ; Port 7  on RC3

;*---------- Variable definitions. ----------*

tmp     EQU     0x08               ; Temporary variable. 
short   EQU     0x08
medium  EQU     0x09
long    EQU     0x0a
stst    EQU     0x0b               ; State pointer for start pulse detect.
flags   EQU     0x0c               ; Program flags.
seqstep EQU     0x0d               ; Where are we in the sequence. 
seqtmr  EQU     0x0e               ; Step time.

;*---------- Program flags. ----------*

start   EQU     0x00               ; Start flag on bit 0.    
on      EQU     0x01               ; Indicates "on" or "off" sequence.  

;**********************************************************************
;* The program starts here after reset.
;**********************************************************************

        ORG     0x3FF             ; Processor reset vector.

        movlw   0x38              ; Osc. cal. value.

        ORG     0x000             ; Coding begins here.

startofprog

        movwf   OSCCAL            ; Update register with factory cal value. 
        clrf    FSR               ; Ensure FSR register points to Bank0. 
        goto    init_code         ; Jump over a few words to enable
                                  ; reprogramming.
        ORG     0x006                                 

;***************************************************************
; A 3.959 ms delay loop, i.e. 3959 instruction cycles.         * 
; (including call and return time).                            *
;***************************************************************

wait_4ms

        movlw   4
        movwf   medium
                
wait_4ms_outer
        
        movlw   0xf6
        movwf   short
 
wait_4ms_inner

        nop
        decfsz  short, F
        goto    wait_4ms_inner   

wait_4ms_endi

        decfsz  medium, F
        goto    wait_4ms_outer
        goto    wait_4ms_end

wait_4ms_end
        
        retlw   0       

;***************************************************************
; State machine for detecting start pulses.                    * 
; This consumes 13 cycles, including call and return.          *
;***************************************************************
        
;*---------- Jump to current state. ----------*

start_det

        movf    stst, W           
        movwf   PCL                

;*---------- Idle state. ----------*

st_idle                               

        movlw   st_idle
        btfsc   PORTC, din
        movlw   st_hi1
        goto    st_epilog

;*---------- High detected once. ----------*

st_hi1

        movlw   st_idle
        btfsc   PORTC, din
        movlw   st_hi2
        goto    st_epilog

;*---------- High detected twice. ----------*

st_hi2

        movlw   st_idle
        btfsc   PORTC, din
        movlw   st_hi3
        goto    st_epilog
     
;*---------- High detected three times. ----------*

st_hi3

        movlw   st_idle
        btfsc   PORTC, din
        bsf     flags, start
        btfsc   flags, start  
        movlw   st_hi4

st_epilog

        movwf   stst
        retlw   0

;*---------- High detected four times. ----------*

st_hi4

        movlw   st_hi4
        btfss   PORTC, din
        movlw   st_lo1
        goto    st_epilog
     
;*---------- Low detected once. ----------*

st_lo1

        movlw   st_hi4
        btfss   PORTC, din
        movlw   st_lo2
        goto    st_epilog

;*---------- Low detected twice. ----------*

st_lo2

        movlw   st_hi4
        btfss   PORTC, din
        movlw   st_lo3
        goto    st_epilog

;*---------- Low detected three times. ----------*

st_lo3

        movlw   st_hi4
        btfss   PORTC, din
        movlw   st_idle
        goto    st_epilog

;***************************************************************
; Sequence subroutine. Set a lamp and return the next          * 
; interval time (in units of 0.1 seconds). Takes 21 cycles.    *
; It uses a sequence table in the upper program bank.          * 
;***************************************************************

sequence
     
        movf    seqstep, W
        movwf   tmp   
        rlf     tmp, F            ; Sequence step * 2.
        bcf     tmp, 0
        btfss   flags, on           
        bsf     tmp, 4            ; Add 16 if "off" sequence.
        btfsc   PORTB, sel0       ; Select alternative.  
        bsf     tmp, 5
        btfsc   PORTB, sel1
        bsf     tmp, 6
        movlw   new_tab & 0xff    
        movlw   seq_tab & 0xff    ; Make this a nop if a new table is loaded.
        addwf   tmp, W
        bsf     STATUS, PA0       ; Select upper bank. 
        movwf   PCL               ; Jump into table.

;***************************************************************
; Short delay.                                                 * 
;***************************************************************

short_del

        retlw   0

;***************************************************************
; Main program.                                                * 
;***************************************************************

;*---------- Here is the initialization code. ----------*

init_code

        movlw   0xc7             ; Internal timer clock, max prescaler.
        option 
        clrf    PORTB            ; Clear output ports.             
        clrf    PORTC 
        movlw   0x38             ; Set output ports to out. 
        tris    PORTB             
        movlw   0x20
        tris    PORTC
        clrf    flags
        movlw   st_idle
        movwf   stst
        movlw   0x08
        movwf   seqstep
        movlw   0x19
        movwf   long
        movlw   0x01
        movwf   seqtmr                 

;*---------- Here is the main loop. ----------*

main
        call    wait_4ms         ; t0 - t3958
        call    start_det        ; t3959 -t3971
        call    short_del        
        call    short_del        
        call    short_del       
        call    short_del 

        btfss   flags, start     ; t3988        
        goto    no_start 
        bcf     flags, start
        movlw   2
        xorwf   flags, F         ; Toggle on/off state.
        clrf    seqstep          ; Start the sequence.  
        call    short_del
        goto    main             ; t3999 

no_start

        btfsc   seqstep, 3       ; t3991
        goto    no_seq           ; No sequence running if seqstep = 8.
        decfsz  long, F          
        goto    go_main          ; t3995 ; long timed out.       
        movlw   0x19
        movwf   long             ; Re-initialize long.
        decfsz  seqtmr, F 
        goto    main             ; t3999

;----- Here we go to the next step in the sequence. -----*

        nop
        call    wait_4ms         ; t0 - t3974
        call    start_det        ; t3959 - t3971
        call    sequence         ; t3972 - t3991
        bcf     STATUS, PA0      ; Select program bank 0.      
        movwf   seqtmr 
        incf    seqstep, F
        decf    long, F
        nop 
        goto    main

;----- Some steps to equalize loop timing. -----*
        
no_seq                          
       
        goto    go_main
go_main

        nop
        nop
        goto    main             ; t3999 


;***************************************************************
; Sequence tables. Set a lamp and return the next              *                                                                                      
; interval time (in units of 0.1 seconds).                     * 
;***************************************************************

        org     0x200   

new_tab

        org     0x280      ; Allows a new table to be loaded at 0x200.
                                        
seq_tab

        ;----- On sequence 0. -----*

        bsf     PORTB, p0
        retlw   0x32             ; 50 decimal. 
        bsf     PORTB, p1
        retlw   0x14             ; 20 decimal
        bsf     PORTB, p2
        retlw   0x28             ; 40 decimal
        bsf     PORTC, p3
        retlw   0x0a             ; 10 decimal
        bsf     PORTC, p4
        retlw   0x1e             ; 30 decimal
        bsf     PORTC, p5
        retlw   0x28
        bsf     PORTC, p6
        retlw   0x0a
        bsf     PORTC, p7
        retlw   1
         
        ;----- Off sequence 0. -----*

        bcf     PORTC, p4
        retlw   0x14
        bcf     PORTB, p2
        retlw   0x32
        bcf     PORTC, p6
        retlw   0x1e
        bcf     PORTB, p1
        retlw   0x14
        bcf     PORTC, p7
        retlw   0x0a
        bcf     PORTB, p0
        retlw   0x32
        bcf     PORTC, p5
        retlw   0x14
        bcf     PORTC, p3
        retlw   1

        ;----- On sequence 1. -----*

        bsf     PORTB, p0
        retlw   0x14
        bsf     PORTB, p1
        retlw   0x0a
        bsf     PORTB, p2
        retlw   0x14
        bsf     PORTC, p3
        retlw   0x0a
        bsf     PORTC, p4
        retlw   0x14
        bsf     PORTC, p5
        retlw   0x14
        bsf     PORTC, p6
        retlw   0x0a
        bsf     PORTC, p7
        retlw   1
         
        ;----- Off sequence 1. -----*

        bcf     PORTC, p4
        retlw   0x0a
        bcf     PORTB, p2
        retlw   0x1e
        bcf     PORTC, p6
        retlw   0x1e
        bcf     PORTB, p1
        retlw   0x0a
        bcf     PORTC, p7
        retlw   0x0a
        bcf     PORTB, p0
        retlw   0x1e
        bcf     PORTC, p5
        retlw   0x0a
        bcf     PORTC, p3
        retlw   1

        ;----- On sequence 2. -----*
  
        bsf     PORTC, p4
        retlw   0x14
        bsf     PORTB, p2
        retlw   0x32
        bsf     PORTC, p6
        retlw   0x1e
        bsf     PORTB, p1
        retlw   0x14
        bsf     PORTC, p7
        retlw   0x0a
        bsf     PORTB, p0
        retlw   0x32
        bsf     PORTC, p5
        retlw   0x14
        bsf     PORTC, p3
        retlw   1

        ;----- Off sequence 2. -----*

        bcf     PORTB, p0
        retlw   0x32
        bcf     PORTB, p1
        retlw   0x14
        bcf     PORTB, p2
        retlw   0x28
        bcf     PORTC, p3
        retlw   0x0a
        bcf     PORTC, p4
        retlw   0x1e
        bcf     PORTC, p5
        retlw   0x28
        bcf     PORTC, p6
        retlw   0x0a
        bcf     PORTC, p7
        retlw   1

        ;----- On sequence 3. -----*

        bsf     PORTC, p4
        retlw   0x0a
        bsf     PORTB, p2
        retlw   0x1e
        bsf     PORTC, p6
        retlw   0x1e
        bsf     PORTB, p1
        retlw   0x0a
        bsf     PORTC, p7
        retlw   0x0a
        bsf     PORTB, p0
        retlw   0x1e
        bsf     PORTC, p5
        retlw   0x0a
        bsf     PORTC, p3
        retlw   1

        ;----- Off sequence 3. -----*

        bcf     PORTB, p0
        retlw   0x14
        bcf     PORTB, p1
        retlw   0x0a
        bcf     PORTB, p2
        retlw   0x14
        bcf     PORTC, p3
        retlw   0x0a
        bcf     PORTC, p4
        retlw   0x14
        bcf     PORTC, p5
        retlw   0x14
        bcf     PORTC, p6
        retlw   0x0a
        bcf     PORTC, p7
        retlw   1

endofprog

        END                       ; directive 'end of program'













