Youen Toupin
10 years ago
4 changed files with 509 additions and 401 deletions
@ -0,0 +1,434 @@ |
|||||||
|
#include "Arduino.h" |
||||||
|
#include "LowLevel.h" |
||||||
|
#include "SerialChannel.h" |
||||||
|
|
||||||
|
#define LEDPin 13 |
||||||
|
#define OWPin 2 |
||||||
|
#define InterruptNumber 0 // Must correspond to the OWPin to correctly detect state changes. On Arduino Uno, interrupt 0 is for digital pin 2
|
||||||
|
|
||||||
|
#define ResetMinDuration 480 |
||||||
|
#define ResetMaxDuration 900 |
||||||
|
|
||||||
|
#define PresenceWaitDuration 30 |
||||||
|
#define PresenceDuration 300 |
||||||
|
|
||||||
|
#define ReadBitSamplingTime 13 // the theorical time is about 30us, but given various overhead, this is the empirical delay I've found works best (on Arduino Uno)
|
||||||
|
|
||||||
|
#define SendBitDuration 35 |
||||||
|
|
||||||
|
const byte InvalidBit = (byte)-1; |
||||||
|
const byte IncompleteBit = (byte)-2; |
||||||
|
|
||||||
|
SerialChannel debug("debug"); |
||||||
|
|
||||||
|
Pin owPin(OWPin); |
||||||
|
Pin owOutTestPin(3); |
||||||
|
Pin led(LEDPin); |
||||||
|
|
||||||
|
enum OwStatus |
||||||
|
{ |
||||||
|
OS_WaitReset, |
||||||
|
OS_Presence, |
||||||
|
OS_WaitCommand, |
||||||
|
OS_SearchRom, |
||||||
|
}; |
||||||
|
OwStatus status; |
||||||
|
|
||||||
|
byte owROM[8] = { 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00 }; |
||||||
|
byte searchROMCurrentByte = 0; |
||||||
|
byte searchROMCurrentBit = 0; |
||||||
|
bool searchROMSendingInverse = false; |
||||||
|
bool searchROMReadingMasterResponseBit = false; |
||||||
|
|
||||||
|
void owPullLow() |
||||||
|
{ |
||||||
|
owPin.outputMode(); |
||||||
|
owPin.writeLow(); |
||||||
|
owOutTestPin.writeLow(); |
||||||
|
} |
||||||
|
|
||||||
|
void owRelease() |
||||||
|
{ |
||||||
|
owPin.inputMode(); |
||||||
|
owOutTestPin.writeHigh(); |
||||||
|
} |
||||||
|
|
||||||
|
void onEnterInterrupt() |
||||||
|
{ |
||||||
|
//owOutTestPin.writeLow();
|
||||||
|
} |
||||||
|
|
||||||
|
void onLeaveInterrupt() |
||||||
|
{ |
||||||
|
//owOutTestPin.writeHigh();
|
||||||
|
} |
||||||
|
|
||||||
|
volatile unsigned long resetStart = (unsigned long)-1; |
||||||
|
unsigned long lastReset = (unsigned long)-1; |
||||||
|
unsigned long bitStart = (unsigned long)-1; |
||||||
|
byte receivingByte = 0; |
||||||
|
byte receivingBitPos = 0; |
||||||
|
bool searchRomNextBit = false; |
||||||
|
bool searchRomNextBitToSend = false; |
||||||
|
|
||||||
|
void setup() |
||||||
|
{ |
||||||
|
owROM[7] = crc8((char*)owROM, 7); |
||||||
|
|
||||||
|
led.outputMode(); |
||||||
|
owPin.inputMode(); |
||||||
|
owOutTestPin.outputMode(); |
||||||
|
owOutTestPin.writeHigh(); |
||||||
|
|
||||||
|
led.writeLow(); |
||||||
|
|
||||||
|
cli(); // disable interrupts
|
||||||
|
attachInterrupt(InterruptNumber, owWaitResetInterrupt, CHANGE); |
||||||
|
|
||||||
|
// set timer0 interrupt at 250KHz (actually depends on compare match register OCR0A)
|
||||||
|
// 4us between each tick
|
||||||
|
TCCR1A = 0; |
||||||
|
TCCR1B = 0; |
||||||
|
TCNT1 = 0; // initialize counter value to 0
|
||||||
|
//TCCR1B |= (1 << WGM12); // turn on CTC mode
|
||||||
|
//TCCR1B |= (1 << CS11) | (1 << CS10); // Set 64 prescaler
|
||||||
|
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
|
||||||
|
sei(); // enable interrupts
|
||||||
|
|
||||||
|
Serial.begin(9600); |
||||||
|
} |
||||||
|
|
||||||
|
int count = 0; |
||||||
|
void loop() |
||||||
|
{ |
||||||
|
if ((count++) % 1000 == 0) |
||||||
|
led.write(!led.read()); |
||||||
|
cli();//disable interrupts
|
||||||
|
SerialChannel::swap(); |
||||||
|
sei();//enable interrupts
|
||||||
|
|
||||||
|
SerialChannel::flush(); |
||||||
|
} |
||||||
|
|
||||||
|
void(*timerEvent)() = 0; |
||||||
|
void setTimerEvent(short microSecondsDelay, void(*event)()) |
||||||
|
{ |
||||||
|
microSecondsDelay -= 10; // this seems to be the typical time taken to initialize the timer on Arduino Uno
|
||||||
|
|
||||||
|
short skipTicks = (microSecondsDelay - 3) / 4; // round the micro seconds delay to a number of ticks to skip (4us per tick, so 4us must skip 0 tick, 8us must skip 1 tick, etc.)
|
||||||
|
if (skipTicks < 1) skipTicks = 1; |
||||||
|
//debug.SC_APPEND_STR_INT("setTimerEvent", (long)skipTicks);
|
||||||
|
TCNT1 = 0; |
||||||
|
OCR1A = skipTicks; |
||||||
|
timerEvent = event; |
||||||
|
TCCR1B = (1 << WGM12) | (1 << CS11) | (1 << CS10); // turn on CTC mode with 64 prescaler
|
||||||
|
} |
||||||
|
|
||||||
|
void owError(const char* message) |
||||||
|
{ |
||||||
|
debug.append(message); |
||||||
|
led.writeHigh(); |
||||||
|
status = OS_WaitReset; |
||||||
|
} |
||||||
|
|
||||||
|
void owClearError() |
||||||
|
{ |
||||||
|
led.writeLow(); |
||||||
|
} |
||||||
|
|
||||||
|
void owWaitResetInterrupt() |
||||||
|
{ |
||||||
|
onEnterInterrupt(); |
||||||
|
bool state = owPin.read(); |
||||||
|
unsigned long now = micros(); |
||||||
|
if (state) |
||||||
|
{ |
||||||
|
if (resetStart == (unsigned int)-1) |
||||||
|
{ |
||||||
|
onLeaveInterrupt(); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
unsigned long resetDuration = now - resetStart; |
||||||
|
resetStart = (unsigned int)-1; |
||||||
|
if (resetDuration >= ResetMinDuration) |
||||||
|
{ |
||||||
|
if (resetDuration > ResetMaxDuration) |
||||||
|
{ |
||||||
|
owError("Reset too long"); |
||||||
|
onLeaveInterrupt(); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
owClearError(); |
||||||
|
lastReset = now; |
||||||
|
status = OS_Presence; |
||||||
|
setTimerEvent(PresenceWaitDuration - (micros() - now), &beginPresence); |
||||||
|
} |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
resetStart = now; |
||||||
|
} |
||||||
|
onLeaveInterrupt(); |
||||||
|
} |
||||||
|
|
||||||
|
//bool debugState = false;
|
||||||
|
volatile unsigned long lastInterrupt = 0; |
||||||
|
void owReceiveCommandInterrupt(void) |
||||||
|
{ |
||||||
|
onEnterInterrupt(); |
||||||
|
unsigned long now = micros(); |
||||||
|
if (now < lastInterrupt + 20) |
||||||
|
{ |
||||||
|
onLeaveInterrupt(); |
||||||
|
return; // don't react to our own actions
|
||||||
|
} |
||||||
|
lastInterrupt = now; |
||||||
|
|
||||||
|
//debugState = !debugState;
|
||||||
|
//owOutTestPin.write(debugState);
|
||||||
|
|
||||||
|
//led.write(state);
|
||||||
|
|
||||||
|
bool bit = readBit(); |
||||||
|
/*if (bit)
|
||||||
|
debug.SC_APPEND_STR("received bit 1"); |
||||||
|
else |
||||||
|
debug.SC_APPEND_STR("received bit 0");*/ |
||||||
|
|
||||||
|
receivingByte |= ((bit ? 1 : 0) << receivingBitPos); |
||||||
|
++receivingBitPos; |
||||||
|
|
||||||
|
if (receivingBitPos == 8) |
||||||
|
{ |
||||||
|
byte receivedByte = receivingByte; |
||||||
|
receivingBitPos = 0; |
||||||
|
receivingByte = 0; |
||||||
|
//debug.SC_APPEND_STR_INT("received byte", (long)receivedByte);
|
||||||
|
|
||||||
|
if (status == OS_WaitCommand && receivedByte == 0xF0) |
||||||
|
{ |
||||||
|
status = OS_SearchRom; |
||||||
|
searchROMReadingMasterResponseBit = false; |
||||||
|
searchROMSendingInverse = false; |
||||||
|
searchROMCurrentByte = 0; |
||||||
|
searchROMCurrentBit = 0; |
||||||
|
byte currentByte = owROM[searchROMCurrentByte]; |
||||||
|
searchRomNextBit = bitRead(currentByte, searchROMCurrentBit); |
||||||
|
searchRomNextBitToSend = searchROMSendingInverse ? !searchRomNextBit : searchRomNextBit; |
||||||
|
//attachInterrupt(InterruptNumber, onewireInterruptSearchROM, FALLING);
|
||||||
|
setTimerEvent(10, owSearchSendBit); |
||||||
|
detachInterrupt(InterruptNumber); |
||||||
|
onLeaveInterrupt(); |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
onLeaveInterrupt(); |
||||||
|
} |
||||||
|
|
||||||
|
bool ignoreNextFallingEdge = false; |
||||||
|
|
||||||
|
void owSearchSendBit() |
||||||
|
{ |
||||||
|
onEnterInterrupt(); |
||||||
|
|
||||||
|
// wait for a falling edge (active wait is more reliable than interrupts to send the bit fast enough)
|
||||||
|
while (!owPin.read()); |
||||||
|
while (owPin.read()); |
||||||
|
|
||||||
|
//sendBit(searchRomNextBitToSend);
|
||||||
|
if (searchRomNextBitToSend) |
||||||
|
{ |
||||||
|
//delayMicroseconds(SendBitDuration);
|
||||||
|
ignoreNextFallingEdge = false; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
owPullLow(); |
||||||
|
//delayMicroseconds(SendBitDuration);
|
||||||
|
//owRelease();
|
||||||
|
ignoreNextFallingEdge = true; |
||||||
|
} |
||||||
|
|
||||||
|
unsigned long sendBitStart = micros(); |
||||||
|
|
||||||
|
if (searchROMSendingInverse) |
||||||
|
{ |
||||||
|
searchROMSendingInverse = false; |
||||||
|
searchROMReadingMasterResponseBit = true; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
searchROMSendingInverse = true; |
||||||
|
} |
||||||
|
|
||||||
|
byte currentByte = owROM[searchROMCurrentByte]; |
||||||
|
searchRomNextBit = bitRead(currentByte, searchROMCurrentBit); |
||||||
|
searchRomNextBitToSend = searchROMSendingInverse ? !searchRomNextBit : searchRomNextBit; |
||||||
|
|
||||||
|
if (searchROMReadingMasterResponseBit) |
||||||
|
{ |
||||||
|
ignoreNextFallingEdge = true; |
||||||
|
attachInterrupt(InterruptNumber, onewireInterruptSearchROM, FALLING); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
setTimerEvent(10, owSearchSendBit); |
||||||
|
} |
||||||
|
|
||||||
|
delayMicroseconds(SendBitDuration - (micros() - sendBitStart)); |
||||||
|
owRelease(); |
||||||
|
|
||||||
|
onLeaveInterrupt(); |
||||||
|
} |
||||||
|
|
||||||
|
void onewireInterruptSearchROM() |
||||||
|
{ |
||||||
|
onEnterInterrupt(); |
||||||
|
|
||||||
|
if (ignoreNextFallingEdge) |
||||||
|
{ |
||||||
|
ignoreNextFallingEdge = false; |
||||||
|
onLeaveInterrupt(); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (searchROMReadingMasterResponseBit) |
||||||
|
{ |
||||||
|
bool bit = readBit(); |
||||||
|
|
||||||
|
if (bit != searchRomNextBit) |
||||||
|
{ |
||||||
|
debug.SC_APPEND_STR("Master didn't send our bit, leaving ROM search"); |
||||||
|
status = OS_WaitReset; |
||||||
|
attachInterrupt(InterruptNumber, owWaitResetInterrupt, CHANGE); |
||||||
|
onLeaveInterrupt(); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
searchROMReadingMasterResponseBit = false; |
||||||
|
++searchROMCurrentBit; |
||||||
|
if (searchROMCurrentBit == 8) |
||||||
|
{ |
||||||
|
++searchROMCurrentByte; |
||||||
|
searchROMCurrentBit = 0; |
||||||
|
//debug.SC_APPEND_STR("sent another ROM byte");
|
||||||
|
} |
||||||
|
|
||||||
|
if (searchROMCurrentByte == 8) |
||||||
|
{ |
||||||
|
searchROMCurrentByte = 0; |
||||||
|
status = OS_WaitReset; |
||||||
|
debug.SC_APPEND_STR("ROM sent entirely"); |
||||||
|
attachInterrupt(InterruptNumber, owWaitResetInterrupt, CHANGE); |
||||||
|
onLeaveInterrupt(); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
byte currentByte = owROM[searchROMCurrentByte]; |
||||||
|
searchRomNextBit = bitRead(currentByte, searchROMCurrentBit); |
||||||
|
searchRomNextBitToSend = searchROMSendingInverse ? !searchRomNextBit : searchRomNextBit; |
||||||
|
|
||||||
|
setTimerEvent(10, owSearchSendBit); |
||||||
|
detachInterrupt(InterruptNumber); |
||||||
|
onLeaveInterrupt(); |
||||||
|
return; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
sendBit(searchRomNextBitToSend); |
||||||
|
/*if (bitToSend)
|
||||||
|
debug.SC_APPEND_STR("sent ROM search bit : 1"); |
||||||
|
else |
||||||
|
debug.SC_APPEND_STR("sent ROM search bit : 0");*/ |
||||||
|
|
||||||
|
if (searchROMSendingInverse) |
||||||
|
{ |
||||||
|
searchROMSendingInverse = false; |
||||||
|
searchROMReadingMasterResponseBit = true; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
searchROMSendingInverse = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
byte currentByte = owROM[searchROMCurrentByte]; |
||||||
|
searchRomNextBit = bitRead(currentByte, searchROMCurrentBit); |
||||||
|
searchRomNextBitToSend = searchROMSendingInverse ? !searchRomNextBit : searchRomNextBit; |
||||||
|
|
||||||
|
onLeaveInterrupt(); |
||||||
|
} |
||||||
|
|
||||||
|
bool readBit() |
||||||
|
{ |
||||||
|
delayMicroseconds(ReadBitSamplingTime); |
||||||
|
bool bit = owPin.read(); |
||||||
|
//owOutTestPin.write(!owOutTestPin.read());
|
||||||
|
//owOutTestPin.write(!owOutTestPin.read());
|
||||||
|
return bit; |
||||||
|
} |
||||||
|
|
||||||
|
void sendBit(bool bit) |
||||||
|
{ |
||||||
|
if (bit) |
||||||
|
{ |
||||||
|
delayMicroseconds(SendBitDuration); |
||||||
|
ignoreNextFallingEdge = false; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
owPullLow(); |
||||||
|
delayMicroseconds(SendBitDuration); |
||||||
|
owRelease(); |
||||||
|
ignoreNextFallingEdge = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void beginPresence() |
||||||
|
{ |
||||||
|
unsigned long now = micros(); |
||||||
|
owPullLow(); |
||||||
|
setTimerEvent(PresenceDuration, &endPresence); |
||||||
|
debug.SC_APPEND_STR_TIME("reset", lastReset); |
||||||
|
debug.SC_APPEND_STR_TIME("beginPresence", now); |
||||||
|
} |
||||||
|
|
||||||
|
void endPresence() |
||||||
|
{ |
||||||
|
unsigned long now = micros(); |
||||||
|
owRelease(); |
||||||
|
debug.SC_APPEND_STR_TIME("endPresence", now); |
||||||
|
|
||||||
|
status = OS_WaitCommand; |
||||||
|
attachInterrupt(InterruptNumber, owReceiveCommandInterrupt, FALLING); |
||||||
|
receivingByte = 0; |
||||||
|
receivingBitPos = 0; |
||||||
|
bitStart = (unsigned long)-1; |
||||||
|
} |
||||||
|
|
||||||
|
ISR(TIMER1_COMPA_vect) // timer1 interrupt
|
||||||
|
{ |
||||||
|
TCCR1B = 0; // disable clock
|
||||||
|
void(*event)() = timerEvent; |
||||||
|
timerEvent = 0; |
||||||
|
if (event != 0) |
||||||
|
event(); |
||||||
|
} |
||||||
|
|
||||||
|
uint8_t crc8(char addr[], uint8_t len) { |
||||||
|
uint8_t crc = 0; |
||||||
|
|
||||||
|
while (len--) { |
||||||
|
uint8_t inbyte = *addr++; |
||||||
|
for (uint8_t i = 8; i; i--) { |
||||||
|
uint8_t mix = (crc ^ inbyte) & 0x01; |
||||||
|
crc >>= 1; |
||||||
|
if (mix) crc ^= 0x8C; |
||||||
|
inbyte >>= 1; |
||||||
|
} |
||||||
|
} |
||||||
|
return crc; |
||||||
|
} |
@ -1,434 +1,49 @@ |
|||||||
#include "Arduino.h" |
#include "Arduino.h" |
||||||
#include "LowLevel.h" |
#include "LowLevel.h" |
||||||
#include "SerialChannel.h" |
#include "SerialChannel.h" |
||||||
|
#include "OneWireSlave.h" |
||||||
|
|
||||||
#define LEDPin 13 |
#define LEDPin 13 |
||||||
#define OWPin 2 |
#define OWPin 2 |
||||||
#define InterruptNumber 0 // Must correspond to the OWPin to correctly detect state changes. On Arduino Uno, interrupt 0 is for digital pin 2
|
|
||||||
|
|
||||||
#define ResetMinDuration 480 |
|
||||||
#define ResetMaxDuration 900 |
|
||||||
|
|
||||||
#define PresenceWaitDuration 30 |
|
||||||
#define PresenceDuration 300 |
|
||||||
|
|
||||||
#define ReadBitSamplingTime 13 // the theorical time is about 30us, but given various overhead, this is the empirical delay I've found works best (on Arduino Uno)
|
|
||||||
|
|
||||||
#define SendBitDuration 35 |
|
||||||
|
|
||||||
const byte InvalidBit = (byte)-1; |
|
||||||
const byte IncompleteBit = (byte)-2; |
|
||||||
|
|
||||||
SerialChannel debug("debug"); |
SerialChannel debug("debug"); |
||||||
|
|
||||||
Pin owPin(OWPin); |
|
||||||
Pin owOutTestPin(3); |
|
||||||
Pin led(LEDPin); |
Pin led(LEDPin); |
||||||
|
|
||||||
enum OwStatus |
byte owROM[7] = { 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }; |
||||||
{ |
OneWireSlave oneWire(owROM, OWPin); |
||||||
OS_WaitReset, |
|
||||||
OS_Presence, |
|
||||||
OS_WaitCommand, |
|
||||||
OS_SearchRom, |
|
||||||
}; |
|
||||||
OwStatus status; |
|
||||||
|
|
||||||
byte owROM[8] = { 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00 }; |
|
||||||
byte searchROMCurrentByte = 0; |
|
||||||
byte searchROMCurrentBit = 0; |
|
||||||
bool searchROMSendingInverse = false; |
|
||||||
bool searchROMReadingMasterResponseBit = false; |
|
||||||
|
|
||||||
void owPullLow() |
|
||||||
{ |
|
||||||
owPin.outputMode(); |
|
||||||
owPin.writeLow(); |
|
||||||
owOutTestPin.writeLow(); |
|
||||||
} |
|
||||||
|
|
||||||
void owRelease() |
|
||||||
{ |
|
||||||
owPin.inputMode(); |
|
||||||
owOutTestPin.writeHigh(); |
|
||||||
} |
|
||||||
|
|
||||||
void onEnterInterrupt() |
|
||||||
{ |
|
||||||
//owOutTestPin.writeLow();
|
|
||||||
} |
|
||||||
|
|
||||||
void onLeaveInterrupt() |
|
||||||
{ |
|
||||||
//owOutTestPin.writeHigh();
|
|
||||||
} |
|
||||||
|
|
||||||
volatile unsigned long resetStart = (unsigned long)-1; |
|
||||||
unsigned long lastReset = (unsigned long)-1; |
|
||||||
unsigned long bitStart = (unsigned long)-1; |
|
||||||
byte receivingByte = 0; |
|
||||||
byte receivingBitPos = 0; |
|
||||||
bool searchRomNextBit = false; |
|
||||||
bool searchRomNextBitToSend = false; |
|
||||||
|
|
||||||
void setup() |
void setup() |
||||||
{ |
{ |
||||||
owROM[7] = crc8((char*)owROM, 7); |
|
||||||
|
|
||||||
led.outputMode(); |
led.outputMode(); |
||||||
owPin.inputMode(); |
|
||||||
owOutTestPin.outputMode(); |
|
||||||
owOutTestPin.writeHigh(); |
|
||||||
|
|
||||||
led.writeLow(); |
led.writeLow(); |
||||||
|
|
||||||
cli(); // disable interrupts
|
oneWire.enable(); |
||||||
attachInterrupt(InterruptNumber, owWaitResetInterrupt, CHANGE); |
|
||||||
|
|
||||||
// set timer0 interrupt at 250KHz (actually depends on compare match register OCR0A)
|
|
||||||
// 4us between each tick
|
|
||||||
TCCR1A = 0; |
|
||||||
TCCR1B = 0; |
|
||||||
TCNT1 = 0; // initialize counter value to 0
|
|
||||||
//TCCR1B |= (1 << WGM12); // turn on CTC mode
|
|
||||||
//TCCR1B |= (1 << CS11) | (1 << CS10); // Set 64 prescaler
|
|
||||||
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
|
|
||||||
sei(); // enable interrupts
|
|
||||||
|
|
||||||
Serial.begin(9600); |
Serial.begin(9600); |
||||||
} |
} |
||||||
|
|
||||||
int count = 0; |
//int count = 0;
|
||||||
void loop() |
void loop() |
||||||
{ |
{ |
||||||
if ((count++) % 1000 == 0) |
/*if (count++ == 10000)
|
||||||
|
{ |
||||||
led.write(!led.read()); |
led.write(!led.read()); |
||||||
|
count = 0; |
||||||
|
}*/ |
||||||
|
|
||||||
cli();//disable interrupts
|
cli();//disable interrupts
|
||||||
SerialChannel::swap(); |
SerialChannel::swap(); |
||||||
sei();//enable interrupts
|
sei();//enable interrupts
|
||||||
|
|
||||||
SerialChannel::flush(); |
SerialChannel::flush(); |
||||||
} |
|
||||||
|
|
||||||
void(*timerEvent)() = 0; |
|
||||||
void setTimerEvent(short microSecondsDelay, void(*event)()) |
|
||||||
{ |
|
||||||
microSecondsDelay -= 10; // this seems to be the typical time taken to initialize the timer on Arduino Uno
|
|
||||||
|
|
||||||
short skipTicks = (microSecondsDelay - 3) / 4; // round the micro seconds delay to a number of ticks to skip (4us per tick, so 4us must skip 0 tick, 8us must skip 1 tick, etc.)
|
|
||||||
if (skipTicks < 1) skipTicks = 1; |
|
||||||
//debug.SC_APPEND_STR_INT("setTimerEvent", (long)skipTicks);
|
|
||||||
TCNT1 = 0; |
|
||||||
OCR1A = skipTicks; |
|
||||||
timerEvent = event; |
|
||||||
TCCR1B = (1 << WGM12) | (1 << CS11) | (1 << CS10); // turn on CTC mode with 64 prescaler
|
|
||||||
} |
|
||||||
|
|
||||||
void owError(const char* message) |
|
||||||
{ |
|
||||||
debug.append(message); |
|
||||||
led.writeHigh(); |
|
||||||
status = OS_WaitReset; |
|
||||||
} |
|
||||||
|
|
||||||
void owClearError() |
|
||||||
{ |
|
||||||
led.writeLow(); |
|
||||||
} |
|
||||||
|
|
||||||
void owWaitResetInterrupt() |
|
||||||
{ |
|
||||||
onEnterInterrupt(); |
|
||||||
bool state = owPin.read(); |
|
||||||
unsigned long now = micros(); |
|
||||||
if (state) |
|
||||||
{ |
|
||||||
if (resetStart == (unsigned int)-1) |
|
||||||
{ |
|
||||||
onLeaveInterrupt(); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
unsigned long resetDuration = now - resetStart; |
|
||||||
resetStart = (unsigned int)-1; |
|
||||||
if (resetDuration >= ResetMinDuration) |
|
||||||
{ |
|
||||||
if (resetDuration > ResetMaxDuration) |
|
||||||
{ |
|
||||||
owError("Reset too long"); |
|
||||||
onLeaveInterrupt(); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
owClearError(); |
|
||||||
lastReset = now; |
|
||||||
status = OS_Presence; |
|
||||||
setTimerEvent(PresenceWaitDuration - (micros() - now), &beginPresence); |
|
||||||
} |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
resetStart = now; |
|
||||||
} |
|
||||||
onLeaveInterrupt(); |
|
||||||
} |
|
||||||
|
|
||||||
//bool debugState = false;
|
|
||||||
volatile unsigned long lastInterrupt = 0; |
|
||||||
void owReceiveCommandInterrupt(void) |
|
||||||
{ |
|
||||||
onEnterInterrupt(); |
|
||||||
unsigned long now = micros(); |
|
||||||
if (now < lastInterrupt + 20) |
|
||||||
{ |
|
||||||
onLeaveInterrupt(); |
|
||||||
return; // don't react to our own actions
|
|
||||||
} |
|
||||||
lastInterrupt = now; |
|
||||||
|
|
||||||
//debugState = !debugState;
|
|
||||||
//owOutTestPin.write(debugState);
|
|
||||||
|
|
||||||
//led.write(state);
|
|
||||||
|
|
||||||
bool bit = readBit(); |
|
||||||
/*if (bit)
|
|
||||||
debug.SC_APPEND_STR("received bit 1"); |
|
||||||
else |
|
||||||
debug.SC_APPEND_STR("received bit 0");*/ |
|
||||||
|
|
||||||
receivingByte |= ((bit ? 1 : 0) << receivingBitPos); |
|
||||||
++receivingBitPos; |
|
||||||
|
|
||||||
if (receivingBitPos == 8) |
|
||||||
{ |
|
||||||
byte receivedByte = receivingByte; |
|
||||||
receivingBitPos = 0; |
|
||||||
receivingByte = 0; |
|
||||||
//debug.SC_APPEND_STR_INT("received byte", (long)receivedByte);
|
|
||||||
|
|
||||||
if (status == OS_WaitCommand && receivedByte == 0xF0) |
|
||||||
{ |
|
||||||
status = OS_SearchRom; |
|
||||||
searchROMReadingMasterResponseBit = false; |
|
||||||
searchROMSendingInverse = false; |
|
||||||
searchROMCurrentByte = 0; |
|
||||||
searchROMCurrentBit = 0; |
|
||||||
byte currentByte = owROM[searchROMCurrentByte]; |
|
||||||
searchRomNextBit = bitRead(currentByte, searchROMCurrentBit); |
|
||||||
searchRomNextBitToSend = searchROMSendingInverse ? !searchRomNextBit : searchRomNextBit; |
|
||||||
//attachInterrupt(InterruptNumber, onewireInterruptSearchROM, FALLING);
|
|
||||||
setTimerEvent(10, owSearchSendBit); |
|
||||||
detachInterrupt(InterruptNumber); |
|
||||||
onLeaveInterrupt(); |
|
||||||
return; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
onLeaveInterrupt(); |
|
||||||
} |
|
||||||
|
|
||||||
bool ignoreNextFallingEdge = false; |
|
||||||
|
|
||||||
void owSearchSendBit() |
byte b; |
||||||
{ |
if (oneWire.read(b)) |
||||||
onEnterInterrupt(); |
|
||||||
|
|
||||||
// wait for a falling edge (active wait is more reliable than interrupts to send the bit fast enough)
|
|
||||||
while (!owPin.read()); |
|
||||||
while (owPin.read()); |
|
||||||
|
|
||||||
//sendBit(searchRomNextBitToSend);
|
|
||||||
if (searchRomNextBitToSend) |
|
||||||
{ |
|
||||||
//delayMicroseconds(SendBitDuration);
|
|
||||||
ignoreNextFallingEdge = false; |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
owPullLow(); |
|
||||||
//delayMicroseconds(SendBitDuration);
|
|
||||||
//owRelease();
|
|
||||||
ignoreNextFallingEdge = true; |
|
||||||
} |
|
||||||
|
|
||||||
unsigned long sendBitStart = micros(); |
|
||||||
|
|
||||||
if (searchROMSendingInverse) |
|
||||||
{ |
|
||||||
searchROMSendingInverse = false; |
|
||||||
searchROMReadingMasterResponseBit = true; |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
searchROMSendingInverse = true; |
|
||||||
} |
|
||||||
|
|
||||||
byte currentByte = owROM[searchROMCurrentByte]; |
|
||||||
searchRomNextBit = bitRead(currentByte, searchROMCurrentBit); |
|
||||||
searchRomNextBitToSend = searchROMSendingInverse ? !searchRomNextBit : searchRomNextBit; |
|
||||||
|
|
||||||
if (searchROMReadingMasterResponseBit) |
|
||||||
{ |
|
||||||
ignoreNextFallingEdge = true; |
|
||||||
attachInterrupt(InterruptNumber, onewireInterruptSearchROM, FALLING); |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
setTimerEvent(10, owSearchSendBit); |
|
||||||
} |
|
||||||
|
|
||||||
delayMicroseconds(SendBitDuration - (micros() - sendBitStart)); |
|
||||||
owRelease(); |
|
||||||
|
|
||||||
onLeaveInterrupt(); |
|
||||||
} |
|
||||||
|
|
||||||
void onewireInterruptSearchROM() |
|
||||||
{ |
|
||||||
onEnterInterrupt(); |
|
||||||
|
|
||||||
if (ignoreNextFallingEdge) |
|
||||||
{ |
|
||||||
ignoreNextFallingEdge = false; |
|
||||||
onLeaveInterrupt(); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
if (searchROMReadingMasterResponseBit) |
|
||||||
{ |
|
||||||
bool bit = readBit(); |
|
||||||
|
|
||||||
if (bit != searchRomNextBit) |
|
||||||
{ |
|
||||||
debug.SC_APPEND_STR("Master didn't send our bit, leaving ROM search"); |
|
||||||
status = OS_WaitReset; |
|
||||||
attachInterrupt(InterruptNumber, owWaitResetInterrupt, CHANGE); |
|
||||||
onLeaveInterrupt(); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
searchROMReadingMasterResponseBit = false; |
|
||||||
++searchROMCurrentBit; |
|
||||||
if (searchROMCurrentBit == 8) |
|
||||||
{ |
|
||||||
++searchROMCurrentByte; |
|
||||||
searchROMCurrentBit = 0; |
|
||||||
//debug.SC_APPEND_STR("sent another ROM byte");
|
|
||||||
} |
|
||||||
|
|
||||||
if (searchROMCurrentByte == 8) |
|
||||||
{ |
|
||||||
searchROMCurrentByte = 0; |
|
||||||
status = OS_WaitReset; |
|
||||||
debug.SC_APPEND_STR("ROM sent entirely"); |
|
||||||
attachInterrupt(InterruptNumber, owWaitResetInterrupt, CHANGE); |
|
||||||
onLeaveInterrupt(); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
byte currentByte = owROM[searchROMCurrentByte]; |
|
||||||
searchRomNextBit = bitRead(currentByte, searchROMCurrentBit); |
|
||||||
searchRomNextBitToSend = searchROMSendingInverse ? !searchRomNextBit : searchRomNextBit; |
|
||||||
|
|
||||||
setTimerEvent(10, owSearchSendBit); |
|
||||||
detachInterrupt(InterruptNumber); |
|
||||||
onLeaveInterrupt(); |
|
||||||
return; |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
sendBit(searchRomNextBitToSend); |
|
||||||
/*if (bitToSend)
|
|
||||||
debug.SC_APPEND_STR("sent ROM search bit : 1"); |
|
||||||
else |
|
||||||
debug.SC_APPEND_STR("sent ROM search bit : 0");*/ |
|
||||||
|
|
||||||
if (searchROMSendingInverse) |
|
||||||
{ |
|
||||||
searchROMSendingInverse = false; |
|
||||||
searchROMReadingMasterResponseBit = true; |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
searchROMSendingInverse = true; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
byte currentByte = owROM[searchROMCurrentByte]; |
|
||||||
searchRomNextBit = bitRead(currentByte, searchROMCurrentBit); |
|
||||||
searchRomNextBitToSend = searchROMSendingInverse ? !searchRomNextBit : searchRomNextBit; |
|
||||||
|
|
||||||
onLeaveInterrupt(); |
|
||||||
} |
|
||||||
|
|
||||||
bool readBit() |
|
||||||
{ |
|
||||||
delayMicroseconds(ReadBitSamplingTime); |
|
||||||
bool bit = owPin.read(); |
|
||||||
//owOutTestPin.write(!owOutTestPin.read());
|
|
||||||
//owOutTestPin.write(!owOutTestPin.read());
|
|
||||||
return bit; |
|
||||||
} |
|
||||||
|
|
||||||
void sendBit(bool bit) |
|
||||||
{ |
|
||||||
if (bit) |
|
||||||
{ |
{ |
||||||
delayMicroseconds(SendBitDuration); |
char msg[32]; |
||||||
ignoreNextFallingEdge = false; |
sprintf(msg, "Received byte : %d", (int)b); |
||||||
} |
debug.write(msg); |
||||||
else |
|
||||||
{ |
|
||||||
owPullLow(); |
|
||||||
delayMicroseconds(SendBitDuration); |
|
||||||
owRelease(); |
|
||||||
ignoreNextFallingEdge = true; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void beginPresence() |
|
||||||
{ |
|
||||||
unsigned long now = micros(); |
|
||||||
owPullLow(); |
|
||||||
setTimerEvent(PresenceDuration, &endPresence); |
|
||||||
debug.SC_APPEND_STR_TIME("reset", lastReset); |
|
||||||
debug.SC_APPEND_STR_TIME("beginPresence", now); |
|
||||||
} |
|
||||||
|
|
||||||
void endPresence() |
|
||||||
{ |
|
||||||
unsigned long now = micros(); |
|
||||||
owRelease(); |
|
||||||
debug.SC_APPEND_STR_TIME("endPresence", now); |
|
||||||
|
|
||||||
status = OS_WaitCommand; |
|
||||||
attachInterrupt(InterruptNumber, owReceiveCommandInterrupt, FALLING); |
|
||||||
receivingByte = 0; |
|
||||||
receivingBitPos = 0; |
|
||||||
bitStart = (unsigned long)-1; |
|
||||||
} |
|
||||||
|
|
||||||
ISR(TIMER1_COMPA_vect) // timer1 interrupt
|
|
||||||
{ |
|
||||||
TCCR1B = 0; // disable clock
|
|
||||||
void(*event)() = timerEvent; |
|
||||||
timerEvent = 0; |
|
||||||
if (event != 0) |
|
||||||
event(); |
|
||||||
} |
|
||||||
|
|
||||||
uint8_t crc8(char addr[], uint8_t len) { |
|
||||||
uint8_t crc = 0; |
|
||||||
|
|
||||||
while (len--) { |
|
||||||
uint8_t inbyte = *addr++; |
|
||||||
for (uint8_t i = 8; i; i--) { |
|
||||||
uint8_t mix = (crc ^ inbyte) & 0x01; |
|
||||||
crc >>= 1; |
|
||||||
if (mix) crc ^= 0x8C; |
|
||||||
inbyte >>= 1; |
|
||||||
} |
|
||||||
} |
} |
||||||
return crc; |
|
||||||
} |
} |
||||||
|
@ -0,0 +1,31 @@ |
|||||||
|
#include "OneWireSlave.h" |
||||||
|
|
||||||
|
OneWireSlave::OneWireSlave(byte* rom, byte pinNumber) |
||||||
|
{ |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
void OneWireSlave::enable() |
||||||
|
{ |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
void OneWireSlave::disable() |
||||||
|
{ |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
bool OneWireSlave::read(byte& b) |
||||||
|
{ |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
void OneWireSlave::setReceiveCallback(void(*callback)()) |
||||||
|
{ |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
void OneWireSlave::write(byte* bytes, short numBytes, void(*complete)(bool error)) |
||||||
|
{ |
||||||
|
|
||||||
|
} |
@ -0,0 +1,28 @@ |
|||||||
|
#ifndef _OneWireSlave_h_ |
||||||
|
#define _OneWireSlave_h_ |
||||||
|
|
||||||
|
#include "Arduino.h" |
||||||
|
|
||||||
|
class OneWireSlave |
||||||
|
{ |
||||||
|
public: |
||||||
|
///! Constructs a 1-wire slave that will be identified by the specified ROM (7 bytes, starting from the family code, CRC will be computed internally). Call enable to actually start listening for the 1-wire master.
|
||||||
|
OneWireSlave(byte* rom, byte pinNumber); |
||||||
|
|
||||||
|
///! Starts listening for the 1-wire master. Reset, Presence and SearchRom are handled automatically. The library will use interrupts on the pin specified in the constructor, as well as one hardware timer. Blocking interrupts (either by disabling them explicitely with sei/cli, or by spending time in another interrupt) can lead to malfunction of the library, due to tight timing for some 1-wire operations.
|
||||||
|
void enable(); |
||||||
|
|
||||||
|
///! Stops all 1-wire activities, which frees hardware resources for other purposes.
|
||||||
|
void disable(); |
||||||
|
|
||||||
|
///! Pops one byte from the receive buffer, or returns false if no byte has been received.
|
||||||
|
bool read(byte& b); |
||||||
|
|
||||||
|
///! Sets (or replaces) a function to be called when at least one byte has been received. Callbacks are executed from interrupts and should be as short as possible.
|
||||||
|
void setReceiveCallback(void(*callback)()); |
||||||
|
|
||||||
|
///! Enqueues the specified bytes in the send buffer. They will be sent in the background. The optional callback is used to notify when the bytes are sent, or if an error occured. Callbacks are executed from interrupts and should be as short as possible.
|
||||||
|
void write(byte* bytes, short numBytes, void(*complete)(bool error)); |
||||||
|
}; |
||||||
|
|
||||||
|
#endif |
Loading…
Reference in new issue