; *******************************************************************
; 8-bit retriggerable monoflop, with 35 second output pulse
; *******************************************************************
;
; 2008 Copyright by Frank Buss
; *******************************************************************

            LIST    P=16F628A

#include "P16F628A.INC"

            __CONFIG _INTOSC_OSC_NOCLKOUT & _WDT_OFF &_PWRTE_OFF & _MCLRE_OFF & _BOREN_OFF & _LVP_OFF & _DATA_CP_OFF & _CP_OFF

; defines
Delay       EQU D'35'   ; Monoflop time in seconds
IRQ_W       EQU 0x20
IRQ_S       EQU 0x21
Counter     EQU 0x22
Seconds     EQU 0x23
tmp         EQU 0x25
Monoflop    EQU 0x26    ; array of 8 counters
OldInput    EQU 0x2e
LastInput   EQU 0x2f
Triggered   EQU 0x30
NewOut      EQU 0x31

            org 0
            goto    start

; interrupt function:
; increment the register Seconds each second by one
; ----------------------------------------------------------
            org 4
; interrupt intro
            movwf  IRQ_W        ; save w
            swapf  STATUS, W    ; save STATUS
            movwf  IRQ_S

; interrupt main
            incf    Counter, F

IrqTest:    movlw   D'61'
            xorwf   Counter, W
            btfss   STATUS, Z   ; skip, if zero
            goto    IrqEnd
            clrf    Counter
            incf    Seconds, F

; interrupt end
IrqEnd:
            bcf    INTCON, T0IF ; delete IRQ flag
            swapf  IRQ_S, W     ; restore STATUS
            movwf  STATUS 
            swapf  IRQ_W, F     ; restore W
            swapf  IRQ_W, W
            retfie 

; program start
; ----------------------------------------------------------
start:
; init hardware
            movlw   D'0'        ; set levels low
            movwf   PORTB       ;  for PortB
            movlw   D'7'        ; turn comparators off and
            movwf   CMCON       ;  enable pins for I/O functions
            clrwdt
            bsf     STATUS, RP0 ; select bank 1
            movlw   D'0'        ; all bits of PortB as output
            movwf   TRISB - 0x80
            movlw   D'255'      ; all bits of PortA as input
            movwf   TRISA - 0x80
            movlw   D'5'        ; prescaler: 64
            movwf   OPTION_REG - 0x80
            bcf     STATUS, RP0 ; select bank 0

; clear variable memory
            movlw   0x20
            movwf   FSR
next:       clrf    INDF
            incf    FSR, F
            btfss   FSR, 6
            goto    next

; save current port state
            movf    PORTA, W
            movwf   OldInput

; global interrupt and timer interrupt enable 
            bsf    INTCON, GIE
            bsf    INTCON, T0IE

; main loop         
loop_start: 
; wait one second and accumulate port changes in "Triggered" while waiting
            clrf    Triggered
            movf    Seconds, W
            movwf   tmp         ; save current second counter
wait:       movf    Seconds, W  ; test current second counter
            xorwf   tmp, W
            btfss   STATUS, Z   ; skip, if zero
            goto    trigger
            movf    PORTA, W
            movwf   LastInput   ; save last port state
            xorwf   OldInput, W
            iorwf   Triggered, F    ; OR changed port bits
            goto    wait

; retrigger monoflops for all changed port bits
trigger:
            movf    LastInput, W
            movwf   OldInput    ; last port state will be start for next test

            movlw   Monoflop    ; save address of first Monoflop counter
            movwf   FSR         ; in FSR for indirect addressing
            movlw   8           ; test 8 bits
            movwf   tmp
            clrf    NewOut
trigger2:   bcf     STATUS, C
            rrf     NewOut, F   ; shift new output byte
            movf    Triggered, W
            andlw   D'1'
            btfsc   STATUS, Z   ; skip, if not zero
            goto    OutTest
            movlw   Delay
            movwf   INDF        ; retrigger Monoflop, if input changed

OutTest:    movf    INDF, W
            btfsc   STATUS, Z   ; skip, if not zero
            goto    OutTest2
            bsf     NewOut, 7   ; set ouput bit, if Monoflop is not zero
            decf    INDF, F     ; decrement Monoflop counter

OutTest2:
            bcf     STATUS, C
            rrf     Triggered, F    ; shift triggered bits for next bit
test

            incf    FSR, F
            decf    tmp, F
            btfss   STATUS, Z   ; skip, if zero
            goto    trigger2

            movf    NewOut, W   ; copy new output bits to output port
            movwf   PORTB

            goto    loop_start

            end
