working temp sensor

This commit is contained in:
user 2024-10-11 18:01:48 +02:00
parent e4f0dab61c
commit 97dfb13b74
10 changed files with 503 additions and 1116 deletions

View file

@ -0,0 +1,31 @@
# DS18B20 Component
Simple DS18B20 temperature sensor library for [ESP8266 RTOS SDK](https://github.com/espressif/ESP8266_RTOS_SDK) for reading Celsius temperature with different resolutions from singular device.
## Usage
```
// Create variable for handler
ds18b20_handler_t sensor;
// Check for any initialization failures
if (!ds18b20_init(&sensor, GPIO_NUM_12, TEMP_RES_12_BIT))
{
ESP_LOGE("TAG", "Failed to initalize DS18B20!");
return 0; // Exit
}
float temp = 0;
// Initalize conversion
ds18b20_convert_temp(&sensor);
// If you doesn't convert temperature you may read 85.0 Celsius,
// as it is default temperature set by DS18B20 if convert command wasn't issued.
temp = ds18b20_read_temp(&sensor); // Read temperature
// Print temperature with 4 decimal places
// (12 bit resolution measurement accuracy is 0.0625 Celsius)
ESP_LOGI("TAG", "Temperature = %.4f", temp);
```
> **_NOTE:_** If last statement doesn't print temperature you may have to disable Newlib nano in `menuconfig` of RTOS SDK.

18
embadet/components/ds18b20/component.mk Normal file → Executable file
View file

@ -1,15 +1,5 @@
# Component makefile for extras/ds18b20
#
# Component Makefile
#
# expected anyone using bmp driver includes it as 'ds18b20/ds18b20.h'
INC_DIRS += $(ds18b20_ROOT)..
# args for passing into compile rule generation
ds18b20_SRC_DIR = $(ds18b20_ROOT)
# users can override this setting and get console debug output
DS18B20_DEBUG ?= 0
ifeq ($(DS18B20_DEBUG),1)
ds18b20_CFLAGS = $(CFLAGS) -DDS18B20_DEBUG
endif
$(eval $(call component_compile_rules,ds18b20))
COMPONENT_ADD_INCLUDEDIRS := .

288
embadet/components/ds18b20/ds18b20.c Normal file → Executable file
View file

@ -1,244 +1,120 @@
#include "FreeRTOS.h"
#include "task.h"
#include "math.h"
#include "ds18b20.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#define DS18B20_WRITE_SCRATCHPAD 0x4E
#define DS18B20_READ_SCRATCHPAD 0xBE
#define DS18B20_COPY_SCRATCHPAD 0x48
#define DS18B20_READ_EEPROM 0xB8
#define DS18B20_READ_PWRSUPPLY 0xB4
#define DS18B20_SEARCHROM 0xF0
#define DS18B20_SKIP_ROM 0xCC
#define DS18B20_READROM 0x33
#define DS18B20_MATCHROM 0x55
#define DS18B20_ALARMSEARCH 0xEC
#define DS18B20_CONVERT_T 0x44
static const char* TAG_DS18B20 = "DS18B20";
static const uint16_t ds18b20_temp_conv_time[] = {94, 188, 375, 750}; // ms
static const uint16_t ds18b20_resolution_val[] = {0x1F, 0x3F, 0x5F, 0x7F};
#define os_sleep_ms(x) vTaskDelay(((x) + portTICK_PERIOD_MS - 1) / portTICK_PERIOD_MS)
uint8_t ds18b20_init(ds18b20_handler_t *device, gpio_num_t pin, ds18b20_temp_res_t resolution)
{
if (!device)
{
ESP_LOGW(TAG_DS18B20, "device is null!");
#define DS18B20_FAMILY_ID 0x28
#define DS18S20_FAMILY_ID 0x10
#ifdef DS18B20_DEBUG
#define debug(fmt, ...) printf("%s" fmt "\n", "DS18B20: ", ## __VA_ARGS__);
#else
#define debug(fmt, ...)
#endif
uint8_t ds18b20_read_all(uint8_t pin, ds_sensor_t *result) {
onewire_addr_t addr;
onewire_search_t search;
uint8_t sensor_id = 0;
onewire_search_start(&search);
while ((addr = onewire_search_next(&search, pin)) != ONEWIRE_NONE) {
uint8_t crc = onewire_crc8((uint8_t *)&addr, 7);
if (crc != (addr >> 56)){
debug("CRC check failed: %02X %02X\n", (unsigned)(addr >> 56), crc);
return 0;
}
onewire_reset(pin);
onewire_select(pin, addr);
onewire_write(pin, DS18B20_CONVERT_T);
if (!onewire_init(&device->bus, pin, NULL))
{
ESP_LOGW(TAG_DS18B20, "Failed to initialize onewire bus");
onewire_power(pin);
vTaskDelay(750 / portTICK_PERIOD_MS);
onewire_reset(pin);
onewire_select(pin, addr);
onewire_write(pin, DS18B20_READ_SCRATCHPAD);
uint8_t get[10];
for (int k=0;k<9;k++){
get[k]=onewire_read(pin);
}
//debug("\n ScratchPAD DATA = %X %X %X %X %X %X %X %X %X\n",get[8],get[7],get[6],get[5],get[4],get[3],get[2],get[1],get[0]);
crc = onewire_crc8(get, 8);
if (crc != get[8]){
debug("CRC check failed: %02X %02X\n", get[8], crc);
return 0;
}
uint8_t temp_msb = get[1]; // Sign byte + lsbit
uint8_t temp_lsb = get[0]; // Temp data plus lsb
uint16_t temp = temp_msb << 8 | temp_lsb;
device->res = resolution;
float temperature;
// Configure resolution
ds18b20_write_scratchpad(device);
ds18b20_read_scratchpad(device);
temperature = (temp * 625.0)/10000;
//debug("Got a DS18B20 Reading: %d.%02d\n", (int)temperature, (int)(temperature - (int)temperature) * 100);
result[sensor_id].id = sensor_id;
result[sensor_id].value = temperature;
sensor_id++;
}
return sensor_id;
return 1;
}
float ds18b20_read_single(uint8_t pin) {
void ds18b20_send_command(ds18b20_handler_t *device, ds18b20_commands_t command)
{
uint8_t payload = 0x0 ^ command;
onewire_reset(pin);
onewire_skip_rom(pin);
onewire_write(pin, DS18B20_CONVERT_T);
onewire_power(pin);
vTaskDelay(750 / portTICK_PERIOD_MS);
onewire_reset(pin);
onewire_skip_rom(pin);
onewire_write(pin, DS18B20_READ_SCRATCHPAD);
uint8_t get[10];
for (int k=0;k<9;k++){
get[k]=onewire_read(pin);
}
//debug("\n ScratchPAD DATA = %X %X %X %X %X %X %X %X %X\n",get[8],get[7],get[6],get[5],get[4],get[3],get[2],get[1],get[0]);
uint8_t crc = onewire_crc8(get, 8);
if (crc != get[8]){
debug("CRC check failed: %02X %02X", get[8], crc);
return 0;
}
uint8_t temp_msb = get[1]; // Sign byte + lsbit
uint8_t temp_lsb = get[0]; // Temp data plus lsb
uint16_t temp = temp_msb << 8 | temp_lsb;
float temperature;
temperature = (temp * 625.0)/10000;
return temperature;
//debug("Got a DS18B20 Reading: %d.%02d\n", (int)temperature, (int)(temperature - (int)temperature) * 100);
onewire_write_byte(&device->bus, payload);
}
bool ds18b20_measure(int pin, ds18b20_addr_t addr, bool wait) {
if (!onewire_reset(pin)) {
return false;
}
if (addr == DS18B20_ANY) {
onewire_skip_rom(pin);
} else {
onewire_select(pin, addr);
}
taskENTER_CRITICAL();
onewire_write(pin, DS18B20_CONVERT_T);
// For parasitic devices, power must be applied within 10us after issuing
// the convert command.
onewire_power(pin);
taskEXIT_CRITICAL();
void ds18b20_convert_temp(ds18b20_handler_t *device)
{
onewire_reset(&device->bus);
onewire_send_command(&device->bus, _ROM_SKIP);
if (wait) {
os_sleep_ms(750);
onewire_depower(pin);
}
ds18b20_send_command(device, _CONVERT_T);
return true;
vTaskDelay(pdMS_TO_TICKS(ds18b20_temp_conv_time[device->res]));
}
bool ds18b20_read_scratchpad(int pin, ds18b20_addr_t addr, uint8_t *buffer) {
uint8_t crc;
uint8_t expected_crc;
void ds18b20_write_scratchpad(ds18b20_handler_t *device)
{
onewire_reset(&device->bus);
onewire_send_command(&device->bus, _ROM_SKIP);
if (!onewire_reset(pin)) {
return false;
}
if (addr == DS18B20_ANY) {
onewire_skip_rom(pin);
} else {
onewire_select(pin, addr);
}
onewire_write(pin, DS18B20_READ_SCRATCHPAD);
ds18b20_send_command(device, _SCRATCH_WRITE);
for (int i = 0; i < 8; i++) {
buffer[i] = onewire_read(pin);
}
crc = onewire_read(pin);
expected_crc = onewire_crc8(buffer, 8);
if (crc != expected_crc) {
debug("CRC check failed reading scratchpad: %02x %02x %02x %02x %02x %02x %02x %02x : %02x (expected %02x)\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7], crc, expected_crc);
return false;
}
return true;
// Th and Tl registers
onewire_write_byte(&device->bus, 0);
onewire_write_byte(&device->bus, 0);
// Resolution value
onewire_write_byte(&device->bus, ds18b20_resolution_val[device->res]);
}
float ds18b20_read_temperature(int pin, ds18b20_addr_t addr) {
uint8_t scratchpad[8];
int16_t temp;
void ds18b20_copy_scratchpad(ds18b20_handler_t *device)
{
onewire_reset(&device->bus);
onewire_send_command(&device->bus, _ROM_SKIP);
if (!ds18b20_read_scratchpad(pin, addr, scratchpad)) {
return NAN;
}
temp = scratchpad[1] << 8 | scratchpad[0];
float res;
if ((uint8_t)addr == DS18B20_FAMILY_ID) {
res = ((float)temp * 625.0)/10000;
}
else {
temp = ((temp & 0xfffe) << 3) + (16 - scratchpad[6]) - 4;
res = ((float)temp * 625.0)/10000 - 0.25;
}
return res;
ds18b20_send_command(device, _SCRATCH_COPY);
}
float ds18b20_measure_and_read(int pin, ds18b20_addr_t addr) {
if (!ds18b20_measure(pin, addr, true)) {
return NAN;
void ds18b20_read_scratchpad(ds18b20_handler_t *device)
{
onewire_reset(&device->bus);
onewire_send_command(&device->bus, _ROM_SKIP);
ds18b20_send_command(device, _SCRATCH_READ);
uint8_t i;
for (i = 0; i < 9; i++)
{
device->scratchpad[i] = onewire_read_byte(&device->bus);
}
return ds18b20_read_temperature(pin, addr);
}
bool ds18b20_measure_and_read_multi(int pin, ds18b20_addr_t *addr_list, int addr_count, float *result_list) {
if (!ds18b20_measure(pin, DS18B20_ANY, true)) {
for (int i=0; i < addr_count; i++) {
result_list[i] = NAN;
void ds18b20_print_scratchpad(ds18b20_handler_t *device)
{
uint8_t i;
for (i = 0; i < 9; i++)
{
printf("%x ", device->scratchpad[i]);
}
return false;
}
return ds18b20_read_temp_multi(pin, addr_list, addr_count, result_list);
printf("\n");
}
int ds18b20_scan_devices(int pin, ds18b20_addr_t *addr_list, int addr_count) {
onewire_search_t search;
onewire_addr_t addr;
int found = 0;
float ds18b20_read_temp(ds18b20_handler_t *device)
{
ds18b20_read_scratchpad(device);
onewire_search_start(&search);
while ((addr = onewire_search_next(&search, pin)) != ONEWIRE_NONE) {
uint8_t family_id = (uint8_t)addr;
if (family_id == DS18B20_FAMILY_ID || family_id == DS18S20_FAMILY_ID) {
if (found < addr_count) {
addr_list[found] = addr;
uint8_t sign = 0x0;
uint8_t lsb = device->scratchpad[0];
uint8_t mask = 0xFF << (TEMP_RES_12_BIT - device->res);
lsb &= mask; // Mask out last 3 bits accordingly
uint8_t msb = device->scratchpad[1];
sign = msb & 0x80;
int16_t temp = 0x0;
temp = lsb + (msb << 8);
if (sign)
{
temp = ~(-temp) + 1; // Convert signed two complement's
}
found++;
}
}
return found;
return temp / 16.0;
}
bool ds18b20_read_temp_multi(int pin, ds18b20_addr_t *addr_list, int addr_count, float *result_list) {
bool result = true;
for (int i = 0; i < addr_count; i++) {
result_list[i] = ds18b20_read_temperature(pin, addr_list[i]);
if (isnan(result_list[i])) {
result = false;
}
}
return result;
}

234
embadet/components/ds18b20/ds18b20.h Normal file → Executable file
View file

@ -1,157 +1,97 @@
#ifndef DRIVER_DS18B20_H_
#define DRIVER_DS18B20_H_
#include <onewire/onewire.h>
#ifndef DS18B20_H
#define DS18B20_H
#ifdef __cplusplus
extern "C" {
#endif
#include "onewire.h"
/** @file ds18b20.h
*
* Communicate with the DS18B20 family of one-wire temperature sensor ICs.
*
*/
typedef enum {
TEMP_RES_9_BIT = 0,
TEMP_RES_10_BIT = 1,
TEMP_RES_11_BIT = 2,
TEMP_RES_12_BIT = 3
} ds18b20_temp_res_t;
typedef onewire_addr_t ds18b20_addr_t;
typedef enum {
_SCRATCH_WRITE = 0x4E,
_SCRATCH_READ = 0xBE,
_SCRATCH_COPY = 0x48,
_CONVERT_T = 0x44
} ds18b20_commands_t;
/** An address value which can be used to indicate "any device on the bus" */
#define DS18B20_ANY ONEWIRE_NONE
/** Find the addresses of all DS18B20 devices on the bus.
*
* Scans the bus for all devices and places their addresses in the supplied
* array. If there are more than `addr_count` devices on the bus, only the
* first `addr_count` are recorded.
*
* @param pin The GPIO pin connected to the DS18B20 bus
* @param addr_list A pointer to an array of ds18b20_addr_t values. This
* will be populated with the addresses of the found
* devices.
* @param addr_count Number of slots in the `addr_list` array. At most this
* many addresses will be returned.
*
* @returns The number of devices found. Note that this may be less than,
* equal to, or more than `addr_count`, depending on how many DS18B20 devices
* are attached to the bus.
*/
int ds18b20_scan_devices(int pin, ds18b20_addr_t *addr_list, int addr_count);
/** Tell one or more sensors to perform a temperature measurement and
* conversion (CONVERT_T) operation. This operation can take up to 750ms to
* complete.
*
* If `wait=true`, this routine will automatically drive the pin high for the
* necessary 750ms after issuing the command to ensure parasitically-powered
* devices have enough power to perform the conversion operation (for
* non-parasitically-powered devices, this is not necessary but does not
* hurt). If `wait=false`, this routine will drive the pin high, but will
* then return immediately. It is up to the caller to wait the requisite time
* and then depower the bus using onewire_depower() or by issuing another
* command once conversion is done.
*
* @param pin The GPIO pin connected to the DS18B20 device
* @param addr The 64-bit address of the device on the bus. This can be set
* to ::DS18B20_ANY to send the command to all devices on the bus
* at the same time.
* @param wait Whether to wait for the necessary 750ms for the DS18B20 to
* finish performing the conversion before returning to the
* caller (You will normally want to do this).
*
* @returns `true` if the command was successfully issued, or `false` on error.
*/
bool ds18b20_measure(int pin, ds18b20_addr_t addr, bool wait);
/** Read the value from the last CONVERT_T operation.
*
* This should be called after ds18b20_measure() to fetch the result of the
* temperature measurement.
*
* @param pin The GPIO pin connected to the DS18B20 device
* @param addr The 64-bit address of the device to read. This can be set
* to ::DS18B20_ANY to read any device on the bus (but note
* that this will only work if there is exactly one device
* connected, or they will corrupt each others' transmissions)
*
* @returns The temperature in degrees Celsius, or NaN if there was an error.
*/
float ds18b20_read_temperature(int pin, ds18b20_addr_t addr);
/** Read the value from the last CONVERT_T operation for multiple devices.
*
* This should be called after ds18b20_measure() to fetch the result of the
* temperature measurement.
*
* @param pin The GPIO pin connected to the DS18B20 bus
* @param addr_list A list of addresses for devices to read.
* @param addr_count The number of entries in `addr_list`.
* @param result_list An array of floats to hold the returned temperature
* values. It should have at least `addr_count` entries.
*
* @returns `true` if all temperatures were fetched successfully, or `false`
* if one or more had errors (the temperature for erroring devices will be
* returned as NaN).
*/
bool ds18b20_read_temp_multi(int pin, ds18b20_addr_t *addr_list, int addr_count, float *result_list);
/** Perform a ds18b20_measure() followed by ds18b20_read_temperature()
*
* @param pin The GPIO pin connected to the DS18B20 device
* @param addr The 64-bit address of the device to read. This can be set
* to ::DS18B20_ANY to read any device on the bus (but note
* that this will only work if there is exactly one device
* connected, or they will corrupt each others' transmissions)
*
* @returns The temperature in degrees Celsius, or NaN if there was an error.
*/
float ds18b20_measure_and_read(int pin, ds18b20_addr_t addr);
/** Perform a ds18b20_measure() followed by ds18b20_read_temp_multi()
*
* @param pin The GPIO pin connected to the DS18B20 bus
* @param addr_list A list of addresses for devices to read.
* @param addr_count The number of entries in `addr_list`.
* @param result_list An array of floats to hold the returned temperature
* values. It should have at least `addr_count` entries.
*
* @returns `true` if all temperatures were fetched successfully, or `false`
* if one or more had errors (the temperature for erroring devices will be
* returned as NaN).
*/
bool ds18b20_measure_and_read_multi(int pin, ds18b20_addr_t *addr_list, int addr_count, float *result_list);
/** Read the scratchpad data for a particular DS18B20 device.
*
* This is not generally necessary to do directly. It is done automatically
* as part of ds18b20_read_temperature().
*
* @param pin The GPIO pin connected to the DS18B20 device
* @param addr The 64-bit address of the device to read. This can be set
* to ::DS18B20_ANY to read any device on the bus (but note
* that this will only work if there is exactly one device
* connected, or they will corrupt each others' transmissions)
* @param buffer An 8-byte buffer to hold the read data.
*
* @returns `true` if the data was read successfully, or `false` on error.
*/
bool ds18b20_read_scratchpad(int pin, ds18b20_addr_t addr, uint8_t *buffer);
// The following are obsolete/deprecated APIs
typedef uint8_t ds18b20_scratchpad_t[9];
typedef struct {
uint8_t id;
float value;
} ds_sensor_t;
onewire_bus_handle_t bus;
ds18b20_temp_res_t res;
ds18b20_scratchpad_t scratchpad;
} ds18b20_handler_t;
// Scan all ds18b20 sensors on bus and return its amount.
// Result are saved in array of ds_sensor_t structure.
uint8_t ds18b20_read_all(uint8_t pin, ds_sensor_t *result);
/**
* @brief Initialize DS18B20
*
* @param device DS18B20 handler
* @param pin Data pin
* @param resolution Temperature resolution
*
* @retval 1: Success
* @retval 0: Incorrect pin or gpio configuration failed (Logs tells which happened)
*/
uint8_t ds18b20_init(ds18b20_handler_t *device, gpio_num_t pin, ds18b20_temp_res_t resolution);
// This method is just to demonstrate how to read
// temperature from single dallas chip.
float ds18b20_read_single(uint8_t pin);
/**
* @brief Send command to DS18B20
*
* @param device DS18B20 handler
* @param command Function command
*/
void ds18b20_send_command(ds18b20_handler_t *device, ds18b20_commands_t command);
/**
* @brief Write to scratchpad
*
* @param device DS18B20 handler
*/
void ds18b20_write_scratchpad(ds18b20_handler_t *device);
/**
* @brief Read from scratchpad
*
* @param device DS18B20 handler
*/
void ds18b20_read_scratchpad(ds18b20_handler_t *device);
/**
* @brief Copy to scratchpad
*
* @param device DS18B20 handler
*/
void ds18b20_copy_scratchpad(ds18b20_handler_t *device);
/**
* @brief Print scratchpad bytes
*
* @param device DS18B20 handler
*/
void ds18b20_print_scratchpad(ds18b20_handler_t *device);
/**
* @brief Initialize temperature conversion and wait for conversion
*
* Function sends CONV_T command and waits for X ms according to `ds18b20_temp_conv_time` static array
*
* @warning Should be called before `ds18b20_convert_temp()` function
*
* @param device DS18B20 handler
*/
void ds18b20_convert_temp(ds18b20_handler_t *device);
/**
* @brief Read temperature from scratchpad
*
* Function reads temperature from scratchpad and converts it to Celsius.
* @warning `ds18b20_convert_temp()` have to be called before for updated temperature.
*
* @param device DS18B20 handler
*/
float ds18b20_read_temp(ds18b20_handler_t *device);
#ifdef __cplusplus
}
#endif
#endif /* DRIVER_DS18B20_H_ */

View file

@ -1,31 +0,0 @@
The MIT License (MIT)
Copyright (c) 2014 zeroday nodemcu.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-------------------------------------------------------------------------------
Portions copyright (C) 2000 Dallas Semiconductor Corporation, under the
following additional terms:
Except as contained in this notice, the name of Dallas Semiconductor
shall not be used except as stated in the Dallas Semiconductor
Branding Policy.

View file

@ -1,14 +0,0 @@
# Yet another one wire driver for the ESP8266
This is a port of a bit-banging one wire driver based on the implementation
from NodeMCU.
This, in turn, appears to have been based on the PJRC Teensy driver
(https://www.pjrc.com/teensy/td_libs_OneWire.html), by Jim Studt, Paul
Stoffregen, and a host of others.
The original code is licensed under the MIT license. The CRC code was taken
(at least partially) from Dallas Semiconductor sample code, which was licensed
under an MIT license with an additional clause (prohibiting inappropriate use
of the Dallas Semiconductor name). See the accompanying LICENSE file for
details.

13
embadet/components/onewire/component.mk Normal file → Executable file
View file

@ -1,10 +1,5 @@
# Component makefile for extras/onewire
#
# Component Makefile
#
# expected anyone using onewire driver includes it as 'onewire/onewire.h'
INC_DIRS += $(onewire_ROOT)..
# args for passing into compile rule generation
onewire_INC_DIR =
onewire_SRC_DIR = $(onewire_ROOT)
$(eval $(call component_compile_rules,onewire))
COMPONENT_ADD_INCLUDEDIRS := .

560
embadet/components/onewire/onewire.c Normal file → Executable file
View file

@ -1,453 +1,175 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "rom/ets_sys.h"
#include "onewire.h"
#include "string.h"
#include "task.h"
#include "esp/gpio.h"
#define ONEWIRE_SELECT_ROM 0x55
#define ONEWIRE_SKIP_ROM 0xcc
#define ONEWIRE_SEARCH 0xf0
uint8_t onewire_configure_gpio(gpio_num_t pin, gpio_config_t *custom_config)
{
if (!GPIO_IS_VALID_GPIO(pin))
{
ESP_LOGE(TAG_ONEWIRE, "Provided pin is incorrect!");
// Waits up to `max_wait` microseconds for the specified pin to go high.
// Returns true if successful, false if the bus never comes high (likely
// shorted).
static inline bool _onewire_wait_for_bus(int pin, int max_wait) {
bool state;
for (int i = 0; i < ((max_wait + 4) / 5); i++) {
if (gpio_read(pin)) break;
sdk_os_delay_us(5);
return 0;
}
state = gpio_read(pin);
// Wait an extra 1us to make sure the devices have an adequate recovery
// time before we drive things low again.
sdk_os_delay_us(1);
return state;
gpio_config_t config = {};
if (!custom_config)
{
config.intr_type = GPIO_INTR_DISABLE;
config.mode = GPIO_MODE_OUTPUT_OD;
config.pin_bit_mask = ((uint32_t) 1 << pin);
config.pull_down_en = 0;
config.pull_up_en = 0;
}
else
{
config = *custom_config;
}
if (gpio_config(&config) != ESP_OK)
{
return 0;
}
return 1;
}
// Perform the onewire reset function. We will wait up to 250uS for
// the bus to come high, if it doesn't then it is broken or shorted
// and we return false;
//
// Returns true if a device asserted a presence pulse, false otherwise.
//
bool onewire_reset(int pin) {
bool r;
uint8_t onewire_init(onewire_bus_handle_t *bus, gpio_num_t bus_pin, gpio_config_t *custom_config)
{
if (!bus)
{
ESP_LOGW(TAG_ONEWIRE, "bus is null! (onewire_init)");
gpio_enable(pin, GPIO_OUT_OPEN_DRAIN);
gpio_write(pin, 1);
// wait until the wire is high... just in case
if (!_onewire_wait_for_bus(pin, 250)) return false;
return 0;
}
gpio_write(pin, 0);
sdk_os_delay_us(480);
bus->pin = bus_pin;
bus->mutex = xSemaphoreCreateMutex();
taskENTER_CRITICAL();
gpio_write(pin, 1); // allow it to float
sdk_os_delay_us(70);
r = !gpio_read(pin);
taskEXIT_CRITICAL();
// configure GPIO
if(!onewire_configure_gpio(bus_pin, custom_config))
{
return 0;
}
// Wait for all devices to finish pulling the bus low before returning
if (!_onewire_wait_for_bus(pin, 410)) return false;
return r;
return 1;
}
static bool _onewire_write_bit(int pin, bool v) {
if (!_onewire_wait_for_bus(pin, 10)) return false;
if (v) {
taskENTER_CRITICAL();
gpio_write(pin, 0); // drive output low
sdk_os_delay_us(10);
gpio_write(pin, 1); // allow output high
taskEXIT_CRITICAL();
sdk_os_delay_us(55);
} else {
taskENTER_CRITICAL();
gpio_write(pin, 0); // drive output low
sdk_os_delay_us(65);
gpio_write(pin, 1); // allow output high
taskEXIT_CRITICAL();
uint8_t onewire_reset(onewire_bus_handle_t *bus)
{
uint8_t presence;
if (xSemaphoreTake(bus->mutex, _BLOCK_TIME))
{
gpio_set_level(bus->pin, 0); // Send reset pulse
ets_delay_us(_ONEWIRE_RESET_WAIT);
gpio_set_level(bus->pin, 1); // Leave floating
ets_delay_us(_ONEWIRE_PRESENCE_WAIT);
presence = !gpio_get_level(bus->pin);
xSemaphoreGive(bus->mutex);
}
sdk_os_delay_us(1);
else
{
ESP_LOGE(TAG_ONEWIRE, _SEMFAIL_MSG, "onewire_reset");
return true;
}
static int _onewire_read_bit(int pin) {
int r;
if (!_onewire_wait_for_bus(pin, 10)) return -1;
taskENTER_CRITICAL();
gpio_write(pin, 0);
sdk_os_delay_us(2);
gpio_write(pin, 1); // let pin float, pull up will raise
sdk_os_delay_us(11);
r = gpio_read(pin); // Must sample within 15us of start
taskEXIT_CRITICAL();
sdk_os_delay_us(48);
return r;
}
// Write a byte. The writing code uses open-drain mode and expects the pullup
// resistor to pull the line high when not driven low. If you need strong
// power after the write (e.g. DS18B20 in parasite power mode) then call
// onewire_power() after this is complete to actively drive the line high.
//
bool onewire_write(int pin, uint8_t v) {
uint8_t bitMask;
for (bitMask = 0x01; bitMask; bitMask <<= 1) {
if (!_onewire_write_bit(pin, (bitMask & v))) {
return false;
}
}
return true;
}
bool onewire_write_bytes(int pin, const uint8_t *buf, size_t count) {
size_t i;
for (i = 0; i < count; i++) {
if (!onewire_write(pin, buf[i])) {
return false;
}
}
return true;
}
// Read a byte
//
int onewire_read(int pin) {
uint8_t bitMask;
int r = 0;
int bit;
for (bitMask = 0x01; bitMask; bitMask <<= 1) {
bit = _onewire_read_bit(pin);
if (bit < 0) {
return -1;
} else if (bit) {
r |= bitMask;
}
}
return r;
ets_delay_us(_ONEWIRE_RESET_RECOVERY);
return presence;
}
bool onewire_read_bytes(int pin, uint8_t *buf, size_t count) {
size_t i;
int b;
void onewire_write_bit(onewire_bus_handle_t *bus, uint8_t bit)
{
if (xSemaphoreTake(bus->mutex, _BLOCK_TIME))
{
if (bit)
{
// Write 1
gpio_set_level(bus->pin, 0);
ets_delay_us(_ONEWIRE_WRITE1_LOW);
for (i = 0; i < count; i++) {
b = onewire_read(pin);
if (b < 0) return false;
buf[i] = b;
gpio_set_level(bus->pin, 1);
ets_delay_us(_ONEWIRE_WRITE1_WAIT);
}
else
{
// Write 0
gpio_set_level(bus->pin, 0);
ets_delay_us(_ONEWIRE_WRITE0_LOW);
gpio_set_level(bus->pin, 1);
ets_delay_us(_ONEWIRE_WRITE0_WAIT);
}
xSemaphoreGive(bus->mutex);
}
else
{
ESP_LOGE(TAG_ONEWIRE, _SEMFAIL_MSG, "onewire_write_bit");
}
return true;
}
bool onewire_select(int pin, onewire_addr_t addr) {
uint8_t onewire_read_bit(onewire_bus_handle_t *bus)
{
uint8_t bit;
if (xSemaphoreTake(bus->mutex, _BLOCK_TIME))
{
gpio_set_level(bus->pin, 0);
ets_delay_us(_ONEWIRE_WRITE1_LOW);
gpio_set_level(bus->pin, 1);
ets_delay_us(_ONEWIRE_READ_WAIT);
bit = !gpio_get_level(bus->pin);
xSemaphoreGive(bus->mutex);
ets_delay_us(_ONEWIRE_READ_RECOVERY);
}
else
{
ESP_LOGE(TAG_ONEWIRE, _SEMFAIL_MSG, "onewire_read_bit");
return -1;
}
return bit;
}
void onewire_write_byte(onewire_bus_handle_t *bus, uint8_t byte)
{
uint8_t i;
if (!onewire_write(pin, ONEWIRE_SELECT_ROM)) {
return false;
for (i = 0; i < 8; i++)
{
onewire_write_bit(bus, (byte >> i) & 0x01);
}
for (i = 0; i < 8; i++) {
if (!onewire_write(pin, addr & 0xff)) {
return false;
}
addr >>= 8;
}
return true;
}
bool onewire_skip_rom(int pin) {
return onewire_write(pin, ONEWIRE_SKIP_ROM);
}
bool onewire_power(int pin) {
// Make sure the bus is not being held low before driving it high, or we
// may end up shorting ourselves out.
if (!_onewire_wait_for_bus(pin, 10)) return false;
gpio_enable(pin, GPIO_OUTPUT);
gpio_write(pin, 1);
return true;
}
void onewire_depower(int pin) {
gpio_enable(pin, GPIO_OUT_OPEN_DRAIN);
}
void onewire_search_start(onewire_search_t *search) {
// reset the search state
memset(search, 0, sizeof(*search));
}
void onewire_search_prefix(onewire_search_t *search, uint8_t family_code) {
uint8_t onewire_read_byte(onewire_bus_handle_t *bus)
{
uint8_t i;
uint8_t byte = 0x0;
search->rom_no[0] = family_code;
for (i = 1; i < 8; i++) {
search->rom_no[i] = 0;
for (i = 0; i < 8; i++)
{
byte |= (!onewire_read_bit(bus) << i);
}
search->last_discrepancy = 64;
search->last_device_found = false;
return byte;
}
// Perform a search. If the next device has been successfully enumerated, its
// ROM address will be returned. If there are no devices, no further
// devices, or something horrible happens in the middle of the
// enumeration then ONEWIRE_NONE is returned. Use OneWire::reset_search() to
// start over.
//
// --- Replaced by the one from the Dallas Semiconductor web site ---
//--------------------------------------------------------------------------
// Perform the 1-Wire Search Algorithm on the 1-Wire bus using the existing
// search state.
// Return 1 : device found, ROM number in ROM_NO buffer
// 0 : device not found, end of search
//
onewire_addr_t onewire_search_next(onewire_search_t *search, int pin) {
//TODO: add more checking for read/write errors
uint8_t id_bit_number;
uint8_t last_zero, search_result;
int rom_byte_number;
int8_t id_bit, cmp_id_bit;
onewire_addr_t addr;
unsigned char rom_byte_mask;
bool search_direction;
void onewire_send_command(onewire_bus_handle_t *bus, onewire_rom_commands_t command)
{
uint8_t payload = 0x0 ^ command;
// initialize for search
id_bit_number = 1;
last_zero = 0;
rom_byte_number = 0;
rom_byte_mask = 1;
search_result = 0;
// if the last call was not the last one
if (!search->last_device_found) {
// 1-Wire reset
if (!onewire_reset(pin)) {
// reset the search
search->last_discrepancy = 0;
search->last_device_found = false;
return ONEWIRE_NONE;
}
// issue the search command
onewire_write(pin, ONEWIRE_SEARCH);
// loop to do the search
do {
// read a bit and its complement
id_bit = _onewire_read_bit(pin);
cmp_id_bit = _onewire_read_bit(pin);
// check for no devices on 1-wire
if ((id_bit < 0) || (cmp_id_bit < 0)) {
// Read error
break;
} else if ((id_bit == 1) && (cmp_id_bit == 1)) {
break;
} else {
// all devices coupled have 0 or 1
if (id_bit != cmp_id_bit) {
search_direction = id_bit; // bit write value for search
} else {
// if this discrepancy if before the Last Discrepancy
// on a previous next then pick the same as last time
if (id_bit_number < search->last_discrepancy) {
search_direction = ((search->rom_no[rom_byte_number] & rom_byte_mask) > 0);
} else {
// if equal to last pick 1, if not then pick 0
search_direction = (id_bit_number == search->last_discrepancy);
}
// if 0 was picked then record its position in LastZero
if (!search_direction) {
last_zero = id_bit_number;
}
}
// set or clear the bit in the ROM byte rom_byte_number
// with mask rom_byte_mask
if (search_direction) {
search->rom_no[rom_byte_number] |= rom_byte_mask;
} else {
search->rom_no[rom_byte_number] &= ~rom_byte_mask;
}
// serial number search direction write bit
_onewire_write_bit(pin, search_direction);
// increment the byte counter id_bit_number
// and shift the mask rom_byte_mask
id_bit_number++;
rom_byte_mask <<= 1;
// if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask
if (rom_byte_mask == 0) {
rom_byte_number++;
rom_byte_mask = 1;
}
}
} while (rom_byte_number < 8); // loop until through all ROM bytes 0-7
// if the search was successful then
if (!(id_bit_number < 65)) {
// search successful so set last_discrepancy,last_device_found,search_result
search->last_discrepancy = last_zero;
// check for last device
if (search->last_discrepancy == 0) {
search->last_device_found = true;
}
search_result = 1;
}
}
// if no device found then reset counters so next 'search' will be like a first
if (!search_result || !search->rom_no[0]) {
search->last_discrepancy = 0;
search->last_device_found = false;
return ONEWIRE_NONE;
} else {
addr = 0;
for (rom_byte_number = 7; rom_byte_number >= 0; rom_byte_number--) {
addr = (addr << 8) | search->rom_no[rom_byte_number];
}
//printf("Ok I found something at %08x%08x...\n", (uint32_t)(addr >> 32), (uint32_t)addr);
}
return addr;
}
// The 1-Wire CRC scheme is described in Maxim Application Note 27:
// "Understanding and Using Cyclic Redundancy Checks with Maxim iButton Products"
//
#if ONEWIRE_CRC8_TABLE
// This table comes from Dallas sample code where it is freely reusable,
// though Copyright (C) 2000 Dallas Semiconductor Corporation
static const uint8_t dscrc_table[] = {
0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65,
157,195, 33,127,252,162, 64, 30, 95, 1,227,189, 62, 96,130,220,
35,125,159,193, 66, 28,254,160,225,191, 93, 3,128,222, 60, 98,
190,224, 2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255,
70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89, 7,
219,133,103, 57,186,228, 6, 88, 25, 71,165,251,120, 38,196,154,
101, 59,217,135, 4, 90,184,230,167,249, 27, 69,198,152,122, 36,
248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91, 5,231,185,
140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205,
17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80,
175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238,
50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115,
202,148,118, 40,171,245, 23, 73, 8, 86,180,234,105, 55,213,139,
87, 9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22,
233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168,
116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53};
#ifndef pgm_read_byte
#define pgm_read_byte(addr) (*(const uint8_t *)(addr))
#endif
//
// Compute a Dallas Semiconductor 8 bit CRC. These show up in the ROM
// and the registers. (note: this might better be done without to
// table, it would probably be smaller and certainly fast enough
// compared to all those delayMicrosecond() calls. But I got
// confused, so I use this table from the examples.)
//
uint8_t onewire_crc8(const uint8_t *data, uint8_t len) {
uint8_t crc = 0;
while (len--) {
crc = pgm_read_byte(dscrc_table + (crc ^ *data++));
}
return crc;
}
#else
//
// Compute a Dallas Semiconductor 8 bit CRC directly.
// this is much slower, but much smaller, than the lookup table.
//
uint8_t onewire_crc8(const uint8_t *data, uint8_t len) {
uint8_t crc = 0;
while (len--) {
uint8_t inbyte = *data++;
for (int i = 8; i; i--) {
uint8_t mix = (crc ^ inbyte) & 0x01;
crc >>= 1;
if (mix) crc ^= 0x8C;
inbyte >>= 1;
}
}
return crc;
}
#endif
// Compute the 1-Wire CRC16 and compare it against the received CRC.
// Example usage (reading a DS2408):
// // Put everything in a buffer so we can compute the CRC easily.
// uint8_t buf[13];
// buf[0] = 0xF0; // Read PIO Registers
// buf[1] = 0x88; // LSB address
// buf[2] = 0x00; // MSB address
// WriteBytes(net, buf, 3); // Write 3 cmd bytes
// ReadBytes(net, buf+3, 10); // Read 6 data bytes, 2 0xFF, 2 CRC16
// if (!CheckCRC16(buf, 11, &buf[11])) {
// // Handle error.
// }
//
// @param input - Array of bytes to checksum.
// @param len - How many bytes to use.
// @param inverted_crc - The two CRC16 bytes in the received data.
// This should just point into the received data,
// *not* at a 16-bit integer.
// @param crc - The crc starting value (optional)
// @return 1, iff the CRC matches.
bool onewire_check_crc16(const uint8_t* input, size_t len, const uint8_t* inverted_crc, uint16_t crc_iv) {
uint16_t crc = ~onewire_crc16(input, len, crc_iv);
return (crc & 0xFF) == inverted_crc[0] && (crc >> 8) == inverted_crc[1];
}
// Compute a Dallas Semiconductor 16 bit CRC. This is required to check
// the integrity of data received from many 1-Wire devices. Note that the
// CRC computed here is *not* what you'll get from the 1-Wire network,
// for two reasons:
// 1) The CRC is transmitted bitwise inverted.
// 2) Depending on the endian-ness of your processor, the binary
// representation of the two-byte return value may have a different
// byte order than the two bytes you get from 1-Wire.
// @param input - Array of bytes to checksum.
// @param len - How many bytes to use.
// @param crc - The crc starting value (optional)
// @return The CRC16, as defined by Dallas Semiconductor.
uint16_t onewire_crc16(const uint8_t* input, size_t len, uint16_t crc_iv) {
uint16_t crc = crc_iv;
static const uint8_t oddparity[16] =
{ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 };
uint16_t i;
for (i = 0; i < len; i++) {
// Even though we're just copying a byte from the input,
// we'll be doing 16-bit computation with it.
uint16_t cdata = input[i];
cdata = (cdata ^ crc) & 0xff;
crc >>= 8;
if (oddparity[cdata & 0x0F] ^ oddparity[cdata >> 4])
crc ^= 0xC001;
cdata <<= 6;
crc ^= cdata;
cdata <<= 1;
crc ^= cdata;
}
return crc;
onewire_write_byte(bus, payload);
}

290
embadet/components/onewire/onewire.h Normal file → Executable file
View file

@ -1,243 +1,121 @@
#ifndef __ONEWIRE_H__
#define __ONEWIRE_H__
#ifndef ONEWIRE_H
#define ONEWIRE_H
#include <espressif/esp_misc.h> // sdk_os_delay_us
#include "FreeRTOS.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "driver/gpio.h"
#include "esp_types.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
#define _ONEWIRE_WRITE1_LOW 6
#define _ONEWIRE_WRITE1_WAIT 64
#define _ONEWIRE_WRITE0_LOW 60
#define _ONEWIRE_WRITE0_WAIT 10
#define _ONEWIRE_READ_WAIT 9
#define _ONEWIRE_READ_RECOVERY 55
#define _ONEWIRE_RESET_WAIT 480
#define _ONEWIRE_PRESENCE_WAIT 70
#define _ONEWIRE_RESET_RECOVERY 410
/** @file onewire.h
*
* Routines to access devices using the Dallas Semiconductor 1-Wire(tm)
* protocol.
*/
#define _BLOCK_TIME pdMS_TO_TICKS(1000)
#define _SEMFAIL_MSG "Failed to obtain semaphore. (%s)"
/** Select the table-lookup method of computing the 8-bit CRC
* by setting this to 1 during compilation. The lookup table enlarges code
* size by about 250 bytes. By default, a slower but very compact algorithm
* is used.
*/
#ifndef ONEWIRE_CRC8_TABLE
#define ONEWIRE_CRC8_TABLE 0
#endif
static const char *TAG_ONEWIRE = "ONEWIRE";
/** Type used to hold all 1-Wire device ROM addresses (64-bit) */
typedef uint64_t onewire_addr_t;
typedef enum {
_ROM_READ = 0x33,
_ROM_SEARCH = 0xF0,
_ROM_MATCH = 0x55,
_ROM_SKIP = 0xCC
} onewire_rom_commands_t;
/** Structure to contain the current state for onewire_search_next(), etc */
typedef struct {
uint8_t rom_no[8];
uint8_t last_discrepancy;
bool last_device_found;
} onewire_search_t;
gpio_num_t pin;
SemaphoreHandle_t mutex;
} onewire_bus_handle_t;
/** ::ONEWIRE_NONE is an invalid ROM address that will never occur in a device
* (CRC mismatch), and so can be useful as an indicator for "no-such-device",
* etc.
/**
* @brief Configure gpio pins for onewire communication
*
* Set `custom_config` to NULL for default config.
*
* @param pin Bus pin
* @param custom_config Custom gpio config
*
* @retval 1: Success
* @retval 0: Incorrect pin or gpio configuration failed (Logs tells which happened)
*/
#define ONEWIRE_NONE ((onewire_addr_t)(0xffffffffffffffffLL))
uint8_t onewire_configure_gpio(gpio_num_t pin, gpio_config_t *custom_config);
/** Perform a 1-Wire reset cycle.
/**
* @brief Initalize onewire bus
*
* @param pin The GPIO pin connected to the 1-Wire bus.
* Set `custom_config` to NULL for default config.
* @warning MUST be called before any other library function!
*
* @returns `true` if at least one device responds with a presence pulse,
* `false` if no devices were detected (or the bus is shorted, etc)
* @param bus Bus handle
* @param pin Bus pin
* @param custom_config Custom gpio config
*
* @retval 1: Success
* @retval 0: `bus` is NULL or gpio configuration failed (Logs tells which happened)
*/
bool onewire_reset(int pin);
uint8_t onewire_init(onewire_bus_handle_t *bus, gpio_num_t bus_pin, gpio_config_t *custom_config);
/** Issue a 1-Wire rom select command to select a particular device.
/**
* @brief Send reset pulse
*
* It is necessary to call onewire_reset() before calling this function.
* @param bus Bus handle
*
* @param pin The GPIO pin connected to the 1-Wire bus.
* @param addr The ROM address of the device to select
*
* @returns `true` if the "ROM select" command could be succesfully issued,
* `false` if there was an error.
* @retval 1: Success (device sent presence pulse)
* @retval -1: Failed to obtain semaphore for gpio handling
* @retval 0: Device failed to return presence pulse
*/
bool onewire_select(int pin, const onewire_addr_t addr);
uint8_t onewire_reset(onewire_bus_handle_t *bus);
/** Issue a 1-Wire "skip ROM" command to select *all* devices on the bus.
/**
* @brief Write bit
*
* It is necessary to call onewire_reset() before calling this function.
*
* @param pin The GPIO pin connected to the 1-Wire bus.
*
* @returns `true` if the "skip ROM" command could be succesfully issued,
* `false` if there was an error.
* @param bus Bus handle
* @param bit Bit to send
*/
bool onewire_skip_rom(int pin);
void onewire_write_bit(onewire_bus_handle_t *bus, uint8_t bit);
/** Write a byte on the onewire bus.
/**
* @brief Write byte
*
* The writing code uses open-drain mode and expects the pullup resistor to
* pull the line high when not driven low. If you need strong power after the
* write (e.g. DS18B20 in parasite power mode) then call onewire_power() after
* this is complete to actively drive the line high.
*
* @param pin The GPIO pin connected to the 1-Wire bus.
* @param v The byte value to write
*
* @returns `true` if successful, `false` on error.
* @param bus Bus handle
* @param bit Byte to send
*/
bool onewire_write(int pin, uint8_t v);
void onewire_write_byte(onewire_bus_handle_t *bus, uint8_t byte);
/** Write multiple bytes on the 1-Wire bus.
/**
* @brief Read bit
*
* See onewire_write() for more info.
* @param bus Bus handle
*
* @param pin The GPIO pin connected to the 1-Wire bus.
* @param buf A pointer to the buffer of bytes to be written
* @param count Number of bytes to write
*
* @returns `true` if all bytes written successfully, `false` on error.
* @retval 1: Device returned 1
* @retval 0: Device returned 0
* @retval -1: Failed to obtain semaphore for gpio handling
*/
bool onewire_write_bytes(int pin, const uint8_t *buf, size_t count);
uint8_t onewire_read_bit(onewire_bus_handle_t *bus);
/** Read a byte from a 1-Wire device.
/**
* @brief Read bit
*
* @param pin The GPIO pin connected to the 1-Wire bus.
* @param bus Bus handle
*
* @returns the read byte on success, negative value on error.
* @return Byte returned by device
*/
int onewire_read(int pin);
uint8_t onewire_read_byte(onewire_bus_handle_t *bus);
/** Read multiple bytes from a 1-Wire device.
/**
* @brief Send command to device
*
* @param pin The GPIO pin connected to the 1-Wire bus.
* @param buf A pointer to the buffer to contain the read bytes
* @param count Number of bytes to read
* @param bus Bus handle
* @param command Onewire rom command
*
* @returns `true` on success, `false` on error.
*/
bool onewire_read_bytes(int pin, uint8_t *buf, size_t count);
void onewire_send_command(onewire_bus_handle_t *bus, onewire_rom_commands_t command);
/** Actively drive the bus high to provide extra power for certain operations
* of parasitically-powered devices.
*
* For parasitically-powered devices which need more power than can be
* provided via the normal pull-up resistor, it may be necessary for some
* operations to drive the bus actively high. This function can be used to
* perform that operation.
*
* The bus can be depowered once it is no longer needed by calling
* onewire_depower(), or it will be depowered automatically the next time
* onewire_reset() is called to start another command.
*
* Note: Make sure the device(s) you are powering will not pull more current
* than the ESP8266 is able to supply via its GPIO pins (this is especially
* important when multiple devices are on the same bus and they are all
* performing a power-intensive operation at the same time (i.e. multiple
* DS18B20 sensors, which have all been given a "convert T" operation by using
* onewire_skip_rom())).
*
* Note: This routine will check to make sure that the bus is already high
* before driving it, to make sure it doesn't attempt to drive it high while
* something else is pulling it low (which could cause a reset or damage the
* ESP8266).
*
* @param pin The GPIO pin connected to the 1-Wire bus.
*
* @returns `true` on success, `false` on error.
*/
bool onewire_power(int pin);
/** Stop forcing power onto the bus.
*
* You only need to do this if you previously called onewire_power() to drive
* the bus high and now want to allow it to float instead. Note that
* onewire_reset() will also automatically depower the bus first, so you do
* not need to call this first if you just want to start a new operation.
*
* @param pin The GPIO pin connected to the 1-Wire bus.
*/
void onewire_depower(int pin);
/** Clear the search state so that it will start from the beginning on the next
* call to onewire_search_next().
*
* @param search The onewire_search_t structure to reset.
*/
void onewire_search_start(onewire_search_t *search);
/** Setup the search to search for devices with the specified "family code".
*
* @param search The onewire_search_t structure to update.
* @param family_code The "family code" to search for.
*/
void onewire_search_prefix(onewire_search_t *search, uint8_t family_code);
/** Search for the next device on the bus.
*
* The order of returned device addresses is deterministic. You will always
* get the same devices in the same order.
*
* @returns the address of the next device on the bus, or ::ONEWIRE_NONE if
* there is no next address. ::ONEWIRE_NONE might also mean that the bus is
* shorted, there are no devices, or you have already retrieved all of them.
*
* It might be a good idea to check the CRC to make sure you didn't get
* garbage.
*/
onewire_addr_t onewire_search_next(onewire_search_t *search, int pin);
/** Compute a Dallas Semiconductor 8 bit CRC.
*
* These are used in the ROM address and scratchpad registers to verify the
* transmitted data is correct.
*/
uint8_t onewire_crc8(const uint8_t *data, uint8_t len);
/** Compute the 1-Wire CRC16 and compare it against the received CRC.
*
* Example usage (reading a DS2408):
* @code
* // Put everything in a buffer so we can compute the CRC easily.
* uint8_t buf[13];
* buf[0] = 0xF0; // Read PIO Registers
* buf[1] = 0x88; // LSB address
* buf[2] = 0x00; // MSB address
* onewire_write_bytes(pin, buf, 3); // Write 3 cmd bytes
* onewire_read_bytes(pin, buf+3, 10); // Read 6 data bytes, 2 0xFF, 2 CRC16
* if (!onewire_check_crc16(buf, 11, &buf[11])) {
* // TODO: Handle error.
* }
* @endcode
*
* @param input Array of bytes to checksum.
* @param len Number of bytes in `input`
* @param inverted_crc The two CRC16 bytes in the received data.
* This should just point into the received data,
* *not* at a 16-bit integer.
* @param crc_iv The crc starting value (optional)
*
* @returns `true` if the CRC matches, `false` otherwise.
*/
bool onewire_check_crc16(const uint8_t* input, size_t len, const uint8_t* inverted_crc, uint16_t crc_iv);
/** Compute a Dallas Semiconductor 16 bit CRC.
*
* This is required to check the integrity of data received from many 1-Wire
* devices. Note that the CRC computed here is *not* what you'll get from the
* 1-Wire network, for two reasons:
* 1. The CRC is transmitted bitwise inverted.
* 2. Depending on the endian-ness of your processor, the binary
* representation of the two-byte return value may have a different
* byte order than the two bytes you get from 1-Wire.
*
* @param input Array of bytes to checksum.
* @param len How many bytes are in `input`.
* @param crc_iv The crc starting value (optional)
*
* @returns the CRC16, as defined by Dallas Semiconductor.
*/
uint16_t onewire_crc16(const uint8_t* input, size_t len, uint16_t crc_iv);
#ifdef __cplusplus
}
#endif
#endif /* __ONEWIRE_H__ */

View file

@ -1,45 +1,45 @@
#include "esp_log.h"
#include <stdio.h>
#include <time.h>
#include <onewire.h>
#include <ds18b20.h> // Die Header-Datei mit DS18B20-Funktionen
#include <task.h>
#define GPIO_PIN 4 // GPIO Pin, an den der DS18B20 angeschlossen ist
#define INTERVAL 100 // Intervall in Sekunden
int app_main() {
// Create variable for handler
ds18b20_handler_t sensor;
void delay(int seconds) {
time_t start_time = time(NULL);
while (time(NULL) - start_time < seconds);
}
// Check for any initialization failures
if (!ds18b20_init(&sensor, GPIO_NUM_2, TEMP_RES_12_BIT))
{
ESP_LOGE("TAG", "Failed to initalize DS18B20!");
int main() {
ds18b20_addr_t sensor_address;
// Sensoren auf dem Bus scannen (angenommen, dass nur ein Sensor angeschlossen ist)
int sensor_count = ds18b20_scan_devices(GPIO_PIN, &sensor_address, 1);
if (sensor_count <= 0) {
printf("Kein DS18B20-Sensor gefunden!\n");
return -1;
return 0; // Exit
}
while (1) {
// Temperaturmessung starten
bool success = ds18b20_measure(GPIO_PIN, sensor_address, true);
if (!success) {
printf("Fehler bei der Temperaturmessung\n");
} else {
// Temperaturwert lesen
float temperature = ds18b20_read_temperature(GPIO_PIN, sensor_address);
if (temperature != temperature) { // NaN-Check
printf("Fehler beim Lesen der Temperatur\n");
} else {
printf("Aktuelle Temperatur: %.2f°C\n", temperature);
}
}
float temp = 0;
// If you doesn't convert temperature you may read 85.0 Celsius,
// as it is default temperature set by DS18B20 if convert command wasn't issued.
// Read temperature
printf("hit");
for(int i = 0; i < 30; ++i) {
// Initalize conversion
ds18b20_convert_temp(&sensor);
temp = ds18b20_read_temp(&sensor);
vTaskDelay(5000 / portTICK_PERIOD_MS);
printf("\n");
printf( "Temperature = %.4f", temp);
};
// Print temperature with 4 decimal places
// (12 bit resolution measurement accuracy is 0.0625 Celsius)
ESP_LOGI("TAG", "Temperature = %.4f", temp);
// Wartezeit von 100 Sekunden
delay(INTERVAL);
}
return 0;
}