Browse Source

basic implementation of DS18B20 emulation

timer1
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); Pin led(13);
// This is the ROM the arduino will respond to, make sure it doesn't conflict with another device // 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. // TODO:
const byte CMD_TurnOn = 0x01; // - handle configuration (resolution, alarms)
const byte CMD_TurnOff = 0x02; // - 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) // 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); void owReceive(OneWireSlave::ReceiveEvent evt, byte data);
@ -32,14 +49,32 @@ void setup()
void loop() void loop()
{ {
delay(1); delay(10);
// You can do anything you want here, the OneWire library works entirely in background, using interrupts.
cli();//disable interrupts 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. // 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. // 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 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) void owReceive(OneWireSlave::ReceiveEvent evt, byte data)
@ -47,27 +82,35 @@ void owReceive(OneWireSlave::ReceiveEvent evt, byte data)
switch (evt) switch (evt)
{ {
case OneWireSlave::RE_Byte: case OneWireSlave::RE_Byte:
if (data == CMD_TurnOn) switch (state)
{
led.writeHigh();
}
else if (data == CMD_TurnOff)
{
led.writeLow();
}
else
{ {
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;
} }
break;
// in this simple example we just reply with one byte to say we've processed the command case OneWireSlave::RE_Reset:
// a real application should have a CRC system to ensure messages are not corrupt, for both directions state = DS_WaitingCommand;
// 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) break;
OWSlave.write(&acknowledge, 1, NULL);
case OneWireSlave::RE_Error:
state = DS_WaitingReset;
break; break;
default:
; // we could also react to reset and error notifications, but not in this sample
} }
} }

Loading…
Cancel
Save