Arduino - Temperatuur meten met een DS18B20 sensor

From SPAD-it Wiki
Jump to: navigation, search

Temperatuur kan op vele manieren worden gemeten, vaak met erg goedkope sensoren. In Allerlei sensoren hebben we gezien hoe je een NTC kunt gebruiken, maar dat het lastig kan zijn om daarmee nauwkeurige metingen te doen. Met een LM35 gaat het al een stuk gemakkelijker maar wordt lang niet het hele volt-bereik gebruikt waardoor de meting minder precies zal zijn. Ook moet je speciale maatregelen nemen om te meten bij vorst. De Pt100 is een uitstekende sensor die ook industrieel vaak wordt toegepast, maar die voor een goede meting wel extra componenten nodig heeft om een signaal te krijgen dat voor een Arduino goed meetbaar is. In dit project zullen we een digitale sensor gebruiken die heel goed samenwerkt met het Arduino platform.

De DS18B20

De DS18B20 sensor is, zoals de titel al aangeeft, een digitale sensor: je hoeft geen spanning te meten die je moet omrekenen naar een temperatuur, maar je ontvangt de meetwaarde direct in digitale vorm. De DS18B20 heeft daarbij een nauwkeurigheid van 0,5°C en is, als het goed is, in de fabriek al gecalibreerd. Weliswaar is een DS18B20 iets duurder dan een LM35 of een elementaire NTC, maar de prijs blijft toch meestal onder de €3,00. De grootste voordelen zijn dat de sensor niet gecalibreerd hoeft te worden en dat de meetwaarde onafhankelijk is van de exacte voedingsspanning, die mag varieren tussen de 3,0V en 5,5V. Daarbij kan een Arduino uitstekend communiceren met de sensor via een seriele lijn. Een extra pluspunt is dat je meerdere sensoren kunt uitlezen via dezelfde seriele verbinding en je dus meer pins over houdt voor andere dingen. Het meetbereik van de sensor is van -55°C tot 125°C.

De DS18B20 heeft drie aansluitingen: een voor de plus, een voor aarde (de nul), en een derde voor het seriele signaal. De sensor is er in meerdere uitvoeringsvormen. De meest elementaire vorm lijkt erg op een transistor (net als de LM35). Er is ook een DIL-chip en hij wordt veel verkocht in een vorm waarbij de sensor is ondergebracht in een waterdichte behuizing (metalen kokertje) en een kabel met drie aansluitdraden. In die laatste vorm is er meestal een rode draad voor de plus, een zwarte voor de nul, terwijl de signaaldraad meestal geel is. In dit project zullen we de sensor op de normale manier aansluiten waarbij alle drie de aansluitingen worden gebruikt. Er is ook een "parasite mode" waarbij de sensor functioneert met slechts twee aansluitdraden. In dat geval wordt de benodigde voeding afgesnoept van het seriele signaal.

DS18B20 uitvoeringsvormen.png
Diverse uitvoeringsvormen van de DS18B20

De schakeling

Extra benodigdheden:

  • 1 DS18B20 sensor
  • 1 weerstand van 4k7Ω
DS18B20 schakeling.png
Een DS18B20 aansluiten op digitale pin 2

Het programma

#include <OneWire.h> 
#include <DallasTemperature.h>
byte Resolution = 10;  // 9, 10, 11, 12
//  9 bit: max  94 ms - hele graden
// 10 bit: max 188 ms - halve graden
// 11 bit: max 375 ms - kwart graden
// 12 bit: max 750 ms - 1/8ste graden - default

// Data wire is plugged into pin 2 on the Arduino 
#define ONE_WIRE_BUS 2 

// Setup a oneWire instance to communicate with any OneWire devices  
// (not just Maxim/Dallas temperature ICs) 
OneWire oneWire(ONE_WIRE_BUS); 
// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature TempSensor(&oneWire);

void setup(void) 
{ 
  Serial.begin(9600); 
  Serial.println("Dallas Temperature IC Control Library Demo"); 
  byte addr[8];
  TempSensor.getAddress(addr,0);
  TempSensor.setResolution(addr,Resolution);  // 9, 10, 11, or 12
  Serial.print("Actual resolution = "); 
  Serial.println(TempSensor.getResolution(addr));
  TempSensor.begin(); 
}

void loop(void) 
{ 
  Serial.print(" Requesting temperatures...");
  unsigned long start = micros(); 
  TempSensor.requestTemperatures(); // Send the command to get temperature readings 
  float duration = (micros() - start)/1000000.0;
  Serial.print("Temperature is: "); 
  Serial.print(TempSensor.getTempCByIndex(0)); // Why "byIndex"?  
  Serial.print(" (took "); 
  Serial.print(duration,3);
  Serial.println(" seconds)"); 
  // You can have more than one DS18B20 on the same bus.  
  // 0 refers to the first IC on the wire 
  delay(1000-TempSensor.millisToWaitForConversion(Resolution)); 
} 

LET OP

Bovenstaand programma gebruikt twee libraries die met de #include regels worden opgenomen. Dit hebben we eerder gezien bij bijvoorbeeld Het 1602 LCD project waar de LiquidCrystal library werd gebruikt. Het is me gebleken dat de libraries die we hier nodig hebben, OneWire en DallasTemperature, niet altijd beschikbaar zijn. Als die libraries er niet zijn krijg je een foutmelding. In dat geval moeten ze eerst worden geinstalleerd. Dat kan gelukkig toch wel vrij gemakkelijk. Ga daarvoor in de Arduino app naar het Tools menu en kies dan voor Manage libraries.... Als je dan zoekt op DallasTemperature of op DS18B20, dan vind je de juiste library (van Miles Burton en anderen). Klik op de library en klik dan op de Install knop. Hetzelfde doe je vervolgens voor de OneWire library (van Jim Studt en anderen). Ook selecteren en installeren. Daarna moet bovenstaand programma werken. Je kunt ook op andere manieren libraries installeren en op die manier libraries gebruiken die niet via het menu zijn te vinden. Als je daar meer over wilt weten kijk dan eens [hier] (in het Engels).

Uitleg

Het programma communiceert via een seriele verbinding digitaal met de sensor. We kunnen alle details van die communicatie in onze code programmeren, maar in dit soort gevallen is het veel aantrekkelijker om daaroor een library te gebruiken. Hier gebruiken we twee libraries:

#include <OneWire.h> 
#include <DallasTemperature.h>

Let op dat deze statements niet worden afgesloten met een ;. De OneWire library bevat de benodigde code van het OneWire communicatie protocol dat de DS18B20 sensor gebruikt. De tweede library maakt het mogelijk om via het OneWire protocol commando's naar de sensor te sturen en informatie uit te lezen. Met het statement:

#define ONE_WIRE_BUS 2

wordt de pin vastgelegd die de Arduino gebruikt om via het OneWire protocol met de sensor te praten. De signaaldraad van de sensor moet dus verbonden zijn met pin 2. Overigens kan de Arduino via dezelfde verbinding met meerdere sensoren praten zolang die maar allemaal het OneWire protocol gebruiken. Merk op dat dit een gewone digitale pin is en niet een van de twee pins die de normale seriele communicatie gebruikt (dat zijn pins 0 en 1). Daarna worden er twee objecten gemaakt. Het eerste is het OneWire object. Een object is een software structuur die zich laat aanspreken als ware het de hardware zelf. Objecten hebben allerlei handige functies die horen bij het type object waar het over gaat. Het oneWire object is van het type OneWire (let op de eerste hoofdletter) en heeft functies aan boord die het communiceren gemakkelijker maken. Het TempSensor object is van het type DallasTemperature en heeft functies aan boord om die sensor aan te sturen en uit te lezen. Het is belangrijk om te zien dat dit object een OneWire object nodig heeft. Dit object wordt als parameter doorgegeven aan het TempSensor object via &oneWire. Dat & teken geeft aan op welke wijze het wordt doorgegeven - het is nu nog te vroeg om daar dieper op in te gaan.

OneWire oneWire(ONE_WIRE_BUS); 
DallasTemperature TempSensor(&oneWire);

De code om deze objecten te maken staat allemaal in de libraries. Daar hebben we geen omkijken naar, al moeten we wel weten welke functies er zijn en hoe die aangeroepen moeten worden. Daarvoor moet je in de documentatie van de libraries zoeken en vaak moet je het een en ander proberen. Je kunt vaak ook voorbeelden vinden die heel illustratief zijn. De setup() functie start een seriele communicatie zodat we de temperatuur kunnen aflezen op de Serial Monitor. De setup() stelt ook de resolutie in van de sensor. De DS18B20 kan een snelle maar onnauwkeurige meting doen in 9 bits (alleen hele graden), of een nauwkeurigere maar veel langzamere meting in 12 bits (in achsten van een graad). De variabele Resolution bepaald dit en wij hebben die ingesteld op 10 bits (dit geeft een resolutie van 0,5 graden). Om die resolutie in te stellen hebben we het adres van de sensor nodig. Dat wordt eerst uitgelezen door de functie TempSensor.getAddress() aan te roepen. Hier wordt het volgnummer van de sensor als parameter opgegeven omdat er meerdere sensoren op de OneWire bus kunnen zitten. Nu hebben we maar een sensor en dus is dat volgnummer 0. De adres variabele moet overigens een lijst met 8 bytes zijn. Vervolgens wordt de resolutie van de sensor op dit adres ingesteld op de gewenste waarde met TempSensor.setResolution(). Voor de zekerheid lezen we de ingestelde resolutie nog een keer uit met TempSensor.getResolution(addr) en geven die resolutie weer op de Serial Monitor. De setup() functie doet dus veel meer dan nodig, maar voor hier is dat leerzamer. In de loop() functie is

  TempSensor.requestTemperatures(); // Send the command to get temperature readings 
  Serial.print(TempSensor.getTempCByIndex(0)); // Why "byIndex"?

het belangrijkste. De aanroep TempSensor.requestTemperatures() vraagt om de meting te starten. Die meting kost tijd en het programma wacht tot de sensor klaar is. Intussen kan er dus niets anders worden gedaan. Vervolgens kan de temperatuur worden uitgelezen via TempSensor.getTempCByIndex(0). De uitgelezen waarde wordt meteen ook weergegeven op de Serial Monitor. De index 0 is nodig omdat het TempSensor object meerdere sensoren kan bedienen. In ons geval is dat er maar een, maar je kunt prima 5 temperatuur sensoren aan een OneWire bus hangen. Rond deze kern wordt een tijdmeting gedaan om te zien hoeveel tijd de temperatuurmeting kostte. Als je de resolutie verandert zul je zien dat de benodigde tijd afhangt van de ingestelde resolutie. Tenslotte wordt even gewacht zodat er ongeveer 1 meting per 5 seconden wordt gedaan. De wachttijd is afhankelijk van de vereiste resolutie en wordt gecorrigeerd voor de meettijd via TempSensor.millisToWaitForConversion(Resolution).

Zoals je kunt zien krijg je de temperatuur in graden Celsius. Dat is voor ons prettig, maar in Dallas zien ze het natuurlijk liever in Fahrenheit (belachelijk, maar daar schijnen ze erg gehecht te zijn aan hun onhandige eenheden). Maar niet getreurd: met deze library kan dat ook. In plaats van getTempCByIndex gebruik je dan getTempFByIndex.

Beetje spelen

We hebben al een paar keer gemeld dat het OneWire protocol toelaat om de Arduino via een en dezelfde signaal pin met meerdere sensoren te laten praten. Je kunt dus meerdere temperaturen uitlezen via een pin! Als je beschikt over een extra DS18B20 is het de moeite om dat eens te proberen. Onderstaande schakeling geeft aan hoe de sensoren aangesloten moeten worden op de plus, min en signaal pin. Let op dat er maar een weerstand nodig is van 4k7Ω. Dit is dan ook de reden dat de weerstand niet al zit ingebouwd in de sensor.

DS18B20 multi-schakeling.png
Het aansluiten van meerdere DS18B20 sensoren
  • Kun jij het programma zo aanpassen dat je alle sensoren kunt uitlezen?

Navigatie