/* This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ /** library for Maxim DS18B20 digital temperature sensor (using 1-Wire protocol) (code) * @file sensor_ds18b20.c * @author King Kévin * @date 2017 * @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 (!onewire_master_rom_match(code)) { // select specific slave return NAN; // 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; }