Implement new ds18b20 APIs

This commit is contained in:
Alex Stewart 2016-03-17 16:03:46 -07:00
parent 60e468bdb2
commit 494c2d9cec
4 changed files with 311 additions and 46 deletions

View file

@ -1,7 +1,7 @@
#include "FreeRTOS.h"
#include "task.h"
#include "math.h"
#include "onewire/onewire.h"
#include "ds18b20.h"
#define DS18B20_WRITE_SCRATCHPAD 0x4E
@ -16,6 +16,8 @@
#define DS18B20_ALARMSEARCH 0xEC
#define DS18B20_CONVERT_T 0x44
#define os_sleep_ms(x) vTaskDelay(((x) + portTICK_RATE_MS - 1) / portTICK_RATE_MS)
uint8_t ds18b20_read_all(uint8_t pin, ds_sensor_t *result) {
onewire_addr_t addr;
onewire_search_t search;
@ -108,3 +110,114 @@ float ds18b20_read_single(uint8_t pin) {
return temperature;
//printf("Got a DS18B20 Reading: %d.%02d\n", (int)temperature, (int)(temperature - (int)temperature) * 100);
}
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();
if (wait) {
os_sleep_ms(750);
onewire_depower(pin);
}
return true;
}
bool ds18b20_read_scratchpad(int pin, ds18b20_addr_t addr, uint8_t *buffer) {
uint8_t crc;
uint8_t expected_crc;
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);
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) {
printf("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;
}
float ds18b20_read_temperature(int pin, ds18b20_addr_t addr) {
uint8_t scratchpad[8];
int temp;
if (!ds18b20_read_scratchpad(pin, addr, scratchpad)) {
return NAN;
}
temp = scratchpad[1] << 8 | scratchpad[0];
return ((float)temp * 625.0)/10000;
}
float ds18b20_measure_and_read(int pin, ds18b20_addr_t addr) {
if (!ds18b20_measure(pin, addr, true)) {
return NAN;
}
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;
}
return false;
}
return ds18b20_read_temp_multi(pin, addr_list, addr_count, result_list);
}
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;
onewire_search_start(&search);
while ((addr = onewire_search_next(&search, pin)) != ONEWIRE_NONE) {
if (found < addr_count) {
addr_list[found] = addr;
}
found++;
}
return found;
}
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;
}

View file

@ -1,6 +1,139 @@
#ifndef DRIVER_DS18B20_H_
#define DRIVER_DS18B20_H_
#include "onewire/onewire.h"
/** @file ds18b20.h
*
* Communicate with the DS18B20 family of one-wire temperature sensor ICs.
*
*/
typedef onewire_addr_t ds18b20_addr_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 struct {
uint8_t id;
float value;