Onewire Dallas (Maxim) Temperatur Library

Aus TippvomTibb
Zur Navigation springen Zur Suche springen

Inhaltsverzeichnis

Allgemeines

Den OneWire Temperatur Sensor DS18XX hab ich irgendwie lieb gewonnen. Gerade sitze ich an einer kleinen Steuerung für die Heizkreise meiner Heizanlage (Gas, Sonne, Holz) und will damit die Temperaturen der Hin- und Ruecklaeufe messen, um aus diesen Informationen die Pumpen und Ventile sinnvoll anzusteuern.

Problem

Die Steuerung uebernimmt z.Z. eine Siemens LOGO!. Die Temperaturen werden durch ein Temperatur-Erfassungs-Modul (DS18S20 -> 0-10V) an die LOGO! uebergeben. Das TEM ist ein Arduino mit mehreren DS18, einem DAC (MCP4822) und einem Ethernetmodul, um einen automatischen Offset-Abgleich ueber Ethernet<->EIB hinzubekommen. Der Arduino kann auch selbststaendig ueber Ethernet alarmieren, falls sich eine unplausible oder grenzwertige Temperatursituation ergibt.

DallasTemperature Library

Ich habe mich fuer diese Library entschieden, da es auf den ersten Blick eine umfangreiche, saubere Implementierung zu sein schien. Es duerfte auch eine der wenigen Libraries sein, die die Alarmierungsfunktion unterstuetzen. Die Kommentare im Programmcode sind sehr umfangreich, der Quellcode sehr strukturiert aufgebaut und auch an so nette Features wie bedingte Compilierung (#define REQUIRESNEW or #define REQUIRESALARMS) wurde gedacht. Miles Burton ist ja auch kein Hobby-Programmierer.

Die Installation der Library (PlatformIO) und das Ueberpruefen einiger Examples (Es gibt insgesamt 18 Stueck!) verlief ohne Probleme.

So weit so gut.

Implementierung

Das erste an was ich mich gewoehnen musste war die DeviceAdresse in einem Array (8 Byte).

Ich haette mir gewuenscht, dass alle Devices (auch) in einem Array gehalten werden. Dass man zu Beginn gleich den Busscan dazu nutzt die Devices in ein Array einzutragen.

typedef uint8_t DeviceAddresses[8];

Ein array aus 8 Elementen reicht mir. Koennte man aber auf 63 erhoehen.

Eine Auflistung aller Methoden fuer jeden der auch tiefer einsteigen moechte. Die Library besteht eigentlich nur aus einer einzigen Klasse 'DallasTemeperature'.

Klasse im Detail

Konstruktoren

DallasTemperature();

DallasTemperature(OneWire*);

DallasTemperature(OneWire*, uint8_t);

Der zweite Parameter ist der "Pullup-Pin". Es wird in diesem Konstruktor zusätzlich die Methode setPullupPin aufgerufen.

void setOneWire(OneWire* _oneWire)

Wird im Beispiel Alarm nicht explizit benutzt. Steckt im Konstruktor mit drin.

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) OneWire oneWire(ONE_WIRE_BUS);

Kommt im Beisiel Multibus_simple.ino vor.

OneWire ds18x20[] = { 3, 7 };
const int oneWireCount = sizeof(ds18x20)/sizeof(OneWire);
DallasTemperature sensor[oneWireCount];  // Fuer jeden Bus (hier an Pin 3 und 7) wird eine eigene Instanz angelegt. 
...
DeviceAddress deviceAddress;
for (int i = 0; i < oneWireCount; i++) {
    sensor[i].setOneWire(&ds18x20[i]);
    sensor[i].begin();
    if (sensor[i].getAddress(deviceAddress, 0)) sensor[i].setResolution(deviceAddress, 12);
}

void setPullupPin(uint8_t);

/*

* Constructs DallasTemperature with strong pull-up turned on. Strong pull-up is mandated in DS18B20 datasheet for parasitic
* power (2 wires) setup. (https://datasheets.maximintegrated.com/en/ds/DS18B20.pdf, p. 7, section 'Powering the DS18B20').
*/

Erwartet als Uebergabeparameter einen PortPin. Ich geh mal davon aus, dass hiermit ein schaltbarer Pullup-Widerstand gemeint ist. Beim Deaktivieren ist der entsprechende Port auf HIGH. Bei der Aktivierung wird der Port auf LOW gesetzt

void begin(void);

//initialise bus

Es wird ein OneWire-Busscan (reset_search und danch search) durchgefuehrt. Beim Scan werden die Anzahl Devices (devices) und speziell auch DS18 Devices (ds18count) am Bus bestimmt. Die privaten Variablen devices und ds18count koenne mit den Methoden getDeviceCOunt und getDS18Count abgefragt werden. Weiterhin wird bei begin auch noch die Art der Spannungsversorung und die Aufloesung bestimmt. z.Z bin ich der Meinung, dass die Resolution hier in begin ueberfluessig (falsch) ist, da es keine Zuordnung zu den einzelnen Devices gibt und nach begin nur die Aufloesung des letzen gefundenen Devices beinhaltet. Oder?

uint8_t getDeviceCount(void);

returns the number of devices found on the bus

Die Anzahl wird von 'begin' in die Variable (Private) devices geschrieben.

uint8_t getDS18Count(void);

returns the number of DS18xxx Family devices on bus

Die Anzahl wird von 'begin' in die Variable (Private) ds18Count geschrieben.

bool validAddress(const uint8_t* deviceAddress);

returns true if address is valid

In dieser Methode wird eine CRC ueberpruefung durchgefuehrt. Und zwar wird geschaut, ob der berechnete Wert der Deviceadresse (die ersten 7 Byte) gleich dem in der ROM-Adresse ist. Eine brauchbare Erlaeuterung der CRC-Berechnung findet sich u.a. hier. Man kann seine Devices auch mal online ueberpruefen. Das CRC8 Polynom des Maxim ist 0x131. Auf der Seite wird nur 0x31 bei Maxim CRC8 angegeben. Das liegt wohl daran, dass die fuehrende Eins beim Polynom ergaenzt wird. Das muss ich mir bei Gelegenheit mal naeher anschauen.

bool validFamily(const uint8_t* deviceAddress);

returns true if address is of the family of sensors the lib supports.

Derzeit (V3.8.1) werden folgende Family-Codes akzeptiert.

#define DS18S20MODEL 0x10  // also DS1820
#define DS18B20MODEL 0x28  // also MAX31820
#define DS1822MODEL  0x22
#define DS1825MODEL  0x3B
#define DS28EA00MODEL 0x42

bool getAddress(uint8_t*, uint8_t);

// finds an address at a given index on the bus

Irgendwo habe ich gelesen, dass die Devices immer in der gleichen Reihenfolge am Bus erkannt werden, damit "stehen" sie in der Reihenfolge immer an der gleichen Stelle und damit am gleichen Index. Der Index beginnt mit 0. Er ist zwar nur durch uint8_t begrenzt, aber nur sinnvoll bis zur Devcice-Anzahl (count) einzusetzen.

bool isConnected(const uint8_t* deviceAddress)

// attempt to determine if the device at the given address is connected to the bus

Es wird ein TRUE zurueckgegeben wenn das Scratchpad lesbar war und den CRC-Check bestanden hat.

bool isConnected(const uint8_t* deviceAddress, uint8_t* scratchPad)

// attempt to determine if the device at the given address is connected to the bus
// also allows for updating the read scratchpad

Siehe isConnected(const uint8_t* deviceAddress)

bool readScratchPad(const uint8_t* deviceAddress, uint8_t* scratchPad)

// read device's scratchpad

Das Scratchpad (9 Byte) des Devices mit der Adresse deviceAddress wird in das array scratchPad uebertragen.

void writeScratchPad(const uint8_t* deviceAddress, const uint8_t* scratchPad)

// write device's scratchpad

Das Scratchpad-Daten (3 Byte EEPROM ALARM, CONFIG) des Devices mit der Adresse deviceAddress wird in das Scratchpad uebertragen und in das EEPROM gesichert.

bool readPowerSupply(const uint8_t* deviceAddress = nullptr);

// read device's power requirements

void setResolution(uint8_t newResolution)

// set global resolution to 9, 10, 11, or 12 bits
// set resolution of all devices to 9, 10, 11, or 12 bits
// if new resolution is out of range, it is constrained.

bool setResolution(const uint8_t*, uint8_t, bool skipGlobalBitResolutionCalculation = false)

// set resolution of a device to 9, 10, 11, or 12 bits

skipGlobalBitResolutionCalculation: wenn 'false' wird die Variable bitResolution auf die maximal vorkommende Aufloesung gesetzt.

uint8_t getResolution()

// get global resolution

Gibt nur den Inhalt der Variablen bitResolution zurueck.

uint8_t getResolution(const uint8_t* deviceAddress)

// returns the device resolution: 9, 10, 11, or 12 bits


void setWaitForConversion(bool);

bool getWaitForConversion(void);

// sets/gets the waitForConversion flag

void setCheckForConversion(bool);

bool getCheckForConversion(void);

// sets/gets the checkForConversion flag

void requestTemperatures(void);

// sends command for all devices on the bus to perform a temperature conversion

bool requestTemperaturesByAddress(const uint8_t*);

// sends command for one device to perform a temperature conversion by address

bool requestTemperaturesByIndex(uint8_t);

// sends command for one device to perform a temperature conversion by index

int16_t getTemp(const uint8_t*);

// returns temperature raw value (12 bit integer of 1/128 degrees C)

float getTempC(const uint8_t*);

// returns temperature in degrees C

float getTempF(const uint8_t*);

// returns temperature in degrees F

float getTempCByIndex(uint8_t);

// Get temperature for device index (slow)

float getTempFByIndex(uint8_t);

// Get temperature for device index (slow)

bool isParasitePowerMode(void)

// returns true if the bus requires parasite power

bool isConversionComplete(void)

// Is a conversion complete on the wire? Only applies to the first sensor on the wire.

int16_t millisToWaitForConversion(uint8_t);

bool saveScratchPadByIndex(uint8_t);

 // Sends command to one device to save values from scratchpad to EEPROM by index
 // Returns true if no errors were encountered, false indicates failure

bool saveScratchPad(const uint8_t* = nullptr);

 // Sends command to one or more devices to save values from scratchpad to EEPROM
 // Returns true if no errors were encountered, false indicates failure
 

bool recallScratchPadByIndex(uint8_t);

 // Sends command to one device to recall values from EEPROM to scratchpad by index
 // Returns true if no errors were encountered, false indicates failure

bool recallScratchPad(const uint8_t* = nullptr);

 // Sends command to one or more devices to recall values from EEPROM to scratchpad
 // Returns true if no errors were encountered, false indicates failure
 

void setAutoSaveScratchPad(bool);

 // Sets the autoSaveScratchPad flag

bool getAutoSaveScratchPad(void);

 // Gets the autoSaveScratchPad flag

void setHighAlarmTemp(const uint8_t*, int8_t);

// sets the high alarm temperature for a device // accepts a int8_t. valid range is -55C - 125C

void setLowAlarmTemp(const uint8_t*, int8_t);

// sets the low alarm temperature for a device // accepts a int8_t. valid range is -55C - 125C

int8_t getHighAlarmTemp(const uint8_t*);

// returns a int8_t with the current high alarm temperature for a device // in the range -55C - 125C

int8_t getLowAlarmTemp(const uint8_t*);

// returns a int8_t with the current low alarm temperature for a device // in the range -55C - 125C

void resetAlarmSearch(void);

// resets internal variables used for the alarm search

bool alarmSearch(uint8_t*);

// search the wire for devices with active alarms

bool hasAlarm(const uint8_t*);

// returns true if ia specific device has an alarm

bool hasAlarm(void);

// returns true if any device is reporting an alarm on the bus

void processAlarms(void);

// runs the alarm handler for all devices returned by alarmSearch()

void setAlarmHandler(const AlarmHandler *);

// sets the alarm handler

bool hasAlarmHandler();

// returns true if an AlarmHandler has been set


void setUserData(const uint8_t*, int16_t);

void setUserDataByIndex(uint8_t, int16_t);

int16_t getUserData(const uint8_t*);

int16_t getUserDataByIndex(uint8_t);

// if no alarm handler is used the two bytes can be used as user data // example of such usage is an ID. // note if device is not connected it will fail writing the data. // note if address cannot be found no error will be reported. // in short use carefully

static float toFahrenheit(float);

// convert from Celsius to Fahrenheit

static float toCelsius(float);

// convert from Fahrenheit to Celsius

static float rawToCelsius(int16_t);

// convert from raw to Celsius

static float rawToFahrenheit(int16_t);

// convert from raw to Fahrenheit

void* operator new (unsigned int);

// initialize memory area

void operator delete(void*);

// delete memory reference

Links

https://wiki.arduino-hannover.de/wiki/DS1820_Temperatursensor_1-Wire

http://www.sunshine2k.de/coding/javascript/crc/crc_js.html

https://de.wikipedia.org/wiki/Zyklische_Redundanzpr%C3%BCfung