Skip to content

Instantly share code, notes, and snippets.

@smittytone
Last active August 29, 2015 14:00
Show Gist options
  • Save smittytone/11370885 to your computer and use it in GitHub Desktop.
Save smittytone/11370885 to your computer and use it in GitHub Desktop.
Electric Imp UART implementation of 1-Wire for multiple devices
function one_wire_reset()
{
// Configure UART for 1-Wire RESET timing
ow.configure(9600, 8, PARITY_NONE, 1, NO_CTSRTS)
ow.write(0xF0)
ow.flush()
if (ow.read() == 0xF0)
{
// UART RX will read TX if there's no device connected
server.log("No 1-Wire devices are present.")
return false
}
else
{
// Switch UART to 1-Wire data speed timing
ow.configure(115200, 8, PARITY_NONE, 1, NO_CTSRTS)
return true
}
}
function one_wire_write_byte(byte)
{
for (local i = 0; i < 8; i++, byte = byte >> 1)
{
// Run through the bits in the byte, extracting the
// LSB (bit 0) and sending it to the bus
one_wire_bit(byte & 0x01)
}
}
function one_wire_read_byte()
{
local byte = 0
for (local i = 0; i < 8; i++)
{
// Build up byte bit by bit, LSB first
byte = (byte >> 1) + 0x80 * one_wire_bit(1)
}
return byte;
}
function one_wire_bit(bit)
{
bit = bit ? 0xFF : 0x00
ow.write(bit)
ow.flush()
local return_value = ow.read() == 0xFF ? 1 : 0
return return_value
}
function one_wire_search(next_node)
{
local last_fork_point = 0
// Reset the bus and exit if no device found
if (one_wire_reset())
{
// There are 1-Wire device(s) on the bus, so issue the 1-Wire SEARCH command (0xF0)
one_wire_write_byte(0xF0)
// Work along the 64-bit ROM code, bit by bit, from LSB to MSB
for (local i = 64 ; i > 0 ; i--)
{
local byte = (i - 1) / 8
// Read bit from bus
local bit = one_wire_bit(1)
// Read the next bit
if (one_wire_bit(1))
{
if (bit)
{
// Both bits are 1 which indicates that there are no further devices
// on the bus, so put pointer back to the start and break out of the loop
last_fork_point = 0
break
}
}
else if (!bit)
{
// First and second bits are both 0: we're at a node
if (next_node > i || (next_node != i && (id[byte] & 1)))
{
// Take the '1' direction on this point
bit = 1
last_fork_point = i
}
}
// Write the 'direction' bit. For example, if it's 1 then all further
// devices with a 0 at the current ID bit location will go offline
one_wire_bit(bit)
// Write the bit to the current ID record
id[byte] = (id[byte] >> 1) + 0x80 * bit
}
}
// Return the last fork point so it can form the start of the next search
return last_fork_point
}
function one_wire_slaves()
{
id <- [0,0,0,0,0,0,0,0]
next_device <- 65
while(next_device)
{
next_device = one_wire_search(next_device)
// Store the device ID discovered by one_wire_search() in an array
// Nb. We need to clone the array, id, so that we correctly save
// each one rather than the address of a single array
slaves.push(clone(id))
}
}
function get_temp()
{
local temp_LSB = 0
local temp_MSB = 0
local temp_celsius = 0
imp.wakeup(5.0, get_temp)
// Reset the 1-Wire bus
one_wire_reset()
// Issue 1-Wire Skip ROM command (0xCC) to select all devices on the bus
one_wire_write_byte(0xCC)
// Issue DS18B20 Convert command (0x44) to tell all DS18B20s to get the temperature
// Even if other devices don't ignore this, we will not read them
one_wire_write_byte(0x44)
// Wait 750ms for the temperature conversion to finish
imp.sleep(0.75)
foreach (device, slave_id in slaves)
{
// Run through the list of discovered slave devices, getting the temperature
// if a given device is of the correct family number: 0x28 for BS18B20
if (slave_id[7] == 0x28)
{
one_wire_reset()
// Issue 1-Wire MATCH ROM command (0x55) to select device by ID
one_wire_write_byte(0x55)
// Write out the 64-bit ID from the array's eight bytes
for (local i = 7 ; i >= 0; i--)
{
one_wire_write_byte(slave_id[i])
}
// Issue the DS18B20's READ SCRATCHPAD command (0xBE) to get temperature
one_wire_write_byte(0xBE)
// Read the temperature value from the sensor's RAM
temp_LSB = one_wire_read_byte()
temp_MSB = one_wire_read_byte()
// Signal that we don't need any more data by resetting the bus
one_wire_reset()
// Calculate the temperature from LSB and MSB
temp_celsius = ((temp_MSB * 256) + temp_LSB) / 16.0
server.log(format("Device: %02d Family: %02x Serial: %02x%02x%02x%02x%02x%02x Temp: %3.2f", (device + 1), slave_id[7], slave_id[1], slave_id[2], slave_id[3], slave_id[4], slave_id[5], slave_id[6], temp_celsius))
}
}
}
// PROGRAM STARTS HERE
ow <- hardware.uart12
slaves <- []
// Enumerate the slaves on the bus
one_wire_slaves()
// Start sampling temperature data
get_temp()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment