- 打卡等级:初来乍到
- 打卡总天数:2
- 最近打卡:2025-03-21 01:55:06
已绑定手机
新手上路
- 积分
- 23
|
求助该单片机不采集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);
}
}
- <blockquote>#include "reg51.h"
复制代码
|
-
|