Pulsin

measures the width of a pulse in 10-instruction-cycle units. Returns a 16-bit value and an error code.

Tachometers, duty-cycle meters, capacitor checkers, and precise interval timers can all be implemented with Pulsin.

To use Pulsin, you must set the desired pin to input and supply three arguments: the pulse direction in state (0 = 1-to-0, 255 = 0-to-1), the pin number (0 to 7) in pin, and the port number (0 = RA, 1 = RB, etc.) in w. When Pulsin returns, the 16-bit pulse width will be in hiB and lowB, and an error code in w. State and pin will have been modified by Pulsin for its own use, so your program should keep copies of these variables if needed.

The error codes returned in w are as follows:

Pulsin, like the other routines that accept pin and port arguments, requires the short table Pinz. Remember that tables must be located in the first 256 words of a 512-word program memory page. The same restriction applies if you decide to use a jump table (see Branch) to process the error code in w; the destinations of the calculated jumps must be in the first half of a program memory page.

One hint on using Pulsin: always assign the port number to w immediately before calling the routine. If you don't, some other instruction that uses w may change its contents, causing an error.

Demonstrating Pulsin.

To see Pulsin in operation, connect the circuit below to an erasable PIC or PIC emulator, such as the Parallax downloader. Assemble and run PULSIN.SRC. When you adjust the function generator, the binary value displayed on the LEDs will change.
 



; PULSIN port (in w), pin, state
; Measures the width of an input pulse in 10-cycle (10 us at 4 MHz) units. 
; Returns a 16-bit (0 to 65,535) value. If no pulse occurs within
; 65,535 10-cycle intervals, the routine returns an error code in w. 
; Routine is edge triggered. If the input pin is already in the target state
; when the routine begins, it will wait for the state to change, then wait
; for the specified edge. The routine waits 65,535 x 10 cycles for 
; each edge, so it normally returns within 0.65535 seconds (4 MHz). 
; However, if each transition is delayed by close to the full 65,535 x 10
; cycles, the routine can take nearly 2 seconds to return (4 MHz). 

        org     8
pin     ds      1       ; Pin number to sample (0-7). 
state   ds      1       ; Trigger: 255 = 0-to-1 transition. 
hiB     ds      1       ; MSB of measurement. 
lowB    ds      1       ; LSB of measurement. 

; Device data and reset vector
        device  pic16c55,xt_osc,wdt_off,protect_off
        reset   start
        org     0
; Table to convert pin number (0-7) into bit mask (00000001b to 10000000b). 
Pinz    jmp     pc+w
        retw    1,2,4,8,16,32,64,128

start   mov     !rb,#0  ; Outputs to display result on LEDs. 
        mov     !rc,#0
        mov     !ra, #1111b     ; All inputs
        mov     state,#0        ; Negative pulse. 
        mov     pin,#2  ; Pin 2. 
        mov     w,#0    ; Port ra. 
        call    Pulsin
        mov     rb,lowB ; Write Pulsin result to ports RB
        mov     rc,hiB  ; and RC for viewing on LEDs. 
        jmp     start   ; Do it again. 

; Upon entry, the desired pin must already be set up as an input. 
; The w register contains a number representing the input port (0-2) for 
; RA through RC. Variable pin contains the pin number (0-7). Variable state 
; contains 255 for a 0-to-1 (positive) pulse, or 0 for a 1-to-0 (negative) pulse. 

; Upon exit, the 16-bit count is in variables lowB and hiB. 
; Variable pin contains the mask bit used by pulsin (not the pin number 
; anymore, but a value with a 1 in the pin position), and state has been 
; ANDed with pin. W contains the error code: 0= no error; 1= pin in 
; already in target state when Pulsin was called--timeout waiting 
; for transition; 2= timeout waiting for initial edge; 3= timeout waiting
; for final edge. 

Pulsin  clr     lowB    ; Clear the 16-bit counter. 
        clr     hiB
        mov     fsr,w   ; Point to the port number. 
        add     fsr,#RA ; Add offset for port RA. 
        mov     w,pin   ; Get bit mask from the table. 
        call    Pinz    
        mov     pin,w   ; Put the mask into pin. 
        AND     state,w         ; Mask extra bits out of state.
:Hold   mov     w,indirect      ; Sample the port. 
        AND     w,pin   ; Mask off bits other than pin. 
        XOR     w,state         ; Check pin against state. 
        jnz     :doneH  ; If pin <> state, set up for edge. 
        inc     lowB    ; Otherwise, lowB = lowB+1. 
        snz             ; Overflow in lowB? 
        incsz   hiB     ; Yes: hiB=hiB+1, watch for overflow. 
        jmp     :Hold   ; Sample the pin again. 
        retw    1       ; Overflow in hiB? Timed out: return.
:doneH  clr     lowB
        clr     hiB
:Edge1  mov     w,indirect      ; Sample the port. 
        AND     w,pin   ; Mask off bits other than pin. 
        XOR     w,state         ; Check pin against state. 
        jz      :doneE  ; If pin = state, wait until change. 
        inc     lowB    ; Otherwise, lowB = lowB+1. 
        snz             ; Overflow in lowB? 
        incsz   hiB     ; Yes: hiB=hiB+1, watch for overflow. 
        jmp     :Edge1  ; Sample the pin again. 
        retw    2       ; Overflow in hiB? Timed out: return.
:doneE  clr     lowB
        clr     hiB
:Edge2  mov     w,indirect      ; Sample the port. 
        AND     w,pin   ; Mask off bits other than pin. 
        XOR     w,state         ; Check pin against state. 
        jnz     :done   ; If pin <> state, we're done. 
        inc     lowB    ; Otherwise, lowB = lowB+1. 
        snz             ; Overflow in lowB? 
        incsz   hiB     ; Yes: hiB=hiB+1, watch for overflow. 
        jmp     :Edge2  ; Sample the pin again. 
        retw    3       ; Overflow in hiB? Timed out: return.
:done   ret             ; Done: pulsewidth in hiB, lowB.