;**********************************************************************
;                                                                     *
;    Filename:	    edgedetect.asm                                    *
;    Date:          11-February-2010                                  *
;    File Version:  A                                                 *
;                                                                     *
;    Author:        Pete Griffiths                                    *
;    Company:       http://picprojects.org.uk                         *
;                                                                     *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Files Required: P16F628A.INC                                     *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Notes:                                                           *
;                                                                     *
;**********************************************************************

	list      p=16f628A           ; list directive to define processor
	#include <p16F628A.inc>       ; processor specific variable definitions

	errorlevel  -302              ; suppress message 302 from list file

	__CONFIG   _CP_OFF & _DATA_CP_OFF & _LVP_OFF & _BOREN_OFF & _MCLRE_ON & _WDT_OFF & _PWRTE_ON & _INTOSC_OSC_NOCLKOUT 

; '__CONFIG' directive is used to embed configuration word within .asm file.
; The lables following the directive are located in the respective .inc file.
; See data sheet for additional information on configuration word settings.




;***** VARIABLE DEFINITIONS
                cblock          0x20
                inputs.this_time
                inputs.last_time
                edge.detected
                endc





;**********************************************************************
	ORG     0x000             ; processor reset vector




init            movlw           1<<CM2 | 1<<CM1 | 1<<CM0
                movwf           CMCON                           ; disable comparator, set inputs to digital

                banksel         TRISB                           ; set bank to 1
                movlw           b'11110000'                     ; set inputs/outputs on PORTB
                movwf           TRISB
              

                bcf             OPTION_REG, NOT_RBPU            ; enable weak pull-up on PORTB

                banksel         PORTB                           ; set bank to 0


                
                ; define bit mask
C.input_mask    equ             b'11110000'

                ; Initialise variables at start up
                movfw           PORTB                           ; load PORTB to Wreg
                andlw           C.input_mask                    ; mask out I/O bits we're not interested in
                movwf           inputs.last_time                ; save result to variable
                movwf           inputs.this_time                ; save result to variable


                ; Uncomment line below to assemble code with falling edge detection
                ;goto            edge.fall


;=================================================================================================
                
             
; RISING EDGE DETECT 

                ;---------------------------------
                ; Logic for Rising Edge Detection
                ; I_last I_now  Edge_True
                ;      0     0  0
                ;      0     1  1
                ;      1     1  0
                ;      1     0  0 
                ;---------------------------------

                ; ~~~ no change low ~~~
                ; last_time 00000000
                ; this_time 00000000 XOR
                ;           ======== 
                ;           00000000  
                ; this_time 00000000 AND  
                ;           ========
                ;           00000000  
                ;~~~~~~~~~~~~~~~~~~~~~~~~


                ; ~~~ rising edge ~~~
                ; last_time 00000000
                ; this_time 00010000 XOR
                ;           ======== 
                ;           00010000 
                ; this_time 00010000 AND 
                ;           ========
                ;           00010000  
                ;~~~~~~~~~~~~~~~~~~~~~~~~


                ; ~~~ no change high ~~~
                ; last_time 00010000
                ; this_time 00010000 XOR
                ;           ======== 
                ;           00000000 
                ; this_time 00010000 AND
                ;           ========
                ;           00000000  
                ;~~~~~~~~~~~~~~~~~~~~~~~~


                ; ~~~ falling edge ~~~
                ; last_time 00010000
                ; this_time 00000000 XOR
                ;           ======== 
                ;           00010000  
                ; this_time 00000000 AND 
                ;           ========
                ;           00000000  
                ;~~~~~~~~~~~~~~~~~~~~~~~~




                ; Detect input bits that change from 0 to 1 - rising edge
                ;
edge.rise       movfw           PORTB                           ; load PORTB to Wreg
                andlw           C.input_mask                    ; mask out I/O bits we're not interested in
                movwf           inputs.this_time                ; save result to variable
                xorwf           inputs.last_time,W              ; XOR last input value with current input value
                andwf           inputs.this_time,W              ; keep only bits that have changed from 0 to 1
                movwf           edge.detected                   ; save result to variable

                movfw           inputs.this_time                ; copy input.this_time to input.last_time
                movwf           inputs.last_time                ; ready for next pass

                call            output                          ; for purpose of the demo, send result to outputs

                goto            edge.rise                       ; run edge detect code loop again

;=================================================================================================
                
             
; FALLING EDGE DETECT 

                ;---------------------------------
                ; Logic for Falling Edge Detection
                ; I_last I_now  Edge_True
                ;      0     0  0
                ;      0     1  0
                ;      1     1  0
                ;      1     0  1 
                ;---------------------------------
   

                ; ~~~ no change low ~~~
                ; last_time 00000000
                ; this_time 00000000 OR
                ;           ======== 
                ;           00000000  
                ; last_time 00000000 AND 
                ;           ========
                ;           00000000 
                ;~~~~~~~~~~~~~~~~~~~~~~~~


                ; ~~~ rising edge ~~~
                ; last_time 00000000
                ; this_time 00010000 XOR
                ;           ======== 
                ;           00010000  
                ; last_time 00000000 AND 
                ;           ========
                ;           00000000  
                ;~~~~~~~~~~~~~~~~~~~~~~~~


                ; ~~~ no change high ~~~
                ; last_time 00010000
                ; this_time 00010000 XOR
                ;           ======== 
                ;           00000000  
                ; last_time 00010000 AND  
                ;           ========
                ;           00000000  
                ;~~~~~~~~~~~~~~~~~~~~~~~~


                ; ~~~ falling edge ~~~
                ; last_time 00010000
                ; this_time 00000000 XOR
                ;           ======== 
                ;           00010000  
                ; last_time 00010000 AND  
                ;           ========
                ;           00010000  
                ;~~~~~~~~~~~~~~~~~~~~~~~~


                ; Detect input bits that change from 1 to 0 - falling edge
                ;
edge.fall       movfw           PORTB                           ; load PORTB to Wreg
                andlw           C.input_mask                    ; mask out I/O bits we're not interested in
                movwf           inputs.this_time                ; save result to variable
                xorwf           inputs.last_time,W              ; XOR last input value with current input value
                andwf           inputs.last_time,W              ; keep only bits that have changed from 0 to 1
                movwf           edge.detected

                movfw           inputs.this_time                 ; copy input.this_time to 
                movwf           inputs.last_time                 ; input.last_time ready for next pass

                call            output

                goto            edge.fall

                ;=================================================================================================


                ; Write edge detect to output
                ; This code is just to show the edge detecion in the simulator.  
                ; In your own code you'll want to do something useful with the edge.detected variabe 

output         swapf           edge.detected,W                  ; since we use 4 bits as input and 4 as output on 
               movwf           PORTB                            ; the same port, swap nibbles and write to PORTB
               return



	END                       ; directive 'end of program'



