Auster
Auster

Reputation: 11

More than 256 operations in an 8 bit pic16F assembler

I am a rookie in assembly programming and I am currently doing a project using a temperature sensor on MPLAB and it's values to be displayed on a LCD.

In order to convert the raw values (0 to 255 based on the output voltage) from the sensor to the LCD I need to do an affine function (8x+1000)/100. But here is the problem, since my microprocessor is in 8 bit, I cannot divide by 100.

Here is the code :

    
    MOVLW d'50'
    MOVWF CAN_Val_Brut;----------------------------------MULTIPLICATION
    clrf CAN_Val_Dec
    clrf CAN_Val_Decp1
    movlw .8
    movwf mpy_cnt
    movlw .8
    bcf STATUS,C
mpy rrf CAN_Val_Brut,f
    btfsc STATUS,C
    addwf CAN_Val_Decp1,f
    rrf CAN_Val_Decp1,f
    rrf CAN_Val_Dec,f
    decfsz mpy_cnt,f
    goto mpy        
;-------------------------------------------------------------ADDITION

;------Je met 1000 dans a et aplus1----
movlw .3;00000011
movwf aplus1
movlw .232;11101000
movwf a

movf a,w
addwf CAN_Val_Dec,f
btfsc STATUS,C
incf CAN_Val_Decp1,f
movf aplus1,w
addwf CAN_Val_Decp1,f

;-----------------------------------------------DIVISION
    movlw .8
    movwf dvy_cnt
    movlw .100
    bcf STATUS,C
dvy 
    btfsc STATUS,C
    addwf CAN_Val_Decp1,f
    rlf CAN_Val_Decp1,f
    rlf CAN_Val_Dec,f
    decfsz dvy_cnt,f
    goto dvy

If someone have a code for 2x8bits division I am glad to take a look :)

Thank you for your help !

Upvotes: 1

Views: 433

Answers (1)

Brendan
Brendan

Reputation: 37222

My 1st step would be to realize that (8x + 1000)/100 is the same as 8x/100 + 1000/100, or x/12.5 + 10 or x*0.08 + 10.

Of course integer maths doesn't like 0.08. We can convert it to shifts and additions using integers. In binary, 0.08 is 0.00010100011110101110000101000111...b. This means that we can convert x*0.08 into something like x*0.0001b + x*0.000001b + x*0.0000000001 + ..., where the multiplications can be done with right shifts. This gives us something like x>>4 + x>>6 + x>>10 + x>>11 + x>>12 + x>>13 + x>>15 ... + 10.

There are 2 problems with this. The first problem is rounding - e.g. if x is an 8-bit value, then x>>10 will be zero (all of the bits in x will be shifted out), which will increase "error due to rounding". The second problem is that 0.08 in binary is an infinite number of bits, so you must choose where to stop and must have some precision loss.

For the 2nd problem, for your purposes (where x is a relatively imprecise number to begin with) 0.000101001b (or 0.0001010001111 rounded up a little) is likely to be plenty of precision. This gives us x>>4 + x>>6 + x>>9 + 10.

For the first problem, we can improve precision by doing addition before shifting. x>>9 + x>>6 + x>>4 + 10 is the same as x>>3>>6 + x>>6 + x>>4 + 10 or (x>>3 + x)>>6 + x>>4 + 10 or (x>>3 + x)>>2>>4 + x>>4 + 10 or ((x>>3 + x)>>2 + x)>>4 + 10.

For an example (and to check that the results are almost identical to the original formula) we can test it with values of x while being careful to do integer operations that truncate. For x = 255 we get (8*255 + 1000)/100 = 3040/100 = 30 and ((255>>3 + 255)>>2 + 255)>>4 + 10 = ((31 + 255)>>2 + 255)>>4 + 10 = (71 + 255)>>4 + 10 = 30 + 10 = 30.

Note that the intermediate values will require 1 more bit than x has; or if x is 8 bits then you will need 9 bits to store something like x>>3 + x. This is easily solved by using the carry flag as the extra (ninth) bit. Specifically, the formula does the addition of a pair of 8 bit values to get "carry + 8 bit" result, and then you can use an RRF instruction ("rotate right by 1 bit with carry" to reduce it back to 8 bits before using a normal shift for the rest of the bits (where normal shifts don't seem to exist in PIC assembly - I guess "shift right by N" becomes a "mask N-1 low bits, clear carry, then do N rotates with carry that's never set". You don't need any 16-bit maths (if x is 8-bit).

Upvotes: 3

Related Questions