Co to jest DS18B20?

Czujnik temperatury DS18B20

DS18B20 to cyfrowy czujnik temperatury firmy Dallas. Wysyła dane o temperaturze wykorzystując do tego tylko jeden pin cyfrowy i specjalny protokół o nazwie 1-Wire. Do tego samego pinu możesz podłączyć wiele czujników. Czujnik podaje sprzętowo temperaturę w stopniach Celsjusza.

Parametry techniczne DS18B20

Co to jest rozdzielczość?

Napisałem, że czujnik może mierzyć temperaturę z różną rozdzielczością. Rozdzielczość jest jak podziałka milimetrowa w linijce pomiędzy kolejnymi centymetrami. Tak rozdzielczość w termometrze to podziałka między kolejnymi stopniami Celsujsza. Rozdzielczość wybiera się za pomocą liczby bitów. Zakres wyboru jest od 9 do 12 bitów. Wybór rozdzielczości pociąga też za sobą pewne konsekwencje. Im wyższa rozdzielczość tym dłużej trzeba czekać na wynik pomiaru.

Wizualizacja rozdzielczości względem liczby bitów

Dla 9 bitów są 2 podziałki między kolejnymi stopniami:

Czyli możesz odczytać temperaturę z rozdzielczością 0,5 °C. Dla tej rozdzielczości czas pomiaru wynosi 93,75 ms. Czyli możesz wykonywać 10,6 pomiarów na sekundę.

Dla 10 bitów są 4 podziałki między kolejnymi stopniami:

Tu odczytujesz temperaturę z rozdzielczością 0,25 °C Czas pomiaru dla tej rozdzielczości wynosi 187,5 ms, co pozwala na 5,3 pomiarów na sekundę

Dla 11 bitów jest 8 podziałek między kolejnymi stopniami:

Czyli rozdzielczość wynosi 0,125 °C Czas pomiaru dla tej rozdzielczości wynosi 375 ms. co pozwala na 2,6 pomiaru na sekundę.

Dla 12 bitów jest 16 podziałek między kolejnymi stopniami:

Czyli rozdzielczośc jest na poziomie 0,0625 °C Czas pomiaru wynosi w tym przypadku 750 ms, czyli możesz dokonać 1,3 pomiaru na sekundę.

Co to jest dokładność pomiaru?

Nic na świecie, a szczególnie w elektronice nie jest doskonałe. Możesz się tylko zbliżać do doskonałości wydając coraz więcej pieniędzy. Tak samo jest i z tym czujnikiem. Ma on pewne niedokładności, o których powinieneś wiedzieć.

Napisałem, że w zakresie od -10 do 85 °C ma on dokładność na poziomie +/- 0,5 °C. To znaczy, że gdy w pokoju masz 22,5 °C, to czujnik może zwrócić ci wynik od 22 do 23 °C. Czyli może pokazać 0,5 °C za mało, albo za dużo. Wszystko to zależy od indywidualnej charakterystyki czujnika.

Błąd pomiaru względem temperatury rzeczywistej

W zakresie od -55 do 125 °C błąd pomiaru może się zwiększyć do +/- 2 °C. Czyli kiedy mierzysz coś o temperaturze 100 °C to czujnik może pokazać temperaturę od 98 do 102 °C.

Wszystkie te nierówności mogą być dla każdej temperatury nieco inne, lecz gdy mierzysz tą samą temperaturę, to odchylenie będzie zawsze takie samo.

Dryf pomiaru

Dryf pomiaru jest nieco gorszą formą niedokładności. Polega on na tym, że przy tej samej mierzonej temperaturze, termometr w jednym czasie może wskazywać jedną temperaturę, a w innym czasie inną.

Dryf czujnika DS18B20 to +/- 0.2 °C. Czyli gdy w pokoju termometr wskazuje nam 24 °C to za jakiś czas mimo tej samej temperatury może pokazywać wynik z zakresu od 23,8 °C do 24,2 °C.

Błąd pomiaru względem temperatury podawanej przez czujnik

Kiedy termometr pokazuje 24 °C, to można założyć, że rzeczywistą temperatura w pokoju jest temperatura od 23 do 25 °C. To wszystko dlatego, że nie wiesz w którym miejscu rzeczywistej temperatury jest błąd pomiaru. Jeśli przyjmiesz, że może leżeć na granicy błędu to zakres temperatur w których może się znajdować rzeczywista temperatura to +/- 1 °C, bo nie wiesz czy to górna czy dolna granica.

Wszystkie te błędy są wartościami skrajnymi mierzonymi przez fabrykę w dość ekstremalnych warunkach. Musisz jednak być na nie przygotowany.

Co będzie potrzebne do budowy układu

Części potrzebne do budowy układu

  1. Arduino
  2. Czujik temperatury DS18B20
  3. Rezystor 4,7 kΩ
  4. Płytka stykowa
  5. Przewody do płytki stykowej

Lub cały zestaw z dodatkami w zestawie Starter Kit

Wyprowadzenia czujnika DS18B20

Wyprowadzenia czujnika DS18B20

Czujnik ma tylko 3 wyprowadzenia, wiec łatwo go będzie podłączyć do Arduino. Znaczenie nóżek:

Podłączenie czujnika DS18B20 do Arduino instrukcja wideo

Podłączenie czujnika DS18B20 do Arduino

Jak podłączyć DS18B20 do Arduino?

Podłączenie czujnika DS18B20 do Arduino

Podłączenie jest bardzo proste.

  1. Wyprowadzenie GND łączysz z pinem GND w Arduino
  2. Wyprowadzenie VDD łączysz z pinem 5V w Arduino
  3. Sygnał danych DQ łączysz z dowolnym pinem cyfrowym w Arduino (W moim przypadku to pin nr 2).
  4. Sygnał DQ łączysz przez rezystor podciągający o wartości 4,7 kΩ do pinu 5V Arduino

Ponieważ sygnał DQ ma wyjście typu otwarty dren, może nadawać albo stan "LOW", albo "niepodłączony". Żeby stan "niepodłączony" był widoczny przez Arduino jako "HIGH", trzeba podłączyć sygnał DQ przez rezystor podciągający do zasilania. Rezystor sprawi, że jeśli w przewodzie nie ma stanu "LOW", to automatycznie będzie stan "HIGH".

Podłączenie czujnika DS18B20 za pomocą 2 przewodów

Czujnik DS18B20 nie wymaga podłączenia zasilania. Może on działać w trybie pasożytniczym, w którym jest zasilany za pomocą sygnałów na wyprowadzeniu DQ przy okazji przesyłania danych. Pozwala to na podłączenie czujnika w większej odległości od Arduino, tylko za pomocą 2 przewodów.

Podłączenie czujnika DS18B20 do Arduinoza pomocą 2 przewodów

  1. Wyprowadzenie GND łączysz z pinem GND w Arduino
  2. Wyprowadzenie VDD łączysz z wyprowadzeniem GND czujnika
  3. Wyprowadzenie DQ łączysz z dowonym pinem cyfrowym Arduino
  4. Sygnał DQ łączysz przez rezystor podciągający do pinu 5V Arduino

Zasilanie pasożytnicze nie jest zalecane gdy mierzysz temperatury przekraczające 100 °C.

Podłączenie kilku czujników DS18B20 do Arduino

Do jednego Arduino możesz podłączyć większą ilość czujników. Wszystkie będą podłączone do jednego pinu cyfrowego.

Podłączenie kilku czujników DS18B20 do Arduino

Pierwszy czujnik łączysz z Arduino tak jak w poprzednim rozdziale:

  1. Wyprowadzenie GND łączysz z pinem GND w Arduino
  2. Wyprowadzenie VDD łączysz z wyprowadzeniem GND czujnika
  3. Wyprowadzenie DQ łączysz z dowonym pinem cyfrowym Arduino
  4. Sygnał DQ łączysz przez rezystor podciągający do pinu 5V Arduino

Kolejne czujniki wymagają już tylko podłączenia sygnałów DQ i GND z poprzedniego czujnika, lub z płytki bazowej.

  1. Wyprowadzenie GND łączysz z wyprowadzeniem GND poprzedniego czujnika
  2. Wyprowadzeni VDD łączysz z wyprowadzeniem GND czujnika
  3. Wyprowadzenie DQ łaczysz z wyprowadzeniem DQ poprzedniego czujnika

Dobieranie rezystora podciagającego

Magistrala 1-Wire pozwala podłączyć czujniki do przewodu o długości nawet 100m. Jednak już przy kilku metrach mogą zacząć się kłopoty z transmisją. Jeśli masz kłopoty z odebraniem prawidłowej temperatury lub nawet połączeniem się z czujnikiem - musisz dobrać wartość rezystora podciągającego.

Domyślnie ma on wartość 4,7 kΩ. Wynika ona z 2 rzeczy. Gdy czujnik wymusza stan niski w przewodzie, prąd nie powinien przekraczać 4 mA. Gdy czujnik potrzebuje zasilania, obwód powinien dostarczyć mu około 1 mA. Zatem między zaciskami DQ i GND powinien być prąd o wartości od 1 do 4 mA.

Prąd można obliczyć ze wzoru

prąd = napięcie / rezystancja = 5 V / 4700 Ω = 0,00106 A = 1,06 mA

lub zmierzyć podłączając miedzy te zaciski multimetr nastawiony na pomiar prądu stałego.

Gdy przewód jest dłuższy, to zaczyna nabierać cech rezystora i kondensatora. Rezystancja przewodu połączona z rezystorem podciągającym zmniejsza prąd jaki może dojść do czujnika. Cechy kondensatora powodują, że przewód ma opóźnienia w zmienianiu stanu z LOW na HIGH i odwrotnie.

Zatem gdy występują problemy z transmisją danych z czujnika należy zmniejszać wartość rezystora podciągającego do takiej aż transmisja zadziała. Mając oczywiście na uwadze wyżej określone granice.

Programowanie czujnika DS18B20 instrukcja wideo

Programowanie czujnika DS18B20

Aby móc programować czujnik potrzebujesz odpowiednich bibliotek sterujących urządzeniem.

Pierwszą jest biblioteka OneWire, która zapewnia obsługę protokołu 1-Wire.

Biblioteka OneWire.zip wersja 2.2

Drugą bibilioteką jest biblioteka o nazwie DS18B20. Służy do obsługi czujnika. Napisał ją dział oprogramowanie Nettigo.

Biblioteka DS18B20.zip wersja 1.0

Ściągniete biblioteki w postaci archiwum ZIP możesz od razu zainstalować w środowisku Arduino IDE. By to uczynić należy wybrać w menu opcję:

Szkic->Importuj bibliotekę...->Dodaj bibliotekę…

Menu instalacji biblioteki

Potem pojawi się okno wyboru plików, w którym wybieramy pliki zip bibliotek.

Wybieranie pliku biblioteki

Czynność trzeba powtórzyć dla każdego pliku biblioteki od nowa.

Jak odczytać adres czujnika DS18B20?

Ponieważ wszystkie czujniki przesyłają dane za pomocą tego samego przewodu, trzeba jakoś odróżnić która temperatura pochodzi z którego czujnika.

Każdy czujnik ma indywidualny 64-bitowy numer seryjny. Numer jest unikalny dla każdego wyprodukowanego czujnika. Numery seryjne czujników, które podłączyłeś do Arduino można odczytać za pomocą tego programu.

// Czytnik numerów seryjnych czujników DS18B20

#include <OneWire.h>

// Numer pinu cyfrowego do którego podłaczyłęś czujniki
const byte ONEWIRE_PIN = 2;

OneWire onewire(ONEWIRE_PIN);

void setup()
{
  while(!Serial);
  Serial.begin(9600);
}

void loop()
{
  byte address[8];

  onewire.reset_search();
  while(onewire.search(address))
  {
    if (address[0] != 0x28)
      continue;

    if (OneWire::crc8(address, 7) != address[7])
    {
      Serial.println(F("Błędny adres, sprawdz polaczenia"));
      break;
    }

    for (byte i=0; i<8; i++)
    {
      Serial.print(F("0x"));
      Serial.print(address[i], HEX);

      if (i < 7)
        Serial.print(F(", "));
    }
    Serial.println();
  }

  while(1);
}

Program wyświetla w Monitorze portu szeregowego numery seryjne czujników. Jeśli chcesz ponowić wyszukiwanie czujników, naciśnij Reset w Arduino.

Pin do którego podłączyłeś czujniki ustawia się w zmiennej ONEWIRE_PIN

const byte ONEWIRE_PIN = 2;

Ja podłączyłem czujniki do pinu 2.

Program zwrócił mi takie numery czujników:

0x28, 0xB1, 0x6D, 0xA1, 0x3, 0x0, 0x0, 0x11
0x28, 0x87, 0x6A, 0xA1, 0x3, 0x0, 0x0, 0x1F

Jak odczytać temperaturę z czujnika DS18B20?

// Program odczytuje temperaturę z czujnika

#include <OneWire.h>
#include <DS18B20.h>

// Numer pinu do którego podłaczasz czujnik
#define ONEWIRE_PIN 2

// Adres czujnika
byte address[8] = {0x28, 0xB1, 0x6D, 0xA1, 0x3, 0x0, 0x0, 0x11};

OneWire onewire(ONEWIRE_PIN);
DS18B20 sensors(&onewire);

void setup() {
  while(!Serial);
  Serial.begin(9600);

  sensors.begin();
  sensors.request(address);
}

void loop() {
  if (sensors.available())
  {
    float temperature = sensors.readTemperature(address);

    Serial.print(temperature);
    Serial.println(F(" 'C"));

    sensors.request(address);
  }

  // tu umieść resztę twojego programu
  // Będzie działał bez blokowania
}

Program odczytuje temperaturę z czujnika i wyświetla ją w Monitorze portu szeregowego. Mój wynik działania programu to:

22.31 'C
22.37 'C
22.37 'C
22.37 'C
22.37 'C

W przykładzie czujnik jest podłączony do pinu 2 w Arduino i ma adres 0x28, 0xB1, 0x6D, 0xA1, 0x3, 0x0, 0x0, 0x11. Jeśli chcesz by program czytał dane z twojego czujnika, musisz zmienić adres na adres twojego czujnika.

Zasada działania programu

#include <OneWire.h>
#include <DS18B20.h>

Dyrektywy include informują Arduino IDE, jakich bibliotek będziesz używał w programie.

#define ONEWIRE_PIN 2

W definicji o nazwie ONEWIRE_PIN przechowywany jest numer pinu do którego podłączasz wyjście danych DQ z czujników.

byte address[8] = {0x28, 0xB1, 0x6D, 0xA1, 0x3, 0x0, 0x0, 0x11};

W tablicy address przechowywany jest adres czujnika z którego chcesz odczytywać temperaturę. Tu musisz wpisać adres twojego czujnika.

OneWire onewire(ONEWIRE_PIN);

Deklaruje obiekt onewire odpowiedzialny za komunikację za pomocą protokołu 1-Wire. W argumencie konstruktora podajesz numer pinu do którego podłaczone są urządzenia magistrali 1-Wire.

DS18B20 sensors(&onewire);

Deklaruje obiekt sensors odpowiedzialny za obsługę czujników DS18B20. W argumecie konstruktora przekazywany jest wskaźnik do obiektu magistrali 1-Wire do której podłączony jest termometr.

sensors.begin();

Metoda begin wyszukuje czujniki i ustawia we wszystkich rozdzielczość. Domyślnie jest to 12 bitów.

sensors.begin(9);

Możesz ustawić swoją rozdzielczość podając ją w argumencie metody begin. W tym przypadku jest to 9 bitów.

sensors.request(address);

Metoda request wysyła rozkaz do czujnika o adresie podanym w argumencie, by zaczął obliczać temperaturę.

if (sensors.available())

Metoda available sprawdza czy czujnik już obiczył temperaturę. Jeśli tak to zwraca wartość true, jeśli nie to false. Metoda ta pozwala nie czekać na obliczenia czujnika, tylko wykonywać program dalej, a gdy wynik obliczeń się pojawi, to go odczytać.

float temperature = sensors.readTemperature(address);

Metoda readTeperature odczytuje temperaturę z czujnika o adresie podanym w argumencie. Metoda zwraca temperaturę jako wartośc typu float w stopniach Celsjusza.

Tą metodę należy wywoływać dopiero po tym jak metoda available zwróci wartość true.

Odczyt temperatury z kilku czujników DS18B20

// Program odczytuje temperaturę kilku czujników

#include <OneWire.h>
#include <DS18B20.h>

// Numer pinu do którego podłaczasz czujnik
#define ONEWIRE_PIN 2

// Ilość czujników
#define SENSORS_NUM 2

// Adresy czujników
const byte address[SENSORS_NUM][8] PROGMEM = {
  0x28, 0xB1, 0x6D, 0xA1, 0x3, 0x0, 0x0, 0x11,
  0x28, 0x87, 0x6A, 0xA1, 0x3, 0x0, 0x0, 0x1F
};

OneWire onewire(ONEWIRE_PIN);
DS18B20 sensors(&onewire);

void setup() {
  while(!Serial);
  Serial.begin(9600);

  sensors.begin();
  sensors.request();
}

void loop() {
  if (sensors.available())
  {
    for (byte i=0; i<SENSORS_NUM; i++)
    {
      float temperature = sensors.readTemperature(FA(address[i]));

      Serial.print(F("#"));
      Serial.print(i);
      Serial.print(F(": "));
      Serial.print(temperature);
      Serial.println(F(" 'C"));
    }

    sensors.request();
  }

  // tu umieść resztę twojego programu
  // Będzie działał bez blokowania
}

Program odczytuje temperaturę z 2 czujników i wyświetla ją w Monitorze portu szeregowego. Mój wynik:

#0: 22.37 'C
#1: 22.19 'C
#0: 22.37 'C
#1: 22.19 'C
#0: 22.37 'C
#1: 22.19 'C
#0: 22.37 'C

W przykładzie czujniki są podłączone do pinu 2 w Arduino. Adres pierwszego czujnika to:

0x28, 0xB1, 0x6D, 0xA1, 0x3, 0x0, 0x0, 0x11

a drugiego to:

0x28, 0x87, 0x6A, 0xA1, 0x3, 0x0, 0x0, 0x1F

Jeśli chcesz by program czytał dane z twoich czujników musisz zmienić adresy na adresy twoich czujników.

Zasada działania programu

#define SENSORS_NUM 2

W definicji SENSORS_NUM przechowywana jest liczba sensorów jaką chcesz obsługiwać.

const byte address[SENSORS_NUM][8] PROGMEM = {
  0x28, 0xB1, 0x6D, 0xA1, 0x3, 0x0, 0x0, 0x11,
  0x28, 0x87, 0x6A, 0xA1, 0x3, 0x0, 0x0, 0x1F
};

Do przechowywania adresów użyłem 2-wymiarowej tablicy typu byte. Dyrektywa PROGMEM powoduje, że tablica jest przechowywana w pamięci Flash. Dzięki temu przy większej ilości czujników oszczędzisz pamięć RAM (której jest mało) na inne zmienne.

// Ilość czujników
#define SENSORS_NUM 5

// Adresy czujników
const byte address[SENSORS_NUM][8] PROGMEM = {
  0x28, 0xB1, 0x6D, 0xA1, 0x3, 0x0, 0x0, 0x11,
  0x28, 0x87, 0x6A, 0xA1, 0x3, 0x0, 0x0, 0x1F,
  0x28, 0x45, 0xAB, 0x94, 0x4, 0x0, 0x0, 0xB2,
  0x28, 0x5D, 0x15, 0xD8, 0x2, 0x0, 0x0, 0x86,
  0x28, 0x33, 0x8d, 0x45, 0x04, 0x0, 0x0, 0x72
};

To jest przykład tablicy dla 5 czujników.

sensors.request();

Metoda request bez argumentów wysyła rozkaz obliczania temperatury do wszystkich podłączoych do magistrali czujników naraz. Dzięki czemu wszystkie obliczą temperaturę w tym samym czasie.

Funkcja nie działa, kiedy czujniki w jednej magistrali są zasilane w różny sposób (wymieszane zasilanie pasożytnicze z normalnym). Wtedy trzeba wywoływać metodę request z adresem indywidualnie dla każdego czujnika.

float temperature = sensors.readTemperature(FA(address[i]));

Metoda readTemperature odczytuje temperaturę z wybranego czujnika. Dyrektywa FA() w argumencie, określa, że adres czujnika pochodzi z pamięci Flash.

Czujnik wybiera się za pomocą indesku tablicy address.

Co zrobić gdy coś nie działa?

// Program pokazuje błędy działania 1-Wire

#include <OneWire.h>
#include <DS18B20.h>

// Numer pinu do którego podłaczasz czujnik
#define ONEWIRE_PIN 2

// Adres czujnika
byte address[8] = {0x28, 0xB1, 0x6D, 0xA1, 0x3, 0x0, 0x0, 0x11};

OneWire onewire(ONEWIRE_PIN);
DS18B20 sensors(&onewire);

void setup() {
  while(!Serial);
  Serial.begin(9600);

  E(sensors.begin());
  E(sensors.request(address));
}

void loop() {
  if (sensors.available())
  {
    float temperature = sensors.readTemperature(address);
    TE(temperature);

    Serial.print(temperature);
    Serial.println(F(" 'C"));

    E(sensors.request(address));
  }

  // tu umieść resztę twojego programu
  // Będzie działał bez blokowania
}

Metody begin oraz request mają możliwość zwracania wartości typu bool. Jeśli zwracają wartość true, to znaczy, że komunikacja przebiega prawidłowo . Jeśli zwracają wartość false, to znaczy, że coś poszło nie tak.

E(sensors.begin());

Stworzyłem dyrektywę E(), która przechwytuje błędy zwracane przez funkcje, zatrzymuje program i zwraca do Monitora portu szeregowego numer linii kodu programu w której wystąpił błąd.

TE(temperature);

Dyrektywa TE() sprawdza czy funkcja tempertury zwraca prawidłową wartość.

23.06 'C
23.06 'C
23.06 'C
23.06 'C
23.06 'C
EXCEPTION at line: 27

Znaczenie błędów w funkcjach

E(sensors.begin());

Błędy występują kiedy:

E(sensors.request(address));

Błędy występują kiedy:

E(sensors.request());

Błędy występują kiedy:

float temperature = sensors.readTemperature(address);
TE(temperature);

Błędy występują kiedy:

Odnośniki