From Tony Nixon [sales at picnpoke.com] and Scott Dattalo
Tony says:
Heres a simple setup using the FSR. Averages for 8 readings though.CBLOCK Average: 8h tempH tempL ENDC mov W, #Average ; initialise FSR mov FSR, W ... ; ; PLACE A2D RESULTS INTO A ROTATING BUFFER ; mov W, ADRES mov INDF, W inc FSR mov W, #Average + 8h xor W, FSR sb Z jmp NFSR mov W, #Average mov FSR, W NFSR ... ;Scott Dattalo interjects: ;If you have only 8 samples, and you were willing to align the array on a mod 8 ;boundary, then advancing the pointer could be done easily: mov W, ++fsr and W, #7 ;*** WARNING: ADDLW was expanded in three instructions! Check if previous instruction is a skip instruction. ; addlw Average mov Hack, W mov W, #Average add W, Hack mov fsr, W ;if you don't wish to align the array, then try this instead: mov W, ++fsr ;*** WARNING: ADDLW was expanded in three instructions! Check if previous instruction is a skip instruction. ; addlw -Average mov Hack, W mov W, #-Average add W, Hack and W, #7 ;*** WARNING: ADDLW was expanded in three instructions! Check if previous instruction is a skip instruction. ; addlw Average mov Hack, W mov W, #Average add W, Hack mov fsr, W ; ; AVERAGE OUT THE 8 STORED VALUES WHEN A RESULT IS NEEDED ; mov W, #Average mov FSR, W clr tempH clr tempL avLoop mov W, INDF ; add up 8 word values add tempL, W snb C inc tempH inc FSR mov W, #Average +8h xor W, FSR sb Z jmp avLoop mov W, #Average mov FSR, W clrb C ; div result by 8 rr tempH rr tempL clrb C rr tempH rr tempL clrb C rr tempH rr tempL ....
And Scott also says:
Again, I think the best way to maintain a running average is by subtracting the oldest value and adding in the newest. Here's something I'll whip out as fast as I can type it - which means there's a good chance for a thinko.; avg_lo:avg_hi - 16bit cumulative sum of last 8 samples ; samples - a circular array that holds the last 8 samples ; assume that samples and avg_lo:avg_hi are initialized to zero ; ; FSR is initialized to the start of samples ; ; W = newest sample AVERAGE: add avg_lo, W ;add newest sample to the average snb C inc avg_hi xor indf, W ; swap oldest and newest samples xor W, indf xor indf, W sub avg_lo, W ;remove the oldest sample from the average sb C dec avg_hi mov W, ++fsr ;advance the sample pointer ;*** WARNING: ADDLW was expanded in three instructions! Check if previous instruction is a skip instruction. ; addlw -sample mov Hack, W mov W, #-sample add W, Hack and W, #7 ;*** WARNING: ADDLW was expanded in three instructions! Check if previous instruction is a skip instruction. ; addlw sample mov Hack, W mov W, #sample add W, Hack mov fsr, W ret There - no more looping through all of the data after every sample is acquired. Now, I'm assuming that the division is not needed at every iteration. I tend to put off the difficult stuff as long as possible - often times, the intermediate calculations are more than sufficient. But, if you want, then this is how I'd do it: mov W, >>avg_hi mov temp_hi, W mov W, >>avg_lo mov temp_lo, W rr temp_hi rr temp_lo rr temp_hi mov W, >>temp_lo and if you wanted rounding: snb C ;*** WARNING: ADDLW was expanded in three instructions! Check if previous instruction is a skip instruction. ; addlw 1 mov Hack, W mov W, #1 add W, Hack (You don't need to worry about clearing the carry because the average is guranteed to be less than or equal to 255.)