乐此不疲 发表于 2024-2-19 12:48:23

请教,我用ADC测直流电压的误差大的原因?

本帖最后由 乐此不疲 于 2024-2-19 12:53 编辑

我用STC8H8K64U-pin20芯片的pin20引脚(P1.0)的ADC0通道测量直流电压感觉误差较大,不知道是采样电阻参数有问题还是数据采集方法有问题亦或是哪里有问题?请各位大神帮忙看看,先谢了。
一、现象与问题:
1.我用数字万用表测量两个采样电阻的阻值都是1.00xMΩ
2.测量VCC=3.294V,Vin=2.370V。
3.测量的12位数据=3092
利用手册中的公式计算,3.3V基准下2.37V信号电压的12位ADC值应为:2942
利用手册中的公式计算,12位采样值3092标定的电压值应为:2.49V
问题:感觉2.37V测出来2.49V的误差大了一些,不知道问题出自哪里?
新入手的数字万用表20V挡分辨率0.001V(+-0.1% +3)
二、接线图:

三、测试代码:
//-------------------------------------------------------
#include <STC8H.h>

#define FOSC 11059200UL
#define BRT (65536 - (FOSC / 115200+2) / 4)

bit busy;

//--------------------------------------------------------
void delay_1ms(u16 value) //@22.1184MHz
{
    u8 i,j;
    while(value>0)
    {
      i = 29;
      j = 183;
      do
      {
            while (--j);
      } while (--i);
      value--;
    }
}
//----字节发送函数---------------------------------------
/*
void SendByte(u8 D)
{
SBUF=D;
while(!TI);
TI=0;
}*/
//------------------------------------------------------
void ADC_Init()
{
P1M0 = 0x00;
P1M1 = 0x02;                        //设置P1.1为高阻模式(ADC 口)
P1IE = 0xfd;                        //关闭P1.1数字通道

ADCTIM = 0x3f;               //设置 ADC 内部时序
ADCCFG = 0x2f;               //设置 数据存放为高4位+低8位模式、ADC 时钟为系统时钟/2/16
ADC_CONTR = 0x80;      //使能 ADC0 模块
delay_1ms(5);      
}

//-------------------------------------------------------------------
void ADCRead()
{
ADC_RES = 0;
ADC_RESL = 0;
ADC_CONTR=0xc1;                                                      //启动AD转换ADC_POWER=1、ADC_START=1
delay_1ms(5);
while ((ADC_CONTR & 0x20)==0);      //等待ADC转换标志ADC_FLAG=1
ADC_CONTR &= ~0x20;               //清除标志
//return ((u16)ADC_RES * 256 + (u16)ADC_RESL);
}
//---------------------------------

void UartIsr() interrupt 4
{
if (TI)
{
TI = 0;
busy = 0;
}
if (RI)
{
RI = 0;
}
}
//--------------------------------
void UartInit()
{
SCON = 0x50;
TMOD = 0x00;
TL1 = BRT;
TH1 = BRT >> 8;
TR1 = 1;
AUXR = 0x40;
busy = 0;
}
//----------------------------------
void UartSend(char dat)
{
while (busy);
busy = 1;
SBUF = dat;
}
//====主函数===========================================
void main()
{
GPIO_set();                //预置所有I/O口全部为准双向口
EAXSFR();
ADC_Init();
UartInit();
ES = 1;
EA=1;
while(1)
{
ADCRead();
UartSend(ADC_RES); //串口输出采样结果高8位
UartSend(ADC_RESL);//串口输出采样结果低8位
delay_1ms(1000);

}
}



王昱顺 发表于 2024-2-19 13:06:53

首先应该尝试较短时间的连续发送adc测量数值,看看是否有波动。
如果存在波动,应该使用均值滤波算法对一段时间内的多个采样值进行滤波取出一个平均值来。
或者可以尝试更改ADCTIM寄存器,延长采样时间,这样会更准确。
当然最准确的,应该是采用独立给adcref参考电压进行供电的方式

乐此不疲 发表于 2024-2-19 13:17:13

王昱顺 发表于 2024-2-19 13:06
首先应该尝试较短时间的连续发送adc测量数值,看看是否有波动。
如果存在波动,应该使用均值滤波算法对一段 ...

多谢你的回复与指点,我会根据你的建议继续各种尝试的,先谢了。

王昱顺 发表于 2024-2-19 13:22:47

乐此不疲 发表于 2024-2-19 13:17
多谢你的回复与指点,我会根据你的建议继续各种尝试的,先谢了。

如果没有测量ADC时间的要求,可以将ADCTIM设置成0xff试试,先从硬件下手,看看是否有有所改变。
使用软件进行滤波并不能提高精度,只是一种抗干扰手段

王昱顺 发表于 2024-2-19 13:26:13

乐此不疲 发表于 2024-2-19 13:17
多谢你的回复与指点,我会根据你的建议继续各种尝试的,先谢了。

我知道你这啥问题了


你测量的是P10
但是却只设置了P11为高阻模式,P10实际上是高阻模式
此时因为准双向口带有一个较大的电阻上拉,所以检测到的数值并不是准确的。
应该使用

    P1M0 &= ~0x01; P1M1 |= 0x01;

这个语句设置P10为高阻模式,应该就可以了

乐此不疲 发表于 2024-2-19 13:28:39

王昱顺 发表于 2024-2-19 13:22
如果没有测量ADC时间的要求,可以将ADCTIM设置成0xff试试,先从硬件下手,看看是否有有所改变。
使用软件 ...

我正在做多次采样取均值的实验,结果比现在的误差还有所增加,回头再测试ADCTIM吧,多谢!

梁工 发表于 2024-2-19 16:50:25

输入内阻太大了,ADC输入需要采样的,有一点点电流,你可以尝试使用两个10K电阻分压对比就能看出来。
太大的输入电阻,最好能佣运放缓冲一下。
也可以用两个三极管(NPN+PNP)做开关接通电池,用2个10K电阻分压测量,将得到准确的数值。

乐此不疲 发表于 2024-2-19 19:01:36

问题解决了,感谢梁老师指出了问题的症结所在,他的答案不但回答了我的问题:“感觉误差较大,不知道是采样电阻参数有问题还是数据采集方法有问题亦或是哪里有问题?”,而且赠送了我一个方法:用三极管做开关、用适当的电流供给采样,这不但保证了采样精度还解决了功耗问题,诚心表示感谢,最后说说结果:
说结果之前还要感谢坛友“王**”的热心指点,他指出了程序中的错误,也给出了调整ADCTIM和多次采样取均值的建议,对此我都做了测试在此一并给出我的测试结果。
1.首先按照例程给出的ADCTIM=0X3F和坛友建议的ADCTIM=0XFF对比结果没有变化。
2.加入16次采样取均值后只在采样值的各位有微小的变化。
3.超低采样电流时如果采样端口设为准双向+关闭数字输入通道时(1#代码中的配置错误)采样数据变大,变大比例如同我提问时的数据正常时的2942变高为3092,如果是正常配置时(高阻+关闭数字)数据会更高偏离更远。
4.最终配置与结果如下:
采样电阻为两只4.7k电阻串联,获得的采样电压Vin=2.52V,单片机电源电压VCC=3.3V,12位ADC理论采样值=3127.8,得到实际采样值=3128-3135



页: [1]
查看完整版本: 请教,我用ADC测直流电压的误差大的原因?