單片機主要作用是控制外圍的器件,并實現一定的通信和數據處理。雖然 單片機不擅長實現算法和進行復雜的運算, 但在某些特定場合,不可避免地要用到數學運算。
比如:在單片機進行數據采集時,會遇到數據的隨機誤差,隨機誤差是由隨機干擾引起的,其特點是在相同條件下測量同一量時,其大小和符號會現無規則的變化而無法預測,但多次測量的結果符合統計規律。
為克服隨機干擾引起的誤差,硬件上可采用濾波技術,軟件上可采用軟件算法實現數字濾波。濾波算法往往是系統測控算法的一個重要組成部分,實時性很強。
采用數字濾波算法克服隨機干擾的誤差具有以下優點:數字濾波無需其他的硬件成本,只有一個計算過程,可靠性高,不存在阻抗匹配問題。尤其是數字濾波可以對頻率很低的信號進行濾波,這是模擬濾波器做不到的。數字濾波使用軟件算法實現,多輸入通道可共用一個濾波程序,降低系統開支。只要適當改變濾波器的濾波程序或運算,就能方便地改變其濾波特性,這對于濾除低頻干擾和隨機信號會有較大的效果。在單片機系統中常用的濾波算法有限幅濾波法、中值濾波法、算術平均濾波法、加權平均濾波法、滑動平均濾波等。
限幅濾波算法
該運算的過程中將兩次相鄰的采樣相減,求出其增量,然后將增量的絕對值,與兩次采樣允許的最大差值A進行比較。
A的大小由被測對象的具體情況而定,如果小于或等于允許的最大差值,則本次采樣有效;否則取上次采樣值作為本次數據的樣本。
算法的程序代碼如下:
2
4
5char filter
6
7{
8
10
12
13if((datanew- data)>A||( data-datanew>A))
14
15returndata;
16
17else
18
19returndatanew;
20
21}
說明:
限幅濾波法主要用于處理變化較為緩慢的數據,如溫度、物體的位置等。使用時,關鍵要選取合適的門限制A。通常這可由經驗數據獲得,必要時可通過實驗得到。
中值濾波算法
該運算的過程是對某一參數連續采樣N次(N一般為奇數),然后把N次采樣的值按從小到大排列,再取中間值作為本次采樣值,整個過程實際上是一個序列排序的過程。
算法的程序代碼如下:
4
5{
1011for(count=0;count
1213{
1415value_buf[count]=get_data;
2021for(j=0;j
2223{
2425if(value_buff[i]>value_buff[i+1])
2627{
2829temp=value_buff[i];
3031value_buff[i]=value_buff[i+1];
3233value_buff[i+1]=temp;
3435}
3637}
3839return value_buff[(N-1)/2];
4041}
說明:中值濾波比較適用于去掉由偶然因素引起的波動和采樣器不穩定而引起的脈動干擾。若被測量值變化比較慢,采用中值濾波法效果會比較好,但如果數據變化比較快,則不宜采用此方法。
算術平均濾波算法
該算法的基本原理很簡單,就是連續取N次采樣值后進行算術平均。
算法的程序代碼如下:
1charfilter
2
3{
4
5intsum= 0;
6
7for(count= 0;count
8
9{
10
11sum+=get_data;
12
13delay:
14
15}
16
17return( char)(sum/N);
18
19}
說明:算術平均濾波算法適用于對具有隨機干擾的信號進行濾波。這種信號的特點是有一個平均值,信號在某一數值附近上下波動。
信號的平均平滑程度完全到決于N值。當N較大時,平滑度高,靈敏度低;當N較小時,平滑度低,但靈敏度高。為了方便求平均值,N一般取4、8、16、32之類的2的整數冪,以便在程序中用移位操作來代替除法。
加權平均濾波算法
由于前面所說的“算術平均濾波算法”存在平滑度和靈敏度之間的矛盾。為了協調平滑度和靈敏度之間的關系,可采用加權平均濾波。
它的原理是對連續N次采樣值分別乘上不同的加權系數之后再求累加,加權系數一般先小后大,以突出后面若干采樣的效果,加強系統對參數變化趨勢的認識。
各個加權系數均小于1的小數,且滿足總和等于1的結束條件。這樣加權運算之后的累加和即為有效采樣值。其中加權平均數字濾波的數學模型是:
式中:D為N個采樣值的加權平均值:XN-i為第N-i次采樣值;N為采樣次數;Ci為加權系數。加權系數Ci體現了各種采樣值在平均值中所占的比例。
一般來說采樣次數越靠后,取的比例越大,這樣可增加新采樣在平均值中所占的比重。
加權平均值濾波法可突出一部分信號抵制另一部分信號,以提高采樣值變化的靈敏度。
樣例程序代碼如下:
2
3char codesum_jq= 1+ 2+ 3+ 4+ 5+ 6+ 7+ 8+ 9+ 10+ 11+ 12;
4
5char filter
6
7{
8
9char count;
10
11char value_buff[N];
12
13intsum= 0;
14
15for(count= 0;count
16
17{
18
19value_buff[count]=get_data;
20
21delay;
22
23}
24
25for(count= 0;count
26
27sum+=value_buff[count]*j q[count];
28
29return(char)(sum/sum_jq);
30
31}