HyunYong_7782 发表于 2025-8-22 17:21:31

ADC转换不正常

以下是我的程序,使用的是20脚的STC8H1K17T

奇怪的是 以前能用的ADC程序直接用也用不了了
电位器稍微拧动一点就到了对应的判断值
是配置的问题吗?

// 头文件
#include "STC8H.H"                                  // 引入STC8系列单片机的头文件
#include "intrins.h"                              // 引入Keil的内部函数头文件


// 端口定义
sbit GM   = P3^3;                                 // 定义AD光敏输入端口
sbit LED    = P5^4;                                 // LED


// 宏定义
// 数据存储
#define ADC_CHANNEL_GM 11                           // 光敏 ADC 通道
#define HIGH_THRESHOLD 4000                         // 亮度变暗的上阈值
#define LOW_THRESHOLD3500                         // 亮度变亮的下阈值

// 数据类型
#defineuint32   unsigned long                     // 定义32位无符号整数类型
#defineuint16   unsigned int                      // 定义16位无符号整数类型
#defineuint8    unsigned char                     // 定义8位无符号整数类型

// 1ms延时函数
void delay_ms(uint16 x)
{
    uint16 j, i;   
    for(j = 0; j < x; j++)   
    {
      for(i = 0; i < 1580; i++);                  // 延时代码
    }
}

// ADC初始化
void ADC_INIT()
{
    ADC_CONTR |= 0x80;                              // 打开ADC电源
    ADCCFG &= ~0x0f;                              // 清除速度选择位
    ADCCFG |= 0x02;                                                // 设置采样速率为 SPEED=2,即 50KSPS
    ADCTIM = 0x35;                                                // CSSETUP(0), CSHOLD(1), SMPDUTY(21)
    ADC_CONTR &= 0xDF;                              // 清AD转换完成标志

    EADC = 0;                                       // 禁止ADC中断
    ADCCFG |= 0x20;                                 // ADC转换结果12位数
}

// ADC口检测AD转换值函数
uint16 ADC_ReadChannel(uint8 channel)
{
    uint16 result;

    ADC_CONTR &= 0xF0;                              // 清通道选择位
    ADC_CONTR |= (channel & 0x0F);                  // 设置通道
    ADC_CONTR &= ~0x20;                           // 清完成标志
    ADC_CONTR |= 0x40;                              // 启动转换

    while (!(ADC_CONTR & 0x20));                  // 等待完成
    ADC_CONTR &= ~0x20;                           // 清完成标志

    result = ADC_RES;                               // 首先读取高八位的数值
    result <<= 8;
    result|= ADC_RESL;                                    // 读取低4位
    return result;
}

// ADC值处理
void process_gm(uint8 channel)
{
    uint16 temp = ADC_ReadChannel(channel);// 用传入的通道号
    uint16 voltage = (uint32)temp * 5000 / 4095;

    if (voltage > HIGH_THRESHOLD)
    {
      LED = 1;
    }
    else if (voltage < LOW_THRESHOLD)
    {
      LED = 0;
    }
}

// 系统初始化
void system_init()
{
    delay_ms(1000);                                     // 延时1s 待市电稳定

    // 引脚定义
    P5M0 |= 0x10; P5M1 &= ~0x10;                        // P54 强推挽

    LED = 0;                                          // 关灯

    ADC_INIT();                                       // ADC初始化
}

// 主函数
void main()
{
    system_init();

    while (1)
    {
      process_gm(ADC_CHANNEL_GM);// AD通道
    }
}

国芯人工智能 发表于 2025-8-22 17:23:00

根据您提供的信息,结合STC8H1K17T单片机的ADC特性及常见配置问题,以下是针对“ADC转换不正常”问题的专业分析与建议:

一、问题现象分析

您描述的现象为:“电位器稍微拧动一点就到了对应的判断值”,表明ADC读数变化较大,可能表现为以下几种情况:

1. ADC采样不稳定或精度不足:ADC数值波动大,导致判断条件容易触发。
2. ADC通道配置错误:未正确配置ADC通道或参考电压源。
3. 外部电路干扰或连接问题:如电位器接线松动、电源噪声等。
4. ADC初始化设置不当:例如采样时间、分辨率、使能位等配置不正确。

二、代码与配置检查建议

您提供的代码片段中缺少关键的ADC初始化部分,建议补充以下内容:

1. ADC初始化配置(示例)

c
// ADC配置函数
void ADCInit(void)
{
    // 使能ADC时钟
    PCON |= 0x01;      // 设置ADC时钟源(具体需参考数据手册)
   
    // 配置ADC通道
    ADCCON = 0x00;      // 清除配置寄存器
    ADCCON |= (ADCCHANNELGM注意:ADCCHANNELGM的值需要根据STC8H1K17T的数据手册确认。例如,某些型号的ADC通道号范围为0~7,而有些支持更高位数。若配置错误,可能导致ADC无法正确采集信号。

2. ADC读取函数c
uint16 ADCRead(void)
{
    uint16 adcvalue = 0;
   
    // 启动ADC转换
    ADCCON |= 0x80;   // 触发一次转换
   
    // 等待转换完成
    while(!(ADCCON & 0x40));// 检查转换是否完成
   
    // 读取ADC结果
    adcvalue = ADCDATAH建议在每次读取前确保ADC已正确启动并完成转换。

三、常见配置问题排查

| 问题点 | 可能原因 | 解决方案 |
|--------|----------|-----------|
| ADC通道未正确选择 | 通道号配置错误 | 根据数据手册确认ADC通道号 |
| ADC参考电压设置错误 | 未使用内部参考电压或外部参考电压不稳定 | 检查VDD和VREF引脚连接,确保稳定 |
| ADC采样时间不足 | 转换速度过快导致采样不准确 | 增加采样时间(通过ADCCON寄存器调整) |
| 外部干扰 | 电位器信号受干扰 | 使用屏蔽线,增加滤波电容 |
| ADC未使能 | 初始化代码未启用ADC模块 | 确保ADCCON寄存器中使能位被置1 |

四、其他建议
检查电源稳定性:ADC对电源噪声敏感,建议使用稳压模块供电,并在电源端添加去耦电容(如10μF电解电容 + 0.1μF陶瓷电容)。
测试ADC功能:可尝试将ADC输入接到固定电压(如GND或VCC),观察输出是否稳定,以排除硬件问题。
更新固件版本:若您使用的是较旧版本的库文件,可能存在兼容性问题,建议升级至最新版本。

五、结论

ADC转换异常可能是由多种因素引起的,包括但不限于配置错误、外部干扰或硬件问题。建议从以下几个方面进行排查:

1. 检查ADC通道配置是否正确;
2. 确保ADC初始化流程完整;
3. 检查外部电路稳定性;
4. 测试ADC基本功能以定位问题。

如需进一步协助,请提供完整的程序代码及ADC相关寄存器配置信息,以便更精确地分析问题根源。

如需帮助调试或优化ADC性能,欢迎继续提问。

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

ercircle 发表于 2025-8-22 18:33:29

这个也没开EAXFR

先用例程试下:
https://www.stcaimcu.com/forum.php?mod=redirect&goto=findpost&ptid=19767&pid=182980
https://www.stcaimcu.com/forum.php?mod=redirect&goto=findpost&ptid=19767&pid=183018


HyunYong_7782 发表于 2025-8-26 13:11:18

/***************************************************************
* 文件名: main.c
* 芯片型号: STC8H 系列
* 功能: 通过 ADC 检测电网电压,控制 LED 灯状态
* 开发环境: Keil C51
***************************************************************/

/*------------------ 头文件 ------------------*/
#include "STC8H.H"      // STC8 系列单片机头文件
#include "intrins.h"    // Keil 内部函数头文件


/*------------------ 宏定义 ------------------*/
// 电压阈值 (单位: mV)
#define HIGH_HP 3500            // 电压上阈值,1000 mV = 1.0V
#define ADC_CHANNEL_HP 3          // 电网电压 ADC 通道

// 数据类型定义
#define uint32unsigned long   // 32位无符号整数
#define uint16unsigned int      // 16位无符号整数
#define uint8   unsigned char   // 8位无符号整数


/*------------------ 端口定义 ------------------*/
sbit LED   = P5^4;   // LED 指示灯


/*------------------ 函数定义 ------------------*/

/**
* @brief 延时函数,粗略延时 x 毫秒
* @param x延时时间 (ms)
* @note 实际延时受主频影响,不够精确
*/
void delay_ms(uint16 x)
{
    uint16 j, i;   
    for (j = 0; j < x; j++)   
    {
      for (i = 0; i < 1580; i++);   // 循环延时
    }
}


/**
* @brief ADC 初始化
* @note 设置为 12 位精度,采样速率 50KSPS
*/
void ADC_INIT()
{
    ADC_CONTR |= 0x80;       // 打开 ADC 电源
    ADCCFG &= ~0x0f;         // 清除速度选择位
    ADCCFG |= 0x02;          // 设置采样速率 SPEED=2 (50KSPS)
    ADCTIM = 0x35;         // CSSETUP(0), CSHOLD(1), SMPDUTY(21)
    ADC_CONTR &= 0xDF;       // 清转换完成标志

    EADC = 0;                // 禁止 ADC 中断
    ADCCFG |= 0x20;          // 12 位 ADC 模式
}


/**
* @brief 读取指定 ADC 通道的数值
* @param channel 通道号 (0~15)
* @return 转换结果,范围 0~4095 (12位)
*/
uint16 ADC_ReadChannel(uint8 channel)
{
    uint16 result;

    ADC_CONTR &= 0xF0;            // 清除通道选择位
    ADC_CONTR |= (channel & 0x0F);// 设置 ADC 通道
    ADC_CONTR &= ~0x20;             // 清完成标志
    ADC_CONTR |= 0x40;            // 启动转换

    while (!(ADC_CONTR & 0x20));    // 等待转换完成
    ADC_CONTR &= ~0x20;             // 清完成标志

    result = ADC_RES;               // 高 8 位
    result <<= 8;
    result |= ADC_RESL;             // 低 4 位
    return result;
}


/**
* @brief 电网电压处理函数
* @param channel 电网 ADC 通道号
* @note 电压换算公式: voltage = ADC * 5000 / 4095 (mV)
*/
void process_hp(uint8 channel)
{
    uint16 temp = ADC_ReadChannel(channel);      // 读取 ADC
    uint16 voltage = (uint32)temp * 5000 / 4095;   // 转换为 mV

    if (voltage > HIGH_HP)      // 电压超过 1.0V
    {
      LED = 1;   // 开灯
    }
    else
    {
      LED = 0;   // 关灯
    }
}


/**
* @brief 系统初始化
* @note 初始化 IO 口、LED、ADC
*/
void system_init()
{
    P_SW2 |= 0x80;          // 使能访问 XFR

    delay_ms(1000);         // 上电延时 1s,等待市电稳定

    // IO 模式配置
    P5M0 |= 0x10;
    P5M1 &= ~0x10;          // P5.4 推挽输出 (LED)

    LED = 0;                // 初始化 LED 关闭

    ADC_INIT();             // 初始化 ADC
}


/**
* @brief 主函数
*/
void main()
{
    system_init();// 系统初始化

    while (1)
    {
      process_hp(ADC_CHANNEL_HP);   // 检测电网电压通道
    }
}



这是我简化了的程序 并打开的XFR
问题还是稍微拧动电位器就会触发阈值 而不是到3500

HyunYong_7782 发表于 2025-8-26 13:11:52

电位器硬件是验证过的 在别的芯片上是可以正常使用的

HyunYong_7782 发表于 2025-8-26 13:12:30

使用例程去修改成这样也是稍微扭动电位器会直接超过阈值

梁工 发表于 2025-8-26 18:06:16

贴下电路看看

HyunYong_7782 发表于 7 天前

如图 不是在PCB上部署的 只是用跳线在测试

芯片烧录座接在link 电位器接在5V和GND 输出接在芯片IO

HyunYong_7782 发表于 7 天前

HyunYong_7782 发表于 2025-8-27 01:33
如图 不是在PCB上部署的 只是用跳线在测试

芯片烧录座接在link 电位器接在5V和GND 输出接在芯片IO ...

破案了 又去对了一次规格书
在用外部参考源的时候VCC没有能力直接拾取参考电压
需要把VCC和 ADC_VREF+接在一起

稍微拧动就点亮是因为浮空了ADC_VREF+引脚 那么参考源就很低 所以稍微拧动就能亮

HyunYong_7782 发表于 7 天前

RT
页: [1]
查看完整版本: ADC转换不正常