DS1820, digitale hoge precisie thermometer

Met de DS1820 en PIC Basic is het eenvoudig om de temperatuur te meten in het bereik -55°C ... +125°C.
De precisie is 0,5°C maar met een trucje is dit te verhogen naar 0,1°C en zelfs nog iets hoger.
Doordat de uitgelezen temperatuurwaarde wordt opgeslagen in een variabele, is er ook simpel een thermostaat van te maken.
De DS1820 communiceert volgens het 1-wire (one wire = 1 draads) protocol van Dallas.
PIC Basic heeft hiervoor de instructies OREAD en OWRITE (de O komt van OneWire).

Sluit een DS1820 of DS18S20 (in TO92 behuizing) aan op een 16F628A.
Een DS18B20 vraagt een andere aansturing en wordt in dit artikel (nog) niet behandeld.
Zie onderstaand schema:


Vergeet de 4k7 pull-up weerstand niet!
 


Voorbeelden voor DS1820 of DS18S20
Het eerste voorbeeld kan alleen gebruikt worden als de temperatuur niet onder 0°C komt.
De resolutie is 0,5°C.

;Voorbeeld 1
DEVICE 16F628A                ;We gebruiken een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Variabele declareren
DIM Temperatuur     AS BYTE   ;Bevat de factor 2 van de temperatuur Celsius

CLEAR                         ;Wis RAM geheugen

DELAYMS 500                   ;LCD stabilisatie


;Hoofdprogramma
CLS                           ;Wis LCD scherm
WHILE 1 = 1
  OWRITE PORTA.0, 1, [$CC, $44]    ;Zend 'Convert' opdracht (temperatuur meten)
  OWRITE PORTA.0, 1, [$CC, $BE]    ;Zend 'Read ScratchPad' opdracht
  OREAD  PORTA.0, 2, [Temperatuur] ;Lees temperatuur en plaats dit in de variabele 

  PRINT AT 1, 1, DEC Temperatuur / 2, ".", DEC1 (Temperatuur // 2) * 5, 223, "C  "
WEND

Als de DS1820 een temperatuur van bijvoorbeeld 20,5°C meet, dan geeft deze de (decimale) waarde 41 aan 'Temperatuur'.
De waarde die in variabele 'Temperatuur' komt te staan moet dus nog door twee worden gedeeld.
En 41 / 2 = 20,5, maar PIC Basic laat de getallen na de komma weg dus houden we 20 over.
Met de modulus berekening / / ) kunnen we de restwaarde terughalen (meer info zie Modulus berekenen).
De uitkomst van modulus zal in dit geval altijd een 0 of een 1 zijn.
Door dit te vermenigvuldigen met 5 is de uitkomst een 0 of een 5, die we achter de decimale punt plaatsen.

Op het forum wordt weleens vermeldt dat de DS1820 niet op PORTA werkt, maar wel op PORTB.
Achteraf blijkt de oorzaak dat ALL_DIGITAL = TRUE niet bovenaan het programma is opgegeven.
Sommige PORTA poorten van de 16F628(A) hebben analoge functies (comparator), die je uitschakelt met ALL_DIGITAL = TRUE.
Een andere oorzaak is soms dat de 4k7 pull-up weerstand is vergeten.

Met een föhn of warme adem en kälte spray (zoals spuitbus freeze 75 van Kontakt Chemie) of de diepvrieskist is de DS1820 te testen.
Pas op dat je breadboard niet smelt als je de föhn gebruikt.
Bovenstaand voorbeeld is niet geschikt voor temperaturen onder 0°C, voorbeelden daarvan worden verderop behandeld.


Wanneer de spanning op de PIC en DS1820 wordt gezet is de allereerste meting fout.
Als dit een probleem is in jouw toepassing, dan moet er vóór de oneindige WHILE ... WEND lus een meting worden gedaan en worden gewacht totdat de DS1820 klaar is met meten:

;Voorbeeld 2
DEVICE 16F628A                ;We gebruiken een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Normale constanten
SYMBOL Convert      = $44     ;DS1820 commando, de DS1820 moet de temperatuur gaan meten
SYMBOL Graad        = 223     ;223 is de ASCII code voor het 'graad' karakter
SYMBOL RdScratchPad = $BE     ;DS1820 commando, temperatuur van de DS1820 uitlezen
SYMBOL SkipROM      = $CC     ;DS1820 commando, geen gebruik maken van het unieke adres

;Poortnamen
SYMBOL DS1820       = PORTA.0 ;Sluit de DS1820 temperatuur sensor aan op deze poort

;Variabelen declareren
;BYTE
DIM Remain          AS BYTE   ;Zie datasheet DS1820
DIM Temperatuur     AS BYTE   ;Bevat de factor 2 van de temperatuur Celsius

CLEAR                         ;Wis RAM geheugen

DELAYMS 500                   ;LCD stabilisatie


;Hoofdprogramma
;============================ Extra code voor direct juiste temperatuurweergave bij opstarten
CLS                           ;Wis LCD scherm
PRINT "Moment a.u.b."         ;Even wachten, DS1820 moet eerst even de temperatuur meten
OWRITE DS1820, 1, [SkipROM, Convert] ;Zend 'Convert' opdracht (meet temperatuur)
REPEAT
  OREAD DS1820, 4, [Remain]   ;Blijf de DS1820 uitlezen...
UNTIL Remain <> 0             ;...totdat de DS1820 klaar is met meten
;============================

CLS                           ;Wis LCD scherm
WHILE 1 = 1
  OWRITE DS1820, 1, [SkipROM, Convert]      ;Zend 'Convert' opdracht (temperatuur meten)
  OWRITE DS1820, 1, [SkipROM, RdScratchPad] ;Zend 'Read ScratchPad' opdracht
  OREAD  DS1820, 2, [Temperatuur]           ;Lees temperatuur en plaats dit in de variabele

  PRINT AT 1, 1, DEC Temperatuur / 2, ".", DEC1 (Temperatuur // 2) * 5, Graad, "C  "
WEND

Er wordt nu heel even Moment a.u.b. op het display gezet als de DS1820 aan het meten is.
Dit duurt minder dan een seconde.

Het gevaar bestaat echter dat als de DS1820 schakeling niet goed werkt, dat de PIC niet verder met zijn programma gaat.
Als je bijvoorbeeld de 4k7 pull-up weerstand weghaalt (probeer dat maar eens), dan zal de PIC nooit met zijn programma verder gaan omdat het maar blijft wachten op een signaal van de DS1820.

De extra instructies die vóór de oneindige WHILE ... WEND lus staan worden in de volgende voorbeelden weer weggelaten, maar als het in jouw toepassing belangrijk is, dat de allereerste meting meteen goed moet zijn dan kan dit eenvoudig in de onderstaande voorbeelden worden toegevoegd.


Bij het volgende voorbeeld is de precisie 0,1°C.
Wederom niet geschikt voor negatieve temperaturen.

;Voorbeeld 3
DEVICE 16F628A                ;We gebruiken een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Normale constanten
SYMBOL Convert      = $44     ;DS1820 commando, de DS1820 moet de temperatuur gaan meten
SYMBOL Graad        = 223     ;223 is de ASCII code voor het 'graad' karakter
SYMBOL RdScratchPad = $BE     ;DS1820 commando, temperatuur van de DS1820 uitlezen
SYMBOL SkipROM      = $CC     ;DS1820 commando, geen gebruik maken van het unieke adres

;Poortnamen
SYMBOL DS1820       = PORTA.0 ;Sluit de DS1820 temperatuur sensor aan op deze poort

;Variabelen declareren
;WORD
DIM Temp            AS WORD   ;Bevat de temperatuur Celsius
;BYTE
DIM Remain          AS BYTE   ;De remain waarde voor berekening temperatuur achter de komma 
DIM Slope           AS BYTE   ;Bevat de 'counts per graad Celsius' waarde
DIM BD1             AS BYTE   ;Byte Dummy 1

CLEAR                         ;Wis RAM geheugen

DELAYMS 500                   ;LCD stabilisatie


;Hoofdprogramma
CLS                           ;Wis LCD scherm
WHILE 1 = 1
  OWRITE DS1820, 1, [SkipROM, Convert]      ;Zend 'Convert' opdracht (temperatuur meten)
  OWRITE DS1820, 1, [SkipROM, RdScratchPad] ;Zend 'Read ScratchPad' opdracht
  OREAD  DS1820, 2, [Temp.LOWBYTE, Temp.HIGHBYTE, BD1, BD1, BD1, BD1, Remain, Slope] ',CRC]

  Temp = (((Temp >> 1) * 100) - 25) + (((Slope - Remain) * 100) / Slope)
  PRINT AT 1, 1, DEC Temp / 100, ".", DEC1 Temp / 10, Graad, "C  "
WEND

Variabelenaam 'Temperatuur' is vanaf hier gewijzigd in kortweg 'Temp' omdat sommige programmaregels anders erg lang zouden worden.
Denk er aan dat 'Temp' vanaf hier geen BYTE variabele, maar een WORD variabele is.
De namen 'Remain', 'Slope', 'Convert', 'RdScratchpad' en 'SkipROM' zijn in het engels weergegeven omdat deze namen ook in de datasheet van de DS1820 worden gebruikt.
Meer info hierover staat in de datasheet en verderop in dit artikel.
Variabele 'BD1' is een dummy, waarden die hierin staan of worden gezet worden verder niet gebruikt.


Als de temperatuur ook onder 0°C kan komen (vriezen), dan moet het PIC Basic programma wat worden uitgebreid.
Het volgende PIC Basic programma geeft de temperatuur weer met een precisie van 0,1°C en geeft de temperatuur ook juist weer als de temperatuur lager dan 0°C is.

;Voorbeeld 4
DEVICE 16F628A                ;We gebruiken een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Normale constanten
SYMBOL Convert      = $44     ;DS1820 commando, de DS1820 moet de temperatuur gaan meten
SYMBOL Graad        = 223     ;223 is de ASCII code voor het 'graad' karakter
SYMBOL RdScratchPad = $BE     ;DS1820 commando, temperatuur van de DS1820 uitlezen
SYMBOL SkipROM      = $CC     ;DS1820 commando, geen gebruik maken van het unieke adres

;Logische constanten
SYMBOL FALSE        = 0
SYMBOL TRUE         = 1

;Poortnamen
SYMBOL DS1820       = PORTA.0 ;Sluit de DS1820 temperatuur sensor aan op deze poort

;Variabelen declareren
;WORD
DIM Temp            AS WORD   ;Bevat de temperatuur Celsius
;BYTE
DIM Remain          AS BYTE   ;De remain waarde voor berekening temperatuur achter de komma 
DIM Slope           AS BYTE   ;Bevat de 'counts per graad Celsius' waarde
DIM TempDeci        AS BYTE   ;Bevat de temperatuur waarde "achter de komma"
DIM BD1             AS BYTE   ;Byte Dummy 1
;BIT
DIM NegTemp         AS BIT    ;TRUE als temperatuur Celsius onder 0 oC komt

CLEAR                         ;Wis RAM geheugen

DELAYMS 500                   ;LCD stabilisatie


;Hoofdprogramma
CLS                           ;Wis LCD scherm
WHILE 1 = 1
  OWRITE DS1820, 1, [SkipROM, Convert]      ;Zend 'Calculate Temperature' opdracht
  OWRITE DS1820, 1, [SkipROM, RdScratchPad] ;Zend 'Read ScratchPad' opdracht
  OREAD  DS1820, 2, [Temp.LOWBYTE, Temp.HIGHBYTE, BD1, BD1, BD1, BD1, Remain, Slope] ',CRC]

  NegTemp  = Temp.8           ;Als bit 8 (het 9e bit) geset is, dan is temperatuur negatief
  TempDeci = ((Slope - Remain) * 100) / Slope
  Temp     = Temp * 5
  
  IF NegTemp = TRUE THEN      ;Als de temperatuur negatief is, dan...
    Temp  =  65530 - Temp     ;De gemeten waarde Inverteren
    TempDeci = 100 - TempDeci ;Ook de waarde achter de komma inverteren
    IF TempDeci < 51 THEN TempDeci = TempDeci + 100
  ENDIF

  Temp = (((Temp + 550) / 10) * 100) + TempDeci - 5500 ;
  PRINT AT 1, 1, REP "-"\NegTemp, DEC Temp / 100, ".", DEC1 Temp / 10, Graad, "C "
WEND

Als de temperatuur onder 0°C komt, moet de waarde geïnverteerd worden, immers, hoe lager de temperatuur onder 0°C, des te groter de waarde achter het minus streepje "" moet zijn (−10°C is kouder dan −5°C).
Met behulp van de REP optie van de PRINT instructie wordt er een voor de waarde geplaatst als de temperatuur onder 0°C komt.


Het volgende voorbeeld is nog wat nauwkeuriger.
De temperatuur wordt weergegeven met maarliefst twee cijfers na de komma.
Ook geschikt voor temperaturen onder het vriespunt.

;Voorbeeld 5
DEVICE 16F628A                ;We gebruiken een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Normale constanten
SYMBOL Convert      = $44     ;DS1820 commando, de DS1820 moet de temperatuur gaan meten
SYMBOL Graad        = 223     ;223 is de ASCII code voor het 'graad' karakter
SYMBOL RdScratchPad = $BE     ;DS1820 commando, temperatuur van de DS1820 uitlezen
SYMBOL SkipROM      = $CC     ;DS1820 commando, geen gebruik maken van het unieke adres

;Logische constanten
SYMBOL FALSE        = 0
SYMBOL TRUE         = 1

;Poortnamen
SYMBOL DS1820       = PORTA.0 ;Sluit de DS1820 temperatuur sensor aan op deze poort

;Variabelen declareren
;WORD
DIM Temp            AS WORD   ;Bevat de temperatuur Celsius
;BYTE
DIM Remain          AS BYTE   ;De remain waarde voor berekening temperatuur achter de komma 
DIM Slope           AS BYTE   ;Bevat de 'counts per graad Celsius' waarde
DIM TempDeci        AS BYTE   ;Bevat de temperatuur waarde "achter de komma"
DIM BD1             AS BYTE   ;Byte Dummy 1
;BIT
DIM NegTemp         AS BIT    ;TRUE als temperatuur Celsius onder 0 oC komt

CLEAR                         ;Wis RAM geheugen

DELAYMS 500                   ;LCD stabilisatie


;Hoofdprogramma
CLS                           ;Wis LCD scherm
PRINT "Temp:"                 ;Plaats eerst deze tekst op het display
WHILE 1 = 1
  OWRITE DS1820, 1, [SkipROM, Convert]      ;Zend 'Calculate Temperature' opdracht
  OWRITE DS1820, 1, [SkipROM, RdScratchPad] ;Zend 'Read ScratchPad' opdracht
  OREAD  DS1820, 2, [Temp.LOWBYTE, Temp.HIGHBYTE, BD1, BD1, BD1, BD1, Remain, Slope] ',CRC]

  NegTemp  = Temp.8           ;Als bit 8 (het 9e bit) geset is, dan is temperatuur negatief
  TempDeci = ((Slope - Remain) * 100) / Slope
  Temp     = Temp * 5
  
  IF NegTemp = TRUE THEN      ;Als de temperatuur negatief is, dan...
    Temp  =  65530 - Temp     ;De gemeten waarde Inverteren
    TempDeci = 100 - TempDeci ;Ook de waarde achter de komma inverteren
    IF TempDeci < 51 THEN TempDeci = TempDeci + 100
  ENDIF

  Temp = (((Temp + 550) / 10) * 100) + TempDeci - 5500 ;
  PRINT AT 1, 7, REP "-"\NegTemp, DEC Temp / 100, ".", DEC2 Temp, Graad, "C "
WEND

De resolutie is hier 0,0625°C, weergegeven in de volgende stappen:
0.00 / 0.06 / 0.12 / 0.18 / 0.25 / 0.31 / 0.37 / 0.43 / 0.50 / 0.56 / 0.62 / 0.68 / 0.75 / 0.81 / 0.87 en 0.93.
Een kleine temperatuurstijging van bijvoorbeeld 20,00°C verspringt dus niet naar 20,01°C, maar naar 20,06°C.


Hoewel het in Nederland praktisch niet wordt gebruikt, hier nog een voorbeeld in Fahrenheit in plaats van Celsius:

;Voorbeeld 6
DEVICE 16F628A                ;We gebruiken een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Normale constanten
SYMBOL Convert      = $44     ;DS1820 commando, de DS1820 moet de temperatuur gaan meten
SYMBOL Graad        = 223     ;223 is de ASCII code voor het 'graad' karakter
SYMBOL RdScratchPad = $BE     ;DS1820 commando, temperatuur van de DS1820 uitlezen
SYMBOL SkipROM      = $CC     ;DS1820 commando, geen gebruik maken van het unieke adres

;Poortnamen
SYMBOL DS1820       = PORTA.0 ;Sluit de DS1820 temperatuur sensor aan op deze poort

;Variabelen declareren
;WORD
DIM Temp            AS WORD   ;Bevat de temperatuur Celsius
DIM TempF           AS WORD   ;Bevat de temperatuur Fahrenheit
;BYTE
DIM Remain          AS BYTE   ;De remain waarde voor berekening temperatuur achter de komma 
DIM Slope           AS BYTE   ;Bevat de 'counts per graad Celsius' waarde
DIM BD1             AS BYTE   ;Byte Dummy 1

CLEAR                         ;Wis RAM geheugen

DELAYMS 500                   ;LCD stabilisatie


;Hoofdprogramma
CLS                           ;Wis LCD scherm
WHILE 1 = 1
  OWRITE DS1820, 1, [SkipROM, Convert]      ;Zend 'Convert' opdracht (temperatuur meten)
  OWRITE DS1820, 1, [SkipROM, RdScratchPad] ;Zend 'Read ScratchPad' opdracht
  OREAD  DS1820, 2, [Temp.LOWBYTE, Temp.HIGHBYTE, BD1, BD1, BD1, BD1, Remain, Slope] ',CRC]

  Temp = (((Temp >> 1) * 100) - 25) + (((Slope - Remain) * 100) / Slope)
  PRINT AT 1, 1, DEC Temp / 100, ".", DEC2 Temp, Graad, "C  "   ;Celsius

  TempF = 18 * (Temp / 10) + 3200 ;Bereken Celsius naar Fahrenheit
  PRINT AT 2, 1, DEC TempF / 100, ".", DEC2 TempF, Graad, "F  " ;Fahrenheit
WEND

Celsius wordt geplaatst op displayregel 1 en de temperatuur Fahrenheit op displayregel 2.
De hier getoonde Fahrenheit berekening is niet geschikt voor negatieve temperaturen.


En vooruit, ook nog een voorbeeld in de thermodynamische temperatuur kelvin:

;Voorbeeld 7
DEVICE 16F628A                ;We gebruiken een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Normale constanten
SYMBOL Convert      = $44     ;DS1820 commando, de DS1820 moet de temperatuur gaan meten
SYMBOL Graad        = 223     ;223 is de ASCII code voor het 'graad' karakter
SYMBOL RdScratchPad = $BE     ;DS1820 commando, temperatuur van de DS1820 uitlezen
SYMBOL SkipROM      = $CC     ;DS1820 commando, geen gebruik maken van het unieke adres

;Poortnamen
SYMBOL DS1820       = PORTA.0 ;Sluit de DS1820 temperatuur sensor aan op deze poort

;Variabelen declareren
;WORD
DIM Temp            AS WORD   ;Bevat de temperatuur Celsius
DIM TempK           AS WORD   ;Bevat de temperatuur kelvin
;BYTE
DIM Remain          AS BYTE   ;De remain waarde voor berekening temperatuur achter de komma 
DIM Slope           AS BYTE   ;Bevat de 'counts per graad Celsius' waarde
DIM BD1             AS BYTE   ;Byte Dummy 1

CLEAR                         ;Wis RAM geheugen

DELAYMS 500                   ;LCD stabilisatie


;Hoofdprogramma
CLS                           ;Wis LCD scherm
WHILE 1 = 1
  OWRITE DS1820, 1, [SkipROM, Convert]      ;Zend 'Convert' opdracht (temperatuur meten)
  OWRITE DS1820, 1, [SkipROM, RdScratchPad] ;Zend 'Read ScratchPad' opdracht
  OREAD  DS1820, 2, [Temp.LOWBYTE, Temp.HIGHBYTE, BD1, BD1, BD1, BD1, Remain, Slope] ',CRC]

  Temp = (((Temp >> 1) * 100) - 25) + (((Slope - Remain) * 100) / Slope)
  PRINT AT 1, 1, DEC Temp / 100, ".", DEC2 Temp, Graad, "C  " ;Celsius

  TempK = Temp + 27315        ;Bereken Celsius naar kelvin
  PRINT AT 2, 1, DEC TempK / 100, ".", DEC2 TempK, "K"        ;kelvin
WEND

De berekening voor kelvin is Celsius + 273,15.


Thermostaat
Nu we dit kunnen is het ook simpel om een thermostaat te maken die bijvoorbeeld een relais inschakelt bij een bepaalde temperatuur.
Het volgende voorbeeld kan alleen gebruikt worden als de temperatuur niet onder 0°C komt.
De resolutie is 0,5°C.

Sluit een 25k potmeter met in serie een 100n condensator op PORTA.0 (zie schemaatje).
Hiermee kun je straks de thermostaat instellen.
Op PORTA.2 kun je een LED (met 1k serieweerstand) aansluiten, waaraan je kunt zien of de thermostaat in- of uitschakelt.

;Voorbeeld 8
DEVICE 16F628A                ;We gebruiken een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Logische constanten
SYMBOL HOOG         = 1
SYMBOL LAAG         = 0

;Normale constanten
SYMBOL Convert      = $44     ;DS1820 commando, de DS1820 moet de temperatuur gaan meten
SYMBOL Graad        = 223     ;223 is de ASCII code voor het 'graad' karakter
SYMBOL RdScratchPad = $BE     ;DS1820 commando, temperatuur van de DS1820 uitlezen
SYMBOL SkipROM      = $CC     ;DS1820 commando, geen gebruik maken van het unieke adres

;Poortnamen
SYMBOL DS1820       = PORTA.0 ;Sluit de DS1820 temperatuur sensor aan op deze poort
SYMBOL Potmeter     = PORTA.1 ;Sluit een 25k potmeter met in serie een 100n condensator
SYMBOL Uitgang      = PORTA.2 ;Sluit een LED met 1k serie weerstand aan op deze poort

;Variabele declareren
;BYTE
DIM Temperatuur     AS BYTE   ;Bevat de factor 2 van de temperatuur Celsius
DIM Thermostaat     AS BYTE   ;Bevat de ingestelde thermostaat temperatuur (potmeter)

;        76543210
PORTA = %00000000             ;Alle PORTA uitgangen laag bij opstart
TRISA = %11111011             ;Alles ingang, behalve PORTA.2 voor de LED

CLEAR                         ;Wis RAM geheugen

DELAYMS 500                   ;LCD stabilisatie


;Hoofdprogramma
CLS                           ;Wis LCD scherm
PRINT AT 1, 1, "Temp."        ;Plaats tekst op regel 1
PRINT AT 2, 1, "Inst."        ;Plaats tekst op regel 2

WHILE 1 = 1
  Thermostaat = POT Potmeter, 40             ;Lees voor de functie POT cursus deel 5 door
  IF Thermostaat > 60 THEN Thermostaat = 60  ;Maximaal tot 30 graden instelbaar (60 / 2)

  OWRITE DS1820, 1, [SkipROM, Convert]       ;Zend 'Convert' opdracht (temperatuur meten)
  OWRITE DS1820, 1, [SkipROM, RdScratchPad]  ;Zend 'Read ScratchPad' opdracht
  OREAD  DS1820, 2, [Temperatuur]            ;Lees temperatuur en plaats dit in variabele 

  PRINT AT 1, 7, @Temperatuur / 2, ".", DEC1 (Temperatuur // 2) * 5, Graad, "C "
  PRINT AT 2, 7, @Thermostaat / 2, ".", DEC1 (Thermostaat // 2) * 5, Graad, "C "

  IF Temperatuur < Thermostaat THEN Uitgang = HOOG ;Uitgang HOOG als temp te laag is
  IF Temperatuur > Thermostaat THEN Uitgang = LAAG ;Uitgang LAAG als temp te hoog is

  DELAYMS 300                                ;Rustig, anders is het display zo nerveus
WEND

De uitgang wordt HOOG als de temperatuur, gemeten door de DS1820, lager is dan de potmeter instelling.
De hysteresis is hier 1°C, dat betekent dat de thermostaat aan gaat (uitgang PORTA.2 wordt hoog) als de DS1820 temperatuur 0,5°C onder de instelling is en pas uitgaat als de temperatuur 0,5°C boven de instelling is.

Ook de thermostaat is in te stellen met een resolutie van 0,5°C.
De thermostaat is hier tot maximaal 30,0°C instelbaar, dit wordt gedaan door de regel direct na de meting met POT.
Parameter Schaal van de functie POT is hier ingesteld op 40 omdat de potmeter nu niet in moet stellen tussen 0 en 255, maar tussen 0 en 60.
Wellicht moet de waarde voor Schaal nog iets hoger of lager gezet worden om het hele bereik van de 25k potmeter in het gebied van 0°C ... 30°C te verkrijgen.
Belangrijk is dat de +5V voeding goed afgevlakt en gestabiliseerd is, anders kan de thermostaat steeds verspringen.
Dit is overigens maar een simpel voorbeeld, de functie POT is niet echt geschikt voor een professionele thermostaat, daarvoor moet een PIC type met ingebouwde ADC worden genomen.

Voor de instelling en gebruik van PIC Basic instructie POT even cursus deel 5 doornemen.


Diverse OneWire componenten op één PIC poort
Het is mogelijk om meerdere DS1820 sensoren op één PIC poort aan te sluiten.
Hiervoor heeft elke DS1820 een uniek adres vanuit de fabriek meegekregen die door het PIC Basic programma is uit te lezen.
Als er maar één OneWire component op een PIC poort is aangesloten is het gebruik van dit adres niet nodig.
De voorbeelden die tot nu toe zijn getoond maken dan ook geen gebruik van dit adres, ze slaan het over door het ROM gedeelte van de DS1820 over te slaan (door 'SkipROM', (= $CC)).
Wil je nu meerdere DS1820 sensoren op dezelfde draad aansluiten, dan moet eerst bepaald worden wat de adressen zijn van de toekomstig aan te sluiten DS1820 sensoren.
Hiervoor moet eerst elke DS1820 afzonderlijk op de PIC aangesloten worden, waarmee met onderstaand programma het adres van de aangesloten DS1820 is uit te lezen.

;Voorbeeld 9: Uitlezen van het unieke OneWire adres
DEVICE 16F628A                ;We gebruiken een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Normale constanten
SYMBOL ReadROM      = $33     ;Vaste, constante waarde (zie datasheet DS1820)

;Poortnamen
SYMBOL DS1820       = PORTA.0 ;Sluit de DS1820 temperatuur sensor aan op deze poort

;Variabelen declareren
;BYTE
DIM CRC             AS BYTE   ;Bevat de CRC code, deze kan steeds anders zijn (zie tekst)
DIM ID1             AS BYTE   ;Bevat zodadelijk een deel van het unieke IDentificatie adres
DIM ID2             AS BYTE   ;Bevat zodadelijk een deel van het unieke IDentificatie adres
DIM ID3             AS BYTE   ;Bevat zodadelijk een deel van het unieke IDentificatie adres
DIM ID4             AS BYTE   ;Bevat zodadelijk een deel van het unieke IDentificatie adres
DIM ID5             AS BYTE   ;Bevat zodadelijk een deel van het unieke IDentificatie adres
DIM ID6             AS BYTE   ;Bevat zodadelijk een deel van het unieke IDentificatie adres
DIM Familie         AS BYTE   ;Bevat de OneWire familiecode (dit zal 10 (hexadecimaal) zijn)

CLEAR                         ;Wis RAM geheugen

DELAYMS 500                   ;LCD stabilisatie


;Hoofdprogramma
CLS                           ;Wis display
OWRITE DS1820, 1, [ReadROM]   ;Geef aan de DS1820 door dat we het adres vanuit ROM willen lezen
OREAD  DS1820, 0, [Familie, ID1, ID2, ID3, ID4, ID5, ID6, CRC] ;Lees het unieke adres
PRINT AT 1, 1, HEX2 ID1, " ", HEX2 ID2, " ", HEX2 ID3, " ", HEX2 ID4, " ", HEX2 ID5, " ", HEX2 ID6
PRINT AT 2, 1, "Fam: ", HEX2 Familie, "  CRC: ", HEX2 CRC

END                           ;Einde programma

Schrijf de familiecode, adres en CRC waarde dat op het display verschijnt op en bewaar deze bij de desbetreffende DS1820.
In je PIC Basic programma moet je dan dit unieke adres opgeven van de DS1820 waarvan je de gemeten temperatuur wilt weten.
Herhaal bovenstaande voor elke DS1820 die je op de OneWire draad (die hier aangesloten is op PORTA.0) wilt aansluiten.
Let op, de waarden worden hexadecimaal weergegeven op het display, bovendien moet het minimaal een 2x20 display zijn (voor een 2x16 moeten de spaties in bovenstaande programma worden verwijderd).

Als het goed is dan moet de familiecode 10 zijn (hexadecimaal, vanaf nu geschreven als 10h).
10h betekent dat het adres afkomstig is van een DS1820 (of DS18S20), er bestaan namelijk ook andere OneWire componenten zoals EEPROM's en klok/kalender IC's, ieder soort heeft zo zijn eigen familiecode.
Geeft het display familiecode 28h aan, dan heb je een DS18B20 aangesloten.
Deze is niet bruikbaar met de voorbeelden hier, omdat de DS18B20 een ander protocol gebruikt.

CRC (= Cyclic Redudancy Check) is een waarde die wordt gebruikt om te kunnen bekijken of de ontvangen data goed is ontvangen.
De DS1820 berekent wat die waarde moet zijn, afhankelijk van de data (waaronder de temperatuur) die verzonden gaat worden en stuurt de uitkomst van die berekening mee.
Ook de PIC kan de ontvangen data berekenen met de CRC methode en zo aan de hand van de uitkomst concluderen of de ontvangen data goed is ontvangen.

Het OneWire protocol heeft een mogelijkheid om alle OneWire componenten die op een draad zijn aangesloten automatisch uit te lezen, wat vooral handig is als er een product wordt gemaakt waarin bijvoorbeeld meerdere DS1820 sensoren zitten.
Om nu voor elk product de adressen van de aangesloten DS1820 sensoren apart in te voeren zou ondoenlijk zijn.
Echter, de manier om de adressen van de aangesloten OneWire componenten automatisch uit te lezen is nogal uitgebreid en vraagt nogal programma geheugen van de PIC, vandaar dat we het hier voorlopig handmatig doen.


Als van alle OneWire componenten de adressen bekend zijn kunnen ze allen parallel op de draad worden aangesloten.
In onderstaande voorbeelden wordt uitgegaan van twee DS1820 temperatuursensoren.


Eén 4k7 pull-up weerstand is voldoende voor meerdere OneWire componenten.
Bij veel meer OneWire componenten kan het nodig zijn de waarde van de weerstand nog wat te verlagen.

 

Onderstaand voorbeeld leest van twee DS1820 sensoren de gemeten temperatuurswaarde.
In dit voorbeeld meet één DS1820 de binnentemperatuur, deze heeft bij mij thuis adres 10 0B 08 7F 00 08 00 79, en een tweede DS1820 meet de buitentemperatuur en heeft bij mij adres 10 1B 62 7F 00 08 00 8E.
Let op, deze adreswaarden moet je wijzigen voor de DS1820 sensoren die jij gebruikt, bekend gemaakt met programmavoorbeeld 9.
Omdat het hier hexadecimale waarden betreft, moet dit in het PIC Basic programma opgegeven worden door er een $ teken voor te zetten (zie het PIC Basic programma hieronder).
Het eerste getal moet ook bij jou altijd $10 zijn, dit is immers de familiecode van de DS1820 en DS18S20, waarvoor de voorbeelden hier zijn gemaakt.

Er wordt door dit PIC Basic programma geen gebruik gemaakt van de CRC code om te checken of de ingelezen waarden goed zijn ontvangen.
De DS1820 zelf verlangt echter wel de CRC code, daarom moet deze er wel naar toe worden gezonden bij instructie OWRITE.
Deze CRC codes zijn bekend gemaakt met behulp van het vorige PIC Basic programma (voorbeeld 9).

;Voorbeeld 10: Twee DS1820 sensoren op een enkele draad
DEVICE 16F628A                ;We gebruiken een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Normale constanten
SYMBOL Convert      = $44     ;Commando die de DS1820 opdracht geeft tot temperatuur lezen
SYMBOL Graad        = 223     ;223 is de ASCII code voor het 'graad' karakter
SYMBOL MatchROM     = $55     ;Na dit commando moet het unieke 64-bit adres opgegeven worden
SYMBOL RdScratchPad = $BE     ;Hierin staat in de DS1820 oa.de laatst gemeten temperatuur

;Poortnamen
SYMBOL DS1820       = PORTA.0 ;Sluit beide DS1820 temperatuur sensoren aan op deze poort

;Variabelen declareren
;BYTE
DIM TempBinnen      AS BYTE   ;Bevat de binnentemperatuur, gemeten door de eerste DS1820
DIM TempBuiten      AS BYTE   ;Bevat de buitentemperatuur, gemeten door de tweede DS1820

CLEAR                         ;Wis RAM geheugen

DELAYMS 500                   ;LCD stabilisatie


;Hoofdprogramma
CLS                           ;Wis display

WHILE 1 = 1
  ;Geef beide DS1820 opdracht tot het meten van de huidige temperatuur
  OWRITE DS1820, 1, [MatchROM, $10, $0B, $08, $7F, $00, $08, $00, $79, Convert]
  OWRITE DS1820, 1, [MatchROM, $10, $1B, $62, $7F, $00, $08, $00, $8E, Convert]

  DELAYMS 25                  ;Geef beide DS1820 de tijd om de temperatuur te meten

  ;Geef de DS1820 die binnen hangt opdracht dat ie de gemeten temperatuur moet terugzenden
  OWRITE DS1820, 1, [MatchROM, $10, $0B, $08, $7F, $00, $08, $00, $79, RdScratchPad]
  OREAD  DS1820, 2, [TempBinnen] ;Plaats de ontvangen data in BYTE variabele 'TempBinnen'

  ;Geef de DS1820 die buiten hangt opdracht dat ie de gemeten temperatuur moet terugzenden
  OWRITE DS1820, 1, [MatchROM, $10, $1B, $62, $7F, $00, $08, $00, $8E, RdScratchPad]
  OREAD  DS1820, 2, [TempBuiten] ;Plaats de ontvangen data in BYTE variabele 'TempBuiten'
  
  ;Plaats de beide temperaturen (in variabelen 'TempBinnen' en 'TempBuiten') op het display
  PRINT AT 1, 1, "Binnen: ", DEC TempBinnen / 2, ".", DEC1 (TempBinnen // 2) * 5, Graad, "C "
  PRINT AT 2, 1, "Buiten: ", DEC TempBuiten / 2, ".", DEC1 (TempBuiten // 2) * 5, Graad, "C " 
  
  DELAYMS 1000                ;Meet elke seconde
WEND

Het bovenstaande (eenvoudige) voorbeeld is niet geschikt voor negatieve temperaturen en heeft een resolutie van (maar) 0,5°C.

Om het eenvoudig te houden wordt hier niet gemeten wanneer de DS1820 klaar is met de meting (met de conversie), maar wordt er gewoon 25mSec gewacht, ruim voldoende voor de DS1820 sensoren om de temperatuur te kunnen meten.
Wil je wél een bevestiging wanneer de conversie voltooid is, dan het programmastukje uit voorbeeld 2 toevoegen op de plek waar nu DELAYMS 25 staat (zie hier).


Het laatste voorbeeld meet met dezelfde twee DS1820 sensoren, alleen is het nu ook geschikt voor negatieve temperaturen en is de resolutie verhoogd naar twee cijfers achter de komma.
Denk eraan dat variabele 'Temp' nu een WORD variabele moet zijn en dat je hier de adressen van beide DS1820 sensoren weer wijzigt in de adressen die jouw DS1820 sensoren hebben.

;Voorbeeld 11: Twee DS1820 sensoren op een enkele draad
DEVICE 16F628A                ;We gebruiken een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Normale constanten
SYMBOL Convert      = $44     ;Commando die de DS1820 opdracht geeft tot temperatuur lezen
SYMBOL Graad        = 223     ;223 is de ASCII code voor het 'graad' karakter
SYMBOL MatchROM     = $55     ;Na dit commando moet het unieke 64-bit adres opgegeven worden
SYMBOL RdScratchPad = $BE     ;Hierin staat in de DS1820 oa.de laatst gemeten temperatuur

;Logische constanten
SYMBOL FALSE        = 0
SYMBOL TRUE         = 1

;Poortnamen
SYMBOL DS1820       = PORTA.0 ;Sluit beide DS1820 temperatuur sensoren aan op deze poort

;Variabelen declareren
;WORD
DIM Temp            AS WORD   ;Bevat de temperatuur Celsius
;BYTE
DIM Remain          AS BYTE   ;De remain waarde voor berekening temperatuur achter de komma 
DIM Slope           AS BYTE   ;Bevat de 'counts per graad Celsius' waarde
DIM TempDeci        AS BYTE   ;Bevat de temperatuur waarde "achter de komma"
DIM BD1             AS BYTE   ;Byte Dummy 1
;BIT
DIM NegTemp         AS BIT    ;TRUE als temperatuur Celsius onder 0 oC komt

CLEAR                         ;Wis RAM geheugen

DELAYMS 500                   ;LCD stabilisatie

GOTO HoofdProgramma           ;Spring over de subroutine


;SUBROUTINE
BerekenTemp:
  ;Lees de zojuist geactiveerde DS1820 en plaats de data in WORD variabele 'Temp' 
  OREAD DS1820, 2, [Temp.LOWBYTE, Temp.HIGHBYTE, BD1, BD1, BD1, BD1, Remain, Slope] ',CRC]

  NegTemp  = Temp.8           ;Als bit 8 (het 9e bit) geset is, dan is temperatuur negatief
  TempDeci = ((Slope - Remain) * 100) / Slope
  Temp     = Temp * 5
  
  IF NegTemp = TRUE THEN      ;Als de temperatuur negatief is, dan...
    Temp  =  65530 - Temp     ;De gemeten waarde inverteren
    TempDeci = 100 - TempDeci ;Ook de waarde achter de komma inverteren
    IF TempDeci < 51 THEN TempDeci = TempDeci + 100
  ENDIF

  Temp = (((Temp + 550) / 10) * 100) + TempDeci - 5500 ;
  PRINT REP "-"\NegTemp, DEC Temp / 100, ".", DEC2 Temp, Graad, "C "
RETURN


HoofdProgramma:
CLS                           ;Wis display

WHILE 1 = 1
  ;Geef beide DS1820 opdracht tot het meten van de huidige temperatuur
  OWRITE DS1820, 1, [MatchROM, $10, $0B, $08, $7F, $00, $08, $00, $79, Convert]
  OWRITE DS1820, 1, [MatchROM, $10, $1B, $62, $7F, $00, $08, $00, $8E, Convert]

  DELAYMS 25                  ;Geef beide DS1820 de tijd om de temperatuur te meten

  ;Geef de DS1820 die binnen hangt opdracht dat ie de gemeten temperatuur moet terugzenden
  OWRITE DS1820, 1, [MatchROM, $10, $0B, $08, $7F, $00, $08, $00, $79, RdScratchPad]
  PRINT AT 1, 1, "Binnen: "   ;Plaats cursor met tekst op regel 1
  GOSUB BerekenTemp           ;Ga de temperatuursberekening doen in de subroutine

  ;Geef de DS1820 die buiten hangt opdracht dat ie de gemeten temperatuur moet terugzenden
  OWRITE DS1820, 1, [MatchROM, $10, $1B, $62, $7F, $00, $08, $00, $8E, RdScratchPad]
  PRINT AT 2, 1, "Buiten: "   ;Plaats cursor met tekst op regel 2
  GOSUB BerekenTemp           ;Ga de temperatuursberekening doen in de subroutine
  
  DELAYMS 1000                ;Meet elke seconde
WEND

Aangezien de berekening relatief groot is, is deze in subroutine 'BerekenTemp' geplaatst zodat beide DS1820 sensoren gebruik kunnen maken van dezelfde berekeningscode.


Met deze voorbeelden moet het nu te doen zijn om nog meer OneWire componenten op de draad aan te sluiten.
Eerst dus telkens maar één OneWire component aansluiten en het adres van dat component uitlezen met programma voorbeeld 9.
Schrijf de weergegeven familiecode, adres en CRC code op en gebruik deze weer in je PIC Basic programma's, zoals gedaan in voorbeelden 10 en 11.

Een programma die het mogelijk maakt om de adressen van de OneWire componenten automatisch op te zoeken verschijnt misschien nog wel eens op deze site.

Bovenstaande beschrijving geldt voor de aloude DS1820.
De voorbeeldprogramma's werken ook op de nieuwe DS18S20, maar niet met de DS18B20.
De DS18S20 heeft dan ook dezelfde familiecode als de DS1820 (10h), de DS18B20 heeft familiecode 28h.

 

Datasheet DS18S20
Datasheet DS18B20, temperatuursensor met programmeerbare resolutie (9 ... 12 bits)
DS18B20 en DS18S20 verkrijgbaar bij Voti (kies de DS18S20 voor bij dit artikel)