00 1-Wire protokolü temelleri
1-Wire — Dallas Semiconductor (şimdi Maxim/Analog Devices) tarafından geliştirilen, tek tel üzerinden hem güç hem de veri taşıyan seri protokol.
SoC GPIO pin 1-Wire Bus (DQ)
│ │
├── 4.7 kΩ ──── VCC ─┤─ DS18B20 (0x28-XXXXXXXXXXXX)
│ │─ DS18B20 (0x28-YYYYYYYYYYYY)
│ │─ DS18B20 (0x28-ZZZZZZZZZZZZ)
│ │
GND ─────────────────────── GND (tüm sensörler)
Temel özellikler
ROM kod yapısı
| Bit | Alan | Açıklama |
|---|---|---|
| [7:0] | Family code | Cihaz tipi. DS18B20 = 0x28, DS18S20 = 0x10, DS2431 (EEPROM) = 0x2D |
| [55:8] | Serial number | 48-bit benzersiz seri numara |
| [63:56] | CRC | İlk 56 bitin CRC-8 doğrulama değeri |
Temel komutlar
| Komut | Hex | Açıklama |
|---|---|---|
| Search ROM | 0xF0 | Bus'taki tüm cihazların ROM kodlarını keşfet |
| Read ROM | 0x33 | Tek cihaz varsa ROM kodunu oku (multi-drop'ta kullanılmaz) |
| Match ROM | 0x55 | 64-bit ROM kodu ile belirli bir cihazı seç |
| Skip ROM | 0xCC | Tüm cihazlara broadcast. Tek cihaz veya eş zamanlı dönüşüm için. |
| Convert T | 0x44 | DS18B20: sıcaklık dönüşümünü başlat |
| Read Scratchpad | 0xBE | DS18B20: 9-byte scratchpad belleği oku |
01 Linux w1 subsystem
Linux'ta 1-Wire desteği w1 (wire-one) subsystem üzerinden sağlanır. w1_gpio driver, herhangi bir GPIO pinini 1-Wire bus master olarak kullanır.
Userspace /sys/bus/w1/devices/28-xxxxxxxxxxxx/w1_slave
│
Kernel w1_therm driver (DS18B20 family)
│
w1 bus master (wire1.c)
│
w1_gpio driver
│
GPIO pin (kernel GPIO API)
Kernel yapılandırması
CONFIG_W1=y # 1-Wire subsystem
CONFIG_W1_MASTER_GPIO=y # GPIO tabanlı master
CONFIG_W1_SLAVE_THERM=y # DS18B20 / DS18S20 / DS1822 / DS28EA00
CONFIG_W1_SLAVE_DS2431=m # DS2431 EEPROM (opsiyonel)
Device Tree tanımı
/ {
onewire: w1 {
compatible = "w1-gpio";
gpios = <&gpio 4 0>; /* GPIO4, active-high */
pinctrl-names = "default";
pinctrl-0 = <&w1_pins>;
};
};
&gpio {
w1_pins: w1_pins {
brcm,pins = <4>;
brcm,function = <0>; /* GPIO input */
brcm,pull = <0>; # pull none (harici 4.7kΩ var) */
};
};
Raspberry Pi'da etkinleştirme
# 1-Wire GPIO4 üzerinde etkinleştir:
dtoverlay=w1-gpio
# Farklı pin (GPIO2) kullanmak için:
dtoverlay=w1-gpio,gpiopin=2
# Parasite power desteği:
dtoverlay=w1-gpio,pullup=on
# Modülleri yükle (=m ise):
sudo modprobe w1-gpio
sudo modprobe w1-therm
# Yüklenen modülleri kontrol et:
lsmod | grep w1
# Kernel mesajlarını izle:
dmesg | grep w1
# [ 5.2] Driver for 1-wire Dallas network protocol.
# [ 5.3] gpio-4 (w1): device address: 28-00000xxxxxx
# w1 bus master durumu:
ls /sys/bus/w1/devices/
# 28-00000xxxxxxx w1_bus_master1
02 /sys/bus/w1/devices/ arayüzü
Kernel, 1-Wire cihazlarını /sys/bus/w1/devices/ altında ROM kodu ile adlandırarak gösterir.
# Tüm 1-Wire cihazlarını listele:
ls /sys/bus/w1/devices/
# 28-00000a123456 28-00000b789abc w1_bus_master1
# ROM kodu formatı: {family_code}-{48bit_serial}
# 28 → DS18B20 family code
# 00000a123456 → 48-bit seri numarası (hex, 6 bayt)
# Belirli cihazın dosyalarını gör:
ls /sys/bus/w1/devices/28-00000a123456/
# driver id name power subsystem uevent w1_slave
# Cihaz adı (family):
cat /sys/bus/w1/devices/28-00000a123456/name
# 28-00000a123456
# w1_bus_master1 altında tarama ayarları:
ls /sys/bus/w1/devices/w1_bus_master1/
# max_slave_count search_count slave_count timeout w1_master_name
# Bağlı cihaz sayısı:
cat /sys/bus/w1/devices/w1_bus_master1/slave_count
# 2
w1 driver, bağlı cihazları otomatik olarak yaklaşık her 10 saniyede bir tarar. Yeni bir sensör takıldığında /sys/bus/w1/devices/ altında otomatik olarak görünür. Tarama sıklığını /sys/bus/w1/devices/w1_bus_master1/timeout dosyasına yazarak değiştirebilirsin (saniye cinsinden).
03 DS18B20 okuma — w1_slave dosyası
w1_therm driver, sıcaklık ölçümü ve ham veriyi w1_slave dosyası üzerinden sunar.
# w1_slave dosyasını oku:
cat /sys/bus/w1/devices/28-00000a123456/w1_slave
50 05 4b 46 7f ff 0c 10 1c : crc=1c YES
50 05 4b 46 7f ff 0c 10 1c t=21312
Çıktı formatını yorumlayalım:
# Sıcaklığı tek satırda oku:
awk '/YES/{found=1} found{match($0,/t=([0-9-]+)/,a); if(a[1]!="") printf "%.3f C\n", a[1]/1000; exit}' \
/sys/bus/w1/devices/28-00000a123456/w1_slave
# 21.312 C
# CRC hatasını filtrele:
awk '/YES/{found=1} found{match($0,/t=([0-9-]+)/,a); if(a[1]!="") printf "%.3f\n", a[1]/1000}' \
/sys/bus/w1/devices/28-00000a123456/w1_slave
# Sürekli izleme (her 2 saniye):
while true; do
cat /sys/bus/w1/devices/28-00000a123456/w1_slave | \
grep 't=' | awk -F'=' '{printf "%.3f C\n", $2/1000}'
sleep 2
done
temperature dosyası (daha yeni kernel'lar)
Linux 5.0+ kernel'larda w1_therm driver, temperature adında ek bir sysfs dosyası sunar:
# Doğrudan sıcaklık (millidegree Celsius):
cat /sys/bus/w1/devices/28-00000a123456/temperature
# 21312
# Python tarzı hesap:
echo "$(cat /sys/bus/w1/devices/28-00000a123456/temperature) / 1000" | bc -l
# 21.312
04 Birden fazla sensör
1-Wire'ın en güçlü özelliği: tüm sensörler aynı iki teli (DQ + GND) paylaşır, her biri ROM kodu ile ayrılır.
# Tüm DS18B20 sensörlerini bul ve oku:
for sensor in /sys/bus/w1/devices/28-*/; do
id=$(basename "$sensor")
raw=$(cat "${sensor}w1_slave" 2>/dev/null)
# CRC kontrolü:
if echo "$raw" | grep -q "YES"; then
temp=$(echo "$raw" | grep 't=' | awk -F'=' '{printf "%.3f", $2/1000}')
echo "$id : ${temp} °C"
else
echo "$id : CRC HATASI"
fi
done
# 28-00000a123456 : 21.312 °C
# 28-00000b789abc : 23.875 °C
# 28-00000c001122 : 19.500 °C
Parasite power ile 4.7 kΩ pull-up önemi
Parasite power modunda DS18B20, DQ hattının yüksek seviyesinden enerji depolar. Sıcaklık dönüşümü sırasında (~750ms) DQ hattından yüksek akım çekilir. Bu nedenle:
- 4.7 kΩ pull-up direnci kesinlikle gereklidir. Daha büyük direnç (10 kΩ) yeterli akımı sağlayamaz ve dönüşüm başarısız olur.
- Parasite power ile birden fazla sensör kullanırken güç yetersizliği daha belirgin olur. 3 veya daha fazla sensör için ayrı VCC bağlantısı önerilir.
- Ayrı VCC kullanıldığında 4.7 kΩ pull-up hâlâ gereklidir (bus sinyalizasyonu için).
| Bağlantı tipi | Sensör sayısı | Pull-up | Not |
|---|---|---|---|
| Parasite power | 1-3 | 4.7 kΩ → 3.3V veya 5V | Sadece DQ + GND gerekir |
| Parasite power | 4+ | 4.7 kΩ + güçlendirilmiş sürücü | Sorunlu, ayrı VCC önerilir |
| Ayrı VCC (3.3V) | Sınırsız (pratikte 32) | 4.7 kΩ → 3.3V | Önerilen bağlantı |
05 Python ile DS18B20 okuma
İki yöntem: hazır w1thermsensor kütüphanesi veya doğrudan dosya parse.
w1thermsensor kütüphanesi
pip3 install w1thermsensor
from w1thermsensor import W1ThermSensor, Sensor
# Tüm sensörleri bul:
for sensor in W1ThermSensor.get_available_sensors():
print(f"ID: {sensor.id} Tip: {sensor.name}")
print(f" Sıcaklık: {sensor.get_temperature():.3f} °C")
print(f" Fahrenheit: {sensor.get_temperature(W1ThermSensor.DEGREES_F):.3f} °F")
# Belirli bir sensörü ID ile bul:
sensor = W1ThermSensor(sensor_type=Sensor.DS18B20, sensor_id="00000a123456")
temp = sensor.get_temperature()
print(f"Belirli sensör: {temp:.2f} °C")
# Çözünürlük ayarı (9, 10, 11, 12 bit):
sensor.set_precision(12)
print(f"12-bit çözünürlük: {sensor.get_temperature():.4f} °C")
Ham dosya parse (kütüphanesiz)
import os
import glob
import time
W1_BASE = "/sys/bus/w1/devices"
def find_sensors():
"""28-* ile başlayan tüm cihaz dizinlerini bul."""
return glob.glob(os.path.join(W1_BASE, "28-*"))
def read_temp(device_path, retries=3):
"""w1_slave dosyasını parse et, CRC hatasında tekrar dene."""
w1_file = os.path.join(device_path, "w1_slave")
for attempt in range(retries):
try:
with open(w1_file, "r") as f:
lines = f.readlines()
if len(lines) < 2:
raise ValueError("Yetersiz satır")
# Satır 1: "xx xx xx ... : crc=xx YES/NO"
if "YES" not in lines[0]:
if attempt < retries - 1:
time.sleep(0.1)
continue
raise ValueError(f"CRC hatası (deneme {attempt+1}/{retries})")
# Satır 2: "xx xx ... t=NNNNN"
pos = lines[1].find("t=")
if pos == -1:
raise ValueError("t= bulunamadı")
raw_temp = int(lines[1][pos+2:].strip())
return raw_temp / 1000.0 # °C
except OSError as e:
raise IOError(f"Dosya okuma hatası: {e}")
raise ValueError("Tüm denemeler başarısız")
sensors = find_sensors()
if not sensors:
print("Hiç DS18B20 bulunamadı. Bağlantı ve modül yüklemesini kontrol et.")
else:
for s in sensors:
name = os.path.basename(s)
try:
temp = read_temp(s)
print(f"{name}: {temp:.3f} °C")
except (ValueError, IOError) as e:
print(f"{name}: HATA — {e}")
06 Dönüşüm hesaplama
w1_slave dosyasındaki t= değeri kernel tarafından hesaplanmış °C×1000 değeridir. Ancak ham scratchpad verisini kendin parse etmek istersen dönüşüm formülü şöyledir.
DS18B20 çözünürlük ve dönüşüm süresi
| Çözünürlük | Bit | Adım (°C) | Dönüşüm süresi (maks.) |
|---|---|---|---|
| 9-bit | Configuration=0x1F | 0.5 °C | 93.75 ms |
| 10-bit | Configuration=0x3F | 0.25 °C | 187.5 ms |
| 11-bit | Configuration=0x5F | 0.125 °C | 375 ms |
| 12-bit (varsayılan) | Configuration=0x7F | 0.0625 °C | 750 ms |
def parse_scratchpad(hex_bytes_str):
"""
w1_slave'nin birinci satırındaki hex baytlarını parse et.
Örnek: "50 05 4b 46 7f ff 0c 10 1c"
"""
raw = [int(x, 16) for x in hex_bytes_str.strip().split()]
if len(raw) != 9:
raise ValueError(f"Beklenen 9 bayt, alınan {len(raw)}")
# CRC-8 doğrulama (Dallas/Maxim CRC8):
crc = 0
for byte in raw[:8]:
for _ in range(8):
bit = (crc ^ byte) & 1
crc >>= 1
if bit:
crc ^= 0x8C
byte >>= 1
if crc != raw[8]:
raise ValueError(f"CRC hatası: hesaplanan=0x{crc:02X} beklenen=0x{raw[8]:02X}")
# Sıcaklık hesabı (Byte0=LSB, Byte1=MSB):
temp_raw = (raw[1] << 8) | raw[0]
# İşaretli 16-bit integer (two's complement):
if temp_raw > 32767:
temp_raw -= 65536
temp_c = temp_raw / 16.0 # 12-bit için ÷16 (0.0625°C adım)
# Yapılandırma register'dan çözünürlük al:
resolution_bits = 9 + ((raw[4] >> 5) & 0x03)
# Byte4[6:5]: 00=9bit, 01=10bit, 10=11bit, 11=12bit
# Düşük bitler çözünürlüğe göre anlamsızdır, maskele:
mask = {9: 0xFFF8, 10: 0xFFFC, 11: 0xFFFE, 12: 0xFFFF}
temp_raw_masked = temp_raw & mask[resolution_bits]
temp_c_final = temp_raw_masked / 16.0
return {
"temperature_c" : temp_c_final,
"resolution_bits": resolution_bits,
"alarm_high" : raw[2],
"alarm_low" : raw[3],
}
# Örnek kullanım:
result = parse_scratchpad("50 05 4b 46 7f ff 0c 10 1c")
print(f"Sıcaklık : {result['temperature_c']:.4f} °C")
print(f"Çözünürlük: {result['resolution_bits']}-bit")
# Sıcaklık : 21.3125 °C
# Çözünürlük: 12-bit
Scratchpad bayt 0-1: 12-bit çözünürlükte 4 bit kesirli kısım içerir (0.0625°C hassasiyet). 9-bit çözünürlükte yalnızca 1 kesirli bit anlamlıdır; kalan 3 bit belirsizdir ve maskelenmelidir. Kernel w1_therm driver her zaman 12-bit varsayılan hassasiyetle okur (yapılandırılmadıkça).
07 Troubleshooting
1-Wire sorunlarının büyük çoğunluğu pull-up eksikliği veya yanlış değeri, parasite power yetersizliği ve CRC hatalarından kaynaklanır.
Hata teşhis adımları
# 1) w1 modüllerinin yüklü olduğunu kontrol et:
lsmod | grep w1
# w1_therm 24576 0
# w1_gpio 16384 0
# wire 36864 2 w1_therm,w1_gpio
# 2) Kernel mesajlarını kontrol et:
dmesg | grep -i 'w1\|wire'
# 3) Bus master var mı?
ls /sys/bus/w1/devices/
# Sadece w1_bus_master1 görünüyorsa sensör bulunamıyor demektir.
# 4) Manuel bus tarama zorla:
echo 1 | sudo tee /sys/bus/w1/devices/w1_bus_master1/search
# 5) CRC hata sayısını izle:
while true; do
result=$(cat /sys/bus/w1/devices/28-*/w1_slave 2>/dev/null | grep 'NO\|YES')
echo "$(date): $result"
sleep 1
done
| Belirti | Olası neden | Çözüm |
|---|---|---|
| /sys/bus/w1/devices/ boş (sadece bus_master) | Pull-up eksik veya çok büyük, sensör beslenmiyor | 4.7 kΩ pull-up ekle; VCC bağlantısını kontrol et |
| Aralıklı CRC hatası (bazen YES, bazen NO) | Pull-up yetersiz, kablo çok uzun, EMI | 4.7 kΩ → 3.3 kΩ değiştir; kablo uzunluğunu kıs |
| t=85000 (85°C) sabit | Dönüşüm başlamadı; Convert T komutu verilmedi | w1_therm modülü sorunlu; modprobe w1_therm tekrar yükle |
| t=-4096 veya saçma değer | Parasite power yetersiz akım | Ayrı VCC bağla; parasite güç kaldır |
| Birden fazla sensör ama sadece biri görünür | Adres çakışması (çok nadir) veya yetersiz pull-up | Pull-up direncini küçült; timeout süresini artır |
t=85000 değeri (85°C) DS18B20'nin power-on reset değeridir ve sensörün dönüşüm yapmadan okunduğunu gösterir. Bu değeri gerçek sıcaklık olarak işleme alma. Sürekli 85°C görmek, Convert T komutunun gitmediğine veya parasite power sorununun olduğuna işaret eder.
Parasite power sorunları
Parasite power modunda dönüşüm sırasında (~750ms) DQ hattından tipik olarak 1.5mA'e kadar akım çekilir. DQ hattının 4.7kΩ pull-up ile VCC'den sağlayabileceği akım: (3.3V - 1.2V) / 4700Ω ≈ 450µA. Bu yeterli değildir.
Çözüm: Dönüşüm sırasında DQ hattını güçlü pull-up ile sür. Bazı SoC'lerin GPIO'su push-pull çıkış olarak yapılandırılabilir; bu durumda DQ dönüşüm süresince yüksek tutulabilir. Alternatif olarak harici MOSFET veya doğrudan VCC bağlantısı kullan.