Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

How to handle a 16bit number and get average?

Status
Not open for further replies.
add two together, them divide the result by two (by right shifting). Then add the next number to that result, and divide by two again. Keep doing that until all the numbers are processed - the result is tha average of all the numbers.
Hi Nigel, have I missed somthing? how can you get an average of a set of numbers when you are consecutivley adding a new value to a previous average and dividing by two?
I can see that bsodmike's latest idea works as long as he is working with even sets of figures in multiples of two and rotates accordingly, i.e. the next set of numbers he can multiply is 8, then 16 etc...
The way I approached averaging was to total all numbers and keep a tally of the divadend. The value of this tally would then be subtracted from the total until I reached zero. The number of divisions I make gives your average total. A small routine then rounds up or down depending on whether the final result hit zero or went negative.
 
Dear Olly,

Yea this only works as you have suggested. In the future if I use this again and if the number of items that need to be averaged is fairly large, I'll add the rffing section into another 'loop'. Would it be too much trouble to ask you to post the averaging code you are using? Thanks.
 
olly_k said:
add two together, them divide the result by two (by right shifting). Then add the next number to that result, and divide by two again. Keep doing that until all the numbers are processed - the result is tha average of all the numbers.
Hi Nigel, have I missed somthing? how can you get an average of a set of numbers when you are consecutivley adding a new value to a previous average and dividing by two?

I see what you mean, I've just gone through it and it doesn't work :?

I would suggest probably the best way is some 16 bit maths routines, here are the ones I use - they use three 16 bit registers, Acc1L, Acc1H etc.
Code:
_Sub16       COMF   Acc2H       ; Take two's complement
	COMF   Acc2L       ; of Acc2. If zero, Acc2L
	INCF   Acc2L
	BTFSC  STATUS, Z   ; overflowed, so carry
	INCF   Acc2H       ; into Acc2H.
_Add16       BCF    Flags, OverFlow ; clear overflow flag
	MOVF   Acc2L, w    ; Add the LSBs. If carry,
	ADDWF  Acc1L
	BTFSC  STATUS, C   ; increment MSB of sum.
	INCF   Acc1H
	MOVF   Acc2H, w    ; Add the MSBs
	ADDWF  Acc1H
	BTFSC  STATUS, C   ; check for sum overflow
	BSF    Flags, OverFlow ; set overflow flag
	MOVF   Acc1L, w    ; return lobyte in W
	RETURN
_Mult16
	CLRF   Acc3H          ; Clear product to make
	CLRF   Acc3L         ; way for new calculation.
	MOVLW  d'16'        ; Number of bits to calc.
	MOVWF  TEMP1
Multiply_loop
	BCF    STATUS, C
	RLF    Acc3L         ; Shift product left.
	RLF    Acc3H
	BCF    STATUS, C
	RLF    Acc1L        ; Shift multiplicand left.
	RLF    Acc1H
	BTFSS  STATUS, C    ; If carry, add multiplier
	GOTO   Multiply_skip
	MOVF   Acc2L,w      ; to the product. Else skip.
	ADDWF  Acc3L
	BTFSC  STATUS, C    ; 16-bit addition: prod+mulp
	INCF   Acc3H
	MOVF   Acc2H, w
	ADDWF  Acc3H
Multiply_skip
	DECFSZ TEMP1
	GOTO   Multiply_loop
	MOVF   Acc3H, w
	MOVWF  Acc1H        ; return answer in Acc1
	MOVF   Acc3L, w
	MOVWF  Acc1L        ; with lobyte in W
	RETURN
_DIV16          MOVF    Acc2H, w                ; Check for division by 0.
	IORWF   Acc2L, w
	BTFSC   STATUS, Z
	RETLW   d'255'        ; Error code= 255: return.
	MOVLW   d'1'          ; Otherwise, initialize variables
	MOVWF   TEMP1
	CLRF    TEMP2         ; index for the division.
	CLRF    Acc3H
	CLRF    Acc3L
Divide_sh_loop  BTFSC   Acc2H, d'7'   ; Shift divisor left
	GOTO    Divide_d1
	BCF     STATUS, C     ; until msb is in
	RLF     Acc2L         ; Acc2H.7.
	RLF     Acc2H         ; TEMP1 = no. of shifts+1.
	INCF    TEMP1
	GOTO    Divide_sh_loop
Divide_d1       BCF     STATUS, C
	RLF     Acc3L          ; Shift quotient left.
	RLF     Acc3H
	MOVF    Acc2L,w       ; top = top - btm.
	SUBWF   Acc1L
	BTFSC   STATUS, C     ; If top - btm < 0 then
	GOTO    Divide_d2
	MOVLW   d'1'          ; top = top + btm
	SUBWF   Acc1H
	BTFSC   STATUS, C     ; The idea is to do the
	GOTO    Divide_d2
	INCF    Acc1H         ; the subtraction and comparison
	MOVF    Acc2L, w      ; (top > btm?) in one step.
	ADDWF   Acc1L
	goto    Divide_reentr ; Then, if btm > top, undo <Microchip instruction>
Divide_d2       MOVF    Acc2H, w      ; the subtraction by adding
	SUBWF   Acc1H
	BTFSS   STATUS, C     ; top and btm back together
	goto    Divide_less   ; <Microchip instruction>
	BSF     Acc3L,  d'0'
Divide_reentr
	BCF     STATUS, C
	RRF     Acc2H
	RRF     Acc2L
	DECFSZ  TEMP1
	GOTO    Divide_d1
	MOVF    Acc3H, w
	MOVWF   Acc1H         ; return answer in Acc1
	MOVF    Acc3L, w
	MOVWF   Acc1L         ; with lobyte in W
	RETURN
Divide_less     MOVF    Acc2L, w      ; btm > top, so
	ADDWF   Acc1L
	BTFSC   STATUS, C     ; undo the subtraction by
	INCF    Acc1H         ; adding them back together.
	MOVF    Acc2H, w
	ADDWF   Acc1H
	goto    Divide_reentr ; <Microchip instruction>
_SHIFTR         MOVWF    Acc2L
_LoopR          BCF      STATUS, C
	RRF      Acc1H, F
	RRF      Acc1L, F
	DECFSZ   Acc2L
	GOTO     _LoopR
	MOVF     Acc1L, W
	RETURN
_SHIFTL         MOVWF    Acc2L
_LoopL          BCF      STATUS, C
	RLF      Acc1L, F
	RLF      Acc1H, F
	DECFSZ   Acc2L
	GOTO     _LoopL
	MOVF     Acc1L, W
	RETURN

You simply load the registers and call the routines _Add16, _DIV16 etc.

This is actually part of the maths module from my BASIC compiler.
 
Would it be too much trouble to ask you to post the averaging code you are using? Thanks.
Hey bsodmike, I have outlined how I performed the operation before your last post, read it and see what you think. It really is dead simple :D
I haven't got round to 'isolating' my average code out of it's program yet abd also I don't think I am the most efficient coder round but if you still struggle I will post my code on to you. someday soon. However I am sure there are better routines on the net. I for one can just never be bothered looking for them!

Things like this make you wander why we ever bother with assembly, but then that's probably the very reason! :?
 
Actually, remember that 'solution' I posted sometime back? Arn't you doing that but with out hte beginning so you don't deal with floating points? I'll work on what you said when I have a bit more spare time. right now I'm trying to sort out the PIC problems posted in the other thread titled 'Erratic A/D output'

Thanks for all your help dude!
 
The ff. is code to get the running average of 256 consecutive samples. It uses the ff. equation to calculate the average.

(OLD_AVERAGE * 255/256) + (NEW_SAMPLE * 1/256) = NEW_AVERAGE

Code:
    MOVF   AVERAGE_HIGH_BYTE,W
    SUBWF  AVERAGE_LOW_BYTE,F
    BTFSS  STATUS,C
    DECF   AVERAGE_HIGH_BYTE,F
;
    MOVF   NEW_SAMPLE,W
    ADDWF  AVERAGE_LOW_BYTE,F
    BTFSC  STATUS,C
    INCF   AVERAGE_HIGH_BYTE,F
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top