找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 28610|回复: 50
收起左侧

stc8单片机自带ADC值跳动严重,采样数据波动很大

  [复制链接]
ID:514692 发表于 2019-4-21 12:54 | 显示全部楼层 |阅读模式
本帖最后由 lidong85 于 2019-4-22 15:24 编辑

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

,最小和最大相差100+。程序如下:
无标题.png

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



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



回复

使用道具 举报

ID:401564 发表于 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次,然后再平均值
QQ截图20190422103444.jpg

回复

使用道具 举报

ID:432823 发表于 2019-4-22 14:56 | 显示全部楼层
这样结果是正常的,可采用软件滤波减少波动。方法:连续采集10次,去除最大、最小各一个,余下8个取平均。
回复

使用道具 举报

ID:514692 发表于 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.模拟通道的地和电源地您是如何进行隔离的?
回复

使用道具 举报

ID:514692 发表于 2019-4-22 15:37 | 显示全部楼层
yaoji123 发表于 2019-4-22 14:56
这样结果是正常的,可采用软件滤波减少波动。方法:连续采集10次,去除最大、最小各一个,余下8个取平均。

您说的对,我之前确实没有加上软件滤波,加上软件滤波后效果也不是太明显,是不是应该考虑硬件滤波,如何加?
回复

使用道具 举报

ID:401564 发表于 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的基准电压源卖的
QQ截图20190423084559.jpg

回复

使用道具 举报

ID:514692 发表于 2019-4-24 18:31 | 显示全部楼层
Y_G_G 发表于 2019-4-23 08:51
1:参考电压那的电容你用一个100uF和一个104的也行,我主是没有那么大的,才用两个的
2:如果你ADC的采样端口 ...

并联了电容还是没有解决,怀疑是VREF不稳定。
回复

使用道具 举报

ID:401564 发表于 2019-4-24 19:46 | 显示全部楼层
lidong85 发表于 2019-4-24 18:31
并联了电容还是没有解决,怀疑是VREF不稳定。

你采样的次数是多少次?
回复

使用道具 举报

ID:386402 发表于 2019-4-24 20:31 | 显示全部楼层
问题出在基准电压使用TL431,他只能做为基准电压用,不能用于负载电压
回复

使用道具 举报

ID:514692 发表于 2019-4-26 10:45 | 显示全部楼层
wqjhj 发表于 2019-4-24 20:31
问题出在基准电压使用TL431,他只能做为基准电压用,不能用于负载电压

没错,这个是正解,接上负载后TL431的波动就特别大,我用示波器测了。
回复

使用道具 举报

ID:547194 发表于 2019-5-25 21:35 | 显示全部楼层
楼主大大,能将您的这个程序发我借鉴下吗?
回复

使用道具 举报

ID:494850 发表于 2019-5-28 07:50 | 显示全部楼层
刚好遇到同问题,参考了
回复

使用道具 举报

ID:346927 发表于 2019-5-28 11:31 | 显示全部楼层
需要加入滤波算法,比如中值滤波,递推平均滤波等,数值会稳定很多
回复

使用道具 举报

ID:419072 发表于 2019-6-9 19:21 来自手机 | 显示全部楼层
楼主可以把你说的那个最大值最小值然后平均值那个给我看看么
回复

使用道具 举报

ID:696952 发表于 2020-2-28 17:09 | 显示全部楼层
我也是遇到这个问题,中位值滤波用了,也不行,测ad口电压很稳定的,就是读取出来跳动很大,中位值取的40次滤波,还是不行,而且adc还不满,最大没有4096,滤波都做了,地也隔离了就是不行
回复

使用道具 举报

ID:401564 发表于 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框图,就会理解我说的了
回复

使用道具 举报

ID:159575 发表于 2020-2-29 18:17 来自手机 | 显示全部楼层
stc精度也就这样,一般五次取平均值就可以了。
回复

使用道具 举报

ID:316880 发表于 2020-3-5 22:52 | 显示全部楼层
说一下我用STC8A8K,12位AD的经验,也是按照PDF资料这个搭建的电路,程序不加软件虑波直接出来的结果跳变特别严重,后面想是不是电压不稳点,用示波器看TL431的2.5V有一点点波浪,不稳点,后面我直接把TL431直接去了,直接5v做基准,数据跳变就没有多大厉害,然后在程序里面加个平均值虑波,数据很稳点,如果数据转换出来不稳点,应该检查TL431的2.5V有没有波浪,和通道输入的虑波,还有电源电压有没有很大波浪。
回复

使用道具 举报

ID:316880 发表于 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电压,结果稳的一批,效果杠杠的
回复

使用道具 举报

ID:633626 发表于 2020-3-6 19:30 | 显示全部楼层
余生不负 发表于 2020-3-5 22:57
示波器看一下电源电压稳点不,然后看TL431的2.5V,我之前就是2.5V示波器看了有一点点文波,我直接把431去 ...

“AVCC经过510R电阻5v直接上”的意思是AVCC经过510R连接到Vref吗?为什么要加电阻,直接连上不可以吗
回复

使用道具 举报

ID:120930 发表于 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
}
回复

使用道具 举报

ID:120930 发表于 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
}
回复

使用道具 举报

ID:120930 发表于 2020-3-14 11:16 | 显示全部楼层
第一次发的代码有个错误 第二次的改正了
回复

使用道具 举报

ID:165291 发表于 2020-3-25 16:16 | 显示全部楼层
同问呢!
回复

使用道具 举报

ID:165291 发表于 2020-3-25 16:16 | 显示全部楼层
这样结果是正常的,可采用软件滤波减少波动。方法:连续采集10次,去除最大、最小各一个,余下8个取平均。
回复

使用道具 举报

ID:602576 发表于 2020-3-25 16:42 | 显示全部楼层
基准芯片TL431驱动能力不够的话,在后面加一个运放跟随,增加驱动电流,或者直接换一个基准源就行了。楼上的几位提得都对,应该软件采集后滤波,平均值,中值滤波都可以,信号到AD输入端,接一个104的电容滤波,中间可以串一个25-50欧的小电阻
回复

使用道具 举报

ID:228467 发表于 2020-3-25 17:05 | 显示全部楼层
都是好经验,学习了!
回复

使用道具 举报

ID:316880 发表于 2020-3-25 20:12 | 显示全部楼层
lenceliu 发表于 2020-3-6 19:30
“AVCC经过510R电阻5v直接上”的意思是AVCC经过510R连接到Vref吗?为什么要加电阻,直接连上不可以吗

不加也可以,因为我把431拿掉了。
回复

使用道具 举报

ID:316880 发表于 2020-3-25 20:20 | 显示全部楼层
sduking 发表于 2020-3-25 16:42
基准芯片TL431驱动能力不够的话,在后面加一个运放跟随,增加驱动电流,或者直接换一个基准源就行了。楼上 ...

用不着那么麻烦,只要AVCC稳定5V直接上,测量范围0-5V,你要是用431,范围就是0-2.5V,这个不好用。
回复

使用道具 举报

ID:241128 发表于 2020-3-26 02:18 | 显示全部楼层
mark最近用到STC8a系列12位AD,希望能用到。。。
回复

使用道具 举报

ID:25310 发表于 2020-3-26 08:58 | 显示全部楼层
431用处不大,看好5V电压纹波比这个重要,用过STC15w32s4 10ADC 精度也能做到10mV
回复

使用道具 举报

ID:65956 发表于 2020-3-26 09:23 | 显示全部楼层
我认为是你计算直接用5V的参数值作计算的,你最好测一下现在板上工作的实际电压值,然后代入这个值进行计算就OK了,不然就读取芯片内部的基准源再计算MCU的工作电压会更稳定
回复

使用道具 举报

ID:420836 发表于 2020-3-26 09:48 | 显示全部楼层
似乎参考电压存在一些问题,如果它平均波动20 mV,则转换后的结果波动可能是平均20点或更大。
回复

使用道具 举报

ID:371527 发表于 2020-5-17 10:24 | 显示全部楼层
首先,VREF稳压输出要加10uF,TL431也有品质好坏。其次采集端口要串接电阻并加104电容
回复

使用道具 举报

ID:420836 发表于 2020-5-17 21:43 | 显示全部楼层
试添加软件滤波器以平均模拟读数,以消除转换中的较大波动。
回复

使用道具 举报

ID:261024 发表于 2020-5-30 13:58 | 显示全部楼层
431基准电压输出滤波电容不能太大,104都大了,用102吧,要不然基准电压都不稳,用示波器观察有纹波的。
回复

使用道具 举报

ID:471427 发表于 2020-6-28 18:46 | 显示全部楼层
同问
回复

使用道具 举报

ID:519089 发表于 2020-6-30 13:51 | 显示全部楼层
MCU_VCC和模拟Vref 要分开,TL431输出电容不够大
回复

使用道具 举报

ID:752906 发表于 2020-7-14 18:59 | 显示全部楼层
STC的ad输入是没有缓冲的,内阻很小
回复

使用道具 举报

ID:420836 发表于 2020-7-15 08:46 | 显示全部楼层
305/5000
ADC值波动的原因有很多,您需要检查参考电压是否稳定,或者是否存在接地噪声,或者信号调节电路中是否有正确的低通滤波器。 从软件的角度来看,您需要软件过滤器算法来平均测量值。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表