Skip to content

Instantly share code, notes, and snippets.

@ElectricImpSampleCode
Last active September 12, 2023 10:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ElectricImpSampleCode/c6981fcb9e30683ead8b to your computer and use it in GitHub Desktop.
Save ElectricImpSampleCode/c6981fcb9e30683ead8b to your computer and use it in GitHub Desktop.
1-Wire Examples
// FUNCTIONS
function onewireReset() {
// Configure UART for 1-Wire RESET timing
ow.configure(9600, 8, PARITY_NONE, 1, NO_CTSRTS);
ow.write(0xF0);
ow.flush();
local read = ow.read();
if (read == -1) {
// No UART data at all
server.log("No circuit connected to UART.");
return false;
} else if (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 onewireWriteByte(byte) {
for (local i = 0 ; i < 8 ; i++) {
// Run through the bits in the byte, extracting the
// LSB (bit 0) and sending it to the bus
byte = byte >> 1;
onewireBit(byte & 0x01);
}
}
function onewireReadByte() {
local byte = 0;
for (local i = 0 ; i < 8 ; i++) {
// Build up byte bit by bit, LSB first
byte = (byte >> 1) + 0x80 * onewireBit(1);
}
return byte;
}
function onewireBit(bit) {
bit = bit ? 0xFF : 0x00;
ow.write(bit);
ow.flush();
local returnVal = ow.read() == 0xFF ? 1 : 0;
return returnVal;
}
function onewireSearch(nextNode) {
// 'lastForkPoint' records where the device tree last branched
local lastForkPoint = 0;
// Reset the bus and exit if no device found
if (onewireReset()) {
// There are 1-Wire device(s) on the bus, so issue the 1-Wire SEARCH command (0xF0)
onewireWriteByte(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 = onewireBit(1);
// Read the next bit
if (onewireBit(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
lastForkPoint = 0;
break;
}
} else if (!bit) {
// First and second bits are both 0: we're at a node
if (nextNode > i || (nextNode != i && (id[byte] & 1))) {
// Take the '1' direction on this point
bit = 1;
lastForkPoint = 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
onewireBit(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 lastForkPoint
}
function onewireDevices() {
id <- [0,0,0,0,0,0,0,0];
nextDevice <- 65;
while (nextDevice) {
nextDevice = onewireSearch(nextDevice);
// 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
peripherals.push(clone(id));
}
}
function getTemp() {
local tempLSB = 0;
local tempMSB = 0;
local tempCelsius = 0;
// Wake up in five seconds for the next reading
imp.wakeup(5.0, getTemp);
// Reset the 1-Wire bus
local result = onewireReset();
if (result) {
// Issue 1-Wire Skip ROM command (0xCC) to select all devices on the bus
onewireWriteByte(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
onewireWriteByte(0x44);
// Wait 750ms for the temperature conversion to finish
imp.sleep(0.75);
foreach (device, peripheralId in peripherals) {
// Run through the list of discovered peripheral devices, getting the temperature
// if a given device is of the correct family number: 0x28 for BS18B20
if (peripheralId[7] == 0x28) {
onewireReset();
// Issue 1-Wire MATCH ROM command (0x55) to select device by ID
onewireWriteByte(0x55);
// Write out the 64-bit ID from the array's eight bytes
for (local i = 7 ; i >= 0 ; i--) {
onewireWriteByte(peripheralId[i]);
}
// Issue the DS18B20's READ SCRATCHPAD command (0xBE) to get temperature
onewireWriteByte(0xBE);
// Read the temperature value from the sensor's RAM
tempLSB = onewireReadByte();
tempMSB = onewireReadByte();
// Signal that we don't need any more data by resetting the bus
onewireReset();
// Calculate the temperature from LSB and MSB, making sure we
// sign-extend the signed 16-bit temperature readinf ('raw')
// to a Squirrel 32-bit signed integer ('tempCelsius')
local raw = (tempMSB << 8) + tempLSB;
tempCelsius = ((raw << 16) >> 16) * 0.0625;
server.log(format("Device: %02d Family: %02x Serial: %02x%02x%02x%02x%02x%02x Temp: %3.2f", (device + 1), peripheralId[7], peripheralId[1], peripheralId[2], peripheralId[3], peripheralId[4], peripheralId[5], peripheralId[6], tempCelsius));
}
}
}
}
// RUNTIME START
// Set up the 1-Wire UART. This is for an imp001 -
// change the UART object in the line below for other imps
ow <- hardware.uart12;
peripherals <- [];
// Enumerate the devices on the bus
onewireDevices();
// Start sampling temperature data
getTemp();
// FUNCTIONS
function onewireReset() {
// Configure UART for 1-Wire RESET timing
ow.configure(9600, 8, PARITY_NONE, 1, NO_CTSRTS);
ow.write(0xF0);
ow.flush();
local read = ow.read();
if (read == -1) {
// No UART data at all
server.log("No circuit connected to UART.");
return false;
} else if (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 onewireWriteByte(byte) {
for (local i = 0 ; i < 8 ; ++i) {
// Run through the bits in the byte, extracting the
// LSB (bit 0) and sending it to the bus
byte = byte >> 1;
onewireBit(byte & 0x01);
}
}
function onewireReadByte() {
local byte = 0;
for (local i = 0 ; i < 8 ; ++i) {
// Build up byte bit by bit, LSB first
byte = (byte >> 1) + 0x80 * onewireBit(1);
}
return byte;
}
function onewireBit(bit) {
bit = bit ? 0xFF : 0x00;
ow.write(bit);
ow.flush();
local returnValue = ow.read() == 0xFF ? 1 : 0;
return returnValue;
}
function awakeAndGetTemp() {
// Wake up every 30 seconds and write to the server
local tempLSB = 0;
local tempMSB = 0;
local tempCelsius = 0;
// Run loop again in 30 seconds
imp.wakeup(30.0, awakeAndGetTemp);
if (onewireReset()) {
onewireWriteByte(0xCC); // 1-Wire Skip ROM command
onewireWriteByte(0x44);
// Wait for at least 750ms for data to be collated
imp.sleep(0.8);
// Get the data
onewireReset();
onewireWriteByte(0xCC); // 1-Wire Skip ROM command
onewireWriteByte(0xBE); // Tell sensor to take a reading
tempLSB = onewireReadByte();
tempMSB = onewireReadByte();
// Reset bus to stop sensor sending unwanted data
onewireReset();
// Calculate the temperature from LSB and MSB, making sure we
// sign-extend the signed 16-bit temperature readinf ('raw')
// to a Squirrel 32-bit signed integer ('tempCelsius')
local raw = (tempMSB << 8) + tempLSB;
tempCelsius = ((raw << 16) >> 16) * 0.0625;
server.log(format("Temperature: %3.2f degrees C", tempCelsius));
}
}
// RUNTIME START
// Set up the 1-Wire UART. This is for an imp001 -
// change the UART object in the line below for other imps
ow <- hardware.uart12;
awakeAndGetTemp();
@mikespolk
Copy link

Thank you for the code example. It is quite clear and helps me to write my customized Python detection routine in Raspberry.
However, I cannot understand the IF clause on line 75:

           // First and second bits are both 0: we're at a node
            if (nextNode > i || (nextNode != i && (id[byte] & 1))) {
                // Take the '1' direction on this point
                bit = 1;
                lastForkPoint = i;
            }        

On that line, it is easy to understand that the direction bit value depends on if the discrepancy in this round appears before or after the bit position during last round. However, why would it ever depend on the LSB bit value (=detected during last round)?

Can you please clarify, thank you!

@karthickrajapetal
Copy link

Hai sir,
I need more information how to read ROM command from Master device in STC15F

@smittytone
Copy link

You need to write your own 1-Wire driver for that. It will issue the signals to the peripheral device from the STC15F via one if the chip's GPIO pins, eg. https://github.com/qalex/blackboard-STC15/blob/master/DS18B20.c

@karthickrajapetal
Copy link

karthickrajapetal commented Jul 27, 2023 via email

@smittytone
Copy link

Commands are sent by the host (Uno) to the peripheral (STC). I don't think the STC will not read 1-Wire natively, so you'll need to write code for the STC that monitors the line and times high and low voltage periods to interpret the signalling. Some general guidance here: https://developer.electricimp.com/resources/onewire#what-is-1-wire

If you only have one peripheral, you can send the Skip ROM command (0xCC) to ignore device identification. The function awakeAndGetTemp() above shows the flow. 0x44 is the command to tell the BS18B20 sensor to take a reading (you can emulate this on the STC) and then you do the process again, this time with the 0xBE command, to receive the reading.

1-Wire is usually used for basic sensor data. If you need to transmit more complex info between the Uno and the STC, use UART.

@karthickrajapetal
Copy link

karthickrajapetal commented Jul 29, 2023 via email

@karthickrajapetal
Copy link

karthickrajapetal commented Aug 4, 2023 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment