basic implementation of DS18B20 emulation
This commit is contained in:
parent
b97a643227
commit
35b866d933
@ -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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
; // we could also react to reset and error notifications, but not in this sample
|
||||
|
||||
case OneWireSlave::RE_Reset:
|
||||
state = DS_WaitingCommand;
|
||||
break;
|
||||
|
||||
case OneWireSlave::RE_Error:
|
||||
state = DS_WaitingReset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user