Implement new ds18b20 APIs
This commit is contained in:
parent
60e468bdb2
commit
494c2d9cec
4 changed files with 311 additions and 46 deletions
|
@ -19,15 +19,14 @@
|
|||
|
||||
// DS18B20 driver
|
||||
#include "ds18b20/ds18b20.h"
|
||||
// Onewire init
|
||||
#include "onewire/onewire.h"
|
||||
|
||||
void broadcast_temperature(void *pvParameters)
|
||||
{
|
||||
|
||||
uint8_t amount = 0;
|
||||
uint8_t sensors = 2;
|
||||
ds_sensor_t t[sensors];
|
||||
uint8_t sensors = 1;
|
||||
ds18b20_addr_t addrs[sensors];
|
||||
float results[sensors];
|
||||
|
||||
// Use GPIO 13 as one wire pin.
|
||||
uint8_t GPIO_FOR_ONE_WIRE = 13;
|
||||
|
@ -36,8 +35,6 @@ void broadcast_temperature(void *pvParameters)
|
|||
|
||||
// Broadcaster part
|
||||
err_t err;
|
||||
// Initialize one wire bus.
|
||||
onewire_init(GPIO_FOR_ONE_WIRE);
|
||||
|
||||
while(1) {
|
||||
|
||||
|
@ -66,18 +63,17 @@ void broadcast_temperature(void *pvParameters)
|
|||
|
||||
for(;;) {
|
||||
// Search all DS18B20, return its amount and feed 't' structure with result data.
|
||||
amount = ds18b20_read_all(GPIO_FOR_ONE_WIRE, t);
|
||||
amount = ds18b20_scan_devices(GPIO_FOR_ONE_WIRE, addrs, sensors);
|
||||
|
||||
if (amount < sensors){
|
||||
printf("Something is wrong, I expect to see %d sensors \nbut just %d was detected!\n", sensors, amount);
|
||||
}
|
||||
|
||||
for (int i = 0; i < amount; ++i)
|
||||
ds18b20_measure_and_read_multi(GPIO_FOR_ONE_WIRE, addrs, sensors, results);
|
||||
for (int i = 0; i < sensors; ++i)
|
||||
{
|
||||
int intpart = (int)t[i].value;
|
||||
int fraction = (int)((t[i].value - intpart) * 100);
|
||||
// Multiple "" here is just to satisfy compiler and don`t raise 'hex escape sequence out of range' warning.
|
||||
sprintf(msg, "Sensor %d report: %d.%02d ""\xC2""\xB0""C\n",t[i].id, intpart, fraction);
|
||||
// ("\xC2\xB0" is the degree character (U+00B0) in UTF-8)
|
||||
sprintf(msg, "Sensor %08x%08x reports: %f \xC2\xB0""C\n", (uint32_t)(addrs[i] >> 32), (uint32_t)addrs[i], results[i]);
|
||||
printf("%s", msg);
|
||||
|
||||
struct netbuf* buf = netbuf_new();
|
||||
|
|
|
@ -1,55 +1,78 @@
|
|||
/* ds18b20 - Retrieves temperature from ds18b20 sensors and print it out.
|
||||
/* ds18b20_onewire.c - Retrieves readings from one or more DS18B20 temperature
|
||||
* sensors, and prints the results to stdout.
|
||||
*
|
||||
* This sample code is in the public domain.,
|
||||
*/
|
||||
#include "espressif/esp_common.h"
|
||||
#include "esp/uart.h"
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "timers.h"
|
||||
#include "queue.h"
|
||||
#include "esp/uart.h"
|
||||
|
||||
// DS18B20 driver
|
||||
#include "ds18b20/ds18b20.h"
|
||||
|
||||
void print_temperature(void *pvParameters)
|
||||
{
|
||||
int delay = 500;
|
||||
uint8_t amount = 0;
|
||||
// Declare amount of sensors
|
||||
uint8_t sensors = 2;
|
||||
ds_sensor_t t[sensors];
|
||||
#define SENSOR_GPIO 13
|
||||
#define MAX_SENSORS 8
|
||||
#define RESCAN_INTERVAL 8
|
||||
#define LOOP_DELAY_MS 250
|
||||
|
||||
// Use GPIO 13 as one wire pin.
|
||||
uint8_t GPIO_FOR_ONE_WIRE = 13;
|
||||
void print_temperature(void *pvParameters) {
|
||||
ds18b20_addr_t addrs[MAX_SENSORS];
|
||||
float temps[MAX_SENSORS];
|
||||
int sensor_count;
|
||||
|
||||
// There is no special initialization required before using the ds18b20
|
||||
// routines. However, we make sure that the internal pull-up resistor is
|
||||
// enabled on the GPIO pin so that one can connect up a sensor without
|
||||
// needing an external pull-up (Note: The internal (~47k) pull-ups of the
|
||||
// ESP8266 do appear to work, at least for simple setups (one or two sensors
|
||||
// connected with short leads), but do not technically meet the pull-up
|
||||
// requirements from the DS18B20 datasheet and may not always be reliable.
|
||||
// For a real application, a proper 4.7k external pull-up resistor is
|
||||
// recommended instead!)
|
||||
|
||||
gpio_set_pullup(SENSOR_GPIO, true, true);
|
||||
|
||||
while(1) {
|
||||
// Search all DS18B20, return its amount and feed 't' structure with result data.
|
||||
amount = ds18b20_read_all(GPIO_FOR_ONE_WIRE, t);
|
||||
// Every RESCAN_INTERVAL samples, check to see if the sensors connected
|
||||
// to our bus have changed.
|
||||
sensor_count = ds18b20_scan_devices(SENSOR_GPIO, addrs, MAX_SENSORS);
|
||||
|
||||
if (amount < sensors){
|
||||
printf("Something is wrong, I expect to see %d sensors \nbut just %d was detected!\n", sensors, amount);
|
||||
}
|
||||
if (sensor_count < 1) {
|
||||
printf("\nNo sensors detected!\n");
|
||||
} else {
|
||||
printf("\n%d sensors detected:\n", sensor_count);
|
||||
// If there were more sensors found than we have space to handle,
|
||||
// just report the first MAX_SENSORS..
|
||||
if (sensor_count > MAX_SENSORS) sensor_count = MAX_SENSORS;
|
||||
|
||||
for (int i = 0; i < amount; ++i)
|
||||
{
|
||||
int intpart = (int)t[i].value;
|
||||
int fraction = (int)((t[i].value - intpart) * 100);
|
||||
// Multiple "" here is just to satisfy compiler and don`t raise 'hex escape sequence out of range' warning.
|
||||
printf("Sensor %d report: %d.%02d ""\xC2""\xB0""C\n",t[i].id, intpart, fraction);
|
||||
// Do a number of temperature samples, and print the results.
|
||||
for (int i = 0; i < RESCAN_INTERVAL; i++) {
|
||||
ds18b20_measure_and_read_multi(SENSOR_GPIO, addrs, sensor_count, temps);
|
||||
for (int j = 0; j < sensor_count; j++) {
|
||||
// The DS18B20 address is a 64-bit integer, but newlib-nano
|
||||
// printf does not support printing 64-bit values, so we
|
||||
// split it up into two 32-bit integers and print them
|
||||
// back-to-back to make it look like one big hex number.
|
||||
uint32_t addr0 = addrs[j] >> 32;
|
||||
uint32_t addr1 = addrs[j];
|
||||
float temp_c = temps[j];
|
||||
float temp_f = (temp_c * 1.8) + 32;
|
||||
printf(" Sensor %08x%08x reports %f deg C (%f deg F)\n", addr0, addr1, temp_c, temp_f);
|
||||
}
|
||||
printf("\n");
|
||||
vTaskDelay(delay / portTICK_RATE_MS);
|
||||
|
||||
// Wait for a little bit between each sample (note that the
|
||||
// ds18b20_measure_and_read_multi operation already takes at
|
||||
// least 750ms to run, so this is on top of that delay).
|
||||
vTaskDelay(LOOP_DELAY_MS / portTICK_RATE_MS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void user_init(void)
|
||||
{
|
||||
void user_init(void) {
|
||||
uart_set_baud(0, 115200);
|
||||
|
||||
printf("SDK version:%s\n", sdk_system_get_sdk_version());
|
||||
|
||||
xTaskCreate(&print_temperature, (signed char *)"print_temperature", 256, NULL, 2, NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue