找回密码
 立即注册
查看: 304|回复: 10

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

[复制链接]
  • TA的每日心情
    开心
    昨天 11:24
  • 签到天数: 129 天

    [LV.7]常住居民III

    30

    主题

    107

    回帖

    944

    积分

    高级会员

    积分
    944
    发表于 2024-2-19 12:48:23 | 显示全部楼层 |阅读模式
    本帖最后由 乐此不疲 于 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)
    二、接线图:
    3333.jpg
    三、测试代码:
    1. //-------------------------------------------------------
    2. #include <STC8H.h>
    3. #define FOSC 11059200UL
    4. #define BRT (65536 - (FOSC / 115200+2) / 4)
    5. bit busy;
    6. //--------------------------------------------------------
    7. void delay_1ms(u16 value) //@22.1184MHz
    8. {
    9.     u8 i,j;
    10.     while(value>0)
    11.     {
    12.         i = 29;
    13.         j = 183;
    14.         do
    15.         {
    16.             while (--j);
    17.         } while (--i);
    18.         value--;
    19.     }
    20. }
    21. //----字节发送函数---------------------------------------
    22. /*
    23. void SendByte(u8 D)
    24. {
    25. SBUF=D;
    26. while(!TI);
    27. TI=0;
    28. }*/
    29. //------------------------------------------------------
    30. void ADC_Init()
    31. {
    32. P1M0 = 0x00;
    33. P1M1 = 0x02;                        //设置P1.1为高阻模式(ADC 口)
    34. P1IE = 0xfd;                        //关闭P1.1数字通道
    35. ADCTIM = 0x3f;                 //设置 ADC 内部时序
    36. ADCCFG = 0x2f;                 //设置 数据存放为高4位+低8位模式、ADC 时钟为系统时钟/2/16
    37. ADC_CONTR = 0x80;        //使能 ADC0 模块
    38. delay_1ms(5);        
    39. }
    40. //-------------------------------------------------------------------
    41. void ADCRead()
    42. {
    43. ADC_RES = 0;
    44. ADC_RESL = 0;
    45. ADC_CONTR=0xc1;                                                        //启动AD转换ADC_POWER=1、ADC_START=1
    46. delay_1ms(5);
    47. while ((ADC_CONTR & 0x20)==0);        //等待ADC转换标志ADC_FLAG=1
    48. ADC_CONTR &= ~0x20;                 //清除标志
    49. //return ((u16)ADC_RES * 256 + (u16)ADC_RESL);
    50. }
    51. //---------------------------------
    52. void UartIsr() interrupt 4
    53. {
    54. if (TI)
    55. {
    56. TI = 0;
    57. busy = 0;
    58. }
    59. if (RI)
    60. {
    61. RI = 0;
    62. }
    63. }
    64. //--------------------------------
    65. void UartInit()
    66. {
    67. SCON = 0x50;
    68. TMOD = 0x00;
    69. TL1 = BRT;
    70. TH1 = BRT >> 8;
    71. TR1 = 1;
    72. AUXR = 0x40;
    73. busy = 0;
    74. }
    75. //----------------------------------
    76. void UartSend(char dat)
    77. {
    78. while (busy);
    79. busy = 1;
    80. SBUF = dat;
    81. }
    82. //====主函数===========================================
    83. void main()
    84. {
    85. GPIO_set();                //预置所有I/O口全部为准双向口
    86. EAXSFR();
    87. ADC_Init();
    88. UartInit();
    89. ES = 1;
    90. EA=1;
    91. while(1)
    92. {
    93. ADCRead();
    94. UartSend(ADC_RES); //串口输出采样结果高8位
    95. UartSend(ADC_RESL);//串口输出采样结果低8位
    96. delay_1ms(1000);
    97. }
    98. }
    复制代码


    回复 送花

    使用道具 举报

  • TA的每日心情
    开心
    昨天 19:05
  • 签到天数: 123 天

    [LV.7]常住居民III

    33

    主题

    397

    回帖

    2048

    积分

    荣誉版主

    积分
    2048
    发表于 2024-2-19 13:06:53 | 显示全部楼层
    首先应该尝试较短时间的连续发送adc测量数值,看看是否有波动。
    如果存在波动,应该使用均值滤波算法对一段时间内的多个采样值进行滤波取出一个平均值来。
    或者可以尝试更改ADCTIM寄存器,延长采样时间,这样会更准确。
    当然最准确的,应该是采用独立给adcref参考电压进行供电的方式
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    昨天 11:24
  • 签到天数: 129 天

    [LV.7]常住居民III

    30

    主题

    107

    回帖

    944

    积分

    高级会员

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

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

    点评

    我知道你这啥问题了 [attachimg]35364[/attachimg] 你测量的是P10 但是却只设置了P11为高阻模式,P10实际上是高阻模式 此时因为准双向口带有一个较大的电阻上拉,所以检测到的数值并不是准确的。 应该使用 P1M  详情 回复 发表于 2024-2-19 13:26
    如果没有测量ADC时间的要求,可以将ADCTIM设置成0xff试试,先从硬件下手,看看是否有有所改变。 使用软件进行滤波并不能提高精度,只是一种抗干扰手段  详情 回复 发表于 2024-2-19 13:22
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    昨天 19:05
  • 签到天数: 123 天

    [LV.7]常住居民III

    33

    主题

    397

    回帖

    2048

    积分

    荣誉版主

    积分
    2048
    发表于 2024-2-19 13:22:47 | 显示全部楼层
    乐此不疲 发表于 2024-2-19 13:17
    多谢你的回复与指点,我会根据你的建议继续各种尝试的,先谢了。

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

    使用道具 举报

  • TA的每日心情
    开心
    昨天 19:05
  • 签到天数: 123 天

    [LV.7]常住居民III

    33

    主题

    397

    回帖

    2048

    积分

    荣誉版主

    积分
    2048
    发表于 2024-2-19 13:26:13 | 显示全部楼层
    乐此不疲 发表于 2024-2-19 13:17
    多谢你的回复与指点,我会根据你的建议继续各种尝试的,先谢了。

    我知道你这啥问题了
    截图202402191324281663.jpg

    你测量的是P10
    但是却只设置了P11为高阻模式,P10实际上是高阻模式

    此时因为准双向口带有一个较大的电阻上拉,所以检测到的数值并不是准确的。
    应该使用

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

    这个语句设置P10为高阻模式,应该就可以了
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    昨天 11:24
  • 签到天数: 129 天

    [LV.7]常住居民III

    30

    主题

    107

    回帖

    944

    积分

    高级会员

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

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

    点评

    请看5#回答  发表于 2024-2-19 13:31
    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    46

    主题

    3044

    回帖

    6863

    积分

    超级版主

    积分
    6863
    发表于 2024-2-19 16:50:25 | 显示全部楼层
    输入内阻太大了,ADC输入需要采样的,有一点点电流,你可以尝试使用两个10K电阻分压对比就能看出来。
    太大的输入电阻,最好能佣运放缓冲一下。
    也可以用两个三极管(NPN+PNP)做开关接通电池,用2个10K电阻分压测量,将得到准确的数值。
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    昨天 11:24
  • 签到天数: 129 天

    [LV.7]常住居民III

    30

    主题

    107

    回帖

    944

    积分

    高级会员

    积分
    944
     楼主| 发表于 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



    回复 支持 反对 送花

    使用道具 举报

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

    本版积分规则

    QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

    GMT+8, 2024-5-20 07:59 , Processed in 0.077022 second(s), 65 queries .

    Powered by Discuz! X3.5

    © 2001-2024 Discuz! Team.

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