PIC Microcontoller Bit Math Method

Counting how many bits are set

Dmitry Kiryashov [zews at AHA.RU] says

Below the examples of convertation of 8 bits input value to bit sum.
; On fly solution
; 7 clocks per convertation , 256 bytes for table is required

        movfw   portX
        call    bit_cnt
;...
bit_cnt:
        addwf   pcl,f
;256 bytes of data at all
        dt      0,1,1,2,1,2,2,3,.....


; Less program memory requiring solution
; 14 clock per convertation but only
; 14 words of program memory is required

        movfw   portX
        movwf   temp_w

        andlw   0x77
        addwf   temp_w,f
        rrf     temp_w,f

        andlw   0x33
        addwf   temp_w,f
        rrf     temp_w,f

        andlw   0x11
        addwf   temp_w,f
        rrf     temp_w,f

        swapf   temp_w,w
        addwf   temp_w,w
        andlw   0x0F

According to your requirements you will choose the right way.
Good luck ;-)

Brian Scearce [bls at BEST.COM] says

bits_set_in_lower_half:
        andlw   0x0f
        addwf   pcl, w
        retlw   0       ; 0000
        retlw   1       ; 0001
        retlw   1       ; 0010
        retlw   2       ; 0011
        retlw   1       ; 0100
        retlw   2       ; 0101
        retlw   2       ; 0110
        retlw   3       ; 0111
        retlw   1       ; 1000
        retlw   2       ; 1001
        retlw   2       ; 1010
        retlw   3       ; 1011
        retlw   2       ; 1100
        retlw   3       ; 1101
        retlw   3       ; 1110
        retlw   4       ; 1111


        movf    portX, w
        movwf   tmp_w
        call    bits_set_in_lower_half
        movwf   sum
        swapf   tmp_w, w
        call    bits_set_in_lower_half
        addwf   sum, f

This is both slower (19 clocks vs. 14) and larger (25 words vs. 14) than Dmitry Kiryashov's amazing solution to the problem, but it does have the advantage of clarity.

There's also the trick that "X & (X-1)" clears the lowest set bit on X; you might be able to take advantage of that, especially if you can fix the threshold number of bits. I don't have my PIC book with me, pardon me if I get tests backward or forget which instructions can set the Z-flag, but I think you can get the gist from this code:

        clrf    sum
        movf    portX, w
        movwf   tmp_w
loop:
        btfsc   status, z
         goto   done
        incf    sum, f
        decf    tmp_w, f
        andwf   tmp_w, w
        movwf   tmp_w
        goto    loop
done:

Only ten instructions, but it takes longer the more 1's there are. If you can fix the threshold number of 1's, you can make it better. Say you require at least three bits be set:

        movlw   3
        movwf   count
        movf    portX, w
        movwf   tmp_w
loop:
        btfsc   status, z
         goto   not_enough_set
        decf    tmp_w, f
        andwf   tmp_w, w
        movwf   tmp_w
        decfsz  count, f
         goto   loop
        goto    enough_set

Twelve instructions, but you save two instructions by not needing to do a compare and test after the number of set bits has been calculated, and this one will finish early if possible.

And, of course, if the threshold is fixed and high enough, you can do it with inlined code:

        comf    portX, w
        btfsc   status, z
         goto   eight_bits_set
        movwf   tmp_w
        addlw   -1
        andwf   tmp_w, w
        btfsc   status, z
         goto   seven_bits_set
fewer_than_seven_bits_set:

see also:

Comments: