#include <TimerOne.h>
#define DATA_IN 4
#define TICK_LENGTH 50
#define PAUSE_TICKS 3500/TICK_LENGTH
#define HIGH_TICK_TIME 500/TICK_LENGTH
#define ONE_TICK_TIME 1500/TICK_LENGTH
#define ZERO_TICK_TIME 500/TICK_LENGTH
#define MIN_DATA_SENDING_INTERVAL 100
#define LOWER_LIMIT 0.7
#define UPPER_LIMIT 1.3
volatile unsigned long lastDataSendTime = 0;
volatile byte dataInState;
volatile byte currentPulseTicks = 0;
struct RawData {
bool receivingData = false;
byte currentPulse = 0;
byte currentBit = 0;
byte data[5];
bool finished = false;
};
volatile RawData rawData;
void setup()
{
pinMode(DATA_IN, INPUT_PULLUP);
pinMode(LED_BUILTIN, OUTPUT);
Timer1.initialize(TICK_LENGTH);
Timer1.attachInterrupt(timerTick);
dataInState = digitalRead(DATA_IN);
lastDataSendTime = millis();
Serial.begin(9600);
}
void loop()
{
digitalWrite(LED_BUILTIN, dataInState);
if (!rawData.finished) return; //nothing to do now
if (millis() - lastDataSendTime > MIN_DATA_SENDING_INTERVAL) {
float temperatures[2];
decodeTemperatures(temperatures);
Serial.print("Temp1: ");
Serial.print(temperatures[0]);
Serial.print("; Temp2: ");
Serial.println(temperatures[1]);
lastDataSendTime = millis();
}
clearRawData();
}
void decodeTemperatures(float temperatures[]) {
temperatures[0] = rawData.data[1];
temperatures[0] += (rawData.data[2] & 0xF0) << 4;
temperatures[0] = temperatures[0] / 10 - 20;
temperatures[1] = rawData.data[3];
temperatures[1] += (rawData.data[2] & 0x0F) << 8;
temperatures[1] = temperatures[1] / 10 - 20;
}
void timerTick(void) {
if (rawData.finished) return; //data received, wait untill data is sent
currentPulseTicks++;
if (dataInState != digitalRead(DATA_IN)) { //state of DATA_IN pin has changed
handleInputPinStateChanged();
}
else {
if (currentPulseTicks > 250) {
clearRawData();
currentPulseTicks = 0;
}
}
}
void handleInputPinStateChanged() {
dataInState = !dataInState;
if (!rawData.receivingData) { // not receiving data, but waiting for beginning
if (curentPulseIsBeginning())
{
rawData.receivingData = true;
}
else {
clearRawData();
}
currentPulseTicks = 0;
return;
}
if (itsTimeForIntervalPulse()) {
if (currentPulseIsInterval())
{
rawData.currentPulse++;
}
else {
clearRawData();
}
currentPulseTicks = 0;
return;
}
if (currentPulseMeansOne())
{
setCurrentBit(1);
}
else if (currentPulseMeansZero())
{
setCurrentBit(0);
}
else {
clearRawData();
currentPulseTicks = 0;
return;
}
rawData.currentBit++;
rawData.currentPulse++;
currentPulseTicks = 0;
if (rawData.currentBit > 39) {
rawData.finished = true;
}
}
bool curentPulseIsBeginning() {
return currentPulseTicks > PAUSE_TICKS * LOWER_LIMIT
&& currentPulseTicks < PAUSE_TICKS * UPPER_LIMIT;
}
bool itsTimeForIntervalPulse() { //even impulses are intervals between data impulses
return rawData.currentPulse % 2 == 0;
}
bool currentPulseMeansZero() {
return currentPulseTicks > ZERO_TICK_TIME * LOWER_LIMIT
&& currentPulseTicks < ZERO_TICK_TIME * UPPER_LIMIT;
}
bool currentPulseMeansOne() {
return currentPulseTicks > ONE_TICK_TIME * LOWER_LIMIT
&& currentPulseTicks < ONE_TICK_TIME * UPPER_LIMIT;
}
bool currentPulseIsInterval() {
return currentPulseTicks > HIGH_TICK_TIME * LOWER_LIMIT
&& currentPulseTicks < HIGH_TICK_TIME * UPPER_LIMIT;
}
void setCurrentBit(int value) {
if (value == 1) {
rawData.data[(rawData.currentBit) / 8] |= 1 << 7 - (rawData.currentBit % 8);
}
else {
rawData.data[rawData.currentBit / 8] &= ~(1 << 7 - (rawData.currentBit % 8));
}
}
void clearRawData() {
rawData.currentBit = 0;
rawData.currentPulse = 0;
rawData.finished = false;
rawData.receivingData = false;
}