基于单片机的AD采集的滤波算法.docx
《基于单片机的AD采集的滤波算法.docx》由会员分享,可在线阅读,更多相关《基于单片机的AD采集的滤波算法.docx(18页珍藏版)》请在冰豆网上搜索。
基于单片机的AD采集的滤波算法
基于单片机的AD采集的滤波算法
1引言
理论上讲单片机从A/D芯片上采集的信号就是需要的量化信号,但是由于
存在电路的相互干扰、电源噪声干扰和电磁干扰,在A/D芯片的模拟输入信号上会叠加周期或者非周期的干扰信号,并会被附加到量化值中,给信号带来一定的恶化。
考虑到数据采集的实时性和安全性,有时需要对采集的数据进行软处理,一尽量减小干扰信号的影响,数字滤波算法就算通过特定的计算机处理,降低干
扰信号中的比例,故实际上是一种基于单片机的程序滤波。
2单片机的AD接口
以AVR单片机atmega128为例,atmega128是10位的逐次逼近式ADC先介绍一下AD转换的主要技术指标。
2.1A/D转换器的主要技术指标
(1)分辨率
ADC的分辨率是指使输出数字量变化一个相邻数码所需输入模拟电压的
变化量。
常用二进制的位数表示。
例如12位ADC勺分辨率就是12位,或者说分辨率为满刻度FS的1/4096。
一个10V满刻度的12位ADC能分辨输入电压变化最小值是10VX1/4096=2.4mV。
(2)偏移误差
偏移误差是指输入信号为零时,输出信号不为零的值,所以有时又称为
零值误差。
假定ADC没有非线性误差,则其转换特性曲线各阶梯中点的连线必定是直线,这条直线与横轴相交点所对应的输入电压值就是偏移误差。
(3)满刻度误差
满刻度误差又称为增益误差。
ADC的满刻度误差是指满刻度输出数码所
对应的实际输入电压与理想输入电压之差。
(4)线性度
线性度有时又称为非线性度,它是指转换器实际的转换特性与理想直线的最大偏差。
(5)绝对精度
在一个转换器中,任何数码所对应的实际模拟量输入与理论模拟输入之差的最大值,称为绝对精度。
对于ADC而言,可以在每一个阶梯的水平中点进行测量,它包括了所有的误差。
(6)转换速率
ADC的转换速率是能够重复进行数据转换的速度,即每秒转换的次数。
而完成一次A/D转换所需的时间(包括稳定时间),则是转换速率的倒数。
2.2AVR单片机内部ADO介
(1)预分频与转换时间
在通常情况下,ADC的逐次比较转换电路要达到最大精度时,需要
50kHz~200kHz之间的采样时钟。
在要求转换精度低于10位的情况下,ADC勺采样时钟可以高于200kHz,以获得更高的采样率。
ADC模块中包含一个预分频器的ADC寸钟源,它可以对大于100KHz的系统时钟进行分频,以获得合适的ADC时钟提供ADC使用。
预分频器的分频系数由ADCSR寄存器中的ADPS位设置的。
一旦寄存器ADCSR中的ADEF位置“1”(ADC开始工作),预分频器就启动开始计数。
ADEN位为“1”时,预分频器将一直工作;ADEh位为“0”时,预分频器一直处在复位状态。
AVR的ADC完成一次转换的时间见表4.1。
从表中可以看出,完成一次ADC专换通常需要13-14个ADC寸钟。
而启动ADC开始第一次转换到完成的时间需要25
个ADC寸钟,这是因为要对ADC单元的模拟电路部分进行初始化
表4.1ADC转换和采样保持时间
转换形式
启动ADC后第一次转换正常转换,单端输入自动触发方式
米样保持时间
13.5个ADC寸钟
1.5个ADC寸钟
2个ADC寸钟
1.5/2.5个ADC寸乍中
完成转换总时间
25个ADC寸钟
13个ADC寸钟
13.5个ADC寸钟
13/14个ADC寸钟
正常转换,差分输入
真当ADCSR寄存器中的ADS(位置位,启动ADC专换时,A/D转换将在随后
ADC寸钟的上升沿开始。
一次正常的A/D转换开始时,需要1.5个ADC寸钟周期
的采样保持时间(ADCt次启动后需要13.5个ADC寸钟周期的采样保持时间)当一次A/D转换完成后,转换结果写入ADCt据寄存器,ADIF(ADC中断标志位)将被置位。
在单次转换模式下,ADS(也同时被清零。
用户程序可以再次置位ADSC位,新的一次转换将在下一个ADC时钟的上升沿开始。
当ADCS置为自动触发方式时,触发信号的上升沿将启动一次ADC转换。
转换完成的结果将一直保持到下一次触发信号的上升沿出现,然后开始新的一次ADC转换。
这就保证了使ADC每隔一定的时间间隔进行一次转换。
在这种方式下,ADC需要2个ADC寸钟周期的采样保持时间。
在自由连续转换模式下,一次转换完毕后马上开始一次新的转换,此时,
ADS(位一直保持为“1”
(2)ADC输入通道和参考电源的选择
寄存器ADMU中的MUXr和REFS1REFSG位实际上是一个缓冲器,该缓冲器与一个MCI可以随机读取的临时寄存器相连通。
采用这种结构,保证了ADC输入通道和参考电源只能在ADC专换过程中的安全点被改变。
在ADC专换开始前,通道和参考电源可以不断被更新,一旦转换开始,通道和参考电源将被锁定,并保持足够时间,以确保ADC专换的正常进行。
在转换完成前的最后一个ADC时钟周期(ADCSR的ADIF位置“T时),通道和参考电源又开始重新更新。
注意,由于A/D转换开始于置位ADSCH的第一个ADC时钟的上升沿,因此,在置位ADSC后的一个ADC时钟周期内不要将一个新的通道或参考电源写入到ADMUXJ存器中。
改变差分输入通道时需特别当心。
一旦确定了差分输入通道,增益放大器需要125s的稳定时间。
所以在选择了新的差分输入通道后的125?
s内不要启动A/D转换,或将这段时间内转换结果丢弃。
通过改变ADMU中的REFS1REFS睐更改参考电源后,第一次差分转换同样要遵循以上的时间处理过程。
1)当要改变ADC俞入通道时,应该遵守以下方式,以保证能够选择到正确的通
道:
在单次转换模式下,总是在开始转换前改变通道设置。
尽管输入通道改变发生在ADS(位被写入“1”后的1个ADC寸钟周期内,然而,最简单的方法是等到转换完成后,再改变通道选择。
在连续转换模式下,总是在启动ADC开始第一次转换前改变通道设置。
尽管输入通道改变发生在ADS(位被写入“1”后的1个ADC寸钟周期内,然而,最简
单的方法是等到第一次转换完成后再改变通道的设置。
然而由于此时新一次的转换已经自动开始,所以,当前这次的转换结果仍反映前一通道的转换值,而下一
次的转换结果将为新设置通道的值。
2)ADC电压参考源
ADC的参考电压(VREF决定了A/D转换的范围。
如果单端通道的输入电压超过VREF将导致转换结果接近于0x3FF(1023)。
ADC的参考电压VREF可以选择为AVCC或芯片内部的2.56V参考源,或者为外接在AREF引脚上的参考电压源。
AVCC通过一个无源开关连接到ADC内部2.56V参考源是由内部能隙参考源(VBC通过内部的放大器产生的。
注意,无论选用什么内部参考电源,外部AREF引|脚都是直接与ADC相连的,因此,可以通过外部在AREF引脚和地之间并接一个电容,使内部参考电源更加稳定和抗噪。
可以通过使用高阻电压表测量AREF引脚,来获得参考电源VREF的电压值。
由于VREF是一个高阻源,因此,只有容性负载可以连接到该引脚。
如果将一个外部固定的电压源连接到AREF引脚,那就不能使用任何的内部参考电源,否则就会使外部电压源短路。
外部参考电源的范围应在2.0V到
AVCC-0.2V之间。
参考电源改变后的第一次ADC专换结果可能不太准确,建议抛弃该次转换结果。
2.3ADC转换结果
A/D转换结束后(ADIF=1),在ADC数据寄存器(ADCL和ADCH中可以取得转换的结果。
对于单端输入的A/D转换,其转换结果为:
ADC=(VnX1024)/Vref
其中VIN表示选定的输入引脚上的电压,VREF表示选定的参考电源的电压。
0x000表示输入引脚的电压为模拟地,0x3FF表示输入引脚的电压为参考电压值减去一个LSB
对于差分转换,其结果为:
ADC=(VOsVneGxGAINX512/Vref
例:
若差分输入通道选择为ADC3-ADC210倍增益,参考电压2.56V,左端对齐
(ADMUX=0xEDADC3^|脚上电压300mVADC勿脚上电压500mV则ADCR=(300-500)X10X512/2560=-400=0x270ADCL=OxO0ADCH=0x9。
若结果为右端对齐时(ADLAR“0”),贝UADCL=0x70ADCH=0x02
3ADC应用设计的深入讨论
尽管AVR内部集成了10位的ADC但是在实际应用中,要想真正实现10位精度,比较稳定的ADC的话,并不象上一节中的例子那么简单。
需要进一步从硬件、软件等方面进行综合的、细致的考虑。
下面介绍一些在ADC设计应用中应该考虑的几个要点。
3.1参考电压Vref的选择确定
在实际应用中,要根据输入测量电压的范围选择正确的参考电压Vref,以
求得到比较好的转换精度。
ADC的参考电压VREF还决定了A/D转换的范围。
如果单端通道的输入电压超过*EF,将导致转换结果全部接近于0x3FF,因此ADC的参考电压应稍大于模拟输入电压的最高值。
ADC的参考电压Vref可以选择为AVCC或芯片内部的2.56V参考源,或者为外接在AREF引脚上的参考电压源。
外接参考电压应该稳定,并大于2.0V(芯片的工作电压为1.8V时,外接参考电压应大于1.0V)。
要求比较高的场合,建议在Vref引脚外接标准参考电压源来作为ADC的参考电源。
3.2模拟噪声的抑制
器件外部和内部的数字电路会产生电磁干扰,并会影响模拟测量的精度。
如果ADC转换精度要求很高,可以采用以下的技术来降低噪声的影响:
(1)使模拟信号的通路尽可能的短。
模拟信号连线应从模拟地的布线盘上通过,并使它们尽可能远离高速开关数字信号线。
(2)AVR的AVcc引脚应该通过LC网络与数字端电源Vcc相连。
(3)采用ADC噪声抑制器功能来降低来自MCI内部的噪声。
(4)如果某些ADC引脚是作为通用数字输出口使用,那么在ADC转换过程中,不要改变这些引脚的状态。
3.3ADC的校正
由于AVD内部ADC部分的放大器非线性等客观原因,ADC的转换结果会有误差的。
如果要获得高精度的ADC专换,还需要对ADC结果进行校正。
具体的方法请参考AVR应用笔记AVR120(avr_app_120.pdf),在这篇应用设计参考中详细介绍了误差的种类,以及校正方案。
3.3ADC精度的提高
在有了上述几点的保证后,通过软件的手段也能适当的提高ADC勺精度。
如采用多次测量取平均,软件滤波算法等。
在AVR应用中可以结合一种采样算法的软件实现,可以将ADC的精度提高到11位或更高,当然这是在花费更多的时间基础上实现的。
4单片机实现数字滤波算法的优点
(1)当今单片机多采用流水线结构,指令执行速度有很大提高。
在系统时钟为25MHZ寸它的峰值速度可达25MIPS最大系统时钟频率已接近100MHz采用软件滤波算法基本可满足测控系统实时性很强的要求。
(2)数字滤波无需硬件,只用一个计算过程,不存在阻抗匹配问题,可靠性高,尤其对频率很高或很低的信号进行滤波,数字滤波相对模拟滤波器的设计其优越性更为显著。
(3)数字滤波是用软件算法实现的,多输入通道可共用一个滤波程序,不仅可以大大降低系统开支,而且可以大大简化硬件电路设计。
(4)只要适当改变软件滤波器的滤波程序或运算参数,就能方便地改变其滤波特性,这对于低频干扰、随机信号的滤波会有较大的效果。
5在单片机系统中常用的数字滤波算法
为便于以下的程序书写方便,这里做一个假设:
假定从8位AD中读取数据,如果是更高位的AD可定义数据类型为int,子程序为getad()。
5.1一阶滞后滤波法
硬件滤波电路中最常用的是一阶惯性RC模拟低通滤波器,当采用这种模拟
滤波器来抑制低频干扰时,要求滤波器有较大的时间常数和高精度的RC网络,增大时间常数有求增大R值,其漏电流也随之增大,从而降低了滤波效果。
而采用数字滤波算法来实现动态的RC滤波,则能很好的克服上述模拟滤波器的缺点。
在模拟常数要求较大的场合这种方法显得更为实用,一阶惯性滤波算法对于周期干扰具有良好的抑制作用,其不足之处是带来了相位滞后,导致灵敏度低。
同时它不能滤除频率高于采样频率二分之一(称为奈奎斯特频率)的干扰信号。
例如采样频率为100Hz,则它不能滤除50Hz以上的干扰信号。
对于高于奈奎斯特频率的干扰信号,应该采用模拟滤波器。
假设X为输入,丫为滤波后的输出值,则其公式为:
yn=a*Xn+(1-a)*yn-i
式中a为与RC值有关的一个参数。
下面是实现一阶惯性滤波算法的程序。
为加快程序处理速度假定基数为100,a=0〜100
#definea50
charvalue;
charfilter()
{
charnewvalue;
newvalue=getad();
return(100-a)*value+a*newvalue;
}
5.2限副滤波法
由于单片机系统中可能存在随机脉冲干扰,或由于变送器不可靠而将脉冲干扰引入输入端,从而造成测量信号的严重失真。
对于这种随机干扰,限副滤波是一种有效的方法。
其基本方法是比较相邻(n和n-1时刻的两个采样值yn和yn-J。
然后根据经验确定两次采样允许的最大偏差。
如果两次采样值yn和yn-1的差值超过了所允许的最大偏差范围,则认为发生可随机干扰,并认为后一次采样值yn为非法值,应予删除,删除yn后,可用yn-1代替yn。
若未超过所允许的最大偏差范围,则认为本次采样值有效。
下面是实现限副滤波法的程序。
A值可根据实际情况调整,value为有效值,newvalue为当前采样值滤波程序返回有效的实际值
#defineA10
charvalue;
charfilter()
{
charnewvalue;
newvalue=getad();
if((newvalue-value>A)II(value-newvalue>A)
returnvalue;
returnnewvalue;
}
5.3中位值滤波法
中位值滤波法是对某一被测参数连续采样n次(一般n取奇数),然后再把采
样值按大小排列,取中间值为本次采样值。
中位值滤波法能有效克服偶然因素引起的波动或采样不稳定引起的误码等脉冲干扰。
对温度、液位等缓慢变化的被测
参数用此法能收到良好的滤波效果,但是对于流量压力等快速变化的参数一般不宜采用中位值滤波法。
下面是实现中位值滤波法的程序。
N值可根据实际情况调整
排序采用冒泡法
#defineN11
charfilter()
{
charvaluebuf[N];
charcount,i,j,temp;
for(count=0;count{
valuebuf[count]=getad();
delay();
}
for(j=0;j{
for(i=0;i{
if(valuebuf[i]>valuebuf[i+1])
{
temp=valuebuf[i];
valuebuf[i]=valuebuf[i+1];
valuebuf[i+1]=temp;
}
}
}
returnvaluebuf[(N-1)/2];
}
5.4算术平均滤波法
算术平均滤波法适用于对一般的具有随机干扰的信号进行滤波。
这种信号的
特点是信号本身在某一数值范围附近上下波动,如测量流量、液位时经常遇到这种情况。
算术平均滤波法是要按输入的N个采样数据,寻找这样一个丫,使得丫与
各个米样值之间的偏差的平方和最小。
在编写算术平均滤波法程序时严格注意两点:
一是对于定时测量,为了减小数据的存储容量,可对测得的值直接进行计算,但由于某些应用场合,为了加快数据测量的速度,可采用先测量数据,并存放在存储器中,测完N点后,再对N个数据进行平均值计算。
二是选取适当的数据格式,也就是说采用定点数还是采用浮点数。
采用浮点数计算比较方便,但计算时间较长,采用定点数可加快计算速度,但必须考虑累加时是否产生溢出。
例如数据为14位二进制定点数时,采用双字节运算,当N>4时,就可能产生溢出。
下面是实现算术平均滤波法的程序。
#defineN12
charfilter()
{
intsum=O;
for(count=0;count{
sum+=getad();
delay();
}
return(char)(sum/N);
}
5.5递推平均滤波法(又称滑动平均值滤波法)
上面介绍的算术平均值滤波,每计算一次数据,需要测量N次。
对于测量速度较慢或要求计算速度较高的实时系统,该方法是无法使用的。
例如某ADC芯片的转换速率为每秒钟10次,而要求每秒输入4次数据时,则不能大于2。
下面介绍一种只需要进行一次测量,就能得到一个新的算术平均值的方法,即滑动平均值滤波法。
滑动平均值滤波法采用队列作为测量数据存储器,设队列的长度为
N,每进行一次测量,把测量结果放于队尾,而扔掉原来队首的一个数据,这样在队列中始终就有N个“最新”的数据。
当计算平均值时,只要把队列中的N个数据进行算数平均,就可得到新的算数平均值。
这样每进行一次测量,就可得到一个新的算术平均值。
滑动平均值滤波法中的队列一般采用循环队列来实现。
下面是实现递推平均滤波法的程序。
#defineN12
charvaluebuf[N];
chari=0;
charfilter()
{
charcount;
intsum=0;
valuebuf[i++]=getad();
if(i=N)i=0;
for(count=0;countsum=valuebuf[count];
return(char)(sum/N);
}
5.6加权滑动平均滤波法
在算术平均滤波和滑动平均滤波法中,N次采样值在输出结果中的比重
是均等的,即1/N,用这样的滤波算法,对于时变信号会引入滞后,N越大,滞后越严重。
为了增加新的采样数据在滑动平均滤波法中的比重,以提高系统对当前采样值中多受干扰的灵敏度,可以采用加权滑动平均滤波法。
实质上它是前面介绍的滑动平均滤波算法一种改进,即对不同时刻的数据加以不同的权,通常越接近现时刻的数据,权取得越大。
加权滑动平均滤波算法适用于由较大纯滞后时间常数的对象和采样周期较短的系统,而对于纯滞后时间常数较小,采样周期较长,变化缓慢的信号,则不能迅速反映系统当前所受干扰的严重程度,滤波效果较差。
5.7复合滤波法
单片机系统在实际应用中,所受到的随机干扰往往不是单一的,又是既要消除脉冲干扰的影响,又要做数据平滑处理。
因此,在实际应用中常常把前面介绍的两种以上的方法结合起来使用,形成所谓的的复合滤波。
例如,防脉冲扰动平均值滤波算法就是一种实例。
这种算法的特点是先用中位值滤波算法滤掉采样值中的脉冲干扰,然后把剩下的各个采样值再进行滑动平均滤波。
由于这种滤波算法兼容了中位值平均滤波算法和滑动平均滤波算法的优点,所以无论是对缓慢变化的过程变量还是对快速变化的过程变量都能起到较好的滤波效果。
6基于AVF单片机的去极值平均滤波法程序
对3个通道交替进行AD转换,滤波时对窗口内的18个数据进行去极值取平均值滤波。
#include
#inelude
#defineuint8unsignedchar
#defineuint16unsignedint
uint8
ucADC_select;
//
三通道AD选择
uint16
uiadc_temp;
//AD转换结果
volatile
uint16ADC0_value;
//0
通道AD数据
volatile
uint16ADC1_value;
//1
通道AD数据
volatile
uint16ADC2_value;
//2
通道AD数据
//18个数据临时寄存器
/*去极值平均滤波法子程序*/uint16arr[18];
uint16average(uint16arr[18])
{uint8i;
uint16temp=O,max=O,min=0x3ff;
for(i=0;i<18;i++)
{
if(max{max=arr[i];}
elseif(min>arr[i])
{min=arr[i];}
temp+=arr[i];
}
temp=(temp-max-min)/16;
return(temp);
}voidadc_init(void)
//
***********
ADC
初始化
{
DDRF&=0XF8;设置PA0PA1、PA2口为输入
PORTF&=0XFE;不使用片内上拉电阻
ADCSRA=0x00;//关闭ADC
ACSR=(1<ADMUX=(1vvREFS1)|(111100000
//ADMUX=0x00;//外部Vref,ADC0通道
ADCSRA=(1vvADEN)|(1vvADSC)|(1v|(0<***********
ADC
初始化
**************
end**〃
//
连续转换3个ADC!
道的值**********〃
#pragmainterrupt_handleradc_isr:
15
//AD转化完成进入中断
voidadc_isr(void){
uiadc_temp=ADCL;
uiadc_temp|=(uint16)ADCH<<8;//AD转换结果存储uiadc_temp=ADCL+ADCH*256switch(ucADC_select)
{
case0:
//ADC0通道数据处理
{
ADMUX=0xc1;//切换到ADC1通道,内部Vref
ADCO_value=uiadc_temp;
ucADC_select++;//切换到ADC1通道
break;
}
case1:
//ADC1通道数据处理
{
ADMUX=0xc2;//切换到ADC2通道,内部Vref
ADC1_value=uiadc_temp;
ucADC_select++;//切换到ADC2通道
break;
}
case2:
//ADC2通道数据处理
{