找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5756|回复: 9
收起左侧

stc8单片机ADC切换采样异常问题

[复制链接]
ID:708541 发表于 2021-3-22 15:23 | 显示全部楼层 |阅读模式
任意单个通道采样没有问题,连续切换通道采样就出现异常,比如我用P1.0和P1.1,这2个脚连续ADC采样,P1.0第一次采样正常,通道++,切换到P1.1采样,也正常,然后循环切换到P1.0的时候,P1.0是没有电压输入的,P1.1的输入3.3V,采样的结果直接赋到P1.0里面,意思就是说,P1.1有电压那直接给P1.0,好像芯片内部P1.0和P1.1联通了一样,程序我调试了一天,我肯定不是程序的问题,我怀疑是芯片的问题了。
回复

使用道具 举报

ID:895064 发表于 2021-3-22 16:06 | 显示全部楼层
我也怀疑是芯片的问题
回复

使用道具 举报

ID:123289 发表于 2021-3-22 16:38 | 显示全部楼层
在AD的硬件中,有一个采样电容,当你下达采样命令后,会经历如下的过程:
1、将这个电容与端口连通,并保持若干个时钟。目的让电容上得到与端口一样的电压。
2、再切断与端口的连接,防止在进行电压比较时,电压有波动,影响、绞乱逐次逼近的逻辑。
3、接下来才进行真正的AD转换(逐次逼近),需要N个时钟周期,得到AD值。
所以,采样时要注意(这是精华):
切换端口后,要过一段时间再下达采样命令,因为刚切换后,采样电容上是上一个通道的电压,需要有一个充放电的过程,才能变为新通道端口上的电压。这一点相当重要!!!新手一般不会考虑到这一点,许多高手也吃它的苦。表现为采样电压的数据不稳定,其实是部分地受上个通道的电压“残余”影响了。

回到楼主的问题:P1.0是没有电压输入的,即空脚。当切换到P1.0之后,采样电容上的电压还是上个通道P1.1上的电压,这时尽管它接改到P1.0上了,但采样电容被浮空(接在空脚上),也就没有充放电回路,电压也就不会有变化了,当然……,不必再说了。

读不透AD采样的原理,就无法理解采样不准的原因!

评分

参与人数 1黑币 +5 收起 理由
ax6808 + 5

查看全部评分

回复

使用道具 举报

ID:708541 发表于 2021-3-22 17:08 | 显示全部楼层
以前STC15系列都不会出现这样的问题,stc8,往后出的单片机感觉技术都不是很成熟,经常出现一些奇怪的问题,
回复

使用道具 举报

ID:879348 发表于 2021-3-22 17:20 | 显示全部楼层
因为采样保持电容的存在
回复

使用道具 举报

ID:1065343 发表于 2023-3-5 23:59 | 显示全部楼层
问题解决了吗?我也遇到同样的问题
回复

使用道具 举报

ID:579397 发表于 2023-3-6 01:00 | 显示全部楼层
yzwzfyz 发表于 2021-3-22 16:38
在AD的硬件中,有一个采样电容,当你下达采样命令后,会经历如下的过程:
1、将这个电容与端口连通,并保 ...

结合这层的评论,楼主在切换通道采用多少次,看官方的范例,需要丢弃前两次的结果。

ADCRead();
  ADCRead();                                  //前两个数据建议丢弃

    res = 0;
    for (i=0; i<8; i++)
    {
        res += ADCRead();                       //读取8次数据
    }
    res >>= 3;                                  //取平均值

回复

使用道具 举报

ID:1034262 发表于 2023-3-6 10:12 | 显示全部楼层
不是芯片的问题,芯片要有这个问题,根本就没法面市。
ADC输入悬空的通道,采样时,采样电容没法充放电,所以看似受上一个通道的影响。
楼主要多了解一下ADC的原理,就不会有此问。
回复

使用道具 举报

ID:975054 发表于 2023-5-24 17:27 | 显示全部楼层
405616736 发表于 2023-3-6 01:00
结合这层的评论,楼主在切换通道采用多少次,看官方的范例,需要丢弃前两次的结果。

ADCRead();

说起STC15通道ADC范例这个8次平均代码,当然没有问题。
我之前用20脚STC8G1K08又多出好多脚感觉不爽,近期改8脚STC8G1K08A (练练多脚复用,体积没小多少,还厚一些,才便宜几毛,好手工焊而已)。双路ADC(因引脚不够,其中1路直接改用15通道先测MCU供电电压VCC,再换算电池电压了,另外一路P55脚复用,P30P31串口调试ISPLED复用等等)。之前2个通道ADC代码全部放在一起共用不少代码,只顺序切换通道读取转换一下,没有刻意中间隔一段时间(之前2个空操作,这次有地方就多加了3个),也没用8次平均方法,每次都一次顺利读取转换成功。可能是我之前测的内置2个都是电池电压,比较稳定或者精度要求没那么高吧(这次另外一路测的光敏电阻和1M大电阻分压值,光敏电阻还并联了一个LED,罕见见的。。。。玩呗)!

void BAT()                //VCC电压ADC15,P55电压ADC5,低电量告警及充电指示等(早晚光控代码另列); P3031P55三脚复用最简方案用   230523;
{  
    u16 res, *BGV;                  //res:ADC结果(分辨率); *BGV:指针变量;
    res=0;                                        //         230524:int全改为u16没有问题(但得同时改!);
    BGV = (u16 idata *)0xef;        //获取内部电压(1次即可),内部1.19V参考源值存放在idata中,EFH高字节F0H低字节;单位mV;

    P5IE=P5M1=0x20, R=G=b=1;                //1、ADC前:P55允许输入短暂置高阻,关彩灯可提高ADC稳定准确度!
                                                    //2. ADC设置(2句共用):
    ADCCFG = 0x2f;                              //设置ADC时钟为系统时钟/2/16 (含右对齐);
    ADCTIM = 0x3f;                              //设置ADC内部时序:(手册建议3f,2A~3F);
                                                    //3、ADC15:        VCC和Vbat电压检测;                     
    ADC_CONTR = 0xcf;                           //使能ADC模块,并选择第15通道,启动转换3合1;
    _nop_(),_nop_(),_nop_(),_nop_(),_nop_();           //参考手册2个空操作
    while (!(ADC_CONTR & 0x20));                //查询ADC完成标志
    ADC_CONTR &= ~0x20;                         //清完成标志
//  ADC_CONTR &=  0x7F;                                    //ADC转换完即断电更省电;        (这里后面再一起关);
    res = (ADC_RES << 8) | ADC_RESL;            //读取ADC结果 (右对齐:高2位低8位,前面自动补0);
    VCC =(u16)(1024L * *BGV/res);        //先算1次后面再分好;  再处理Vbat修正值+150;
    Vbat=VCC+150L;                                 //

                                                 //4、ADC5: VP55电压检测/早晚判断;                                             
    ADC_CONTR = 0xc5;                           //使能ADC模块,并选择第15通道,启动转换3合1;
    _nop_(),_nop_(),_nop_(),_nop_(),_nop_();           //参考手册2个空操作
    while (!(ADC_CONTR & 0x20));                //查询ADC完成标志
    ADC_CONTR &= ~0x20;                         //清完成标志
    ADC_CONTR &=  0x7F;                                    //ADC转换完即断电更省电;        (这里后面再一起关);
    res  = (ADC_RES << 8) | ADC_RESL;           //读取ADC结果 (右对齐:高2位低8位,前面自动补0);
    VP55 =(u16)((u32)VCC*(u32)res >>10);        //220524:/1024改右移10位快,注意变量运算转换避免溢出错误等;                           

    if(CHG==0)                      //5、低电量告警/自动待机; 未充电有效;   230518;               
   {
    if(Vbat>=3438 && Vbat<=3480)                                                 //1-5%告警:红灯PD2秒快慢闪1遍;同时关大灯;           
      {W=R=G=b=1, dl_ms(100),R=0,dl_ms(50),R=1,dl_ms(100),R=0,dl_ms(100),R=1;}
    if(Vbat<3438) { W=R=G=b=1, status=2;}                           //<1%灯全灭转状态2:自动待机;                                                                        
   }                                                                                                                                                   
    else                            //6、充电状态指示:4种;   不进PD不待机!  230516;            
   {status=3, R=G=b=1;                                                        //转状态3:充电指示;先灭彩灯;
    if   (Vbat>4132) {G=0,dl_ms( 100),G=1,     dl_ms( 500);}       //   100%:绿灯常闪;  可当提醒;  (95%当充满保护,全按0℃,+5mV);
    else                                                                                 
    {if  (Vbat>4077) {G=0,dl_ms(1000),G=1,     dl_ms( 100);}       // > 90%:绿灯亮1秒,    闪1次;
     else                                                                                          
     {if (Vbat>3918) {G=0,dl_ms(1000),G=1, R=0,dl_ms( 100),  R=1;} // > 75%:绿灯亮1秒,红灯闪1次;         230502 增加1档;
      else                                                                                   
      {if(Vbat>3716) {R=0,dl_ms(1000),R=1, G=0,dl_ms( 100),  G=1;} // > 50%:红灯亮1秒,绿灯闪1次;                                             
       else          {R=0,dl_ms(1000),R=1,     dl_ms( 100);}       //<= 50%:红灯亮1秒,    闪1次;                                      
   }}}}
}


评分

参与人数 1黑币 +60 收起 理由
admin + 60 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:975054 发表于 2023-5-25 01:11 | 显示全部楼层
ax6808 发表于 2023-5-24 17:27
说起STC15通道ADC范例这个8次平均代码,当然没有问题。
我之前用20脚STC8G1K08又多出好多脚感觉不爽,近 ...

串口测试/监控打印情况:
   printf("VCC = %4.3f",(f32)VCC /1000),printf("V  \n\n");          
   printf("Vbat= %4.3f",(f32)Vbat/1000),printf("V  \n\n");          
   printf("VP55= %4.3f",(f32)VP55/1000),printf("V  \n\n");          
   printf("VLED= %4.3f",(f32)(VCC-VP55)/1000),printf("V  \n\n");        
   printf("  Kc=%2bu",Kc),printf("  DN=%2bu",DN), printf("  status=%1bu\n",status);

串口助手显示:
VCC = 3.736V                 //ADC15
Vbat= 3.886V                  // VCC+0.15V 电池防反接二极管5819压降
VP55= 1.371V                //ADC5:光控电路检测点电压
VLED= 2.365V                //大LED灯压降( VCC-VP55)
Kc= 6  DN= 1  status=0  //Kc:短按组合彩灯模式切换次数0-10循环
                                     //DN=0白天/1晚上   
                                     //status=0正常工作/1一键关机ISP/2自动待机/3充电指示
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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