十年專注單片機方案開發的方案公司英銳恩,分享求平均值的簡捷方法。英銳恩現提供服務產品涉及主控芯片:8位單片機、16位單片機、32位單片機及各類運算放大器等。
首先說明,這是前人所推薦的求平均值的方法,只是經過我的一點點加工整理這里開頭先說一個重要的概念,在二進制數值表示方法中,一個無限長的二進制數順序向左移動一位就是原值乘以二,而如果二進制數順序向右移一位就是原值除以二。我們利用這個特性在PIC單片機中可以很方便地求得兩個數的平均值:將兩個數相加,然后將和右移一位便是兩個數的平均值,如果和是奇數,那么余數就在C里面。更進一步的方法,比如我們要求一段時間內AD值的平均值,通常需要把幾十次的和再除以幾十,而利用移位其實非常方便,甚至求和后都可以不用再作任何運算就可以得到平均值。
舉一個很特殊的例子說明:我們要為8位的AD結果做平均值運算,如果我們一次做256次(注意剛好是2的8次方哦)AD轉換,將每次的AD結果相加,這樣256次AD轉換之后我們得到一個16位的和,這時我們就不用再把和除以256了,實際上我們已經得到了8位的平均值整數部分,那就是16位和的高8位!怎么證明?很簡單:我們求得的和要除以256,將256拆開,就是這樣一個方程(假設平均值為X,和為Y): X=Y/(2*2*2*2*2*2*2*2) 也就是將Y除以8次2,換句話說按照上面的說法就是要將“和”右移8位————剛好將16位和的高8位移入低8位,而原低8位如果作為小數舍去的話,那么原高8位就是平均值的整數部分!
既然如此簡單就沒有理由再去自找麻煩移位8次了,直接取16位和的高8位多簡單?若是有人拿了那個16位的和直接去冒充16位精度的AD結果,我也不反對。讓我們再來思考一下10位AD值的平均值如何求:再做256次?太麻煩了,取得的和要18位占用3個字節,而且時間太長不允許,怎么樣才更簡便呢?右對齊的10位AD值占用兩個字節,高字節前面還有6位空的,6位就是2的6次方=64,這就是我們需要做AD的次數,做完64次AD之后結果相加的和剛好是10位的左對齊值!當然要舍去低字節的低6位,那是小數,我們取整的時候并不關心的。有人說:我還是需要結果是右對齊的以方便計算————那就右移6位…………有必要嗎?其實還有更簡單的:那就是只需要左移2位!呵呵大家都是明眼人不用我多說為什么了,可以看得出來這有多方便。推而廣之,如果我們要作若干整數的平均值,只需要先求2的n次方次的和然后右移n次或者左移(8-n)次就可得到它們的平均值整數了。往哪移,看往哪近嘍。附:10位AD轉換求64次平均值程序:
MOVLW D'64' MOVWF COUNT MOVLW ADRESL MOVWF FSR CLRF ADMEANH CLRF ADMEANL ;這個不要忘了 LOOPAD CALL AD轉換 MOVF ADRESH,W ADDWF ADMEANL,F ;加高字節,因為高字節只有最低兩位,64次求和不會溢出,所以不用判斷是否有進位。 MOVF INDF,W ADDWF ADMEANH,F ;加低字節 BTFSC STATUS,C ;是否有進位 INCF ADMEANL DECFSZ COUNT GOTO LOOPAD 平均值調整 BCF STATUS,C ;這是一個移位之前的好習慣,許多找不到原因的錯誤就源于此 RLF ADMEANH RLF ADMEANL RLF ADMEANH RLF ADMEANL RLF ADMEANH ;思考:為什么要做兩次半左移?為什么先前加的時候AD結果高字節加到暫存低字節? MOVLW B'11' ANDLW ADMEANH ;舍掉高字節高六位的余數。 ;至此,64次AD的結果平均值高字節兩位結果在ADMEANH中,低字節8位在ADMEANL中 ;============================================================= AD
轉換 重新選擇AD通道 重新開啟AD模塊 ;這兩項比較重要,在同一個通道反復采樣中,必須每次都重新采樣才能得到準確的AD結果 CALL 采樣延時 ;大約幾十微秒使采樣電容充飽,此延時視AD口輸入阻抗而定。若阻抗大于10K,應適當延長采樣時間。 BSF ADCON0,GO BTFSC ADCON0,GO GOTO $-1 AD返回