forked from IanF/OneWireArduinoSlaveATTINY85
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
117 lines
3.3 KiB
117 lines
3.3 KiB
#include "Arduino.h" |
|
#include "LowLevel.h" |
|
#include "OneWireSlave.h" |
|
|
|
// This is the pin that will be used for one-wire data (depending on your arduino model, you are limited to a few choices, because some pins don't have complete interrupt support) |
|
// On Arduino Uno, you can use pin 2 or pin 3 |
|
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] = { 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }; |
|
|
|
// 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; |
|
|
|
// TODO: |
|
// - handle configuration (resolution, alarms) |
|
|
|
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); |
|
|
|
void setup() |
|
{ |
|
led.outputMode(); |
|
led.writeLow(); |
|
|
|
// Setup the OneWire library |
|
OWSlave.setReceiveCallback(&owReceive); |
|
OWSlave.begin(owROM, oneWireData.getPinNumber()); |
|
} |
|
|
|
void loop() |
|
{ |
|
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; |
|
OWSlave.writeBit(1, true); // now that conversion is finished, start sending ones until reset |
|
sei(); |
|
} |
|
} |
|
|
|
void owReceive(OneWireSlave::ReceiveEvent evt, byte data) |
|
{ |
|
switch (evt) |
|
{ |
|
case OneWireSlave::RE_Byte: |
|
switch (state) |
|
{ |
|
case DS_WaitingCommand: |
|
switch (data) |
|
{ |
|
case DS18B20_START_CONVERSION: |
|
state = DS_ConvertingTemperature; |
|
conversionStartTime = millis(); |
|
OWSlave.writeBit(0, true); // send zeros as long as the conversion is not finished |
|
break; |
|
|
|
case DS18B20_READ_SCRATCHPAD: |
|
state = DS_WaitingReset; |
|
OWSlave.write((const byte*)scratchpad, 9, 0); |
|
break; |
|
|
|
case DS18B20_WRITE_SCRATCHPAD: |
|
|
|
break; |
|
} |
|
break; |
|
} |
|
break; |
|
|
|
case OneWireSlave::RE_Reset: |
|
state = DS_WaitingCommand; |
|
break; |
|
|
|
case OneWireSlave::RE_Error: |
|
state = DS_WaitingReset; |
|
break; |
|
} |
|
}
|
|
|