找回密码
 立即注册
查看: 274|回复: 15

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

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:2
  • 最近打卡:2025-03-21 01:55:06
已绑定手机

1

主题

6

回帖

23

积分

新手上路

积分
23
发表于 2025-3-20 01:48:49 | 显示全部楼层 |阅读模式
求助该单片机不采集ADC数值,原理图中得其它引脚测试,输出高低电平,UART2通讯,DS18B20温度采集都能功能正常。但是无法ADC包括NTC和电压采集,P0.0,P0.1,P0.4号引脚。

[01:03:58.528]接收←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[20];  // 数据缓冲区使用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[20];     // 调试字符串缓冲区
   
    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[30];  // 使用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);
    }
}
  1. <blockquote>#include "reg51.h"
复制代码


截图202503200115589029.jpg
回复

使用道具 举报 送花

3

主题

1160

回帖

1031

积分

等待验证会员

积分
1031
发表于 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>[本文内容由国芯人工智能辅助生成,仅供参考]
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:2
  • 最近打卡:2025-03-21 01:55:06
已绑定手机

1

主题

6

回帖

23

积分

新手上路

积分
23
发表于 2025-3-20 02:33:11 | 显示全部楼层
国芯人*** 发表于 2025-3-20 01:53
针对您提到的STC8H3K64S2-45I-LQFP48单片机无法采集ADC数值的问题,以下是一些可能的原因及解决方案:1. AD ...

都测试了没有问题,你看一下代码吧,就是ADC不采集,#include "reg51.h"

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:435
  • 最近打卡:2025-04-30 08:43:23

33

主题

2351

回帖

4860

积分

论坛元老

积分
4860
发表于 2025-3-20 09:27:16 | 显示全部楼层
有没有一种可能 P0.0 和P0.1 是ADC通道8 和 9 呢?
参考例程并不是对技术参 考手册的补充,而是对技术参 考手册的解释。
技术参 考手册不应该需要参考例程作为补充,而是解释成了参考例程的样子
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:163
  • 最近打卡:2025-05-02 13:26:59
已绑定手机

56

主题

1319

回帖

2942

积分

荣誉版主

无情的代码机器

积分
2942
发表于 2025-3-20 09:34:46 | 显示全部楼层
截图202503200934449537.jpg
截图202503200939147293.jpg
ADC_Read里有0x80 | ,看着没问题嗯   X
看错位了,通道传参不对,少|0x08


话说日志里不是有数吗:
截图202503200944205347.jpg

三天不学习,赶不上刘少奇~
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:424
  • 最近打卡:2025-05-02 14:37:11
已绑定手机

77

主题

4849

回帖

8382

积分

超级版主

DebugLab

积分
8382
发表于 2025-3-20 11:45:05 | 显示全部楼层
该型号有独立的AVCC和AGND,注意硬件连接
DebugLab
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:2
  • 最近打卡:2025-03-21 01:55:06
已绑定手机

1

主题

6

回帖

23

积分

新手上路

积分
23
发表于 2025-3-20 12:39:40 来自手机 | 显示全部楼层
ercircle 发表于 2025-3-20 09:34
ADC_Read里有0x80 | ,看着没问题嗯



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

点评

有时不是有变化吗?拿示波器看下ADC引脚处实际波形? [attachimg]88701[/attachimg]  详情 回复 发表于 2025-3-20 13:44
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:2
  • 最近打卡:2025-03-21 01:55:06
已绑定手机

1

主题

6

回帖

23

积分

新手上路

积分
23
发表于 2025-3-20 12:40:26 来自手机 | 显示全部楼层
DebugLab 发表于 2025-3-20 11:45
该型号有独立的AVCC和AGND,注意硬件连接

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

点评

没有问题  详情 回复 发表于 2025-3-20 13:28
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:424
  • 最近打卡:2025-05-02 14:37:11
已绑定手机

77

主题

4849

回帖

8382

积分

超级版主

DebugLab

积分
8382
发表于 2025-3-20 13:28:02 | 显示全部楼层
woshic*** 发表于 2025-3-20 12:40
帮我看看我的原理图有没有问题

没有问题
DebugLab
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:163
  • 最近打卡:2025-05-02 13:26:59
已绑定手机

56

主题

1319

回帖

2942

积分

荣誉版主

无情的代码机器

积分
2942
发表于 2025-3-20 13:44:14 | 显示全部楼层
woshic*** 发表于 2025-3-20 12:39
那个读数不变的,调节采集电压,改变阻值都没反应。在不同的电源电压下有不同的固定adc值,就是adc值一直 ...

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

三天不学习,赶不上刘少奇~
回复 支持 反对

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-5-2 20:47 , Processed in 0.137493 second(s), 106 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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