标题: stc8单片机自带ADC值跳动严重,采样数据波动很大 [打印本页]

作者: lidong85    时间: 2019-4-21 12:54
标题: stc8单片机自带ADC值跳动严重,采样数据波动很大
本帖最后由 lidong85 于 2019-4-22 15:24 编辑

STC8A8K64S4A12单片机用自带ADC进行转换,硬件采用高精度连接模式(TL431),采样数据波动很大请问是什么原因?采样值如图:

,最小和最大相差100+。程序如下:


使用一个22K的可调电阻来改变采样电压,可调电阻两端分别连Vref和地,中间抽头接在P1.0上。
我使用的是某宝买的简易开发板,基准电压为TL431的输出电压,同时我把这个电压也作为负载的供电电压。如图:




我怀疑是采样端没有进行硬件滤波的原因造成的,因为P1.0口没有任何的RC电路。





作者: Y_G_G    时间: 2019-4-22 10:37
你那些25XX是什么,是2500mV吗?
电路图搞上来看一下
数据波动原因:C语言本身计算的误差,但并不大
                    ADC采样的误差,这个数据变化比较大,原因很多,电源的波动,外部的干扰都有可能,说不清楚,我用示波器看过ADC的端口的波形,有的时候会有20mV左右的波动,就算是加了一个电容也是这样的.
STC8A系列是12位的ADC,你想要好一点的ADC结果,那就取12位的运算结果
ADC的参考电压要用TL431来作为参考电压,电压取值为:4.096V,不是5V的VCC,我的电路给你参考ADC采样的次数设定为128次或者256次,然后再平均值



作者: yaoji123    时间: 2019-4-22 14:56
这样结果是正常的,可采用软件滤波减少波动。方法:连续采集10次,去除最大、最小各一个,余下8个取平均。
作者: lidong85    时间: 2019-4-22 15:34
Y_G_G 发表于 2019-4-22 10:37
你那些25XX是什么,是2500mV吗?
电路图搞上来看一下
数据波动原因:C语言本身计算的误差,但并不大

谢谢指教。回答您几个问题。
1.25XX是ADC采样的12位结果,我转换成10进制然后通过串口输出。
2.我的基准使用的是TL431输出的2.5V,没有用示波器观察电源的波动情况。
PS:电路图我已经在原帖中进行了更新。

还有3个问题想请教:
1.您给出的电路图中ADC的参考电压端并联两套47u电解电容和104的瓷片电容的目的是什么?用一套行不行?
2.ADC的采样口是不是要加RC进行滤波,一般要加多大的?
3.模拟通道的地和电源地您是如何进行隔离的?
作者: lidong85    时间: 2019-4-22 15:37
yaoji123 发表于 2019-4-22 14:56
这样结果是正常的,可采用软件滤波减少波动。方法:连续采集10次,去除最大、最小各一个,余下8个取平均。

您说的对,我之前确实没有加上软件滤波,加上软件滤波后效果也不是太明显,是不是应该考虑硬件滤波,如何加?
作者: Y_G_G    时间: 2019-4-23 08:51
1:参考电压那的电容你用一个100uF和一个104的也行,我主是没有那么大的,才用两个的
2:如果你ADC的采样端口是由运放输出的,那么就并联一个104电容和一个10K电阻试一下.如果只是一个电压的采样而已,那就一个104就可以了,不需要其它的电路了
3:电路中如果没有高频信号和大电流,地实际上不用管的,联通就可以
但如果是有高频信号,你就得对地进行一定隔离,给你一个电路参考一下
如果可以的话,你采样的次数要多一些,130次,然后再减去一个最大值和一个最小值,再除以128,这效果会好一点
不管是参考电压还是采样的平均次数,都尽可能的和2的次幂有关2.048V 4.096V  32 64 128,不要取10进制的整数100次,2.500V之类的,如果你了解编译的原理你就会知道为什么要取这些值了,网上也会有专门的2.048V或者4.096V的基准电压源卖的



作者: lidong85    时间: 2019-4-24 18:31
Y_G_G 发表于 2019-4-23 08:51
1:参考电压那的电容你用一个100uF和一个104的也行,我主是没有那么大的,才用两个的
2:如果你ADC的采样端口 ...

并联了电容还是没有解决,怀疑是VREF不稳定。
作者: Y_G_G    时间: 2019-4-24 19:46
lidong85 发表于 2019-4-24 18:31
并联了电容还是没有解决,怀疑是VREF不稳定。

你采样的次数是多少次?
作者: wqjhj    时间: 2019-4-24 20:31
问题出在基准电压使用TL431,他只能做为基准电压用,不能用于负载电压
作者: lidong85    时间: 2019-4-26 10:45
wqjhj 发表于 2019-4-24 20:31
问题出在基准电压使用TL431,他只能做为基准电压用,不能用于负载电压

没错,这个是正解,接上负载后TL431的波动就特别大,我用示波器测了。
作者: 伊和苏    时间: 2019-5-25 21:35
楼主大大,能将您的这个程序发我借鉴下吗?
作者: ljb68    时间: 2019-5-28 07:50
刚好遇到同问题,参考了
作者: irisice008    时间: 2019-5-28 11:31
需要加入滤波算法,比如中值滤波,递推平均滤波等,数值会稳定很多
作者: miyuhao    时间: 2019-6-9 19:21
楼主可以把你说的那个最大值最小值然后平均值那个给我看看么
作者: 太阳的心    时间: 2020-2-28 17:09
我也是遇到这个问题,中位值滤波用了,也不行,测ad口电压很稳定的,就是读取出来跳动很大,中位值取的40次滤波,还是不行,而且adc还不满,最大没有4096,滤波都做了,地也隔离了就是不行
作者: Y_G_G    时间: 2020-2-29 08:26
太阳的心 发表于 2020-2-28 17:09
我也是遇到这个问题,中位值滤波用了,也不行,测ad口电压很稳定的,就是读取出来跳动很大,中位值取的40次 ...

ADC本身就不是一个稳定的,就算是硬件ADC也是要有一定的滤波的
你取值的方法不对
并不是你进行了多次的ADC然后平均就能得到一个平均值的
打个比方:进入ADC中断或者函数调用ADC,你进行一次ADC之后,ADC结果的值为:1024,如果你直接再进行39次ADC,结果基本上也都是1024.下一次再进行ADC的时候,结果可能是1000,显示就会有波动了
我的方法是:进行一次ADC之后,保存ADC结果了,就选择一个不用的通道进行一次ADC,然后再来进行一次当前通道的ADC,不用担心速度的问题,使用中断就可以了
你去看一下这个单片机的ADC框图,就会理解我说的了
作者: lyl44    时间: 2020-2-29 18:17
stc精度也就这样,一般五次取平均值就可以了。
作者: 余生不负    时间: 2020-3-5 22:52
说一下我用STC8A8K,12位AD的经验,也是按照PDF资料这个搭建的电路,程序不加软件虑波直接出来的结果跳变特别严重,后面想是不是电压不稳点,用示波器看TL431的2.5V有一点点波浪,不稳点,后面我直接把TL431直接去了,直接5v做基准,数据跳变就没有多大厉害,然后在程序里面加个平均值虑波,数据很稳点,如果数据转换出来不稳点,应该检查TL431的2.5V有没有波浪,和通道输入的虑波,还有电源电压有没有很大波浪。
作者: 余生不负    时间: 2020-3-5 22:57
太阳的心 发表于 2020-2-28 17:09
我也是遇到这个问题,中位值滤波用了,也不行,测ad口电压很稳定的,就是读取出来跳动很大,中位值取的40次 ...

示波器看一下电源电压稳点不,然后看TL431的2.5V,我之前就是2.5V示波器看了有一点点文波,我直接把431去了,AVCC经过510R电阻5v直接上,不要2.5v,程序里面加了 平均值虑波,转换的结果显示 0-30V电压,结果稳的一批,效果杠杠的
作者: lenceliu    时间: 2020-3-6 19:30
余生不负 发表于 2020-3-5 22:57
示波器看一下电源电压稳点不,然后看TL431的2.5V,我之前就是2.5V示波器看了有一点点文波,我直接把431去 ...

“AVCC经过510R电阻5v直接上”的意思是AVCC经过510R连接到Vref吗?为什么要加电阻,直接连上不可以吗
作者: nhlieaiong    时间: 2020-3-14 11:12
我正在用stc8a8k64s4a12做了个产品,正好用到pt100温度采集,用adc0采集,官方的高精度电路和官方的代码,数据变化的厉害,变化幅度有5%,我采用先取10次数据去掉最大和最小再取平均值还是有跳动,然后取100次数据去掉最大和最小再取平均值还是有跳动,最后取100次数据去掉最大和最小再取平均值,把取得100次的平均值再取1000次平均值后就稳定了,一点跳动也没有,其实也不用取这么多次,因为单片机的资源充足,时间有限我就没再继续增减数值做实验,就这样用了,最后把代码奉上
void ADC_Isr() interrupt 5
{
        static uint8 i = 0,j = 0;
        uint8 max,min;
        uint16 tmp;
        ADC_CONTR &= ~0X20;       //清零ADC_FLAG       
        if(i<100)
        {
                if(j<100)
                {
                        adcstr[j] = 255-ADC_RES;
                        j ++;
                }
                else
                {
                        tmp = 0;
                        for(j=0;j<100;j++)
                        {
                                tmp += adcstr[j];
                        }
                        max = min = adcstr[0];
                        for(j=0;j<100;j++)
                        {
                                if(min>adcstr[j])
                                        min = adcstr[j];
                                if(max<adcstr[j])
                                        max = adcstr[j];
                        }
                        adcstr1[i] = (tmp-min-max)/98;
                        j = 0;
                        i ++;
                }               
        }
        else
        {
                tmp = 0;
                for(i=0;i<100;i++)
                {
                        tmp += adcstr1[i];
                }
                max = min = adcstr1[0];
                for(i=0;i<50;i++)
                {
                        if(min>adcstr1[i])
                                min = adcstr1[i];
                        if(max<adcstr1[i])
                                max = adcstr1[i];
                }
                temperature = (tmp-min-max)/98;
                i = 0;               
        }
        ADC_CONTR |= 0X40;     //关闭ADC
}
作者: nhlieaiong    时间: 2020-3-14 11:15
void ADC_Isr() interrupt 5
{
        static uint8 i = 0,j = 0;
        uint8 max,min;
        uint16 tmp;
        ADC_CONTR &= ~0X20;       //清零ADC_FLAG       
        if(i<100)
        {
                if(j<100)
                {
                        adcstr[j] = 255-ADC_RES;
                        j ++;
                }
                else
                {
                        tmp = 0;
                        for(j=0;j<100;j++)
                        {
                                tmp += adcstr[j];
                        }
                        max = min = adcstr[0];
                        for(j=0;j<100;j++)
                        {
                                if(min>adcstr[j])
                                        min = adcstr[j];
                                if(max<adcstr[j])
                                        max = adcstr[j];
                        }
                        adcstr1[i] = (tmp-min-max)/98;
                        j = 0;
                        i ++;
                }               
        }
        else
        {
                tmp = 0;
                for(i=0;i<100;i++)
                {
                        tmp += adcstr1[i];
                }
                max = min = adcstr1[0];
                for(i=0;i<100;i++)
                {
                        if(min>adcstr1[i])
                                min = adcstr1[i];
                        if(max<adcstr1[i])
                                max = adcstr1[i];
                }
                temperature = (tmp-min-max)/98;
                i = 0;               
        }
        ADC_CONTR |= 0X40;     //关闭ADC
}
作者: nhlieaiong    时间: 2020-3-14 11:16
第一次发的代码有个错误 第二次的改正了
作者: timeabcd    时间: 2020-3-25 16:16
同问呢!
作者: timeabcd    时间: 2020-3-25 16:16
这样结果是正常的,可采用软件滤波减少波动。方法:连续采集10次,去除最大、最小各一个,余下8个取平均。
作者: sduking    时间: 2020-3-25 16:42
基准芯片TL431驱动能力不够的话,在后面加一个运放跟随,增加驱动电流,或者直接换一个基准源就行了。楼上的几位提得都对,应该软件采集后滤波,平均值,中值滤波都可以,信号到AD输入端,接一个104的电容滤波,中间可以串一个25-50欧的小电阻
作者: 上善若水001    时间: 2020-3-25 17:05
都是好经验,学习了!
作者: 余生不负    时间: 2020-3-25 20:12
lenceliu 发表于 2020-3-6 19:30
“AVCC经过510R电阻5v直接上”的意思是AVCC经过510R连接到Vref吗?为什么要加电阻,直接连上不可以吗

不加也可以,因为我把431拿掉了。
作者: 余生不负    时间: 2020-3-25 20:20
sduking 发表于 2020-3-25 16:42
基准芯片TL431驱动能力不够的话,在后面加一个运放跟随,增加驱动电流,或者直接换一个基准源就行了。楼上 ...

用不着那么麻烦,只要AVCC稳定5V直接上,测量范围0-5V,你要是用431,范围就是0-2.5V,这个不好用。
作者: fzhlpp    时间: 2020-3-26 02:18
mark最近用到STC8a系列12位AD,希望能用到。。。
作者: pcbboy    时间: 2020-3-26 08:58
431用处不大,看好5V电压纹波比这个重要,用过STC15w32s4 10ADC 精度也能做到10mV
作者: aking991    时间: 2020-3-26 09:23
我认为是你计算直接用5V的参数值作计算的,你最好测一下现在板上工作的实际电压值,然后代入这个值进行计算就OK了,不然就读取芯片内部的基准源再计算MCU的工作电压会更稳定
作者: TTQ001    时间: 2020-3-26 09:48
似乎参考电压存在一些问题,如果它平均波动20 mV,则转换后的结果波动可能是平均20点或更大。
作者: 1113634577    时间: 2020-5-17 10:24
首先,VREF稳压输出要加10uF,TL431也有品质好坏。其次采集端口要串接电阻并加104电容
作者: TTQ001    时间: 2020-5-17 21:43
试添加软件滤波器以平均模拟读数,以消除转换中的较大波动。
作者: xtp1230    时间: 2020-5-30 13:58
431基准电压输出滤波电容不能太大,104都大了,用102吧,要不然基准电压都不稳,用示波器观察有纹波的。
作者: 阿祥爷    时间: 2020-6-28 18:46
同问

作者: 单片机爱好者223    时间: 2020-6-30 13:51
MCU_VCC和模拟Vref 要分开,TL431输出电容不够大
作者: xingzhihaodz    时间: 2020-7-14 18:59
STC的ad输入是没有缓冲的,内阻很小
作者: TTQ001    时间: 2020-7-15 08:46
305/5000
ADC值波动的原因有很多,您需要检查参考电压是否稳定,或者是否存在接地噪声,或者信号调节电路中是否有正确的低通滤波器。 从软件的角度来看,您需要软件过滤器算法来平均测量值。
作者: univers    时间: 2020-7-15 16:43
这样波动正常的很,楼主你用这TL431就注定了波动,怎么搞都没用的,
想要高精度的,必须要用其它的高精度,超低温漂的基准,基准这里用5PPM-15PPM的温漂器件,还有就是DAC供电引脚也要稳定。50PPm的器件,不跳来跳去才怪呢。
另外上楼上很多人都说了,DAC要检测多次,再求和取平均值才对。


作者: 188610329    时间: 2020-12-2 16:43
先选ADC通道,再启动ADC试试。
或者直接 ADC_CONTR = 0xc2;  选通道启动一步到位。
TL431 即便不加电容, 应该ADC转换高8位应该也能保持稳定的数值的。
作者: cocolala    时间: 2020-12-4 10:20
    你的问题不像是来源于硬件,但使用STC8A8K64S4A12单片机确实有几点需要注意:
    1、相对于之前的STC15及更早的单片机系列,STC8A有了ADC电源引脚及参考电压引脚,所以单片机的最大IO口说是单片机总引脚数减去5(之前单片机是减去2,这个2就是VCC和GND)。
    2、STC8A的ADC电源引脚及参考电压引脚必须要接,否则单片机不会正常工作。参考电压引脚接2.5V基准电压没有任何问题,而且这样接只会提高ADC采样的精度。
    3、一定注意ADC引脚带采集信号的电压不要大于STC8A参考电压引脚的电压,即待测信号不要大于2.5V(如果采用的是2.5V电压基准)。
    4、附上一段ADC采集的源码,对采集的结果没有做任何软件滤波的,效果也是刚刚的。



   5、再附上ADC的电路图部分及实物图片段,以鉴真相。







作者: 碥闲传    时间: 2020-12-26 12:31
公开一个基本经验:AD是高噪声系统,无论怎么设法减少噪声都是无用的,单次采样绝对精度只有高5~6bit,其余低位均被噪声淹没,5%的误差也可以可以,真要保证12bit精度,要求被采信号稳定,采样数次然后算术平均
作者: dhc51    时间: 2020-12-26 15:20
STC8A的ADC电源引脚及参考电压引脚必须要接,否则单片机不会正常工作。参考电压引脚接2.5V基准电压没有任何问题,而且这样接只会提高ADC采样的精度。
作者: aking991    时间: 2020-12-26 16:08
我用读内部基准源去换算,就很准啊,就算不用中值虑波法也还可以啊,跳动也就小数点后面第2、3位在一点跳动,还是不错的啊
作者: xhaity    时间: 2020-12-26 16:51
基准源是作为基准用的,不能做电源用,输出不了足够的电流驱动负载,引起电压波动
作者: rm543    时间: 2021-12-25 12:23
TL431输出电容接0.1uF肯定是震荡的,自己去查手册的稳定性描述。
431想稳定电容要么小于等于1nF,要么大于10uF。
作者: 000ing    时间: 2023-5-4 16:17
如果我一份代码,ADC采集以后分别10进制输出和16进制输出,发现16进制输出的数据的折线图有突变,就是在一定范围内随机随时跳变一下。但是10进制很正常,10进制折线图很平缓,没有突变,这是为什么啊?
作者: coody_sz    时间: 2023-5-5 11:30
任何一个ADC都不会这么差的,何况我用STC8系列的MCU真的是稳如狗,精度高。
楼主最大问题,是碰到问题不用示波器测量一下电源、参考电压、输入电压的纹波。
楼主用的TL431并联104电容,基本上必然自激,示波器一看便知,那么多人分析,说的奥431自激的不多。
431输出2.5V时内阻0.3欧姆,我从里不加电容。只有用于开关电源反馈那样的,TL431处于放大状态,在输出和反馈端要串联合适的RC消振。
作者: raobydz    时间: 2023-5-5 12:20
调整好采样间隔时间,并用中值滤波就可以了




欢迎光临 (http://www.51hei.com/bbs/) Powered by Discuz! X3.1