Tag Archives: ESP8266 Dallas chip

Arduino Libraries and ESP8266

DallasSo I’m working on a side project – which may or may not go anywhere – to make a working version of my home control 2016 ESP8266 software in the Arduino environment. 

One popular device is the Dallas DS18b20 temperature sensor, a simple 3 wire device that looks like a transistor, has a single communications line and returns accurate temperature digitally.

Well, I’ve had this running for AGES on my code and can handle both the normal and P-suffix variety – so I was a bit dismayed after wasting an hour and throwing a chip away to find that the Arduino version does not.  Also it seems people are still writing libraries out there which wait for the chip – wasting valuable time – so I thought I’d do a short write-up on my own code.

Another annoyance I discovered was the need to predefine which GPIO pin you’re using for the temperature sensor – making dynamic change impossible. There really is no need for this.

So – how do I get around the delay – simple – I swap things around – instead of priming the unit, waiting and taking a reading, I take a reading and prime the unit – making the first ever reading after power-up a waste of time – and I use a flag to return zero the first time. This means no waiting and hence VERY fast reading. I also check the result and if the DS18b20 fails I try for a DS18b20P.

In my own code I use EASYGPIO which isn’t available on the Arduino version – which means (as I understand it) putting the GPIO pin from output to input means two operations, one to reverse the state of the pin and another to set the output value – but hey, it works.

No libraries needed of any kind though if you were cleverer than I you could dump my routines into a library. Of course nothing is new and some of my code is simply refactored from elsewhere as you’ll see.

Firstly – I’m not going for accuracy here, I’m only interested in temperature to the nearest degree – if you want more you’ll have to make minor changes. I’m also not interested in multiple devices per pin. I am however interested in changing pins without static declarations. Funny enough this all started for the Arduino, got adapted for ESP8266 and ended up back in an ESP8266/Arduino setup.

/*
   Adaptation of Paul Stoffregen's One wire library to the ESP8266 and
   Necromant's Frankenstein firmware by Erland Lewin <erland@lewin.nu>

   Paul's original library site:
    
http://www.pjrc.com/teensy/td_libs_OneWire.html

   See also http://playground.arduino.cc/Learning/OneWire

   Stripped down to bare minimum by Peter Scargill for single DS18B20 or DS18B20P integer read
*/

// 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;

void ds_reset(void)
{
  uint8_t retries = 125;

  pinMode(temperaturePort, INPUT_PULLUP);
  // wait until the wire is high... just in case
  do {
    if (--retries == 0) return;
    delayMicroseconds(2);
  } while (!digitalRead(temperaturePort));
  digitalWrite(temperaturePort,LOW);
  pinMode(temperaturePort, OUTPUT);
  delayMicroseconds(480);
  pinMode(temperaturePort, INPUT_PULLUP);
  delayMicroseconds(480);
}

// Write a bit. Port and bit is used to cut lookup time and provide
// more certain timing.
//
static inline void write_bit(int v)
{
  digitalWrite(temperaturePort,LOW);
  pinMode(temperaturePort, OUTPUT);
  if (v) {
    delayMicroseconds(10);
    digitalWrite(temperaturePort,HIGH);
    delayMicroseconds(55);
  }
  else {
    delayMicroseconds(65);
    digitalWrite(temperaturePort,HIGH);
    delayMicroseconds(5);
  }
}

//
// Read a bit. Port and bit is used to cut lookup time and provide
// more certain timing.
//
static inline int read_bit(void)
{
  int r;
  digitalWrite(temperaturePort,LOW);
  pinMode(temperaturePort, OUTPUT);
  delayMicroseconds(3);
  pinMode(temperaturePort, INPUT_PULLUP);
  delayMicroseconds(10);
  r = digitalRead(temperaturePort);
  delayMicroseconds(53);
  return r;
}

//
// Write a byte. The writing code uses the active drivers to raise the
// pin high, if you need power after the write (e.g. DS18S20 in
// parasite power mode) then set 'power' to 1, otherwise the pin will
// go tri-state at the end of the write to avoid heating in a short or
// other mishap.
//
void ds_write(uint8_t v, int power)
{
  uint8_t bitMask;

  for (bitMask = 0x01; bitMask; bitMask <<= 1) {
    write_bit((bitMask & v) ? 1 : 0);
  }
  if (!power) {
    pinMode(temperaturePort, INPUT_PULLUP);
    digitalWrite(temperaturePort,LOW);
    pinMode(temperaturePort, OUTPUT);
  }
}

//
// Read a byte
//
uint8_t ds_read()
{
  uint8_t bitMask;
  uint8_t r = 0;

  for (bitMask = 0x01; bitMask; bitMask <<= 1) {
    if (read_bit()) r |= bitMask;
  }
  return r;
}

So what you see above are the basic routines for talking to the two  chip variations. Here’s the actual code I call once a minute (you could use any interval) to store the temperature. I don’t stop interrupts as I might be running an RGB fader and I don’t want any flashing.

Doesn’t seem to present issues, never has, but if you wanted you could average temperature over time.

testing

I run my heating without any of that and I don’t get glitches on my Home Control software – this is the same code but with changes for the Arduino-style port handling.  I wonder if I’m missing a single instruction to set an input to an output and make it zero at the same time?

ds_reset();
   ds_write(0xcc, 1);
   ds_write(0xbe, 1);
   temperature = (int) ds_read();
   temperature = temperature + (int) ds_read() * 256;
   temperature /= 16;
   if (temperature > 100) temperature -= 4096;
   ds_reset();
   ds_write(0xcc, 1);
   ds_write(0x44, 1);
   if (gotDsReading == 0) { gotDsReading=1; temperature = 0; }    // ignore first reading
   else
     {
    Serial.printf(“Here’s your temperature %dc”,temperature);
     }

It would be nice to see this in a stand-alone library somehow. temperaturePort is the number of the GPIO pin. I generally use 2 or 14 on the ESP and I don’t want them dedicated in case I want to use them for something else. Define gotDSReading and make it zero on power-up or change of pin. If the dummy value of zero is no good – change it.

Oh and in the process of putting this together I realised a slight silly in my main Home Control software – and that is now fixed….

Works for me!!

Facebooktwittergoogle_pluspinterestlinkedin