woshicainiao 发表于 2025-3-20 01:48:49

求助8H3K64S2-45I-LQFP48不采集ADC电压

求助该单片机不采集ADC数值,原理图中得其它引脚测试,输出高低电平,UART2通讯,DS18B20温度采集都能功能正常。但是无法ADC包括NTC和电压采集,P0.0,P0.1,P0.4号引脚。

接收←DS18B20-1: 12.75°C
                  DS18B20-2: -100.00°C
                  NTC1(P0.1): 18.74°C (ADC:351).NTC2(P0.0): -40.00°C (ADC:408.ADC P0.4: 3
                  P2.3: HIGH, P3.2: LOW
                  -------------------
                  



1,5块样板同样得问题,也尝试拆除元件测试还是电压一直晃动,无财季值。
2,分别尝试调节电压都不行。
3,万用表在每个接口都测试电压正常,分压电压正常。
4,用ESP32单片机从STC引脚处飞线,正常采集ADC值和NTC温度数据。
5,用3.3V和5V电压都测试过,都是没有读取ADC数值。
6,本人STC新手小白,请查看是我原理图得问题还是代码得问题,希望能解决一下。
7,代码如下:

#include "reg51.h"
#include "intrins.h"
#include <stdio.h>
#include <string.h>
#include <math.h>// 用于NTC温度计算

// 系统时钟定义
#define FOSC            11059200UL
#define BRT             (65536 - FOSC / 115200 / 4)

// SFR定义
sfr   AUXR      =   0x8e;
sfr   ADC_CONTR   =   0xbc;
sfr   ADC_RES   =   0xbd;
sfr   ADC_RESL    =   0xbe;
sfr   ADCCFG      =   0xde;
sfr   P_SW2       =   0xba;
#define ADCTIM      (*(unsigned char volatile xdata *)0xfea8)
sfr   P0M1      =   0x93;
sfr   P0M0      =   0x94;
sfr   P1M1      =   0x91;
sfr   P1M0      =   0x92;
sfr   P2M1      =   0x95;
sfr   P2M0      =   0x96;
sfr   P3M1      =   0xb1;
sfr   P3M0      =   0xb2;
sfr   P4M1      =   0xb3;
sfr   P4M0      =   0xb4;
sfr   P5M1      =   0xc9;
sfr   P5M0      =   0xca;

// 引脚定义
sbit P2_3 = P2^3;   // P2.3输出高电平
sbit P3_2 = P3^2;   // P3.2输出低电平
sbit DQ1 = P2^6;      // DS18B20数据线1连接到P2.6
sbit DQ2 = P2^7;      // DS18B20数据线2连接到P2.7

// NTC参数定义 - 更新为B3950
#define NTC_R25      10000.0   // NTC在25℃时的阻值(欧姆)
#define NTC_B      3950.0    // 更新NTC的B值为B3950
#define T25          298.15    // 25℃对应的开尔文温度

// 变量定义
int *BGV;            // 内部1.19V参考信号源值
bit busy;
unsigned char xdata data_buffer;// 数据缓冲区使用xdata空间
unsigned int ntc1_value, ntc2_value, adc_value;
float ds18b20_temp1, ds18b20_temp2;// 存储两个DS18B20的温度
float ntc1_temp, ntc2_temp;          // 存储两个NTC的温度

// 函数声明
void Delay1ms(unsigned int ms);
void DelayUs(unsigned int us);
void UartInit();
void UartSendString(char *str);
void ADCInit();
unsigned int ADCRead(unsigned char channel);
bit InitDS18B20_1();      // DS18B20 #1 (P2.6)初始化
bit InitDS18B20_2();      // DS18B20 #2 (P2.7)初始化
void DS18B20WriteByte_1(unsigned char dat);
void DS18B20WriteByte_2(unsigned char dat);
unsigned char DS18B20ReadByte_1();
unsigned char DS18B20ReadByte_2();
float ReadDS18B20Temp_1();// 读取DS18B20 #1温度
float ReadDS18B20Temp_2();// 读取DS18B20 #2温度
float ReadNTCTemp(unsigned char channel);// 读取NTC温度

// 串口中断服务程序
void UartIsr() interrupt 4
{
    if (TI)
    {
      TI = 0;
      busy = 0;
    }
    if (RI)
    {
      RI = 0;
    }
}

// 延时函数,参数为毫秒数
void Delay1ms(unsigned int ms)
{
    unsigned int i, j;
    for (i = 0; i < ms; i++)
      for (j = 0; j < 110; j++);
}

// 微秒级延时 - 调整为更精确的延时
void DelayUs(unsigned int us)
{
    while(us--)
    {
      _nop_();
      _nop_();
      _nop_();
      _nop_();
      _nop_();
      _nop_();
    }
}

// 串口初始化函数 - 恢复原始配置
void UartInit()
{
    SCON = 0x50;    // 8位数据,可变波特率,允许接收
    TMOD = 0x00;    // 定时器1,模式0 (16位自动重载)
    TL1 = BRT;
    TH1 = BRT >> 8;
    TR1 = 1;      // 启动定时器1
    AUXR = 0x40;    // 定时器1为1T模式
    busy = 0;
}

// 串口发送字符
void UartSend(char dat)
{
    while (busy);
    busy = 1;
    SBUF = dat;
}

// 串口发送字符串
void UartSendString(char *str)
{
    while (*str)
    {
      UartSend(*str++);
    }
}

// ADC初始化
void ADCInit()
{
    P_SW2 |= 0x80;
    ADCTIM = 0x3f;      // 设置ADC内部时序
    P_SW2 &= 0x7f;
    ADCCFG = 0x2f;      // 设置ADC时钟为系统时钟/2/16
}

// ADC读取函数
unsigned int ADCRead(unsigned char channel)
{
    unsigned int res;
   
    ADC_CONTR = 0x80 | channel;// 使能ADC模块,选择通道
    ADC_CONTR |= 0x40;         // 启动AD转换
    _nop_();
    _nop_();
    while (!(ADC_CONTR & 0x20)); // 查询ADC完成标志
    ADC_CONTR &= ~0x20;          // 清完成标志
    res = (ADC_RES << 8) | ADC_RESL; // 读取ADC结果
   
    return res;
}

// DS18B20 #1 (P2.6)初始化 - 修改延时参数
bit InitDS18B20_1()
{
    bit presence;
    unsigned char retry = 3;// 添加重试次数
   
    while(retry--)
    {
      DQ1 = 1;
      DelayUs(5);
      DQ1 = 0;
      DelayUs(600);    // 增加复位脉冲宽度,确保至少480us
      DQ1 = 1;
      DelayUs(60);   // 增加等待时间
      presence = DQ1;// 如果DS18B20存在,DQ将被拉低
      DelayUs(240);    // 增加完成时间
      
      if(!presence)    // 如果检测到存在脉冲,立即返回成功
            return 1;
    }
   
    return 0;// 多次尝试后仍失败
}

// DS18B20 #2 (P2.7)初始化 - 修改延时参数
bit InitDS18B20_2()
{
    bit presence;
    unsigned char retry = 3;// 添加重试次数
   
    while(retry--)
    {
      DQ2 = 1;
      DelayUs(5);
      DQ2 = 0;
      DelayUs(600);    // 增加复位脉冲宽度,确保至少480us
      DQ2 = 1;
      DelayUs(60);   // 增加等待时间
      presence = DQ2;// 如果DS18B20存在,DQ将被拉低
      DelayUs(240);    // 增加完成时间
      
      if(!presence)    // 如果检测到存在脉冲,立即返回成功
            return 1;
    }
   
    return 0;// 多次尝试后仍失败
}

// 向DS18B20 #1写一个字节 - 调整时序
void DS18B20WriteByte_1(unsigned char dat)
{
    unsigned char i;
   
    for (i = 0; i < 8; i++)
    {
      DQ1 = 0;
      DelayUs(2);                // 延时2us
      if (dat & 0x01) DQ1 = 1;   // 发送位值
      else DQ1 = 0;
      DelayUs(60);               // 延时至少60us
      DQ1 = 1;                   // 释放总线
      DelayUs(2);                // 恢复时间
      dat >>= 1;
    }
}

// 从DS18B20 #1读一个字节 - 调整时序
unsigned char DS18B20ReadByte_1()
{
    unsigned char i, dat = 0;
   
    for (i = 0; i < 8; i++)
    {
      dat >>= 1;
      DQ1 = 0;
      DelayUs(2);                // 延时2us
      DQ1 = 1;                   // 释放总线
      DelayUs(8);                // 延时读取时间,等待数据稳定
      if (DQ1) dat |= 0x80;      // 读取位值
      DelayUs(60);               // 延时至少60us
    }
   
    return dat;
}

// 向DS18B20 #2写一个字节 - 调整时序
void DS18B20WriteByte_2(unsigned char dat)
{
    unsigned char i;
   
    for (i = 0; i < 8; i++)
    {
      DQ2 = 0;
      DelayUs(2);                // 延时2us
      if (dat & 0x01) DQ2 = 1;   // 发送位值
      else DQ2 = 0;
      DelayUs(60);               // 延时至少60us
      DQ2 = 1;                   // 释放总线
      DelayUs(2);                // 恢复时间
      dat >>= 1;
    }
}

// 从DS18B20 #2读一个字节 - 调整时序
unsigned char DS18B20ReadByte_2()
{
    unsigned char i, dat = 0;
   
    for (i = 0; i < 8; i++)
    {
      dat >>= 1;
      DQ2 = 0;
      DelayUs(2);                // 延时2us
      DQ2 = 1;                   // 释放总线
      DelayUs(8);                // 延时读取时间,等待数据稳定
      if (DQ2) dat |= 0x80;      // 读取位值
      DelayUs(60);               // 延时至少60us
    }
   
    return dat;
}

// 读取DS18B20 #1 (P2.6)温度 - 增加重试和错误处理
float ReadDS18B20Temp_1()
{
    unsigned char temp_LSB, temp_MSB;
    unsigned int temp;
    float temperature;
    unsigned char retry = 3;
   
    while(retry--)
    {
      if (InitDS18B20_1())// 初始化DS18B20 #1
      {
            DS18B20WriteByte_1(0xCC);// 跳过ROM命令
            DS18B20WriteByte_1(0x44);// 启动温度转换
            
            Delay1ms(800);// 等待转换完成,增加等待时间
            
            if (InitDS18B20_1())// 重新初始化总线
            {
                DS18B20WriteByte_1(0xCC);// 跳过ROM命令
                DS18B20WriteByte_1(0xBE);// 读取温度寄存器
               
                temp_LSB = DS18B20ReadByte_1();// 读取温度低字节
                temp_MSB = DS18B20ReadByte_1();// 读取温度高字节
               
                // 简单校验,检查前5个字节是否全为0xFF,这通常表示读取错误
                if (temp_LSB != 0xFF || temp_MSB != 0xFF)
                {
                  temp = (temp_MSB << 8) | temp_LSB;
                  
                  if (temp & 0x8000)// 负温度处理
                  {
                        temp = ~temp + 1;
                        temperature = -(temp * 0.0625);
                  }
                  else// 正温度
                  {
                        temperature = temp * 0.0625;
                  }
                  
                  // 进行简单的数值范围检查
                  if (temperature > -55.0 && temperature < 125.0)
                        return temperature;
                }
            }
      }
      
      Delay1ms(50);// 短暂延时后重试
    }
   
    return -100.0;// 多次尝试后仍然失败,返回错误值
}

// 读取DS18B20 #2 (P2.7)温度 - 增加重试和错误处理
float ReadDS18B20Temp_2()
{
    unsigned char temp_LSB, temp_MSB;
    unsigned int temp;
    float temperature;
    unsigned char retry = 3;
   
    while(retry--)
    {
      if (InitDS18B20_2())// 初始化DS18B20 #2
      {
            DS18B20WriteByte_2(0xCC);// 跳过ROM命令
            DS18B20WriteByte_2(0x44);// 启动温度转换
            
            Delay1ms(800);// 等待转换完成,增加等待时间
            
            if (InitDS18B20_2())// 重新初始化总线
            {
                DS18B20WriteByte_2(0xCC);// 跳过ROM命令
                DS18B20WriteByte_2(0xBE);// 读取温度寄存器
               
                temp_LSB = DS18B20ReadByte_2();// 读取温度低字节
                temp_MSB = DS18B20ReadByte_2();// 读取温度高字节
               
                // 简单校验,检查前5个字节是否全为0xFF,这通常表示读取错误
                if (temp_LSB != 0xFF || temp_MSB != 0xFF)
                {
                  temp = (temp_MSB << 8) | temp_LSB;
                  
                  if (temp & 0x8000)// 负温度处理
                  {
                        temp = ~temp + 1;
                        temperature = -(temp * 0.0625);
                  }
                  else// 正温度
                  {
                        temperature = temp * 0.0625;
                  }
                  
                  // 进行简单的数值范围检查
                  if (temperature > -55.0 && temperature < 125.0)
                        return temperature;
                }
            }
      }
      
      Delay1ms(50);// 短暂延时后重试
    }
   
    return -100.0;// 多次尝试后仍然失败,返回错误值
}

// 读取NTC温度 - 根据ADC值计算温度
float ReadNTCTemp(unsigned char channel)
{
    unsigned int adc_value;
    float resistance, temperature;
    char buffer;   // 调试字符串缓冲区
   
    adc_value = ADCRead(channel);

    // 确保ADC值有效(防止除以零或溢出)
    if (adc_value <= 100) adc_value = 100;   // 防止在极端情况下计算出过大电阻
    if (adc_value >= 4000) adc_value = 4000;   // 防止在电阻极小时出现异常
   
    // 根据分压公式计算NTC电阻值
    // 电路是:VCC -- 10K上拉电阻 -- ADC测量点 -- NTC -- GND
    // 分压器: Vout = Vcc * (R_NTC / (R_NTC + R_上拉))
    // 则: R_NTC = R_上拉 * Vout / (Vcc - Vout)
    // ADC值 / 4096 = Vout / Vcc,所以:
    resistance = 10000.0 * (float)adc_value / (4096.0 - (float)adc_value);
   
    // 使用B公式计算温度(开尔文)
    // T = 1 / (1/T25 + (1/B) * ln(R/R25))
    temperature = 1.0 / (1.0 / T25 + (1.0 / NTC_B) * log(resistance / NTC_R25));
   
    // 转换为摄氏度
    temperature = temperature - 273.15;
   
    // 温度范围限制,避免异常值
    if (temperature < -40.0) temperature = -40.0;
    if (temperature > 150.0) temperature = 150.0;
   
    return temperature;
}

void main()
{
    char xdata str;// 使用xdata空间
   
    // 获取内部参考电压
    BGV = (int idata *)0xef;
   
    // 初始化外设 - 恢复原顺序
    ADCInit();    // ADC初始化
    UartInit();   // 串口初始化
   
    // 配置IO口 - 正确配置ADC输入和输出端口
    P0M0 = 0x00;// P0.0和P0.1设为高阻输入模式(用于ADC)
    P0M1 = 0x13;// P0.0、P0.1和P0.4设为高阻输入(ADC使用)
    P2M0 = 0x08;// P2.3设为推挽输出
    P2M1 = 0x00;
    P3M0 = 0x04;// P3.2设为推挽输出
    P3M1 = 0x00;
   
    // 设置初始电平状态
    P2_3 = 1;   // P2.3输出高电平
    P3_2 = 0;   // P3.2输出低电平
   
    // 开启中断
    ES = 1;
    EA = 1;
   
    // 发送欢迎信息
    UartSendString("STC8H3K64S2 Multi-Sensor System\r\n");
    Delay1ms(100);
   
    while (1)
    {
      // 读取两个DS18B20温度传感器
      ds18b20_temp1 = ReadDS18B20Temp_1();// P2.6上的DS18B20
      ds18b20_temp2 = ReadDS18B20Temp_2();// P2.7上的DS18B20
      
      // 获取NTC的ADC原始值
      ntc1_value = ADCRead(1);// P0.1对应通道1
      ntc2_value = ADCRead(0);// P0.0对应通道0
      
      // 根据ADC值计算NTC温度
      ntc1_temp = ReadNTCTemp(1);// NTC1 - P0.1
      ntc2_temp = ReadNTCTemp(0);// NTC2 - P0.0
      
      // 读取P0.4的ADC值
      adc_value = ADCRead(4);      // P0.4对应通道4
      
      // 格式化并发送数据
      sprintf(str, "DS18B20-1: %.2f°C\r\n", ds18b20_temp1);
      UartSendString(str);
      
      sprintf(str, "DS18B20-2: %.2f°C\r\n", ds18b20_temp2);
      UartSendString(str);
      
      sprintf(str, "NTC1(P0.1): %.2f°C (ADC:%u)\r\n", ntc1_temp, ntc1_value);
      UartSendString(str);
      
      sprintf(str, "NTC2(P0.0): %.2f°C (ADC:%u)\r\n", ntc2_temp, ntc2_value);
      UartSendString(str);
      
      sprintf(str, "ADC P0.4: %u\r\n", adc_value);
      UartSendString(str);
      
      sprintf(str, "P2.3: HIGH, P3.2: LOW\r\n");// 显示输出端口状态
      UartSendString(str);
      
      UartSendString("-------------------\r\n");
      
      // 延时1秒
      Delay1ms(1000);
    }
}
<blockquote>#include "reg51.h"

国芯人工智能 发表于 2025-3-20 01:53:00

针对您提到的STC8H3K64S2-45I-LQFP48单片机无法采集ADC数值的问题,以下是一些可能的原因及解决方案:<br><br>1. ADC初始化设置:请确认ADC模块已正确初始化。检查ADC相关的寄存器配置,包括ADC控制寄存器(ADCCONTR)、ADC时钟分频寄存器(ADCCLK)等,确保ADC工作在正确的时钟频率和模式。<br><br>2. 引脚配置:确保P0.0、P0.1、P0.4引脚已配置为ADC输入模式。通过设置P0M0、P0M1寄存器,将相应引脚设置为模拟输入模式。<br><br>3. 参考电压:检查ADC的参考电压是否稳定。STC8H3K64S2的ADC模块支持内部和外部参考电压,请根据实际需求选择合适的参考电压源,并确保其稳定。<br><br>4. 采样时间:适当调整ADC的采样时间,以确保ADC有足够的时间进行采样和转换。可以通过设置ADCSAMP寄存器来调整采样时间。<br><br>5. 中断与轮询:如果使用ADC中断,请确保中断服务程序(ISR)已正确编写,并且中断已启用。如果使用轮询方式,请确保在转换完成后读取ADC结果。<br><br>6. 硬件连接:检查硬件连接,确保ADC输入引脚与外部信号源连接正确,且无短路或断路现象。<br><br>7. 调试与测试:可以通过读取ADC结果寄存器(ADCRES)的值来调试,确认ADC模块是否正常工作。如果读取的ADC值异常,可以逐步排查上述设置和连接问题。<br><br>建议您按照以上步骤逐一排查,确保ADC模块能够正常工作。如果问题依然存在,建议进一步检查硬件电路或更换芯片进行测试。<br><br>[本文内容由国芯人工智能辅助生成,仅供参考]

woshicainiao 发表于 2025-3-20 02:33:11

国芯人工智能 发表于 2025-3-20 01:53
针对您提到的STC8H3K64S2-45I-LQFP48单片机无法采集ADC数值的问题,以下是一些可能的原因及解决方案:1. AD ...
都测试了没有问题,你看一下代码吧,就是ADC不采集,#include "reg51.h"

_奶咖君_ 发表于 2025-3-20 09:27:16

有没有一种可能 P0.0 和P0.1 是ADC通道8 和 9 呢?

ercircle 发表于 2025-3-20 09:34:46



ADC_Read里有0x80 | ,看着没问题嗯   X
看错位了,通道传参不对,少|0x08


话说日志里不是有数吗:


DebugLab 发表于 2025-3-20 11:45:05

该型号有独立的AVCC和AGND,注意硬件连接

woshicainiao 发表于 2025-3-20 12:39:40

ercircle 发表于 2025-3-20 09:34
ADC_Read里有0x80 | ,看着没问题嗯




那个读数不变的,调节采集电压,改变阻值都没反应。在不同的电源电压下有不同的固定adc值,就是adc值一直不变化。

woshicainiao 发表于 2025-3-20 12:40:26

DebugLab 发表于 2025-3-20 11:45
该型号有独立的AVCC和AGND,注意硬件连接

帮我看看我的原理图有没有问题

DebugLab 发表于 2025-3-20 13:28:02

woshicainiao 发表于 2025-3-20 12:40
帮我看看我的原理图有没有问题

没有问题

ercircle 发表于 2025-3-20 13:44:14

woshicainiao 发表于 2025-3-20 12:39
那个读数不变的,调节采集电压,改变阻值都没反应。在不同的电源电压下有不同的固定adc值,就是adc值一直 ...

有时不是有变化吗?拿示波器看下ADC引脚处实际波形?


页: [1] 2
查看完整版本: 求助8H3K64S2-45I-LQFP48不采集ADC电压