From 75658c2c1a386cf8d69887c04c7a5566df42e9af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?King=20K=C3=A9vin?= Date: Tue, 28 Mar 2017 12:39:11 +0200 Subject: [PATCH] add DS18B20 temperature sensor library from thermo-regulator project --- lib/sensor_ds18b20.c | 196 +++++++++++++++++++++++++++++++++++++++++++ lib/sensor_ds18b20.h | 56 +++++++++++++ 2 files changed, 252 insertions(+) create mode 100644 lib/sensor_ds18b20.c create mode 100644 lib/sensor_ds18b20.h diff --git a/lib/sensor_ds18b20.c b/lib/sensor_ds18b20.c new file mode 100644 index 0000000..1923837 --- /dev/null +++ b/lib/sensor_ds18b20.c @@ -0,0 +1,196 @@ +/* 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; +} diff --git a/lib/sensor_ds18b20.h b/lib/sensor_ds18b20.h new file mode 100644 index 0000000..f813dc0 --- /dev/null +++ b/lib/sensor_ds18b20.h @@ -0,0 +1,56 @@ +/* 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) (API) + * @file sensor_ds18b20.h + * @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 + */ +#pragma once + +/** setup 1-Wire peripheral to communicate with sensors on bus */ +void sensor_ds18b20_setup(void); +/** get number of DS18B20 sensors on bus + * @return number of DS18B20 sensors on bus + */ +uint64_t sensor_ds18b20_number(void); +/** verify if only DS18B20 sensors are on the bus + * @return if only DS18B20 sensors are on the bus + */ +bool sensor_ds18b20_only(void); +/** send all DS18B20 slaves on the bus + * @param[out] code ROM code for sensor (0 if error occurred) + * @return if an additional sensors have been detected + */ +bool sensor_ds18b20_list(uint64_t* code); +/** start converting (e.g. measuring) temperature + * @waning conversion time to wait before reading temperature depends on the resolution set (9 bits: 93.75ms, 10 bits: 187.5ms, 11 bits: 375ms, 12 bits: 950ms) + * @param[in] code ROM code of sensor to start conversion on (0 for all, if only DS18B20 sensors are on the bus) + * @return if conversion started + */ +bool sensor_ds18b20_convert(uint64_t code); +/** get converted temperature + * @note 85.0 C is the default temperature when no conversion has been performed + * @param[in] code ROM code of sensor + * @return temperature (NaN if error) + */ +float sensor_ds18b20_temperature(uint64_t code); +/** set conversion precision + * @param[in] code ROM code of sensor to start conversion on (0 for all, if only DS18B20 sensors are on the bus) + * @param[in] precision precision in bits (9-12) + * @return if operation succeeded + */ +bool sensor_ds18b20_precision(uint64_t code, uint8_t precision);