Skip to content

Commit

Permalink
feat: Improve DS1820 driver
Browse files Browse the repository at this point in the history
New features:
* Handle all types of DS1820 tempature sensors by detecting the family of the sensor and calculating the temperature accordingly
* Clean up some log prints
* Set the channel value with current temperature
* Update the reading every second instead of every 15s
  • Loading branch information
Lenart12 committed Oct 6, 2024
1 parent e0f5038 commit b1f5710
Showing 1 changed file with 137 additions and 25 deletions.
162 changes: 137 additions & 25 deletions src/driver/drv_ds1820_simple.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ static int Pin;
static int t=-127;
static int errcount=0;
static int lastconv; // secondsElapsed on last successfull reading
static uint8_t ds18_family = 0;


// usleep adopted from DHT driver
Expand Down Expand Up @@ -366,7 +367,109 @@ void DS1820_AppendInformationToHTTPIndexPage(http_request_t *request)
hprintf255(request, "<h5>DS1820 Temperature: %.2f C (read %i secs ago)</h5>",(float)t/100, g_secondsElapsed-lastconv);
}

// Adapted from Arduino OneWire library
int DS1820_DiscoverFamily() {
uint8_t id_bit_number;
uint8_t last_zero, rom_byte_number;
int search_result;
uint8_t id_bit, cmp_id_bit;

unsigned char rom_byte_mask, search_direction;

// initialize for search
id_bit_number = 1;
last_zero = 0;
rom_byte_number = 0;
rom_byte_mask = 1;
search_result = false;

uint8_t LastDiscrepancy = 0;
uint8_t LastFamilyDiscrepancy = 0;

char ROM_NO[8];
for (int i = 0; i < 8; i++) ROM_NO[i] = 0;

// 1-Wire reset
if (!OWReset(Pin)) {
addLogAdv(LOG_DEBUG, LOG_FEATURE_CFG, "DS1820 - Discover -- No device - Pin %i", Pin);
return false;
}

OWWriteByte(Pin,0xF0);

// loop to do the search
do
{
// read a bit and its complement
id_bit = OWReadBit(Pin);
cmp_id_bit = OWReadBit(Pin);

// check for no devices on 1-wire
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 < LastDiscrepancy) {
search_direction = ((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 == LastDiscrepancy);
}
// if 0 was picked then record its position in LastZero
if (search_direction == 0) {
last_zero = id_bit_number;

// check for Last discrepancy in family
if (last_zero < 9)
LastFamilyDiscrepancy = last_zero;
}
}

// set or clear the bit in the ROM byte rom_byte_number
// with mask rom_byte_mask
if (search_direction == 1)
ROM_NO[rom_byte_number] |= rom_byte_mask;
else
ROM_NO[rom_byte_number] &= ~rom_byte_mask;

// serial number search direction write bit
OWWriteBit(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 LastDiscrepancy,LastDeviceFlag,search_result
search_result = true;
}

// if no device found then reset counters so next 'search' will be like a first
if (!search_result || !ROM_NO[0]) {
addLogAdv(LOG_DEBUG, LOG_FEATURE_CFG, "DS1820 - Discover -- Search failed",Pin);
} else {
ds18_family = ROM_NO[0];
addLogAdv(LOG_DEBUG, LOG_FEATURE_CFG, "DS1820 - Discover -- Found device - %x%x%x%x%x%x%x%x",Pin,
ROM_NO[0], ROM_NO[1], ROM_NO[2], ROM_NO[3], ROM_NO[4], ROM_NO[5], ROM_NO[6], ROM_NO[7]);
}
return search_result;
}

void DS1820_OnEverySecond() {

Expand All @@ -379,10 +482,6 @@ void DS1820_OnEverySecond() {
// if (dsread == 1 && g_secondsElapsed % 5 == 2) {
// better if we don't use parasitic power, we can check if conversion is ready
if (dsread == 1 && DS1820TConversionDone(Pin) == 1) {

uint8_t Low=0,High=0,negative=0;
int Val,Tc;

if (OWReset(Pin) == 0) addLogAdv(LOG_ERROR, LOG_FEATURE_CFG, "DS1820 - Pin=%i -- Reset failed",Pin);
OWWriteByte(Pin,0xCC);
OWWriteByte(Pin,0xBE);
Expand All @@ -403,33 +502,37 @@ void DS1820_OnEverySecond() {
}
else
{
Low = scratchpad[0];
High = scratchpad[1];
int16_t raw = (scratchpad[1] << 8) | scratchpad[0];

if (ds18_family == 0x10) { // DS18S20 or old DS1820
int16_t dT = 128 * (scratchpad[7] - scratchpad[6]);
dT /= scratchpad[7];
raw = 64 * (raw & 0xFFFE) - 32 + dT;
addLogAdv(LOG_DEBUG, LOG_FEATURE_CFG, "DS1820 - Pin=%i -- Family %x, raw %i, count_remain %i, count_per_c %i, dT %i",Pin, ds18_family, raw, scratchpad[6], scratchpad[7], dT);
} else {
uint8_t cfg = scratchpad[4] & 0x60;
if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms
else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
raw = raw << 3; // multiply by 8
addLogAdv(LOG_DEBUG, LOG_FEATURE_CFG, "DS1820 - Pin=%i -- Family %x, cfg %x, raw %i",Pin, ds18_family, cfg, raw);
}

// Raw is t * 128
t = (raw / 128) * 100; // Whole degrees
int frac = (raw % 128) * 100 / 128; // Fractional degrees
t += t > 0 ? frac : -frac;

Val = (High << 8) + Low; // combine bytes to integer
negative = (High >= 8); // negative temperature
if (negative)
{
Val = (Val ^ 0xffff) + 1;
}
// Temperature is returned in multiples of 1/16 °C
// we want a simple way to display e.g. xx.yy °C, so just multiply with 100 and we get xxyy
// --> the last two digits will be the fractional part (Val%100)
// --> the whole part of temperature is (int)Val/100
// so we want 100/16 = 6.25 times the value (the sign to be able to show negative temperatures is in "factor")
Tc = (6 * Val) + Val / 4 ;
t = negative ? -1 : 1 * Tc ;
dsread=0;
lastconv=g_secondsElapsed;
addLogAdv(LOG_INFO, LOG_FEATURE_CFG, "DS1820 - Pin=%i temp=%s%i.%02i \r\n",Pin, negative ? "-" : "+", (int)Tc/100 , (int)Tc%100);
addLogAdv(LOG_INFO, LOG_FEATURE_CFG, "DS1820 - High=%i Low=%i Val=%i Tc=%i -- Read CRC=%x - calculated:%x \r\n",High, Low, Val,Tc,scratchpad[8],crc);
CHANNEL_Set(g_cfg.pins.channels[Pin], t, CHANNEL_SET_FLAG_SILENT);
addLogAdv(LOG_INFO, LOG_FEATURE_CFG, "DS1820 - Pin=%i temp=%i.%02i \r\n", Pin, (int)t/100 , (int)t%100);
}
}
else if (g_secondsElapsed % 15 == 0) { // every 15 seconds
// ask for "conversion"

if (OWReset(Pin) == 0){
else {
if (OWReset(Pin) == 0) {
if (g_secondsElapsed % 15 != 0) return; // only log every 15 seconds
addLogAdv(LOG_ERROR, LOG_FEATURE_CFG, "DS1820 - Pin=%i -- Reset failed",Pin);

// if device is not found, maybe "usleep" is not working as expected
Expand Down Expand Up @@ -459,6 +562,15 @@ void DS1820_OnEverySecond() {

}
else {
if (ds18_family == 0) {
int discovered = DS1820_DiscoverFamily();
if (!discovered) {
addLogAdv(LOG_ERROR, LOG_FEATURE_CFG, "DS1820 - Pin=%i -- Family not discovered",Pin);
return;
}
addLogAdv(LOG_INFO, LOG_FEATURE_CFG, "DS1820 - Pin=%i -- Family discovered %x",Pin, ds18_family);
}

OWWriteByte(Pin,0xCC);
OWWriteByte(Pin,0x44);
addLogAdv(LOG_INFO, LOG_FEATURE_CFG, "DS1820 - asked for conversion - Pin %i",Pin);
Expand Down

0 comments on commit b1f5710

Please sign in to comment.