// DS18B20 (1-Wire) multi-sensor example for ESP32 Arduino, no external libs
// DQ -> GPIO13, pull-up 4.7k to 3.3V
#include <Arduino.h>
#define ONE_WIRE_PIN 13
#define MAX_SENSORS 8
static uint8_t g_sensors[MAX_SENSORS][8];
static int g_sensorCount = 0;
// ---- Low-level 1-Wire ----
static inline void owDriveLow() {
pinMode(ONE_WIRE_PIN, OUTPUT);
digitalWrite(ONE_WIRE_PIN, LOW);
}
static inline void owRelease() {
// External 4.7k pull-up is present, but INPUT_PULLUP is fine in simulation too
pinMode(ONE_WIRE_PIN, INPUT_PULLUP);
}
static bool owReset() {
owDriveLow();
delayMicroseconds(480);
owRelease();
delayMicroseconds(70);
bool presence = (digitalRead(ONE_WIRE_PIN) == LOW);
delayMicroseconds(410);
return presence;
}
static void owWriteBit(uint8_t v) {
if (v) {
owDriveLow();
delayMicroseconds(6);
owRelease();
delayMicroseconds(64);
} else {
owDriveLow();
delayMicroseconds(60);
owRelease();
delayMicroseconds(10);
}
}
static uint8_t owReadBit() {
owDriveLow();
delayMicroseconds(6);
owRelease();
delayMicroseconds(9);
uint8_t r = digitalRead(ONE_WIRE_PIN);
delayMicroseconds(55);
return r;
}
static void owWriteByte(uint8_t v) {
for (uint8_t i = 0; i < 8; i++) {
owWriteBit(v & 0x01);
v >>= 1;
}
}
static uint8_t owReadByte() {
uint8_t v = 0;
for (uint8_t i = 0; i < 8; i++) {
v >>= 1;
if (owReadBit()) v |= 0x80;
}
return v;
}
// ---- CRC8 (Dallas/Maxim) ----
static uint8_t crc8(const uint8_t *data, uint8_t len) {
uint8_t crc = 0;
while (len--) {
uint8_t inbyte = *data++;
for (uint8_t i = 8; i; i--) {
uint8_t mix = (crc ^ inbyte) & 0x01;
crc >>= 1;
if (mix) crc ^= 0x8C; // reversed polynomial 0x31
inbyte >>= 1;
}
}
return crc;
}
// ---- 1-Wire Search ROM (to find multiple devices on one bus) ----
static uint8_t ROM_NO[8];
static int LastDiscrepancy = 0;
static int LastDeviceFlag = 0;
static void owResetSearch() {
LastDiscrepancy = 0;
LastDeviceFlag = 0;
memset(ROM_NO, 0, sizeof(ROM_NO));
}
static bool owSearch(uint8_t *newAddr /*8 bytes*/) {
uint8_t id_bit_number = 1;
uint8_t last_zero = 0;
uint8_t rom_byte_number = 0;
uint8_t rom_byte_mask = 1;
uint8_t id_bit, cmp_id_bit;
uint8_t search_direction;
if (LastDeviceFlag) return false;
if (!owReset()) {
owResetSearch();
return false;
}
owWriteByte(0xF0); // SEARCH ROM
do {
id_bit = owReadBit();
cmp_id_bit = owReadBit();
if ((id_bit == 1) && (cmp_id_bit == 1)) {
break; // no devices
}
if (id_bit != cmp_id_bit) {
search_direction = id_bit; // only one path
} else {
if (id_bit_number < (uint8_t)LastDiscrepancy) {
search_direction = ((ROM_NO[rom_byte_number] & rom_byte_mask) > 0);
} else {
search_direction = (id_bit_number == (uint8_t)LastDiscrepancy);
}
if (search_direction == 0) {
last_zero = id_bit_number;
}
}
if (search_direction == 1) ROM_NO[rom_byte_number] |= rom_byte_mask;
else ROM_NO[rom_byte_number] &= ~rom_byte_mask;
owWriteBit(search_direction);
id_bit_number++;
rom_byte_mask <<= 1;
if (rom_byte_mask == 0) {
rom_byte_number++;
rom_byte_mask = 1;
}
} while (rom_byte_number < 8);
if (id_bit_number >= 65) {
LastDiscrepancy = last_zero;
if (LastDiscrepancy == 0) LastDeviceFlag = 1;
memcpy(newAddr, ROM_NO, 8);
// ROM CRC check
if (crc8(newAddr, 7) != newAddr[7]) {
return false;
}
return true;
}
owResetSearch();
return false;
}
static void printRom(const uint8_t rom[8]) {
for (int i = 0; i < 8; i++) {
if (rom[i] < 0x10) Serial.print("0");
Serial.print(rom[i], HEX);
if (i < 7) Serial.print(":");
}
}
// ---- DS18B20 helpers ----
static bool ds18b20SetResolution12bit(const uint8_t rom[8]) {
// WRITE SCRATCHPAD: 0x4E, then TH, TL, CONFIG
// 12-bit config = 0x7F (R1=1,R0=1)
if (!owReset()) return false;
owWriteByte(0x55); // MATCH ROM
for (int i = 0; i < 8; i++) owWriteByte(rom[i]);
owWriteByte(0x4E); // WRITE SCRATCHPAD
owWriteByte(0x00); // TH
owWriteByte(0x00); // TL
owWriteByte(0x7F); // CONFIG 12-bit
return true;
}
static bool ds18b20ReadTempC(const uint8_t rom[8], float &outC) {
uint8_t data[9];
if (!owReset()) return false;
owWriteByte(0x55); // MATCH ROM
for (int i = 0; i < 8; i++) owWriteByte(rom[i]);
owWriteByte(0xBE); // READ SCRATCHPAD
for (int i = 0; i < 9; i++) data[i] = owReadByte();
if (crc8(data, 8) != data[8]) return false;
int16_t raw = (int16_t)((data[1] << 8) | data[0]);
outC = raw / 16.0f; // for 12-bit: 1/16 °C
return true;
}
static bool ds18b20ConvertAllAndWait() {
if (!owReset()) return false;
owWriteByte(0xCC); // SKIP ROM (broadcast)
owWriteByte(0x44); // CONVERT T
// wait until all sensors complete conversion (bus goes high)
unsigned long start = millis();
while (owReadBit() == 0) {
if (millis() - start > 1000) break; // 12-bit max 750ms
delay(1);
}
return true;
}
// ---- App ----
void setup() {
Serial.begin(115200);
delay(200);
Serial.println("DS18B20 (1-Wire) multi-sensor, no libs");
Serial.print("DQ pin: GPIO"); Serial.println(ONE_WIRE_PIN);
Serial.println("Searching devices...");
owRelease();
owResetSearch();
g_sensorCount = 0;
uint8_t rom[8];
while (g_sensorCount < MAX_SENSORS && owSearch(rom)) {
// DS18B20 family code is 0x28
if (rom[0] == 0x28) {
memcpy(g_sensors[g_sensorCount], rom, 8);
Serial.print("Found DS18B20["); Serial.print(g_sensorCount); Serial.print("] ROM: ");
printRom(rom);
Serial.println();
ds18b20SetResolution12bit(rom);
g_sensorCount++;
} else {
Serial.print("Found non-DS18B20 device ROM: ");
printRom(rom);
Serial.println();
}
}
Serial.print("Total DS18B20 found: ");
Serial.println(g_sensorCount);
Serial.println();
}
void loop() {
if (g_sensorCount == 0) {
Serial.println("No sensors. Check wiring + 4.7k pull-up to 3.3V on DQ.");
delay(1000);
return;
}
if (!ds18b20ConvertAllAndWait()) {
Serial.println("1-Wire reset/presence failed!");
delay(500);
return;
}
for (int i = 0; i < g_sensorCount; i++) {
float tC = 0;
Serial.print("Sensor["); Serial.print(i); Serial.print("] ");
printRom(g_sensors[i]);
Serial.print(" | Temp: ");
if (ds18b20ReadTempC(g_sensors[i], tC)) {
Serial.print(tC, 2);
Serial.println(" C");
} else {
Serial.println("READ ERROR (CRC/presence)");
}
}
Serial.println();
delay(500);
}