单片机主要作用是控制外围的器件,并实现一定的通信和数据处理。虽然 单片机不擅长实现算法和进行复杂的运算, 但在某些特定场合,不可避免地要用到数学运算。
比如:在单片机进行数据采集时,会遇到数据的随机误差,随机误差是由随机干扰引起的,其特点是在相同条件下测量同一量时,其大小和符号会现无规则的变化而无法预测,但多次测量的结果符合统计规律。
为克服随机干扰引起的误差,硬件上可采用滤波技术,软件上可采用软件算法实现数字滤波。滤波算法往往是系统测控算法的一个重要组成部分,实时性很强。
采用数字滤波算法克服随机干扰的误差具有以下优点:数字滤波无需其他的硬件成本,只有一个计算过程,可靠性高,不存在阻抗匹配问题。尤其是数字滤波可以对频率很低的信号进行滤波,这是模拟滤波器做不到的。数字滤波使用软件算法实现,多输入通道可共用一个滤波程序,降低系统开支。只要适当改变滤波器的滤波程序或运算,就能方便地改变其滤波特性,这对于滤除低频干扰和随机信号会有较大的效果。在单片机系统中常用的滤波算法有限幅滤波法、中值滤波法、算术平均滤波法、加权平均滤波法、滑动平均滤波等。
限幅滤波算法
该运算的过程中将两次相邻的采样相减,求出其增量,然后将增量的绝对值,与两次采样允许的最大差值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}