Browse Source

basic implementation of DS18B20 emulation

pull/5/head
Youen Toupin 9 years ago
parent
commit
35b866d933
  1. 91
      OneWireIO.ino

91
OneWireIO.ino

@ -9,13 +9,30 @@ Pin oneWireData(2);
Pin led(13);
// This is the ROM the arduino will respond to, make sure it doesn't conflict with another device
const byte owROM[7] = { 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 };
const byte owROM[7] = { 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 };
const byte acknowledge = 0x42;
// This sample emulates a DS18B20 device (temperature sensor), so we start by defining the available commands
const byte DS18B20_START_CONVERSION = 0x44;
const byte DS18B20_READ_SCRATCHPAD = 0xBE;
const byte DS18B20_WRITE_SCRATCHPAD = 0x4E;
// This sample implements a simple protocol : sending match ROM, then the ROM, then 0x01 will turn the arduino light on. Sending 0x02 will turn it off. In each case, the byte 0x42 is sent as acknowledgement.
const byte CMD_TurnOn = 0x01;
const byte CMD_TurnOff = 0x02;
// TODO:
// - handle configuration (resolution, alarms)
// - send 0 bits while conversion is in progress, 1 bits when it's done (until reset)
enum DeviceState
{
DS_WaitingReset,
DS_WaitingCommand,
DS_ConvertingTemperature,
DS_TemperatureConverted,
};
volatile DeviceState state = DS_WaitingReset;
// scratchpad, with the CRC byte at the end
volatile byte scratchpad[9];
volatile unsigned long conversionStartTime = 0;
// This function will be called each time the OneWire library has an event to notify (reset, error, byte received)
void owReceive(OneWireSlave::ReceiveEvent evt, byte data);
@ -32,14 +49,32 @@ void setup()
void loop()
{
delay(1);
// You can do anything you want here, the OneWire library works entirely in background, using interrupts.
delay(10);
cli();//disable interrupts
// Be sure to not block interrupts for too long, OneWire timing is very tight for some operations. 1 or 2 microseconds (yes, microseconds, not milliseconds) can be too much depending on your master controller, but then it's equally unlikely that you block exactly at the moment where it matters.
// This can be mitigated by using error checking and retry in your high-level communication protocol. A good thing to do anyway.
DeviceState localState = state;
unsigned long localConversionStartTime = conversionStartTime;
sei();//enable interrupts
if (localState == DS_ConvertingTemperature && millis() > localConversionStartTime + 750)
{
float temperature = 42.0f; // here you could plug any logic you want to return the emulated temperature
int16_t raw = (int16_t)(temperature * 16.0f + 0.5f);
byte data[9];
data[0] = (byte)raw;
data[1] = (byte)(raw >> 8);
for (int i = 2; i < 8; ++i)
data[i] = 0;
data[8] = OWSlave.crc8(data, 8);
cli();
memcpy((void*)scratchpad, data, 9);
state = DS_TemperatureConverted;
sei();
}
}
void owReceive(OneWireSlave::ReceiveEvent evt, byte data)
@ -47,27 +82,35 @@ void owReceive(OneWireSlave::ReceiveEvent evt, byte data)
switch (evt)
{
case OneWireSlave::RE_Byte:
if (data == CMD_TurnOn)
{
led.writeHigh();
}
else if (data == CMD_TurnOff)
{
led.writeLow();
}
else
switch (state)
{
case DS_WaitingCommand:
switch (data)
{
case DS18B20_START_CONVERSION:
state = DS_ConvertingTemperature;
conversionStartTime = millis();
break;
case DS18B20_READ_SCRATCHPAD:
state = DS_WaitingReset;
OWSlave.write((const byte*)scratchpad, 9, 0);
break;
case DS18B20_WRITE_SCRATCHPAD:
break;
}
break;
}
break;
// in this simple example we just reply with one byte to say we've processed the command
// a real application should have a CRC system to ensure messages are not corrupt, for both directions
// you can use the static OneWireSlave::crc8 method to add CRC checks in your communication protocol (it conforms to standard one-wire CRC checks, that is used to compute the ROM last byte for example)
OWSlave.write(&acknowledge, 1, NULL);
case OneWireSlave::RE_Reset:
state = DS_WaitingCommand;
break;
default:
; // we could also react to reset and error notifications, but not in this sample
case OneWireSlave::RE_Error:
state = DS_WaitingReset;
break;
}
}

Loading…
Cancel
Save