An arduino library to communicate using the Dallas one-wire protocol, where the Arduino takes the role of a slave. Implementation of a DS2413 on Arduino UNO and ATTINY85
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.

188 lines
5.0 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 or ATTINY85
// 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); // PB2 only attiny85 pin with rising/falling interrupts
//Pin led(0);
// 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, 0x55, 0xAA, 0x00, 0x11, 0x22 };
#define PIOA 3 // (pin 3)
#define PIOB 4 // (pin 4)
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();
// led.writeLow();
// OSCCAL = 85;
// 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.
sei();//enable interrupts
}
//////////////////////////////////////////
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 copy latch to EEPROM
}
//////////////////////////////////////////
void owReceive(OneWireSlave::ReceiveEvent evt, byte data)
{
switch (evt)
{
case OneWireSlave::RE_Byte:
switch (state)
{
case DS_WaitingCommand:
switch (data)
{
case DS2413_ACCESS_WRITE:
state = DS_WaitingStatus1;
break;
case DS2413_ACCESS_READ:
state = DS_WaitingReset;
scratchpad[0] = getstatus();
OWSlave.beginWrite((const byte*)scratchpad, 1, 0);
break;
//case :
// break;
}
break;
case DS_WaitingStatus1:
statusbyte1 = data;
state = DS_WaitingStatus2;
break;
case DS_WaitingStatus2:
statusbyte2 = data;
if (statusbyte1 != ~statusbyte2) {
set(statusbyte1);
response[0] = DS2413_ACK_SUCCESS;
} else {
response[0] = 0x11; // mark error - real DS2413 does not do this
}
response[1] = getstatus();
OWSlave.beginWrite((const byte*)response, 2, 0);
state = DS_WaitingCommand;
break;
}
break;
case OneWireSlave::RE_Reset:
state = DS_WaitingCommand;
break;
case OneWireSlave::RE_Error:
state = DS_WaitingReset;
break;
}
}