Printy陈 发表于 2025-8-26 16:05:32

15W408AS AD采集数据波动大

一个简单的AD采集,用ACS712ELCTR-05B-T(XBLW)检测电路电流情况,但结果很打脸,ADC数据波动很大,电路中AD端忘了串电阻,后面加上了,效果也不行。最近用STC单片机做了两个小项目,原本觉得很简单,实际很难受了,串口调试工具也是,有时候会连不上,需要断电重启才有用。

串口调试信息如下:

接收←串口初始化成功
                  ADC_12V_Value: 771
                  
接收←ADC_12V_Value: 769
                  
接收←ADC_12V_Value: 515
                  
接收←ADC_12V_Value: 768
                  
接收←ADC_12V_Value: 2
                  
接收←ADC_12V_Value: 771
                  
接收←ADC_12V_Value: 769
                  
接收←ADC_12V_Value: 1
                  
接收←ADC_12V_Value: 1
                  
接收←ADC_12V_Value: 770
                  
接收←ADC_12V_Value: 771
                  
接收←ADC_12V_Value: 770
                  
接收←ADC_12V_Value: 771
                  
接收←ADC_12V_Value: 515
                  
接收←ADC_12V_Value: 771
                  
接收←ADC_12V_Value: 771
                  
接收←ADC_12V_Value: 771
                  
接收←ADC_12V_Value: 771
                  
接收←ADC_12V_Value: 771
                  
接收←ADC_12V_Value: 771
                  
接收←ADC_12V_Value: 771
                  
接收←ADC_12V_Value: 771
                  
接收←ADC_12V_Value: 771
                  
接收←ADC_12V_Value: 771
                  
接收←ADC_12V_Value: 2
                  
接收←ADC_12V_Value: 770
                  
接收←ADC_12V_Value: 2
                  
接收←ADC_12V_Value: 768
                  
接收←ADC_12V_Value: 1
                  
接收←ADC_12V_Value: 771
                  
接收←ADC_12V_Value: 770
                  
接收←ADC_12V_Value: 1
                  
接收←ADC_12V_Value: 771
                  
接收←ADC_12V_Value: 1
                  
接收←ADC_12V_Value: 771
                  
接收←ADC_12V_Value: 515
                  
接收←ADC_12V_Value: 771
                  
接收←ADC_12V_Value: 769
                  
接收←ADC_12V_Value: 1
                  
接收←ADC_12V_Value: 771
                  
接收←ADC_12V_Value: 1
                  
接收←ADC_12V_Value: 770
                  
接收←ADC_12V_Value: 2
                  
接收←ADC_12V_Value: 2
                  
接收←ADC_12V_Value: 1
                  
接收←ADC_12V_Value: 1
                  
接收←ADC_12V_Value: 2
                  
接收←ADC_12V_Value: 515
                  
接收←ADC_12V_Value: 2
                  
接收←ADC_12V_Value: 771
                  
接收←ADC_12V_Value: 3
                  
接收←ADC_12V_Value: 771
                  
接收←ADC_12V_Value: 771
                  
接收←ADC_12V_Value: 771
                  
接收←ADC_12V_Value: 771
                  
接收←ADC_12V_Value: 3
                  
接收←ADC_12V_Value: 771
                  
接收←ADC_12V_Value: 770
                  
接收←ADC_12V_Value: 771


下面是代码,简单的AD数据采集程序:

#include <stc15.h>
#include <stdio.h>
#include <intrins.h>
// 引脚定义
sbit ADC_12V = P1 ^ 0;
sbit ADC_12V_NEG = P1 ^ 1;
sbit JDQ_12V = P3 ^ 6;
sbit JDQ_12V_NEG = P3 ^ 7;
sbit FMQ = P1 ^ 4;
sbit LED_12V = P1 ^ 3;
sbit LED_12V_NEG = P1 ^ 2;
//定义一些AD采集常量
#define ADC_POWER   0x80            //ADC电源控制位
#define ADC_FLAG    0x10            //ADC完成标志
#define ADC_START   0x08            //ADC起始控制位
#define ADC_SPEEDLL 0x00            //540个时钟
#define ADC_SPEEDL0x20            //360个时钟
#define ADC_SPEEDH0x40            //180个时钟
#define ADC_SPEEDHH 0x60            //90个时钟
/************************** */
// printf重定向到串口
char putchar(char c)
{
    SBUF = c;
    while (!TI)
      ;
    TI = 0;
    return c;
}
void UART1_Init(void)
{
    SCON = 0x50;// 8位数据,可变波特率
    AUXR |= 0x01; // 串口1选择定时器2为波特率发生器
    AUXR |= 0x04; // 定时器时钟1T模式
    T2L = 0xE0;   // 设置定时初始值
    T2H = 0xFE;   // 设置定时初始值
    AUXR |= 0x10; // 定时器2开始计时
}


/************************** */
void Delay(unsigned int n)
{
    unsigned int x;

    while (n--)
    {
      x = 5000;
      while (x--);
    }
}
void Delay1000us(void)//@11.0592MHz
{
    unsigned char data i, j;

    _nop_();
    _nop_();
    _nop_();
    i = 11;
    j = 190;
    do
    {
      while (--j);
    } while (--i);
}

void Delay1000ms(void)//@11.0592MHz
{
    unsigned char data i, j, k;

    _nop_();
    _nop_();
    i = 43;
    j = 6;
    k = 203;
    do
    {
      do
      {
            while (--k);
      } while (--j);
    } while (--i);
}


/************************** */
unsigned int GetADCResult(unsigned char ch)
{
    unsigned int adc_value;
    ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ch | ADC_START;
    _nop_();                        //等待4个NOP
    _nop_();
    _nop_();
    _nop_();
    while (!(ADC_CONTR & ADC_FLAG));//等待ADC转换完成
    ADC_CONTR &= ~ADC_FLAG;         //Close ADC

    adc_value = ( (ADC_RES & 0x03) << 8 ) | ADC_RESL;// 组合10位结果

    return adc_value;               //返回ADC结果
}

/**************************** */
// IO初始化
void IO_Init(void)
{
    // 设置P1.0 P1.1为模拟输入
    P1ASF = 0X03; // P1.0和P1.1设置为模拟功能
    // 设置P36P37为推挽输出,P3口其他不改变
    P3M0 = 0xC0; // P3.6、P3.7设置为推挽输出
    P3M1 = 0x00; // P3.6、P3.7设置为推挽输出
    // 设置P1.2、P1.3、P1.4为推挽输出(故障灯和蜂鸣器)
    P1M0 = 0x1C; // P1.2、P1.3、P1.4设置为推挽输出
    P1M1 = 0x00; // P1.2、P1.3、P1.4设置为推挽输出

    JDQ_12V = 1;
    JDQ_12V_NEG = 1;
    FMQ = 1;
    LED_12V = 1;
    LED_12V_NEG = 1;
    //初始化AD
    ADC_RES = 0;                  //清除结果寄存器
    ADC_CONTR = ADC_POWER | ADC_SPEEDLL;
    Delay(2);   
}
// 主函数示例(初始化+发送测试)
void main(void)
{
    IO_Init();
    UART1_Init(); // 初始化串口1
    printf("串口初始化成功\r\n");
   
    while (1)
    {
    //打印P1.0 P1.1的AD值
    printf("ADC_12V_Value: %u\r\n", GetADCResult(0));
   // printf("ADC_12V_NEG_Value: %u\r\n", GetADCResult(1));
    Delay1000ms();
    }
}


国芯人工智能 发表于 2025-8-26 16:08:00

尊敬的用户,您好!

感谢您对国芯人工智能的关注与支持。针对您在使用STC15W408AS单片机进行AD采集时遇到的数据波动问题,以及串口通信不稳定的现象,我们进行了详细分析,并结合实际应用经验为您提供以下专业建议和解决方案。

首先,关于ADC数据波动较大的问题:

1. 电路设计方面
   您提到在AD采集端未串联电阻,后虽已添加,但效果不佳。这可能涉及以下几个方面:
信号源阻抗匹配:ACS712ELCTR-05B-T传感器输出为电压信号,其输出阻抗较低,但若与ADC输入阻抗不匹配,可能导致采样误差。建议在ADC输入端增加一个适当的RC低通滤波器(如10kΩ电阻+0.1μF电容),以抑制高频噪声。
电源稳定性:ADC采集结果受供电电压影响较大,建议采用独立的稳压电源或在ADC参考电压(Vref)端并联大容量电容(如10μF电解电容)以提高稳定性。
接地方式:确保ADC与传感器共地,避免地线环路引入干扰。可尝试将模拟地与数字地分开处理,再通过一点连接。

2. 软件配置方面
采样率与转换时间:STC15W408AS的ADC支持多种采样模式,建议根据实际需求选择合适的采样率。过高的采样率可能导致采样窗口过短,无法准确捕捉真实信号。
多次采样平均:在软件中对ADC数据进行多次采样后取平均值,可以有效降低随机噪声带来的波动。例如,每次读取16次ADC值,取其平均值作为最终结果。
ADC校准:部分STC系列MCU支持内部ADC校准功能,建议查阅数据手册并启用相关校准程序,以提升采集精度。

3. 外部干扰因素
电磁干扰(EMI):若系统工作环境存在强电磁场,可能会对ADC采集造成干扰。建议对敏感电路进行屏蔽处理,或在PCB布局上优化布线,减少信号回路面积。
温度漂移:ACS712ELCTR-05B-T具有一定的温度漂移特性,建议在软件中加入温度补偿算法,或在稳定环境下进行校准。

其次,关于串口通信不稳定的问题:

1. 硬件连接检查
确保USB转TTL模块与单片机之间的TXD、RXD、GND引脚正确连接,无虚接或短路现象。
使用示波器检测串口信号是否正常,观察是否存在波形失真或噪声干扰。

2. 波特率设置一致性
确认单片机与调试工具的波特率设置一致(如9600、115200等),且未因时钟源误差导致误码。
若使用内部RC振荡器,建议改用外部晶振以提高时钟精度。

3. 软件逻辑优化
在串口接收过程中,建议使用缓冲区机制,防止因数据溢出导致丢包或解析错误。
对于异常数据(如突然出现的“2”、“1”等异常值),可增加校验逻辑,判断数据有效性后再进行处理。

综上所述,ADC数据波动和串口通信不稳定问题通常由多方面因素共同作用所致。建议您从电路设计、软件配置和外部环境三方面逐一排查,并结合实际测试数据进行调整优化。

如您有进一步的技术问题或需要更详细的调试指导,欢迎随时联系国芯人工智能技术团队,我们将竭诚为您服务。

祝您项目顺利,技术进步!

[本文内容由国芯人工智能辅助生成,仅供参考]

Printy陈 发表于 2025-8-26 17:30:43

10K电阻+0.1uf电容组合,IO配置如下更改,继电器,蜂鸣器这些都没有吸合,万用表测量数据很稳定,但串口数据如下:

接收←串口初始化成功
                  ADC_12V_Value: 1
                  
接收←ADC_12V_Value: 257
                  
接收←ADC_12V_Value: 256
                  
接收←ADC_12V_Value: 1
                  
接收←ADC_12V_Value: 257
                  
接收←ADC_12V_Value: 1
                  
接收←ADC_12V_Value: 769
                  
接收←ADC_12V_Value: 2
                  
接收←ADC_12V_Value: 257
                  
接收←ADC_12V_Value: 1
                  
接收←ADC_12V_Value: 515
                  
接收←ADC_12V_Value: 3
                  
接收←ADC_12V_Value: 3
                  
接收←ADC_12V_Value: 771
                  
接收←ADC_12V_Value: 2
                  
接收←ADC_12V_Value: 1
                  
接收←ADC_12V_Value: 256
                  
接收←ADC_12V_Value: 257
                  
接收←ADC_12V_Value: 3
                  
接收←ADC_12V_Value: 258
                  
接收←ADC_12V_Value: 3
                  

void IO_Init(void)
{
   
    // 设置P36P37为推挽输出,P3口其他不改变
    P3M0 = 0xC0; // P3.6、P3.7设置为推挽输出
    P3M1 = 0x00; // P3.6、P3.7设置为推挽输出
    // 设置P1.2、P1.3、P1.4为推挽输出(故障灯和蜂鸣器)
    P1M0 = 0x1C; // P1.2、P1.3、P1.4设置为推挽输出
    P1M1 = 0x03; // P1.2、P1.3、P1.4设置为推挽输出
// 设置P1.0 P1.1为模拟输入
    P1ASF = 0X03; // P1.0和P1.1设置为模拟功能
   
    JDQ_12V = 1;
    JDQ_12V_NEG = 1;
    FMQ = 1;
    LED_12V = 1;
    LED_12V_NEG = 1;
    //初始化AD
    ADC_RES = 0;                  //清除结果寄存器
    ADC_CONTR = ADC_POWER | ADC_SPEEDLL;
    Delay(2);   
}



梁工 发表于 2025-8-26 18:04:42

1、先示波器看看单片机电源是否纹波大,纹波越小越好,ADC是以VCC为参考的。
2、先不接ACS712的输出,改接VCC-R1-R2-GND经过电阻分压给ADC,比如1K+1K分压到ADC输入,输入对地接10~100nF电容,测试结果看看。

STC15W408AS的10位ADC还是比较稳定的,就是在512读数那里有几个字的误差。

vb2002 发表于 2025-8-26 18:24:33

adc并地试试,之前我也是跳

vb2002 发表于 2025-8-26 18:25:15

不对,是adc引脚并联个电容到地,,0,1uf就行

Printy陈 发表于 2025-8-26 19:02:58

vb2002 发表于 2025-8-26 18:25
不对,是adc引脚并联个电容到地,,0,1uf就行

不用串电阻吗,我试试

Printy陈 发表于 2025-8-26 19:03:43

梁工 发表于 2025-8-26 18:04
1、先示波器看看单片机电源是否纹波大,纹波越小越好,ADC是以VCC为参考的。
2、先不接ACS712的输出,改接V ...

是啊,之前也没有遇到这种事情,郁闷了

vb2002 发表于 2025-8-26 19:28:22

Printy陈 发表于 2025-8-26 19:02
不用串电阻吗,我试试

ADC那个引脚这样,,参考ai8051试验箱那个电路,

Printy陈 发表于 2025-8-26 20:53:16

把ACS712ELCTR-05B-T(XBLW)去掉后,单片机ADC接入5V后,数据很稳,这个苾片怎么会对单片机产生这么大的影响
页: [1] 2
查看完整版本: 15W408AS AD采集数据波动大