forked from youen/OneWireArduinoSlave
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.
193 lines
5.3 KiB
193 lines
5.3 KiB
|
|
/* Ian Fleet 2018 |
|
|
|
All files, software, schematics and designs are provided as-is with no warranty. |
|
All files, software, schematics and designs are for experimental/hobby use. |
|
Under no circumstances should any part be used for critical systems where safety, |
|
life or property depends upon it. You are responsible for all use. |
|
You are free to use, modify, derive or otherwise extend for your own purposes |
|
|
|
*/ |
|
|
|
|
|
// This example emulates a DS2413 device on an Arduino UNO |
|
// note : physical DS2413 devices found in 2018 are often clones with |
|
// a device code different to the Maxim datasheet |
|
|
|
#include "Arduino.h" |
|
#include "OneWireSlave.h" |
|
#include "comptime.h" |
|
|
|
|
|
// This is the pin that will be used for one-wire data |
|
// On Arduino Uno, you can use pin 2 or pin 3 |
|
|
|
Pin oneWireData(2); |
|
|
|
Pin led(13); // builtin led |
|
|
|
// This sample emulates a DS2413 device , so we start by defining the available commands |
|
|
|
const byte DS2413_FAMILY_ID = 0x3A; // Maxim DS2413 device code |
|
const byte CLONE_FAMILY_ID = 0x85; // Clone device code |
|
const byte DS2413_ACCESS_READ = 0xF5; |
|
const byte DS2413_ACCESS_WRITE = 0x5A; |
|
const byte DS2413_ACK_SUCCESS = 0xAA; |
|
|
|
// generate unique id |
|
const byte owROM[7] = { DS2413_FAMILY_ID, SERIAL_NUMBER}; |
|
// will be calculated in begin:---------------^^^^ |
|
|
|
// or use fixed id - make sure it doesn't conflict with another device |
|
//const byte owROM[7] = { 0x3A, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22 }; |
|
|
|
|
|
#define PIOA 4 // DS2413 PIO PINS on the UNO |
|
#define PIOB 5 // |
|
|
|
uint8_t latch = 0; |
|
uint8_t statusbyte1 = 0; |
|
uint8_t statusbyte2 = 0; |
|
|
|
enum DeviceState |
|
{ |
|
DS_WaitingReset, |
|
DS_WaitingCommand, |
|
DS_WaitingStatus1, |
|
DS_WaitingStatus2, |
|
|
|
}; |
|
volatile DeviceState state = DS_WaitingReset; |
|
|
|
// scratchpad |
|
volatile byte scratchpad[2]; |
|
|
|
volatile byte response[2]; |
|
|
|
|
|
// 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(); |
|
|
|
Serial.begin(115200); |
|
|
|
// Setup the OneWire library |
|
OWSlave.setReceiveCallback(&owReceive); |
|
OWSlave.begin(owROM, oneWireData.getPinNumber()); |
|
|
|
} |
|
|
|
////////////////////////////////////////// |
|
|
|
void loop() |
|
{ |
|
delay(1000); |
|
|
|
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. |
|
|
|
sei();//enable interrupts |
|
|
|
led.writeLow(); // flash the led |
|
delay(1000); |
|
led.writeHigh(); |
|
} |
|
|
|
////////////////////////////////////////// |
|
|
|
static uint8_t getstatus() { |
|
uint8_t c = 0; |
|
if (latch & 0x01) c |= 0x02; |
|
if (digitalRead(PIOA)) c |= 0x01; |
|
if (latch & 0x02) c |= 0x08; |
|
if (digitalRead(PIOB)) c |= 0x04; |
|
uint8_t x = (~c) << 4; |
|
return x + c; |
|
} |
|
////////////////////////////////////////// |
|
|
|
static void port(int PIO, bool stat) { |
|
if (stat) { |
|
digitalWrite(PIO, HIGH); |
|
pinMode(PIO, INPUT); |
|
} else { |
|
pinMode(PIO, OUTPUT); |
|
digitalWrite(PIO, LOW); |
|
} |
|
} |
|
////////////////////////////////////////// |
|
|
|
static void set(uint8_t val) { |
|
latch = val; |
|
port(PIOA, latch & 1); |
|
port(PIOB, latch & 2); |
|
// TODO store latch value for recovery at startup |
|
} |
|
|
|
////////////////////////////////////////// |
|
|
|
void owReceive(OneWireSlave::ReceiveEvent evt, byte data) |
|
{ |
|
switch (evt) |
|
{ |
|
case OneWireSlave::RE_Byte: |
|
switch (state) |
|
{ |
|
case DS_WaitingCommand: |
|
switch (data) // on command byte |
|
{ |
|
case DS2413_ACCESS_WRITE: |
|
state = DS_WaitingStatus1; // wait for status byte 1 |
|
break; |
|
|
|
case DS2413_ACCESS_READ: |
|
state = DS_WaitingReset; |
|
scratchpad[0] = getstatus(); //return status in DS2413 format |
|
OWSlave.beginWrite((const byte*)scratchpad, 1, 0); |
|
break; |
|
|
|
default: |
|
//TODO : report invalid commands |
|
break; |
|
} // end switch (data) command |
|
break; |
|
|
|
|
|
case DS_WaitingStatus1: |
|
statusbyte1 = data; |
|
state = DS_WaitingStatus2; // wait for status byte 2 |
|
break; |
|
|
|
case DS_WaitingStatus2: |
|
statusbyte2 = data; |
|
if (statusbyte1 != ~statusbyte2) { // is DS2413 status data valid? |
|
set(statusbyte1); |
|
response[0] = DS2413_ACK_SUCCESS; |
|
} else { |
|
response[0] = 0x11; // mark error - real DS2413 don't do this |
|
} |
|
response[1] = getstatus(); // DS2413 expects an update of new status |
|
OWSlave.beginWrite((const byte*)response, 2, 0); |
|
state = DS_WaitingCommand; |
|
break; |
|
|
|
} // end switch state |
|
break; |
|
|
|
|
|
|
|
case OneWireSlave::RE_Reset: |
|
state = DS_WaitingCommand; |
|
break; |
|
|
|
case OneWireSlave::RE_Error: |
|
state = DS_WaitingReset; |
|
break; |
|
} // end switch evt |
|
}
|
|
|