#include <Arduino.h>
#include <OneWire.h>
// 与你原代码一致:GPIO5
#define ONE_WIRE_BUS 5
OneWire oneWire(ONE_WIRE_BUS);
// 保存第一个设备的 ROM(不再只限 0x28)
uint8_t g_rom[8];
bool g_found = false;
uint8_t g_family = 0x00; // 0x28=DS18B20, 0x10=DS18S20, 0x22=DS1822
static void printRom(const uint8_t rom[8]) {
for (int i = 0; i < 8; i++) {
Serial.printf("%02X", rom[i]);
if (i != 7) Serial.print(":");
}
Serial.println();
}
// 扫描总线,记录第一个有效 ROM(CRC 过)
bool findFirstDeviceAnyFamily() {
oneWire.reset_search();
uint8_t addr[8];
while (oneWire.search(addr)) {
if (OneWire::crc8(addr, 7) != addr[7]) continue; // ROM CRC fail
memcpy(g_rom, addr, 8);
g_family = addr[0];
return true;
}
return false;
}
// 触发温度转换(外接供电:第二个参数 0;若寄生电源,改为 1)
bool convertT_blocking(uint32_t timeout_ms = 1000) {
if (!g_found) return false;
if (!oneWire.reset()) return false; // presence
oneWire.select(g_rom); // Match ROM
oneWire.write(0x44, 0); // Convert T(0=不强上拉)
unsigned long t0 = millis();
while (millis() - t0 < timeout_ms) {
if (oneWire.read_bit() == 1) return true; // 1=完成
delay(2);
}
return false; // 超时
}
// 读 Scratchpad(9 字节,校验前 8 字节 CRC 对第 9 字节)
bool readScratchpad(uint8_t sp[9]) {
if (!g_found) return false;
if (!oneWire.reset()) return false;
oneWire.select(g_rom);
oneWire.write(0xBE); // Read Scratchpad
for (int i = 0; i < 9; i++) sp[i] = oneWire.read();
return OneWire::crc8(sp, 8) == sp[8];
}
// 统一的温度解码:兼容 0x28 / 0x22 / 0x10
bool decodeTemperatureC(const uint8_t sp[9], uint8_t family, float &celsius) {
if (family == 0x28 || family == 0x22) {
// DS18B20 / DS1822: 1/16 °C
int16_t raw = (int16_t)((sp[1] << 8) | sp[0]);
celsius = raw / 16.0f;
if (fabsf(celsius - 85.0f) < 0.0001f) return false;
return true;
} else if (family == 0x10) {
// DS18S20 (9-bit base), 使用 Count Per C 和 Count Remain 细化
int16_t raw = (int16_t)((sp[1] << 8) | sp[0]);
int16_t integer_part = (raw >> 1); // 去掉0.5位后的整数部分
uint8_t countRemain = sp[6];
uint8_t countPerC = sp[7];
if (countPerC == 0) return false; // 防止除零
celsius = (float)integer_part - 0.25f
+ (float)(countPerC - countRemain) / (float)countPerC;
if (fabsf(celsius - 85.0f) < 0.0001f) return false;
return true;
} else {
// 其它family,先按B20方式尝试
int16_t raw = (int16_t)((sp[1] << 8) | sp[0]);
celsius = raw / 16.0f;
return true;
}
}
void setup() {
Serial.begin(115200);
// 与你原例一致:空闲用内部上拉;若有物理 4.7k 外部上拉,可换 INPUT
pinMode(ONE_WIRE_BUS, INPUT_PULLUP);
Serial.println("Dallas Temperature IC Control (OneWire-only, any family) Demo");
// 连续尝试几次扫描,避免上电瞬间找不到
for (int i = 0; i < 5 && !g_found; ++i) {
g_found = findFirstDeviceAnyFamily();
if (!g_found) { delay(200); }
}
if (g_found) {
Serial.print("Found device ROM: ");
printRom(g_rom);
Serial.print("Family code: 0x"); Serial.println(g_family, HEX);
} else {
Serial.println("No 1-Wire device found on the bus!");
}
}
void loop() {
if (!g_found) {
// 每秒重试扫描一次
g_found = findFirstDeviceAnyFamily();
if (g_found) {
Serial.print("Found device ROM: ");
printRom(g_rom);
Serial.print("Family code: 0x"); Serial.println(g_family, HEX);
} else {
delay(1000);
return;
}
}
Serial.print("Requesting temperatures...");
bool ok = convertT_blocking();
if (!ok) {
Serial.println("FAILED");
delay(500);
return;
}
Serial.println("DONE");
uint8_t sp[9];
if (!readScratchpad(sp)) {
Serial.println("Read failed (scratchpad CRC).");
delay(500);
return;
}
float tC = NAN;
if (decodeTemperatureC(sp, g_family, tC)) {
Serial.print("Temperature for the device 1 (index 0) is: ");
Serial.println(tC); // 摄氏度
} else {
Serial.println("Read failed (decode).");
}
delay(500);
}