Code Example - DS18B20 via DS2482 (OneWire via I2C)

I wanted to be able to use some DS18B20 OneWire temperature sensors, but as the Imp doesn’t yet support OneWire, I used a DS2482-100 to convert from I2C to OneWire. This added some complexity because all the OneWire commands have to be encapsulated in I2C messages. When you request data from a OneWire device, you have to request the data, wait for OneWire data to complete, then read the data from the buffer on the DS2482.

There are a handful of functions to send/receive OneWire data via the I2C commands, so the code for this example is ~400 lines long. For this reason, I have posted to code over at PasteBin rather than make a long long post here.

http://pastebin.com/0d93ZuRb

Output will look something like this:

8/4/2013 11:16:31 PM: OneWire Device D100000404BD2D28 = 77.3 °F 8/4/2013 11:16:34 PM: OneWire Device 5E00000404F90728 = 77.4 °F 8/4/2013 11:16:35 PM: OneWire Search Complete

Thanks! I’m sure many will find this useful. I’m sure Matt will ask, but could we put it in our central imp code repo so it’s easy to find? We’re building this up now.

btw, for maximum efficiency, you should put globals in the root table, and use consts where applicable, eg:

local I2CAddr = 0x30; //Address of DS2482 on I2C bus local owTripletDirection = 1; local owTripletFirstBit = 0; local owTripletSecondBit = 0;

…would be more efficient as:

const I2CAddr = 0x30; //Address of DS2482 on I2C bus owTripletDirection <- 1; owTripletFirstBit <- 0; owTripletSecondBit <- 0;

Peter has been keeping this page updated with various tips for the squirrel writer - good to go over and look at the examples: http://devwiki.electricimp.com/doku.php?id=writingefficientsquirrel

Hugo, thanks for the tip. Code has been changed, tested, and pastebin updated.

You are free to include it in a central repository.

Excellent! We’ll get that added today :slight_smile:

Do you have a github, twitter, or other kind of account we can link to for attribution?

Lance@Lefebure.com
https://twitter.com/LanceLefebure

The use of the DS2482 does not seem to make it any easier compared to the use of the standard serial port as described in the OneWire Support discussion that is using a lot less code and hardware …

Update: The original version of this code didn’t handle temperatures below 0°C. I just updated the code in pastebin to handle negative numbers. Essentially the following three lines were added:

local SignBit = raw & 0x8000; // test most significant bit
if (SignBit) {raw = (raw ^ 0xffff) + 1;} // negative, 2’s compliment

if (SignBit) {celsius *= -1;}

Very nice, got it working out of the box :slight_smile:

If you have multiple temperature sensors on the bus, you can issue a general convert command and then collect the temperatures afterwards, that way you dont need to wait for 1second per sensor.

I changed the owSearch to return 0 when the search is over and then changed the if (OWSearch()) { in the loop function to a while, that way it runs trough all the sensors as fast as possible.

`
function owloop() {
OWReset();
OWWriteByte(0xCC); //Issue the Skip ROM command
OWWriteByte(0x44); //start conversion
imp.sleep(1); //Wait for conversion

while (OWSearch()) { //Search found something
    if ((owDeviceAddress[1] & 0xFF) == 0x28) { //Device is a DS18B20
        if (OWReset()) { //Reset was successful
                OWSelect();
                OWWriteByte(0xBE); //Read Scratchpad
                OWReadTemperature();
        }
    }
}

}`

Can anyone offer some assistance on this? I’ve got a DS2482-100 connected to the IMP on Pins 1/2. I’m using the code shared by mx270a (https://discourse.electricimp.com/discussion/1423/code-example-ds18b20-via-ds2482-onewire-via-i2c/p1). The only change was to setup i2c on pins 1/2 per this link. https://electricimp.com/docs/resources/i2c/

local i2c = hardware.i2c12;

The IMP server log just shows 2015-01-24 15:57:36 UTC-5 [Device] I2C Reset Failed.

I’m using these DS2482 specs as reference. http://www.mouser.com/ds/2/256/DS2482-100-39831.pdf

I’ve tried using pullup resistors valued at 2.2K and 1.2K. No change in output.
I’ve also tried Vcc of 5v and 3.3v, again, no change in output.
I get the same result whether the DS18B20 is not connected at all, connected to +5 (in addition to data and ground going to their respective connections), or just connected to data and ground (which I understand to be parasitic mode).

Can anyone offer some ideas or suggestions as to why this isn’t working?

Looks like the two pins (7 & 8) that set the address of the DS2482 are set high, which will give it a different address than the default that is in the example code.

I’m using 4.7K pullups on both I2C lines and the onewire line. Attached is the schematic I’ve been using.

If you’re having issues with seeing the DS2482 on the I2C bus, run a scanner on the bus to confirm that you can see it and find what address it is on. Here’s a simple I2C bus scanner:
`local i2c = hardware.i2c12;
i2c.configure(CLOCK_SPEED_100_KHZ);
local Address = 0;

function loop() {
if (Address == 0) server.log(“Starting I2C Scan”);
local e = i2c.write(Address, “\x00”); //Try writing some data
if (e != -2) { //Found something.
server.log(format(“Found something with address %3i (%#2x), result = %d”, Address, Address, e));
}
Address+=2; //Increment by 2.
if (Address == 256) Address = 0; //Start over
imp.wakeup(0.1, loop);
}
loop();`

mx270a -
Thanks for the quick reply. Your schematic shows AD0 & AD1 tied to ground which is the same configuration I was using.

I tried the I2C bus scanner, but it seemed to report that it found something at every possible address.
Example…

2015-01-25 13:56:16 UTC-5 [Device] Found something with address 50 (0x32), result = -1
2015-01-25 13:56:18 UTC-5 [Device] Found something with address 52 (0x34), result = -1
2015-01-25 13:56:28 UTC-5 [Device] Found something with address 54 (0x36), result = -1
2015-01-25 13:56:28 UTC-5 [Device] Found something with address 56 (0x38), result = -1

FWIW, I had a device that I could not get to work at all via i2c12, but would every time on i2c89. Might be worth a try to rewire and change the instantiation call.

On the suggestion of another user, I switched to IMP pins i2c89 and also switched my power source from 5v to the 3.3 supplied by the IMP. Using the I2C scanner suggested, I came back with two answers, one matching the spec for the DS2482 (0x36).

I guess I changed too many variables at once, so I’m not exactly sure what fixed it, but I am reading data off the wire now. Thanks to mx270a and hvacspei for offering suggestions…

Looking at the datasheet it was probably because you were powering it with 5V. It looks like the component can run at 3.3V or 5V.

If you’re running it at 5V (which it sounds like you were) - VIH1 (the voltage required for a high signal) is 3.4V - slightly more than the imp can produce.

If you’re running at 3.3V (which you are now) - VIH1 is 1.9V.

(These values came from the Electrical Characteristics table on page 2 of the datasheet).

Trying to implement the above code using
HAL_I2C using c++. The squirrel code command of I2C.write and I2C.read is not clear , please can someone help me on this.
HAL I2C write function takes three arguments slave address, memaddr/reg addr/command code and data to send.