yingbin 发表于 2025-9-19 09:59:58

SOP16封装的STC8H8K64U单片机没有ADC功能?| 已解决

我最近用了一块16脚的STC8H8K64U的单片机做项目,需要测出实际工作电压作条件启用某功能,但是我的代码实际测出内部通道15的ADC值一直是4095,反推出工作电压就是1.19V,这明显是不对的,同样的代码烧入16脚的STC8H2K12U的单片机中就能测出正常的工作电压是5V,所以我怀疑16脚的8H8K64U不支持ADC,但是我翻遍数据手册也没发现说不支持,请大神解惑!


国芯人工智能 发表于 2025-9-19 10:03:00

您好,感谢您的提问。

根据您所描述的情况,您使用的是SOP16封装的STC8H8K64U单片机,并尝试通过ADC功能读取内部通道15(通常为内部带隙基准电压通道)以推算实际供电电压。但您发现ADC值始终为4095(即12位ADC的最大值),换算后得出的电压值异常,而使用相同代码在STC8H2K12U上却能正常工作。

我们从以下几个方面来分析您的问题:

一、STC8H8K64U是否具备ADC功能?

根据宏晶科技(STC)官方发布的《STC8H系列技术手册》,STC8H8K64U 是具备12位逐次逼近型ADC模块的,且支持多达15个外部通道 + 1个内部通道(通道15)。

结论:STC8H8K64U确实具备ADC功能,且支持内部通道15。

二、为何ADC读数始终为4095?

ADC读数为最大值(4095),意味着输入电压等于或高于参考电压(Vref)。这可能由以下几种原因造成:

1. 供电电压异常
若实际供电电压高于参考电压(如Vref = 3.0V,而实际VCC > 3.0V),则ADC将饱和。
建议使用万用表测量实际VCC电压,确认其是否为标准5V或3.3V。

2. 参考电压配置错误
STC8H系列的ADC参考电压可通过寄存器选择为内部1.19V、2.56V、3.0V或外部Vref引脚。
若配置为内部1.19V参考电压,而实际VCC为5V,则通道15(内部基准电压)将无法正常反映VCC电压。
检查代码中是否正确配置了ADCREF寄存器,推荐使用内部2.56V或3.0V参考电压以提高测量精度。

3. 通道15采样时间不足或未启用
通道15为内部基准电压,其稳定时间较长(约100μs),若未等待其稳定就进行采样,可能导致读数异常。
建议在首次启动ADC或切换到通道15后,加入适当延时(例如Delayms(1))。

4. ADC模块未正确初始化
检查ADC使能位(ADCCONTR |= 0x80)、通道选择、转换启动方式等配置是否正确。
若ADC未正确启动或配置,可能返回默认最大值。

5. 芯片型号或封装限制
虽然STC8H8K64U在手册中说明支持ADC功能,但在某些封装中可能存在通道限制(如SOP16封装可能部分引脚复用受限)。
建议确认所使用封装是否为完整ADC通道支持版本,可参考数据手册中的“Pin Description”部分,确认是否有ADC引脚被复用为其他功能。

三、如何正确测量VCC电压?

STC8H系列单片机提供了通过内部通道15测量VCC的方法,公式如下:

VCC = (InternalVoltage4095) / ADCValue

其中,InternalVoltage为内部基准电压,通常为1.19V、2.56V或3.0V(取决于配置)。

示例代码片段(建议参考):

c
void InitADC(void) {
    ADCCONTR = 0x80;         // 开启ADC模块
    P1ASF = 0x00;               // 设置P1口为通用IO(避免干扰)
    Delayms(1);                // 等待稳定
}

unsigned int GetADCValue(unsigned char ch) {
    ADCCONTR = (ADCCONTR & 0xE0) | ch | 0x10; // 选择通道并启动转换
    while (!(ADCCONTR & 0x20));               // 等待转换完成
    ADCCONTR &= ~0x20;                         // 清除标志
    return ADCDATA;                            // 返回12位结果
}

float GetVcc(void) {
    unsigned int adcval;
    float internalref = 2.56; // 假设使用2.56V参考电压

    InitADC();
    adcval = GetADCValue(15); // 读取内部通道15
    if (adcval == 0) adcval = 1;
    return (internalref4095) / adcval;
}

四、建议与排查步骤

1. 确认参考电压配置是否正确(1.19V、2.56V、3.0V)。
2. 检查通道15是否被正确选择并等待稳定时间。
3. 确认ADC模块已正确初始化和启动。
4. 使用万用表测量实际VCC电压,排除外部电源问题。
5. 查阅手册确认所用封装是否支持完整ADC功能。
6. 更换芯片测试,排除硬件损坏可能。

五、结语

综上所述,SOP16封装的STC8H8K64U是支持ADC功能的,包括内部通道15的电压测量。您遇到的问题更可能是由于参考电压配置不当、采样时间不足或初始化错误所致,而非芯片本身不支持ADC。

建议您按照上述思路逐一排查,相信可以找到问题所在。若您愿意提供具体代码或配置截图,也欢迎继续交流,我将尽力协助。

祝您项目顺利!

—— 国芯人工智能

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

小飞侠 发表于 2025-9-19 13:37:59

仔细看看数据手册,跟使用的哪一个ADC通道有关系

yingbin 发表于 2025-9-19 15:11:48

小飞侠 发表于 2025-9-19 13:37
仔细看看数据手册,跟使用的哪一个ADC通道有关系

我使用的是ADC通道15,这是内部参考电源通道,和管脚无关吧

yingbin 发表于 2025-9-19 15:24:54


#include "STC8H.H"
#include "stc32_stc8_usb.h"
#include "intrins.h"

#define MAIN_Fosc12000000UL//定义主时钟 24000000L

sbit LED       = P1^0;    //运行灯
u16        FlashDelay=0;//运行灯计闪烁驱动计数器

void delay_ms(u8 ms)
{
    u16 i;
    do{
      i = MAIN_Fosc / 10000;
      while(--i);   //10T per loop
    }while(--ms);
}


unsigned int VDDA; // VDDA的电压值 单位毫伏
unsigned int BGV; // 内部参考电压值 单位毫伏

void ADCInit()
{
       
        BGV=((unsigned int)CHIPID7<<8)+(unsigned int)CHIPID8;
       
      ADCCFG = 0X2F; // 设置ADC时钟 = 24000000/2/16/512 = 1465Hz 转换结果右对齐
}

u16 ADCRead(int channel)
{
          ADC_RES = 0;
    ADC_RESL = 0;

    ADC_CONTR = (ADC_CONTR & 0xF0) | 0x40 | channel;    //启动 AD 转换
    _nop_();
    _nop_();
    _nop_();
    _nop_();

    while((ADC_CONTR & 0x20) == 0);   //wait for ADC finish
    ADC_CONTR &= ~0x20;   //清除ADC结束标志
    return(((u16)ADC_RES << 8) | ADC_RESL);
}


void main()
{
   u8i;
u16 res;

    //系统初始化
          P_SW2 |= 0x80;   //扩展寄存器(XFR)访问使能
   
    P0M1 = 0x00;   P0M0 = 0x00;
    P1M1 = 0x00;   P1M0 = 0x00;
    P2M1 = 0x00;   P2M0 = 0x00;
    P3M1 = 0x00;   P3M0 = 0x00;
    P4M1 = 0x00;   P4M0 = 0x00;
    P5M1 = 0x00;   P5M0 = 0x00;
    P6M1 = 0x00;   P6M0 = 0x00;
    P7M1 = 0x00;   P7M0 = 0x00;
       
    usb_init();      //USB CDC 接口配置
    EA = 1;
       
   ADCInit();
       
    while (1)
    {

                                                delay_ms(1);
                       
                                        FlashDelay++;
                                               
                                                if (FlashDelay==2000) LED=0;//运行灯
                                                if (FlashDelay==2100) LED=1;
                                                       
                                                if (FlashDelay==2400) LED=0;//运行灯
                                                if (FlashDelay==2500)       
                                                {
                                                               LED=1;
                                                               FlashDelay=0;
                                                       
                        /************************ADC 15                ***********************************************/               
                                                       
                                                                        ADC_CONTR = 0x80; // 使能ADC模块 并选择第15通道                                                                       
                                                                        ADCRead(15);
                                                                        ADCRead(15); //前两个数据建议丢弃
                                                                        res = 0;
                                                                        for (i=0; i<8; i++)
                                                                        {
                                                                                res += ADCRead(15); //读取 8 次数据
                                                                        }
                                                                        res >>= 3; //取平均值
                                                                       
                                                                //        vcc = (4096L * 1.19 / res); //(12 位 ADC 算法)计算 VREF 管脚电压,即电池电压
                                                                        VDDA =(unsigned int)((unsigned long)BGV*4096UL/(unsigned long)res);                                                                       
                                                       
                                                                        printf_usb("ADC15=%d   VCC=%dmV\r\n",res,VDDA);                                                                       
                                                                                                                                       

                                                }               
                       

                       
      if (bUsbOutReady)
      {
                                                                               
            USB_SendData(UsbOutBuffer,OutNumber);//);   //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
                                          usb_OUT_done();
                                       
      }
                               
    }
}

yingbin 发表于 2025-9-19 15:37:40

调试CDC串口输出如下图:可以看到
接收←ADC15=1052   VCC=4652mV    这个是同一代码我烧录到16脚的8H2K12U单片机中输出的电压信号完全正常

接收←ADC15=4095   VCC=1189mV    这个是我上面代码烧录到16脚的8H8K64U单片机后输出的CDC串口数据,就不对了

以上都是针对测量ADC15通道数据来反推VCC 电源电压


yingbin 发表于 2025-9-19 15:38:31

百思不得其解{:4_167:}

梁工 发表于 2025-9-19 18:24:17

你ADC值为4095,怎么可能计算出来1.190V?你是怎么计算的?
你的AVREF接电压多少V?

网老四 发表于 2025-9-19 21:06:41

建议先用官方例程去检查验证硬件有没有问题,例程运行没问题后,再检查自己的程序哪里不合适

yingbin 发表于 2025-9-19 22:42:18

梁工 发表于 2025-9-19 18:24
你ADC值为4095,在呢么可能计算出来1.190V?你是怎么计算的?
你的AVREF接电压多少V? ...

可以看我代码:公式 VDDA=BGV*4096/adc
也就是:1.19*4096再除以ADC值4095=1.19V
页: [1] 2
查看完整版本: SOP16封装的STC8H8K64U单片机没有ADC功能?| 已解决