DS18B20 – om en temperatursensor, 1-wire og 2’ers komplement binær matematik

image_pdfimage_print

I en del af mine forrige posts harjeg mixet detaljerne ind i de enkelte projekter og der har gjort det lidt svært at referere til dele senere… Så jeg prøver nu at skille de lidt tungere dele ud af projekterne…

DS18B20 er et “Programmable Resolution 1-Wire Digital Thermometer”. I al sin enkelthed er det en temperatursensor med konfigurerbar opløsning og 1-wire interface.

1-wire

1-wire er en standard som Dallas Semiconductors har lavet (de er senere blevet købt af Maxim). Det er en simpel bus der gør det muligt at have mange enheder på samme få ledninger. Man behøver faktisk kun to – signal/forsyning og gnd. Der er dog en del devices der helst skal have særskilt forsyning. Hvis man vil drive enheder “parasitisk” (altså uden en ledning til forsyning) så skal porten vendes til et output og drives høj når man ikke kommunikerer.

Der er en app-note (link) der beskriver detaljerne hvis man vil drive porten. Jeg valgte den dovne løsning – og fandt et library (link). Det er ikke et officielt Arduino lib – men det næstbedste – nemlig et Arduino Contributed library. Det betyder at det har en vis standard og Arduino promoverer det – men uafhængige vedligeholder det.

Der er dog et lille “men” ved det library – det er et “bit-bang” library. Det vil sige at når der skal læses/skrives/ventes på bussen så sker det direkte i kodeflowet – så er der en forsinkelse på 1ms – ja så venter alt andet på at det er klaret. Omvendt er det også positivt da det gør at man kan bruge alle pins – og ikke kun dem der er tilsluttet til nogle bestemte ben…

OneWire devices har en unik 64-bit id som man skal bruge hvis man har flere devices på samme bus. Til dette formål har onewire biblioteket en scan-funktion der kan vise hvilke devices der er på bussen. Jeg har lavet et lille program der kan detektere devices og udskrive deres “family name”. Det kan hentes her: Download.

DS18B20

DS18B20 har som omtalt programmerbar opløsning – 9-10-11-12 bit. Den måler med bedre end +/-0.5 grads præcision fra -10 til +85grader – men kan måle fra -128 til ca. +128 grader. Sensoren kan enten køre med “parasitisk” strømforsyning eller forsynes direkte.

En (vigtig) detalje som man skal være opmærksom hvis man kommunikerer med enheder der indeholder en  A/D converter er konverteringstiden. Årsagen er at en konvertering fra analog til digital kan tage meget lang tid. I DS18B20 i 12 bit mode tager en konvertering 750ms! Det skal man altså ikke stå og vente på for så kommer UI og alt andet til at føles helt ulideligt langsomt. Heldigvis kan man konfigurere den til et lavere antal bit – og så tager konverteringen markant kortere tid – en halvering per bit man undværer (det er en successive approximation converter). Måske kommer den en blog om A/D-konvertering en anden dag :-). 9-bit konvertering tager max 94 ms. Men uanset bør man designe sin software så andet kan ske mens man venter på A/D-konverteringen.

Man styrer kredsen ved at starte konverteringen med en kommando. Derefter kan man enten vente et antal milisekunder og så læse temperaturen. Eller man kan polle status for konverteringen – og så hente målingen når konverteringen er overstået. Outputtet er en 16-bit størrelse i 2’s komplement signed format…

Ok – det kræver vist en forklaring… Først lidt om binære tal generelt – og derefter om hvordan man håndterer negative tal.

Binære tal

Først – om binære tal… Det binære talsystem er bygget op som det decimale (10-tals baserede) med den forskel at basen er 2. I 10-talssystemet betyder første ciffer (altså første plads til venstre for decimalseperatoren – komma) antal “enere” (100), 2. ciffer er antal 10’ere (101), 3. ciffer er antal 100’ere (102) etc. I det binære er første ciffer antal 1’ere (20), 2. ciffer er antal 2’ere (21), 3. ciffer er antal 4’ere (22). Dvs. mindste tal er 0 og største tal er 2n-1. Eks. 137 som binært 8-bit tal:

Vægt 27 26 25 24 23 22 21 20
Vægt 128 64 32 16 8 4 2 1
Bit 1 0 0 0 1 0 0 1
Værdi 128 8 1

128+8+1 = 136…

Negative tal i binært format – 1’ers komplement

Nå – men hvad så med negative tal… Dem repeæsenterer vi decialt normalt bare med et “-” fortegn. Det kunne man sådan set også godt gøre for binære tal…. Man vil så bruge et bit som “sign-bit”. Konventionen er normalt at 0 er positivt fortegn og 1 er negativt fortegn. Metoden kaldes “eners komplement” og indbærer at der er både +0 og -0. Mindste tal er -(2n-1-1); største tal er +2n-1-1. Eks. -67 som 8 bit binært tal i eners komplement:

Vægt -1 26 25 24 23 22 21 20
Vægt -1 64 32 16 8 4 2 1
Bit 1 1 0 0 0 0 1 1
Værdi 64 2 1

-(64+2+1)=-67

Negative tal i binært format – 2’ers komplement

Det er dog ret besværligt at lave matematik med negative tal i eners komplement. Derfor opfandt man 2’ers komplement. Der er stadig et sign-bit – men dette signbit indgår også direkte i tallets højeste bit. det betyder at der kun er ét “0” og at mindste værdi er -2n-1; højeste tal er 2n-1-1. Eks. -67 som 8 bit binært tal i 2’ers komplement:

Vægt -27 26 25 24 23 22 21 20
Vægt -128 64 32 16 8 4 2 1
Bit 1 0 1 1 1 1 0 1
Værdi -128 0 32 16 8 4 0 1

-128+32+16+8+4+1=-67

Binær matematik

Men hvorfor er det smartere – altså ud over at man ikke behøver tænke over at der både  er +0 og -0…? Den nemmeste måde at forklare det på er ved en skive.

Hvis man eks skal summere to tal – eks. 3+4, er er det i 3-bit binær:

tal operator bit 2 bit 1 bit 0
2 0 1 0
+
3 0 1 1
5 = 1 0

(1 i mente)

1

Ok – det er ikke så nemt at vise summationen i en tabel her – men ideen er ligesom at addere i decimalt så får man en mente der flyder over til næste ciffer.

Men – hvad nu med negetive tal… Eks. 3 + -2 i 4-bit binært 2’ers komplement:

tal operator bit 3 bit 2 bit 1 bit 0
3 0 0 1 1
+
-2 1 1 1 0
 1 = 0

(1 i mente)

0

(1 i mente)

0

(1 i mente)

1

Som det ses ender svaret med at være korrekt selvom den sidste mente (1) ender med at være til overs. Som det er illustreret med bit 2 og 3 så betyder menten at fortegnet bliver ved med at være korrekt uanset hvor mange bit man arbejder med…

Et eksempel med negativt resultat: 1 + -3

tal operator bit 3 bit 2 bit 1 bit 0
1 0 0 0 1
+
-3 1 1 0 1
 -2 = 1 1 1 0

(1 i mente)

binary_circle2Så med andre ord virker helt almindelig “positiv” matematik på binære tal i 2’ers komplement. Men hvorfor egentligt det?

Hvis tegner talsystemet som en cirkel – som vist. Så svarer addition af et positivt tal til at flytte med uret. At addere et negativt tal svarer til at flytte mod uret. Eks. 1 + -3: Fra 0001 -> 0000 -> 1111 -> 1110 = -2.

Nå – sådan virker det altså – og det kan vi så herefter glemme alt om da både micro controlleren og temperatursensoren arbejder i 2’ers komplement 🙂

En dag skal jeg beskrive hvordan man kan opfatte binære tal som tal mellem -1 og +1 og derved opnå en række fordele når man laver matematik…

Output fra DS18B20

Nå – med den lange søforklaring er vi tilbage til outputtet fra A/D converteren. Af databladet fremgår det at kredsen giver følgende opløsning ved forskellig bit-opløsning:

Antal bit Opløsning Min Max
9 bit 0.5°C/bit -256
-128.0°C
+255
+127.5°C
10 bit 0.25°C/bit -512
-128.0°C
+511
+127.75°C
11 bit 0.125°C/bit -1024
-128.0°C
+1023
+127.875°C
12 bit 0.0625°C/bit -2018
-128.0°C
+2047
+127.9375°C

Så for at få temperaturen i grader celcius ganger man bare med 2n hvor n er opløsningen i bit…

DallasTemperature

Jeg fandt et library der hedder “DallasTemperature” (link). Det indeholder support for flere devices – og altså også DS18B20. Dokumentationen kan findes her: link. Download zip-filen fra github og udpak den i arduino\libraries folderen. Så kan compileren finde den. Der er et hav af eksempler med. Med dette library er det utroligt simplelt at få hul igennem:


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

OneWire oneWire(ONE_WIRE_BUS); //one wire device

DallasTemperature sensors(&oneWire); //Temp sensor device

DeviceAddress tempDeviceAddress; //Address of the device

uint8_t resolution = 10; //set number of bits

void setup(void)
{
  sensors.begin();
  sensors.getAddress(tempDeviceAddress, 0);
  sensors.setResolution(tempDeviceAddress, resolution);

  sensors.setWaitForConversion(false);
  sensors.requestTemperatures();

  sensors.setResolution(tempDeviceAddress, resolution);
}

void loop(void)
{
  sensors.requestTemperatures(); //start conversion

  delay(750 / (1 << (12 - resolution))); //delay is 750 ms @ 12 bit - this is the NO-GO way to wait... (but easy for demonstration)

  Serial.print("Temperature: ");
  Serial.println(sensors.getTempCByIndex(0), resolution - 8); //display 4 decimals for 12 bit conversion
}

Så med den nyvundne viden og funktionalitet er første step af mit sousvide projekt klar 🙂

 

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.