 
;-----------------------------------------------------------------------;
; SWCNT.ASM            Counts presses of a pushbutton on RB7            ;
;-----------------------------------------------------------------------;
        LIST P=16F84           ;  tells which processor is used
        INCLUDE "p16f84.inc"   ;  defines various registers etc. Look it over.
        ERRORLEVEL -224        ;  supress annoying message because of tris
        __CONFIG _PWRTE_ON & _LP_OSC & _WDT_OFF   ;  configuration switches
;-----------------------------------------------------------------------;
;    Here we set up our own registers start at the 1st free address     ;
;-----------------------------------------------------------------------;
           CBLOCK H'0C'
               dlycount         ; counter used in delays
           ENDC
           ORG 0              ; start a program memory location zero
;-----------------------------------------------------------------------;
;        First we set up all bits of PORT A and B as outputs            ;
;-----------------------------------------------------------------------;
         movlw B'00000000'    ; all bits low in W
         tris PORTA           ; contents of W copied to PORT A ...
         movlw B'00010000'    ; RB4 input, all other output
         tris PORTB           ; and PORT B
         movlw B'00000000'    ; port B pull-ups active
         option               
 
;-----------------------------------------------------------------------;
;                       This is the main program                        ;
;-----------------------------------------------------------------------;
         clrf PORTB           ; start with zero
loop:
         btfsc PORTB, 4       ; switch closed, (gives 0)?
         goto loop            ; not yet
                              ; switch has been detected closed
         incf PORTB, f        ; add 1 to port B
                              ; wait a while to make sure switch has 
                              ; settled  (debounce closure)
         movlw D'10'          ; wait about 10 msec
         call nmsec
                              ; now wait for release 
         btfss PORTB, 4       ; will be high (1) when released
         goto $ -1            ; still low
                              ; now must wait a make sure bouncing stopped
         movlw D'10'          ; 10 milliseconds
         call nmsec
                              ; and check again
         btfss PORTB, 4       ; if set, still released
         goto $ -5            ; still low start release wait all over
         goto loop            ; loop forever
;-----------------------------------------------------------------------;
;  Here is a subroutine: delays number of millisec in 'W' on entry      ;
;-----------------------------------------------------------------------;
nmsec:
         movwf dlycount       ; save 'W' in a register of our own
dlyloop: 
         nop                  ; each nop is 0.122 milliseconds
         nop
         nop                  ; each total loop is 8 X 0.122 = 0.976 msec
         nop
         nop
         decfsz dlycount, f   ; this is 0.122 msec if skip not taken
         goto dlyloop         ; this is  2 X 0.122 msec  
         return               ; back to calling point
         end                  ; end of program
Time delays can be handled by using the time taken to execute instructions rather than waiting for a flag set by at timer overflow. An advantage of the PIC instruction set is that almost all instructions take the same amount of time to execute. This is the period of the oscillator divided by four. For a 4 mHz crystal this is 1 microsecond. For a 32.768 kHz crystal it is about 122 microseconds. The only exceptions to this are when the next instruction is not the next in sequence, (goto,call,return,btfss etc.). In these cases, the program counter has to be changed and the instruction takes two instruction cycles rather than one. Notice the delay subroutine at the end of the program which delays for the number of milliseconds given in 'W' on entry.
I no longer recommend attaching loose wires to the test circuit. The problem is that if these are made outputs they can move around and short against something else. I recently smoked a power supply and burnt out some ports on a PIC. I think the problem was loose wires. For the same reason I also recommend mounting the test circuit board on stand-offs or at least covering the bottom with electrical tape. It is easy to lay the board down on something that will short things out.
You must be concerned with bounce on release also. We cannot loop back and check for closure again as soon as we detect the first open. We must be certain that no bouncing remains on release. In the program, a second check is made after 10 msec and if the switch still appears closed, additional 10 msec check/s are made. A faster way would require checking for a certain number of consecutive highs at regular intervals.
BINCNT.ASM used only what Microchip calls special purpose registers, those built into the chip and given definite names in 'p16F84.inc'. There are 12 of these at register locations 0-11 and that is why our register was defined at location 12, ( H'0C' ). There are 68 eight bit register locations in total. Actually, there are two 'pages' of 68 bit registers, but most are duplicated in both pages, including all of the general purpose registers that we get to make up names for. It is just those few that are different in the two pages that screw everything up. You don't want to know about this 'page flipping' until you have to.
'nop' stands for no operation. It doesn't do anything really but it does take up time and that is what we use it for here. The time taken is one instruction cycle, (the crystal period divided by four), 0.122 msec in this case.
Khristine Joyce de Jesus Cruz of De La Salle University Says:
This tutorial is a big help for me...it helped me eternalize what the datasheet is talkin about. Thank s for the unselfish guys who willingly impart their knowledge....REGARDS n keep helpin'!
See: