找回密码
 立即注册
楼主: 我的用户名

ADC采集为什么有时候是0?

[复制链接]
  • 打卡等级:偶尔看看III
  • 打卡总天数:45
  • 最近打卡:2025-04-28 09:23:48

3

主题

43

回帖

493

积分

中级会员

积分
493
发表于 2024-11-19 15:22:30 | 显示全部楼层
pzeg*** 发表于 2024-11-16 16:47
重点是:使用SOP8 或DIP8  
使用8脚的就有这种现象 使用16脚的就没有
是不是设置上还要设置什么

我复制了你的代码进行测试,运行了数十分钟没有出现ADC异常为0的状态

这段代码中发现有一处错误:设置 ADCTIM  寄存器前应先将 P_SW2 的第7位置1,否则是向此地址的XDATA进行操作。
但我在本次测试中并无修改此处,所以这个寄存器的设置应该是没有生效的。

代码运行读取ADC第1通道,如果读取结果小于10,将在OLED显示屏上显示结果,并进行次数累加,否则显示当前值(为演示效果,实际上去掉正常时显示,让ADC快速重复读取也不影响结果)。
且可以见到,开关切换到USB输入电压测量时,并未出现ADC值小于10的情况,开关切换到外部输入时,测量值为零,计数累加,逻辑无误。

电路板中使用的主控是 STC8G1K08A ,封装为 SOP8,单片机供电电压为3V
电路图如下:输入USB的5V连接到 USB_VINP ,外部切换开关按下后,USB输入电压切换到 VIN1_ADC,单片机P3.1引脚(ADC1通道)连接到 VIN1_ADC 进行测量。
截图202411191510283470.jpg

完整工程见:oshwhub.com/rm543/dig_loader_v06  (立创OSHW开源广场,复制到浏览器打开)



video_20241119_150026.mp4

41.38 MB, 下载次数: 67

测试视频

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2024-05-02 21:48:56

6

主题

48

回帖

614

积分

高级会员

积分
614
发表于 2024-11-19 19:39:55 | 显示全部楼层
本帖最后由 qq603599910 于 2024-11-19 19:48 编辑

我这边有复制到靠近DC-DC电路偶尔值为零会更加频繁,单独焊了一片MCU连线到原板子做ADC读取.我的板子很小不能远离DC-DC电路,现在在尝试判定输出值为零就重新读一次.

以下是ADC循环10次轮询2个通道的输出值截图,没有规律偶发输出值为0 .

截图202411191948127374.jpg
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2024-05-02 21:48:56

6

主题

48

回帖

614

积分

高级会员

积分
614
发表于 2024-11-19 19:56:58 | 显示全部楼层
以上是调试代码,试了其他时钟和ADC时序配置都一样,靠近DC-DC后出现偶发输出零值,IC地线连接可靠,增加电源和输入滤波调试没有改善.

========================
    //启动ADC
    P_SW2 |= 0x80;
    ADC_CONTR = 0x80;
    //ADCTIM = 0x2f;        
    ADCTIM = 0xff;                              //设置ADC内部时序
    P_SW2 &= 0x7f;
    ADCCFG = RES_FMT + ADC_SPEED;
    //ADCCFG = 0x2f;                              //设置ADC时钟为系统时钟

========================
//读取ADC
int ADC_Read(u8 ch)
{
    u16 adc_value[10],i;
    for(i = 0 ; i < 10 ; i++)
    {
        ADC_CONTR = (ADC_CONTR & 0xf0) | 0x40 | ch ;  //启动AD转换+通道
        _nop_();
        _nop_();
        _nop_();
        while (!(ADC_CONTR & 0x20));                //查询ADC完成标志
        ADC_CONTR &= ~0x20;                         //清完成标志
        adc_value[i]= ((ADC_RES << 8) | ADC_RESL);
    }

    if(ch != 15)
    {
        for(i = 0 ; i < 10 ; i++)
        {
            uart_send(adc_value[i]+1);
            SBUF = 0X2C ;
            Delay10ms();

        }
        SBUF = 0X0D ;
        Delay10ms();
        SBUF = 0X0A ;
        Delay10ms();

    }
    return(adc_value[7]);

}




回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:45
  • 最近打卡:2025-04-28 09:23:48

3

主题

43

回帖

493

积分

中级会员

积分
493
发表于 2024-11-19 20:04:13 | 显示全部楼层
qq6035*** 发表于 2024-11-19 19:56
以上是调试代码,试了其他时钟和ADC时序配置都一样,靠近DC-DC后出现偶发输出零值,IC地线连接可靠,增加电源和 ...

既然是靠近干扰源出的问题,用示波器表笔加弹簧接地怼到MCU引脚上看波形吧,别纠结代码了。
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2024-05-02 21:48:56

6

主题

48

回帖

614

积分

高级会员

积分
614
发表于 2024-11-19 20:33:30 | 显示全部楼层
rm5*** 发表于 2024-11-19 20:04
既然是靠近干扰源出的问题,用示波器表笔加弹簧接地怼到MCU引脚上看波形吧,别纠结代码了。 ...

要是能从波形解决早解决啦,我最早就是用示波器确认各路波形,平滑稳定的很,MCU供电和ADC_REF使用LDO二次稳压,ADC的输入也是用10U叠层电容滤波,干扰纹波基本看不到,为了MCU不被干扰,多余几个PIN还直接接地了.
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2024-05-02 21:48:56

6

主题

48

回帖

614

积分

高级会员

积分
614
发表于 2024-11-19 20:37:44 | 显示全部楼层
rm5*** 发表于 2024-11-19 20:04
既然是靠近干扰源出的问题,用示波器表笔加弹簧接地怼到MCU引脚上看波形吧,别纠结代码了。 ...

一般干扰出现是ADC数值乱跳吧,但看原数值是很稳定输出正常值然后就偶发一次"0"值,都是无间隙循环采集,这得多尖峰的干扰能做到这样子的状态呢...
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:45
  • 最近打卡:2025-04-28 09:23:48

3

主题

43

回帖

493

积分

中级会员

积分
493
发表于 2024-11-19 21:00:40 | 显示全部楼层
qq6035*** 发表于 2024-11-19 20:33
要是能从波形解决早解决啦,我最早就是用示波器确认各路波形,平滑稳定的很,MCU供电和ADC_REF使用LDO二次稳 ...

ADC时钟有没有超速?把原理图和PCB贴出来才好分析
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2024-11-19 22:19:37
已绑定手机

0

主题

12

回帖

80

积分

注册会员

积分
80
发表于 2024-11-19 21:38:05 | 显示全部楼层

把前面说的缺少 P_SW2的这两句也补了上去 还是一样,现在是显示累加小于100的次数
因为输入端脚已经直接连接5V电源,不存在输入端口干扰问题,
主要是同一程序在16脚的芯片上没有问题,现在用8脚的STC8G1K08A-DIP8 这个0值好像没有规律
有1秒来的 几秒来的十几秒也有




/**************************************************
*实验项目:ADC转换显示
*MCU 配置:STC8G1K08A(DIP8/SOP8)  (1T 晶振11MHz)

**************************************************/
#include <REG51.H>     //定义头文件 包含端口及各种特殊寄存器
sfr P4=0xC0;           //端口4
sfr P5=0xC8;           //端口5
#include <INTRINS.H>   //包含内部函数 _nop_();空函数需要


//--------------- 定义端口功能 ----------------------
sbit SB0=P3^2;    //功能按键

sbit LED=P5^5;    //状态灯
sbit KA0=P5^4;    //继电器

sbit SDA_1637=P3^1;    //数据DIO
sbit SCL_1637=P3^0;    //时钟CLK

bit Mzh=0;   //转换显示
bit Msd;     //锁定计数一次

unsigned int CCtemp; //计数
unsigned int DDadc; //读取模拟量
unsigned int DDmax=0, DDmin=1000; //用于存放最大和最小值

//----------------   端口初始化设置   --------------------------
sfr P_SW1 = 0xA2;
sfr P_SW2 = 0xBA;

sfr P0M1  = 0x93; //设置P0 端口模式寄存器
sfr P0M0  = 0x94; //
sfr P1M1  = 0x91; //设置P1 端口模式寄存器
sfr P1M0  = 0x92; //
sfr P2M1  = 0x95; //设置P2 端口模式寄存器
sfr P2M0  = 0x96; //
sfr P3M1  = 0xB1; //设置P3 端口模式寄存器
sfr P3M0  = 0xB2; //
sfr P4M1  = 0xB3; //设置P4 端口模式寄存器
sfr P4M0  = 0xB4; //
sfr P5M1  = 0xC9; //设置P5 端口模式寄存器
sfr P5M0  = 0xCA; //

/*===================================
STC8系端口初始化
====================================*/
void Port_Init(void) //端口初始化
{
P0M1 = 0x00; //0000 0000 设置P0全部为准双向模式
P0M0 = 0x00; //0000 0000

P1M1 = 0x00; //0000 0000 设置P1全部为准双向模式
P1M0 = 0x00; //0000 0000

P2M1 = 0x00; //0000 0000 设置P2全部为准双向模式
P2M0 = 0x00; //0000 0000

P3M1 = 0x08; //0000 1000 设置P3.3为高阻输入模式(读取模拟量)
P3M0 = 0x00; //0000 0000

P4M1 = 0x00; //0000 0000 设置P4全部为准双向模式
P4M0 = 0x00; //0000 0000

P5M1 = 0x00; //0000 0000 设置P5全部为准双向模式
P5M0 = 0x00; //0000 0000
}


//---------------------------------   程序开始   ---------------------------------//

//--------------------------------------------------------------------------------//

/*===================================
1毫秒延时函数(1T 晶振12MHz)
====================================*/
void Delay1ms(unsigned char x)       
{
unsigned char a,b;
for(;x>0;x--)
  for(b=222;b>0;b--)
   for(a=12;a>0;a--);
}//. . . . . . . . . . . . . . . . . .

//--------------------------------- 链接外部模块 ---------------------------------
//#include <EEPROM8.H> //包含IAPReadByte();IAPEraseSector();IAPWriteByte(,);
//#include <IIC_OLED12864.H>//显示模块 包含显示函数; OLED_Init();    //OLED初始化
//#include <MAX7219.H> //显示模块 包含显示函数display(H,L); Initial_MAX7219();//显示初始化
  #include <TM1637.H>  //包含display(x);Init_TM1637(); //TM1637初始化
//--------------------------------------------------------------------------------


//++++++++++++++++++++++++++++++++  ADC读取程序操作  ++++++++++++++++++++++++++++++++//
#define rAD0  GetADCResult(3)  //读取模拟量 设定为P1^3脚 ***修改要把该端口设成高阻模式

/*-------------STC8H系列 与ADC相关地址声明----------*/
sfr ADC_CONTR = 0xBC;  //控制寄存器
sfr ADC_RES   = 0xBD;  //转换结果高位寄存器
sfr ADC_RESL  = 0xBE;  //转换结果低位寄存器
sfr ADCCFG    = 0xDE;  //配置寄存器:设置转换结果保存格式和转换速度寄存器

#define ADCTIM  (*(unsigned char volatile xdata *)0xFEA8) //ADC时序控制寄存器

/*-------设定ADC_CONTR寄存器的操作常量---------*/
#define ADC_POWER   0x80  //1000 0000 ADC电源控制位   
#define ADC_START   0x40  //0100 0000 ADC启动转换控制位
#define ADC_FLAG    0x20  //0010 0000 ADC转换结束标志位

/*-------设定ADCCFG寄存器的操作常量---------*/
#define RESFMT   0x20

#define SPEED16  0x0F

/*----------------------------
Initial ADC sfr 寄存器初始化
----------------------------*/
void InitADC() //ADC初始化

{
P_SW2 |= 0x80;
ADCTIM = 0x3F; //设置ADC内部时序
P_SW2 &= 0x7f;
ADCCFG = RESFMT | SPEED16;  //设置对齐方式为高4位低8位 、时钟为系统时钟/2/16
}//. . . . . . . . . . . . . . . . . .

/*----------------------------
Get ADC result 模数转换
----------------------------*/
unsigned int GetADCResult(unsigned char ch)
{
unsigned int Temp = 0;

ADC_CONTR = ADC_POWER | ADC_START | ch ;
_nop_();  //查询前等待
_nop_();   
while (!(ADC_CONTR & ADC_FLAG));          //等待FLAG为1即等待转换完成
ADC_CONTR &= ~ADC_FLAG;                   //清FLAG为0

Temp=ADC_RES*256+ADC_RESL;

return Temp;              //返回 ADC结果
}//. . . . . . . . . . . . . . . . . .
//++++++++++++++++++++++++++++++ AD模块操作结束 ++++++++++++++++++++++++++++++//

/*===================================
主函数 --- 程序执行入口=== >>>>>>>>
====================================*/
void main()
{
Port_Init();   //端口初始化
InitADC();     //ADC寄存器初始化
Init_TM1637(); //TM1637初始化
while (1)
{
  DDadc=rAD0;

  if(DDadc > DDmax) DDmax=DDadc; //获取最大值
  if(DDadc < DDmin) DDmin=DDadc; //获取最小值

  if(DDadc<100 && Msd==0){CCtemp++;Msd=1;}
  if(DDadc>100)Msd=0;

  if(SB0==0){Mzh=~Mzh; DDmin=1000; while(SB0==0); Delay1ms(200);}

  if(Mzh==0)display(CCtemp);else display(DDadc); //显示ADC结果
}
}//. . . . . . . . . . . . . . . . . .

//------------------------------ END ------------------------------


IMG_20241119_212134.jpg



回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:45
  • 最近打卡:2025-04-28 09:23:48

3

主题

43

回帖

493

积分

中级会员

积分
493
发表于 2024-11-19 22:29:17 | 显示全部楼层
pzeg*** 发表于 2024-11-19 21:38
把前面说的缺少 P_SW2的这两句也补了上去 还是一样,现在是显示累加小于100的次数
因为输入端脚已经直接 ...

代码我已经直接复制验证过了,没有出现问题。
你把原理图和PCB贴出来再分析吧。
直连电源也要保证电源是可靠的。
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2024-05-02 21:48:56

6

主题

48

回帖

614

积分

高级会员

积分
614
发表于 2024-11-20 10:50:17 | 显示全部楼层
pzeg*** 发表于 2024-11-19 21:38
把前面说的缺少 P_SW2的这两句也补了上去 还是一样,现在是显示累加小于100的次数
因为输入端脚已经直接 ...

兄弟,你的问题和我的差不多就是读数偶发出现读值为零,看上去边上是工控,是否可以怀疑边上有强磁干扰.
然后你的MCU的PIN脚旁边就近有焊接滤波电容吗,就近没有焊接电容人家就会说你的电路有问题滤波不行.
我也在寻找这个偶然读值为零的解决办法,增加输出值判断重读还是有漏洞,今天继续试代码.电路因为板子特别小没法搬离两个DC-DC模块很远.
回复 支持 1 反对 0

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-5-2 02:31 , Processed in 0.159463 second(s), 114 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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