Onewire Dallas (Maxim) Temperatur Library
Inhaltsverzeichnis
- 1 Allgemeines
- 2 Problem
- 2.1 DallasTemperature Library
- 2.2 Implementierung
- 2.3 Klasse im Detail
- 2.3.1 Konstruktoren
- 2.3.2 void setOneWire(OneWire* _oneWire)
- 2.3.3 void setPullupPin(uint8_t);
- 2.3.4 void begin(void);
- 2.3.5 uint8_t getDeviceCount(void);
- 2.3.6 uint8_t getDS18Count(void);
- 2.3.7 bool validAddress(const uint8_t* deviceAddress);
- 2.3.8 bool validFamily(const uint8_t* deviceAddress);
- 2.3.9 bool getAddress(uint8_t*, uint8_t);
- 2.3.10 bool isConnected(const uint8_t* deviceAddress)
- 2.3.11 bool isConnected(const uint8_t* deviceAddress, uint8_t* scratchPad)
- 2.3.12 bool readScratchPad(const uint8_t* deviceAddress, uint8_t* scratchPad)
- 2.3.13 void writeScratchPad(const uint8_t* deviceAddress, const uint8_t* scratchPad)
- 2.3.14 bool readPowerSupply(const uint8_t* deviceAddress = nullptr);
- 2.3.15 void setResolution(uint8_t newResolution)
- 2.3.16 bool setResolution(const uint8_t*, uint8_t, bool skipGlobalBitResolutionCalculation = false)
- 2.3.17 uint8_t getResolution()
- 2.3.18 uint8_t getResolution(const uint8_t* deviceAddress)
- 2.3.19 void setWaitForConversion(bool);
- 2.3.20 bool getWaitForConversion(void);
- 2.3.21 void setCheckForConversion(bool);
- 2.3.22 bool getCheckForConversion(void);
- 2.3.23 void requestTemperatures(void);
- 2.3.24 bool requestTemperaturesByAddress(const uint8_t*);
- 2.3.25 bool requestTemperaturesByIndex(uint8_t);
- 2.3.26 int16_t getTemp(const uint8_t*);
- 2.3.27 float getTempC(const uint8_t*);
- 2.3.28 float getTempF(const uint8_t*);
- 2.3.29 float getTempCByIndex(uint8_t);
- 2.3.30 float getTempFByIndex(uint8_t);
- 2.3.31 bool isParasitePowerMode(void)
- 2.3.32 bool isConversionComplete(void)
- 2.3.33 int16_t millisToWaitForConversion(uint8_t);
- 2.3.34 bool saveScratchPadByIndex(uint8_t);
- 2.3.35 bool saveScratchPad(const uint8_t* = nullptr);
- 2.3.36 bool recallScratchPadByIndex(uint8_t);
- 2.3.37 bool recallScratchPad(const uint8_t* = nullptr);
- 2.3.38 void setAutoSaveScratchPad(bool);
- 2.3.39 bool getAutoSaveScratchPad(void);
- 2.3.40 void setHighAlarmTemp(const uint8_t*, int8_t);
- 2.3.41 void setLowAlarmTemp(const uint8_t*, int8_t);
- 2.3.42 int8_t getHighAlarmTemp(const uint8_t*);
- 2.3.43 int8_t getLowAlarmTemp(const uint8_t*);
- 2.3.44 void resetAlarmSearch(void);
- 2.3.45 bool alarmSearch(uint8_t*);
- 2.3.46 bool hasAlarm(const uint8_t*);
- 2.3.47 bool hasAlarm(void);
- 2.3.48 void processAlarms(void);
- 2.3.49 void setAlarmHandler(const AlarmHandler *);
- 2.3.50 bool hasAlarmHandler();
- 2.3.51 void setUserData(const uint8_t*, int16_t);
- 2.3.52 void setUserDataByIndex(uint8_t, int16_t);
- 2.3.53 int16_t getUserData(const uint8_t*);
- 2.3.54 int16_t getUserDataByIndex(uint8_t);
- 2.3.55 static float toFahrenheit(float);
- 2.3.56 static float toCelsius(float);
- 2.3.57 static float rawToCelsius(int16_t);
- 2.3.58 static float rawToFahrenheit(int16_t);
- 2.3.59 void* operator new (unsigned int);
- 2.3.60 void operator delete(void*);
- 3 Links
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