/** library for Maxim DS18B20 digital temperature sensor (using 1-Wire protocol) (code) * @file * @author King Kévin * @copyright SPDX-License-Identifier: GPL-3.0-or-later * @date 2017-2020 * @note peripherals used: 1-Wire (timer @ref onewire_master_timer, GPIO @ref onewire_master_gpio) * @warning this library does not support parasite power mode and alarms */ /* standard libraries */ #include // standard integer types #include // boolean type #include // size_t definition #include // NAN definition /* own libraries */ #include "global.h" // help macros #include "onewire_master.h" // 1-Wire utilities #include "sensor_ds18b20.h" // own definitions /** remember number of DS18B20 sensors on 1-Wire bus for certain functions */ uint64_t sensors = 0; /** remember if only DS18B20 sensors on 1-Wire bus for certain functions */ bool only = false; /** remember code of last sensor **/ uint64_t last = 0; void sensor_ds18b20_setup(void) { onewire_master_setup(); // setup 1-Wire peripheral to communicate with sensors on bus sensor_ds18b20_number(); // scan for sensor (remembers sensor number and exclusivity) } uint64_t sensor_ds18b20_number(void) { sensors = 0; // reset number only = true; // reset state uint64_t code = 0; // ROM code found (use 0 to start from scratch) bool more = true; // save if other additional slaves exist while (more) { // scan for all 1-Wire slaves if (!onewire_master_reset()) { // send reset to start communication return 0; // no slave presence detected } more = onewire_master_rom_search(&code, false); // get next slave ROM code (without alarm) if (0 == code) { // error occurred return 0; } if (0x28 == (code & 0xff)) { // family code (8-LSb) for DS18B20 sensors is 0x28 last = code; // save last found code sensors++; // we found an additional sensor } else { only = false; // we found a slave which is not a sensor } } return sensors; } bool sensor_ds18b20_only(void) { sensor_ds18b20_number(); // this also checks for exclusivity return only; } bool sensor_ds18b20_list(uint64_t* code) { if (!onewire_master_reset()) { // send reset to start communication return false; // no slave presence detected } onewire_master_rom_search(code, false); // get next code return (last != *code); // verify if the last has been found } bool sensor_ds18b20_convert(uint64_t code) { if (0 == code && !only) { // asked for broadcast but there are different slaves on bus return false; // broadcast not possible when there are also different slaves on bus } // send reset pulse if (!onewire_master_reset()) { // send reset to start communication return false; // no slave presence detected } // send ROM command to select slave(s) if (0 == code) { // broadcast convert if (!onewire_master_rom_skip()) { // select all slaves return false; // ROM command failed } } else { if (!onewire_master_rom_match(code)) { // select specific slave return false; // ROM command failed } } // send convert T function command return onewire_master_function_read(0x44, NULL, 0); } float sensor_ds18b20_temperature(uint64_t code) { if (0 == code && (sensors > 1 || !only)) { // broadcast read requested return NAN; // this function is not possible when several sensors or other devices are present } // send reset pulse if (!onewire_master_reset()) { // send reset to start communication return NAN; // no slave presence detected } // send ROM command to select slave if (0 == code) { // broadcast convert if (!onewire_master_rom_skip()) { // select all slaves return false; // ROM command failed } } else { if (!onewire_master_rom_match(code)) { // select specific slave return false; // ROM command failed } } // read scratchpad to get temperature (on byte 0 and 1) uint8_t scratchpad[9] = {0}; // to store read scratchpad if (!onewire_master_function_read(0xbe, scratchpad, sizeof(scratchpad) * 8)) { // read complete scratchpad return NAN; // error occurred during read } // verify if data is valid if (onewire_master_crc(scratchpad, sizeof(scratchpad))) { // check CRC checksum return NAN; // data corrupted } // calculate temperature (stored as int16_t but on 0.125 C steps) return ((int16_t)(scratchpad[1] << 8) + scratchpad[0]) / 16.0; // get temperature (on < 16 precision the last bits are undefined, but that doesn't matter for the end result since the lower precision is still provided) } bool sensor_ds18b20_precision(uint64_t code, uint8_t precision) { if (precision < 9 || precision > 12) { // check input return false; // wrong precision value } if (0 == code && !only) { // asked for broadcast but there are different slaves on bus return false; // broadcast not possible when there are also different slaves on bus } // send reset pulse if (!onewire_master_reset()) { // send reset to start communication return false; // no slave presence detected } // send ROM command to select slave(s) if (0 == code) { // broadcast convert if (!onewire_master_rom_skip()) { // select all slaves return false; // ROM command failed } } else { if (!onewire_master_rom_match(code)) { // select specific slave return false; // ROM command failed } } // read scratchpad to get alarm values (on byte 2 and 3) uint8_t scratchpad[9] = {0}; // to store read scratchpad if (!onewire_master_function_read(0xbe, scratchpad, sizeof(scratchpad) * 8)) { // read complete scratchpad return false; // error occurred during read } // verify if data is valid if (onewire_master_crc(scratchpad, sizeof(scratchpad))) { // check CRC checksum return false; // data corrupted } // send new configuration (and keep the alarm values) uint8_t configuration[3] = {0}; // to store T_HIGH, T_LOW, and configuration configuration[0] = scratchpad[2]; // keep T_HIGH configuration[1] = scratchpad[3]; // keep T_LOW configuration[2] = 0x1f + ((precision - 9) << 5); // set precision bit (R1-R0 on bit 6-5) if (!onewire_master_function_write(0x4e, configuration, sizeof(configuration) * 8)) { // write scratchpad with new configuration (all three bytes must be written) return false; // error occurred during write } // store new configuration into sensor's EEPROM for retrieval on next power up if (!onewire_master_function_read(0x48, NULL, 0)) { // copy scratchpad (to EEPROM) return false; // error during copy } return true; }